168 lines
5.7 KiB
Markdown
168 lines
5.7 KiB
Markdown
# 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`:
|
|
|
|
```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.
|