Files
bot-bottle/docs/prds/0045-workspace-porting-plan.md
didericis-codex a08829573d
test / unit (pull_request) Successful in 33s
test / integration (pull_request) Successful in 40s
docs(prd): activate workspace porting plan
2026-06-02 17:01:53 +00:00

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 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:

@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:

[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.