PRD 0045: Workspace Porting Plan #149
@@ -0,0 +1,167 @@
|
||||
# PRD 0045: Workspace Porting Plan
|
||||
|
||||
- **Status:** Draft
|
||||
- **Author:** didericis-codex
|
||||
- **Created:** 2026-06-02
|
||||
- **Issue:** #116
|
||||
|
||||
## Summary
|
||||
|
||||
Add a backend-neutral `WorkspacePlan` that describes how the operator's current
|
||||
workspace is represented inside a bottle. Docker and smolmachines should both
|
||||
use this plan for workspace path, working directory, content copy, `.git` copy,
|
||||
ownership, and provider trust configuration instead of rediscovering
|
||||
`/home/node/workspace` in separate launch and provisioning code paths.
|
||||
|
||||
## Problem
|
||||
|
||||
The current `--cwd` behavior is spread across backend-specific code:
|
||||
|
||||
- Docker builds a derived image that copies the host cwd to
|
||||
`/home/node/workspace`, sets that as `WORKDIR`, and patches Claude trust in
|
||||
the generated Dockerfile.
|
||||
- Docker git provisioning separately copies `.git` into
|
||||
`/home/node/workspace/.git`.
|
||||
- smolmachines git provisioning reconstructs `<guest_home>/workspace/.git`, but
|
||||
does not copy the full working tree.
|
||||
- Codex provider setup trusts `guest_home`, not the copied workspace path.
|
||||
|
||||
These details create backend drift and make provider-specific workspace fixes
|
||||
easy to hard-code in the wrong layer.
|
||||
|
||||
## Goals / Success Criteria
|
||||
|
||||
- `BottleSpec` remains the CLI intent shape (`copy_cwd`, `user_cwd`), while a
|
||||
resolved `WorkspacePlan` carries the backend-neutral guest workspace contract.
|
||||
- `BottlePlan` exposes `workspace_plan` so shared and backend-specific
|
||||
provisioning paths consume one resolved object.
|
||||
- The default in-bottle workspace path remains `/home/node/workspace` when
|
||||
`--cwd` is enabled.
|
||||
- Docker uses `WorkspacePlan` when building the derived cwd image and when
|
||||
provisioning cwd `.git` state.
|
||||
- smolmachines copies the host cwd contents into the same logical workspace
|
||||
path and uses `WorkspacePlan` when provisioning cwd `.git` state.
|
||||
- Provider trust configuration is written for the workspace path when `--cwd`
|
||||
is enabled, and for the guest home when `--cwd` is disabled.
|
||||
- Unit tests cover plan resolution, provider trust path selection, Docker
|
||||
derived image rendering, and both backends' `.git` copy targets.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- No new user-facing flags for custom workspace paths.
|
||||
- No manifest schema changes.
|
||||
- No redesign of git-gate or `bottle.git` entries.
|
||||
- No switch from Docker image-copy to bind-mount.
|
||||
- No unrelated provider auth changes.
|
||||
|
||||
## Scope
|
||||
|
||||
In scope:
|
||||
|
||||
- Add a small workspace planning module.
|
||||
- Add `workspace_plan` to `BottlePlan` and populate it in Docker and
|
||||
smolmachines prepare paths.
|
||||
- Thread the trusted project path into provider provisioning.
|
||||
- Replace hard-coded `/home/node/workspace` cwd copy and `.git` copy sites with
|
||||
`WorkspacePlan` values.
|
||||
- Copy full host cwd contents for smolmachines `--cwd` parity.
|
||||
- Update focused unit tests.
|
||||
|
||||
Out of scope:
|
||||
|
||||
- Integration tests that launch real Docker containers or smolmachines VMs.
|
||||
- Path customization in the bottle manifest or CLI.
|
||||
- Runtime synchronization after bottle launch; this remains a launch-time copy.
|
||||
|
||||
## Design
|
||||
|
||||
Add `bot_bottle/workspace.py`:
|
||||
|
||||
```python
|
||||
@dataclass(frozen=True)
|
||||
class WorkspacePlan:
|
||||
enabled: bool
|
||||
host_path: Path
|
||||
guest_home: str
|
||||
guest_path: str
|
||||
workdir: str
|
||||
owner: str = "node:node"
|
||||
mode: str = "755"
|
||||
copy_contents: bool = True
|
||||
copy_git: bool = True
|
||||
has_host_git_dir: bool = False
|
||||
```
|
||||
|
||||
`workspace_plan(spec, guest_home)` resolves:
|
||||
|
||||
- `enabled` from `spec.copy_cwd`.
|
||||
- `host_path` from `spec.user_cwd`.
|
||||
- `guest_path` as `<guest_home>/workspace` when enabled, else `guest_home`.
|
||||
- `workdir` as `guest_path` when enabled, else `guest_home`.
|
||||
- `has_host_git_dir` from `<host_path>/.git`.
|
||||
|
||||
Backends resolve this in `prepare` using their existing guest-home knobs:
|
||||
|
||||
- Docker: `BOT_BOTTLE_CONTAINER_HOME`, default `/home/node`.
|
||||
- smolmachines: `BOT_BOTTLE_GUEST_HOME`, default `/home/node`.
|
||||
|
||||
`BottlePlan` carries the result so launch, git provisioning, and provider
|
||||
provisioning stop consulting `spec.copy_cwd` and hard-coded paths directly.
|
||||
|
||||
### Docker
|
||||
|
||||
Keep the current derived-image transport. Change
|
||||
`build_image_with_cwd(derived, base, cwd)` to accept a `WorkspacePlan` or
|
||||
explicit guest path/workdir fields, then render:
|
||||
|
||||
- `COPY --chown=node:node . <workspace_plan.guest_path>`
|
||||
- `WORKDIR <workspace_plan.workdir>`
|
||||
|
||||
Claude trust should move out of the generated cwd Dockerfile and into provider
|
||||
provisioning so Docker and smolmachines share the same provider trust behavior.
|
||||
|
||||
### smolmachines
|
||||
|
||||
Copy host cwd contents into `workspace_plan.guest_path` during provisioning or
|
||||
VM initialization, then chown the resulting workspace to `node:node`. Continue
|
||||
to copy `.git` through the existing smolvm transport, but target
|
||||
`<workspace_plan.guest_path>/.git`.
|
||||
|
||||
This intentionally closes the current parity gap where smolmachines receives
|
||||
repo metadata without the working tree.
|
||||
|
||||
### Provider Trust
|
||||
|
||||
Extend provider planning with a `trusted_project_path` argument. Callers pass
|
||||
`workspace_plan.workdir`.
|
||||
|
||||
Codex writes:
|
||||
|
||||
```toml
|
||||
[projects."<trusted_project_path>"]
|
||||
trust_level = "trusted"
|
||||
```
|
||||
|
||||
Claude writes or updates `.claude.json` so `projects` includes
|
||||
`trusted_project_path` with `hasTrustDialogAccepted: true`. This provisioning
|
||||
belongs in `AgentProvisionPlan` so both backends apply it through their existing
|
||||
provider file-copy primitives.
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
- Unit-test `workspace_plan()` for enabled and disabled cwd, guest-home
|
||||
overrides, and `.git` detection.
|
||||
- Unit-test Docker cwd image rendering to prove it uses the plan's guest path
|
||||
and workdir.
|
||||
- Unit-test provider planning for Codex and Claude trusted project paths.
|
||||
- Unit-test Docker and smolmachines git provisioning targets using mocked copy
|
||||
and exec primitives.
|
||||
- Unit-test smolmachines workspace content copy target and ownership command.
|
||||
|
||||
Run:
|
||||
|
||||
- `python3 -m unittest discover -s tests/unit`
|
||||
|
||||
## Open Questions
|
||||
|
||||
None.
|
||||
Reference in New Issue
Block a user