5.7 KiB
PRD 0045: Workspace Porting Plan
- Status: Active
- 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 asWORKDIR, and patches Claude trust in the generated Dockerfile. - Docker git provisioning separately copies
.gitinto/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
BottleSpecremains the CLI intent shape (copy_cwd,user_cwd), while a resolvedWorkspacePlancarries the backend-neutral guest workspace contract.BottlePlanexposesworkspace_planso shared and backend-specific provisioning paths consume one resolved object.- The default in-bottle workspace path remains
/home/node/workspacewhen--cwdis enabled. - Docker uses
WorkspacePlanwhen building the derived cwd image and when provisioning cwd.gitstate. - smolmachines copies the host cwd contents into the same logical workspace
path and uses
WorkspacePlanwhen provisioning cwd.gitstate. - Provider trust configuration is written for the workspace path when
--cwdis enabled, and for the guest home when--cwdis disabled. - Unit tests cover plan resolution, provider trust path selection, Docker
derived image rendering, and both backends'
.gitcopy targets.
Non-goals
- No new user-facing flags for custom workspace paths.
- No manifest schema changes.
- No redesign of git-gate or
bottle.gitentries. - 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_plantoBottlePlanand populate it in Docker and smolmachines prepare paths. - Thread the trusted project path into provider provisioning.
- Replace hard-coded
/home/node/workspacecwd copy and.gitcopy sites withWorkspacePlanvalues. - Copy full host cwd contents for smolmachines
--cwdparity. - 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:
@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:
enabledfromspec.copy_cwd.host_pathfromspec.user_cwd.guest_pathas<guest_home>/workspacewhen enabled, elseguest_home.workdirasguest_pathwhen enabled, elseguest_home.has_host_git_dirfrom<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:
[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.gitdetection. - 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.