diff --git a/README.md b/README.md index f7cb8a9..2de3bdf 100644 --- a/README.md +++ b/README.md @@ -166,7 +166,8 @@ echo "AIDC_ISOLATE_VM=1" >> .ai-container/project.env ## Notes - Generated files are added to `.git/info/exclude` when the target directory is a git repo, so your project stays clean. The seeded project docs (`CHANGELOG.md`, `DETAILED_CHANGELOG.md`, `logs/`) are *not* excluded — they belong to your repo and are meant to be committed. -- Settings can be set host-wide in `~/.config/aidc/config.env` (universal defaults for every project) or per project in `.ai-container/project.env`, which overrides the global default. Both files are sourced for env vars like `AIDC_AUTO_SYNC_SESSIONS`, `AIDC_ENABLE_EGRESS_FIREWALL`, and `AIDC_ISOLATE_VM`. +- Settings can be set host-wide in `~/.config/aidc/config.env` (universal defaults for every project) or per project in `.ai-container/project.env`, which overrides the global default. Both files are sourced for env vars like `AIDC_AUTO_SYNC_SESSIONS`, `AIDC_ENABLE_EGRESS_FIREWALL`, `AIDC_ISOLATE_VM`, and `AIDC_AGENTS`. +- **Coding agents are opt-in per project.** `aidc claude` bakes only `claude` into the image (plus any agents pinned via `AIDC_AGENTS=claude,codex` in `.ai-container/project.env`). Unset, the image includes all five agents (`claude`, `codex`, `opencode`, `cursor-agent`, `grok`) — about 1 GB of binaries. Listing an agent your project doesn't use is safe: the Dockerfile skips unknown names. - Container egress is open by default; set `AIDC_ENABLE_EGRESS_FIREWALL=1` in `.ai-container/project.env` for a default-deny allowlist. See [`docs/security.md`](docs/security.md#optional-egress-firewall). - The host-clipboard bridge is **off by default** — no host clipboard socket is mounted into the container. Opt in per (re)create with `aidc up --clipboard` / `aidc rebuild --clipboard`, or persist `AIDC_ENABLE_CLIPBOARD=1` in `.ai-container/project.env`. See [`docs/clipboard-bridge.md`](docs/clipboard-bridge.md). - Per-project VM isolation (`--isolate-vm`) is **off by default** due to resource cost. Opt in per (re)create with `aidc up --isolate-vm` / `aidc rebuild --isolate-vm`, or persist `AIDC_ISOLATE_VM=1` in `.ai-container/project.env`. See [Isolation modes](#isolation-modes) above. diff --git a/lib/aidc.sh b/lib/aidc.sh index c526fd5..c43a499 100644 --- a/lib/aidc.sh +++ b/lib/aidc.sh @@ -879,6 +879,14 @@ aidc::run_tool() { local workspace workspace="$(aidc::default_workspace)" + + # Seed the agent list from the tool being run so the first build only bakes + # in the agent(s) actually used. Explicit AIDC_AGENTS in project.env or the + # environment wins; 'all' bakes in every agent for back-compat. + if [[ -z "${AIDC_AGENTS:-}" ]]; then + export AIDC_AGENTS="$tool" + fi + aidc::ensure_container_running "$workspace" if [[ "$tool" == "claude" ]]; then @@ -1789,6 +1797,10 @@ aidc::export_compose_env() { # base image; this layer adds grype/syft/checkov/bandit when requested). export AIDC_SECURITY_TOOLS AIDC_SECURITY_TOOLS="${AIDC_SECURITY_TOOLS:-}" + # Coding agents baked into the image. Tool commands (aidc claude etc.) seed + # this to the invoked tool; 'aidc up' without a tool defaults to all five. + export AIDC_AGENTS + AIDC_AGENTS="${AIDC_AGENTS:-all}" # VM isolation: when active, point DOCKER_HOST at the per-project VM's # Docker daemon so all compose commands run inside the VM transparently. diff --git a/templates/devcontainer/Dockerfile.tmpl b/templates/devcontainer/Dockerfile.tmpl index bae5a6f..11f8884 100644 --- a/templates/devcontainer/Dockerfile.tmpl +++ b/templates/devcontainer/Dockerfile.tmpl @@ -201,19 +201,36 @@ RUN pmg setup install \ # so pmg has nothing to vet here; the "pmg first" invariant above still holds. # Grok's binary is forced into ~/.local/bin via GROK_BIN_DIR so the grok_home # volume mounted at ~/.grok at runtime cannot shadow it. -RUN mkdir -p \ +# +# AIDC_AGENTS (comma-separated) selects which agents get baked into the image; +# default is all five for back-compat. A claude-only project can set +# AIDC_AGENTS=claude and skip ~800MB of unused agent binaries. +ARG AIDC_AGENTS="claude,codex,opencode,cursor-agent,grok" +RUN agents="${AIDC_AGENTS:-all}" \ + && if [ "$agents" = "all" ]; then agents="claude,codex,opencode,cursor-agent,grok"; fi \ + && mkdir -p \ /home/vscode/.local/bin \ /home/vscode/.claude \ /home/vscode/.codex \ /home/vscode/.config/opencode \ /home/vscode/.cursor-agent \ /home/vscode/.grok \ - && curl -fsSL https://claude.ai/install.sh | bash \ - && curl -fsSL https://chatgpt.com/codex/install.sh | sh \ - && curl -fsSL https://opencode.ai/install | bash -s -- --no-modify-path \ - && curl -fsS https://cursor.com/install | bash \ - && { cursor-agent --version || true; } \ - && curl -fsSL https://x.ai/cli/install.sh | GROK_BIN_DIR=/home/vscode/.local/bin bash + && for agent in $(echo "$agents" | tr ',' ' '); do \ + case "$agent" in \ + claude) \ + curl -fsSL https://claude.ai/install.sh | bash ;; \ + codex) \ + curl -fsSL https://chatgpt.com/codex/install.sh | sh ;; \ + opencode) \ + curl -fsSL https://opencode.ai/install | bash -s -- --no-modify-path ;; \ + cursor-agent) \ + curl -fsS https://cursor.com/install | bash && { cursor-agent --version || true; } ;; \ + grok) \ + curl -fsSL https://x.ai/cli/install.sh | GROK_BIN_DIR=/home/vscode/.local/bin bash ;; \ + *) \ + echo "aidc: unknown agent '$agent' (skipped)" >&2 ;; \ + esac; \ + done # Auto-detected toolchains. aidc fills AIDC_TOOLCHAINS by scanning the # workspace for marker files (go.mod, Cargo.toml, etc.). Override per repo diff --git a/templates/devcontainer/compose.yaml.tmpl b/templates/devcontainer/compose.yaml.tmpl index cc520fe..e5e56b0 100644 --- a/templates/devcontainer/compose.yaml.tmpl +++ b/templates/devcontainer/compose.yaml.tmpl @@ -7,6 +7,7 @@ services: args: AIDC_TOOLCHAINS: ${AIDC_TOOLCHAINS:-} AIDC_SECURITY_TOOLS: ${AIDC_SECURITY_TOOLS:-} + AIDC_AGENTS: ${AIDC_AGENTS:-} init: true stdin_open: true tty: true