|
| 1 | +## Devcontainer Design — Requirements, Rationale, Implementation |
| 2 | + |
| 3 | +### Scope |
| 4 | + |
| 5 | +Define a layered devcontainer architecture for Agents‑Workflow: |
| 6 | + |
| 7 | +- A lower‑level Nix devcontainer base that standardizes Nix, caches, and host↔guest cache sharing. |
| 8 | +- An Agents Base Image that builds on the Nix base and ships all supported agentic CLIs plus the framework glue for task execution, recording, and credential propagation. |
| 9 | +- Downstream project images that extend the Agents Base Image by adding a project‑specific Nix devshell for building/testing that codebase. |
| 10 | + |
| 11 | +This document describes requirements, rationale, and implementation details. Nix base specifications live under `docs/nix-devcontainer/`. |
| 12 | + |
| 13 | +### Requirements |
| 14 | + |
| 15 | +- Provide a consistent developer experience across Linux, macOS, and Windows (Docker Desktop/WSL) with minimal host prerequisites. |
| 16 | +- Support all agentic CLIs integrated by agents‑workflow (see per‑agent docs under `docs/agents/`). |
| 17 | +- Implement credential propagation: when host is authenticated to a provider, the guest resolves the same credentials without re‑login. |
| 18 | +- Provide persistent build caches and Nix store layers across container rebuilds; enable optional host↔guest cache sharing for language package managers. |
| 19 | +- Integrate execution hooks needed by Agent Time‑Travel (timeline markers, snapshot triggers) without interfering with normal shell use. |
| 20 | +- Keep secrets out of images; use runtime env/secrets and read‑only mounts; be auditable. |
| 21 | + |
| 22 | +### Design Rationale |
| 23 | + |
| 24 | +- Layering separates concerns: |
| 25 | + - Nix base focuses on reproducibility and performant builds via shared caches. |
| 26 | + - Agents base concentrates agent tools, shell setup, recording hooks, and credential bridges. |
| 27 | + - Projects remain small: generally a `devcontainer.json` and a Nix devshell. |
| 28 | +- Nix is the lingua franca for project dependencies and toolchains; downstream projects reuse the same workflow regardless of language. |
| 29 | +- Cache sharing is opt‑in and explicit per package manager to avoid accidental leakage and permission issues. |
| 30 | +- Credential propagation prioritizes agent‑approved mechanisms (env vars, config files, OS agents) and relies on read‑only host mounts or forwarded sockets where feasible. |
| 31 | + |
| 32 | +### Layered Images |
| 33 | + |
| 34 | +1) Nix Devcontainer Base (see `docs/nix-devcontainer/`) |
| 35 | + - Installs Nix (flakes enabled), configures substituters/cachix. |
| 36 | + - Declares persistent volumes for `/nix`, Nix DB, and general caches. |
| 37 | + - Provides optional shared cache mounts for common package managers (npm/pnpm/yarn, pip/pipx, cargo, go, maven/gradle, etc.). |
| 38 | + - Exposes a thin entrypoint that sources project devshell when present. |
| 39 | + |
| 40 | +2) Agents Base Image |
| 41 | + - FROM: Nix Devcontainer Base. |
| 42 | + - Installs agentic CLIs supported by Agents‑Workflow (see `docs/agents/`). Examples include: OpenAI/Anthropic CLI tooling, GitHub CLI, and other agent runners referenced by `bin/*` and `*-setup` scripts. |
| 43 | + - Copies `bin/`, `common-pre-setup`, `common-post-setup`, and setup shims (`codex-setup`, `copilot-setup`, `open-hands-setup`, `goose-setup`, `jules-setup`). |
| 44 | + - Configures shell integration (zsh/bash/fish) to emit execution markers via preexec/DEBUG traps in support of time‑travel anchors. |
| 45 | + - Prepares netrc/SSH/gh credential bridges (runtime only; nothing baked into the image). |
| 46 | + |
| 47 | +3) Project Image |
| 48 | + - FROM: Agents Base Image. |
| 49 | + - Adds project `flake.nix`/`devshell` and any extra tools. |
| 50 | + - Optionally extends cache mounts for project‑specific package managers. |
| 51 | + |
| 52 | +### devcontainer.json (reference) |
| 53 | + |
| 54 | +Downstream projects consume the base like this (illustrative): |
| 55 | + |
| 56 | +```json |
| 57 | +{ |
| 58 | + "name": "agents-workflow-dev", |
| 59 | + "image": "ghcr.io/blocksense/agents-workflow-agents-base:latest", |
| 60 | + "features": {}, |
| 61 | + "remoteUser": "vscode", |
| 62 | + "updateRemoteUserUID": true, |
| 63 | + "containerEnv": { |
| 64 | + "ZDOTDIR": "/home/vscode/.zsh", |
| 65 | + "NIX_CONFIG": "experimental-features = nix-command flakes" |
| 66 | + }, |
| 67 | + "mounts": [ |
| 68 | + "source=aw-nix-store,target=/nix,type=volume", |
| 69 | + "source=aw-cache-home,target=/home/vscode/.cache,type=volume", |
| 70 | + "source=aw-cargo,target=/home/vscode/.cargo,type=volume", |
| 71 | + "source=aw-go-cache,target=/home/vscode/.cache/go-build,type=volume", |
| 72 | + "source=aw-go-mod,target=/home/vscode/go/pkg/mod,type=volume" |
| 73 | + ], |
| 74 | + "runArgs": ["--init"], |
| 75 | + "customizations": { |
| 76 | + "vscode": { |
| 77 | + "settings": { |
| 78 | + "terminal.integrated.defaultProfile.linux": "zsh" |
| 79 | + }, |
| 80 | + "extensions": ["ms-vscode-remote.remote-containers"] |
| 81 | + } |
| 82 | + }, |
| 83 | + "postCreateCommand": "./codex-setup || true" |
| 84 | +} |
| 85 | +``` |
| 86 | + |
| 87 | +### Credential Propagation Framework |
| 88 | + |
| 89 | +Principles: |
| 90 | + |
| 91 | +- Never bake secrets into images. Use runtime environment variables, forwarded agents/sockets, and read‑only mounts of host config where safe. |
| 92 | +- Normalize through the shell setup scripts so agent CLIs find credentials predictably. |
| 93 | + |
| 94 | +Mechanisms: |
| 95 | + |
| 96 | +- Env pass‑through: Allowlist known vars (examples: `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `OPENROUTER_API_KEY`, `HUGGING_FACE_HUB_TOKEN`, `GITHUB_TOKEN`, `GITLAB_TOKEN`, `BITBUCKET_TOKEN`). |
| 97 | +- Git hosting: generate `~/.netrc` from `GITHUB_TOKEN`/`GITLAB_TOKEN`/`BITBUCKET_TOKEN` (as in `codex-setup`). |
| 98 | +- GitHub CLI and Copilot CLI: prefer `gh auth` state by mounting `~/.config/gh/hosts.yml` read‑only or exporting `GH_TOKEN` if org policy allows. |
| 99 | +- SSH agent forwarding: mount `SSH_AUTH_SOCK` and pass through `~/.ssh/known_hosts` read‑only; avoid copying private keys. |
| 100 | +- Cloud SDKs: allow optional read‑only mounts of provider config (e.g., `~/.aws`, `~/.config/gcloud`) when required by a specific agent; otherwise rely on env‑based credentials. |
| 101 | + |
| 102 | +Each agent’s exact mapping is captured in `docs/agents/<tool>.md` and validated in CI with probe commands (e.g., `gh auth status`, minimal API ping for OpenAI/Anthropic). |
| 103 | + |
| 104 | +### Time‑Travel Execution Hooks in Devcontainer |
| 105 | + |
| 106 | +- zsh: `preexec` emits a timeline marker before execution; `precmd` after. bash: `trap DEBUG` + `PROMPT_COMMAND`. fish: `fish_preexec`/`fish_postexec`. |
| 107 | +- The hook writes a small JSON event (`{ts, cmd, cwd, session}`) to a FIFO/log consumed by the runner to align markers with snapshot anchors. |
| 108 | +- Hooks are opt‑out via config key (see `docs/configuration.md`), and no‑op for non‑interactive shells. |
| 109 | + |
| 110 | +### Caching and Host↔Guest Cache Sharing |
| 111 | + |
| 112 | +- Persistent volumes for: `/nix`, language caches (Cargo, Go, npm/pnpm/yarn, pip, maven/gradle), and compiler caches (sccache/ccache). |
| 113 | +- Host↔guest sharing guidelines and test plans are defined in `docs/nix-devcontainer/cache-guidelines.md` and `test-suite.md`. |
| 114 | +- For Windows hosts, prefer Docker volumes over bind mounts to avoid permission/line‑ending pitfalls; on macOS/Linux, bind mounts are acceptable for read‑only config. |
| 115 | + |
| 116 | +### Implementation Details |
| 117 | + |
| 118 | +- User/UID: set `remoteUser` to a non‑root user matching host UID to simplify shared cache permissions. |
| 119 | +- Entrypoint: minimal init (tini), run `common-pre-setup`, source project hooks if present `.agents/*-setup`, then `common-post-setup`. |
| 120 | +- Health: ship `aw doctor` checks for snapshot providers, Nix, caches, gh/ssh/auth readiness. |
| 121 | +- Security: secrets via env or forwarded sockets; config mounts read‑only; no tokens written to image layers. |
| 122 | + |
| 123 | +### Testing and CI |
| 124 | + |
| 125 | +- Cold/warm build benchmarks with and without caches. |
| 126 | +- Credential probes for each agent (non‑destructive): `gh auth status`, short `curl` to model/provider endpoints when keys present. |
| 127 | +- Time‑travel hook smoke tests: run a few commands and verify markers are emitted. |
| 128 | +- Cross‑platform matrix: Linux, macOS (Docker Desktop), Windows (WSL2/Hyper‑V). |
| 129 | + |
| 130 | +### Migration Plan |
| 131 | + |
| 132 | +- Phase 1 (this repo): build and publish `agents‑workflow‑nix‑base` and `agents‑workflow‑agents‑base` images to a registry (e.g., GHCR). |
| 133 | +- Phase 2 (extraction): split Nix base to a standalone repo; keep Agents base here, pinning base by digest. |
| 134 | + |
| 135 | +### Open Questions |
| 136 | + |
| 137 | +- Exact per‑agent credential files and minimal scopes (document in `docs/agents/`). |
| 138 | +- Which package manager caches to enable by default vs opt‑in. |
| 139 | +- Windows credential manager integrations (e.g., Git Credential Manager) via bind vs env. |
| 140 | + |
| 141 | + |
0 commit comments