Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions acq.backends/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ PATTERNS_KIT_REPO="git+https://github.com/GSA-TTS/agentic-coding-patterns.git"
# the bundle-version anchor recorded in a sandbox's host-side provenance record
# (see ACQ_BUILTIN_BUNDLE below + the provenance helpers) so acq can tell a
# stale sandbox from a current one.
PATTERNS_KIT_REF="2dd2ad6ad5f63b842d732424bed5ba9aebeed676" # agentic-coding-patterns v1.10.0
PATTERNS_KIT_REF="f2227413df78dc5ef6580b5e29c59542dfe1f66a" # agentic-coding-patterns v1.11.0
PATTERNS_KIT_DIR="integrations/isolation/acq-kits"

USAI_PROVIDER_KIT_NAME="usai-provider"
Expand Down Expand Up @@ -110,13 +110,16 @@ fi
# directory under PATTERNS_KIT_DIR; DESC[i] is the one-line picker description.
# `prime-agent` is intentionally omitted: it is a skeleton at the current pin
# (see the patterns kits.yaml parity note) and would be non-functional if
# offered. Add it here once it is functional.
# offered. Add it here once it is functional. Heavier kits such as `oci-engine`
# still belong here when they are functional; the picker description must make
# their create-time cost clear.
# shellcheck disable=SC2034 # consumed by `acq configure` (cross-function reader)
ACQ_OPTIN_KIT_NAMES=(openchamber paseo)
ACQ_OPTIN_KIT_NAMES=(openchamber paseo oci-engine)
# shellcheck disable=SC2034
ACQ_OPTIN_KIT_DESCS=(
"Browser UI for OpenCode alongside the terminal TUI (publishes ports 3000/4096)"
"Self-hosted Paseo browser web UI for coding agents (one port, loopback only)"
"Rootless podman for docker run / docker compose inside the sandbox (installs packages)"
)

# _acq_optin_kit_ref NAME — echo the fully-pinned git+https kit ref for an opt-in
Expand Down
366 changes: 3 additions & 363 deletions acq.backends/msb.sh

Large diffs are not rendered by default.

73 changes: 33 additions & 40 deletions docs/BACKEND_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: "acq Backend Guide"
description: "Per-backend strengths, tradeoffs, and configuration for acq"
status: canonical
tier: 2
last_updated: "2026-09-30"
last_updated: "2026-10-03"
audience: "developers"
keywords: ["acq", "backend", "sbx", "msb", "microsandbox", "tradeoffs"]
related_files: ["docs/howto/acq.md", "docs/howto/msb.md", "docs/howto/sbx.md", "docs/CONCEPTS.md", "docs/adr/0010-acq-pluggable-backends.md", "docs/adr/0011-msb-backend-and-neutral-kits.md", "docs/adr/0014-neutral-port-publish-and-background-vocab.md", "docs/adr/0015-msb-post-hoc-port-publish-via-ssh.md", "docs/adr/0034-host-port-selection-and-publish-override.md"]
Expand Down Expand Up @@ -196,8 +196,6 @@ Tunables:
| `ACQ_OPENCODE_POSTINSTALL_TIMEOUT` | `120` | Seconds to bound opencode's in-guest `postinstall.mjs` (which fetches a platform binary) so a wedged registry can't hang `acq run`; used only when the guest provides `timeout` |
| `ACQ_MSB_OPENCODE_PKG` | `opencode-ai` | npm package spec for the opencode install (pin e.g. `opencode-ai@1.2.3`) |
| `ACQ_MSB_NPM_HOSTS` | `registry.npmjs.org` | npm registry host(s) to allow-list for the agent install (space-separated; set for an internal mirror) |
| `ACQ_MSB_ENSURE_OCI` | `1` (on) | Provision an OCI container engine (podman) at create so agents can run OCI images (`docker run`, `docker compose`). Installs `ACQ_MSB_PODMAN_PKGS` and aliases `docker` → `podman`. Set `0`/`false`/`no`/`off`/empty to skip (e.g. a base that bakes its own working engine). Fails soft if the OS package mirror is unreachable. See ADR-0020. |
| `ACQ_MSB_PODMAN_PKGS` | `podman podman-compose` | Packages installed to provide the OCI engine (space-separated). `podman-compose` is the `docker compose` / `podman compose` provider. Override for a different set or an internal mirror's names. |
| `ACQ_NETWORK_TIER` | `balanced` | Neutral egress posture (`strict`\|`balanced`\|`open`), the backend-agnostic selector defined by the agentic-coding-patterns network-tiers contract (ADR-0002). **All tiers are deny-by-default except `open`**; the tier only sizes the baseline allowlist. `strict` = `--net-default-egress deny` + gateway DNS + the kits' own `caps.network.allow` hosts ONLY (recommended for GFE / high-assurance). `balanced` = the same deny-default + the curated sbx-`balanced` baseline (ADR-0018) unioned with the kit hosts. `open` = **unrestricted egress** (no deny-default); testing only, never for GFE, and refused unless `ACQ_NETWORK_TIER_CONFIRM_OPEN=1`. Invalid values fail closed to `balanced`. |
| `ACQ_NETWORK_TIER_CONFIRM_OPEN` | (unset) | Required confirmation for `ACQ_NETWORK_TIER=open`. Set to `1` to acknowledge that the sandbox runs with unrestricted egress; otherwise `open` is refused at provision time (fail-closed). Treated like `--privileged` — never a default. |
| `ACQ_MSB_BALANCED_EGRESS` | (deprecated) | **Deprecated alias** for `ACQ_NETWORK_TIER`; retained for one deprecation window and removed in a future major. A `1`/on value maps to `ACQ_NETWORK_TIER=balanced`; a `0`/`false`/`no`/`off`/empty value maps to `ACQ_NETWORK_TIER=strict` (deny-by-default, kit hosts only — a former "off" no longer means permissive; an upgrade never silently loosens egress). `ACQ_NETWORK_TIER` wins when both are set, and a one-time notice is printed. Migrate to `ACQ_NETWORK_TIER`; use `open` if you truly need unrestricted egress. |
Expand Down Expand Up @@ -625,11 +623,11 @@ mirroring the sbx
- The four kit prerequisites present: `node`, `git`, `curl`,
`update-ca-certificates`.

For OCI-run support (`docker run` / `docker compose`), the adapter installs
podman at provision (see [Running OCI images inside the sandbox](#running-oci-images-inside-the-sandbox-podman)),
so a base image does **not** need a container engine baked in — only a supported
package manager (apt-get/dnf/apk) and mirror reachability. Bake podman in (and
set `ACQ_MSB_ENSURE_OCI=0`) only if you want to skip the runtime install.
For OCI-run support (`docker run` / `docker compose`), opt into the
`oci-engine` catalog kit (see [Running OCI images inside the sandbox](#running-oci-images-inside-the-sandbox-podman)).
The base image does **not** need a container engine baked in if the kit can reach
its package mirrors; alternatively, use a base that already includes a working
engine and skip the kit.

**Build on Docker's `sandbox-templates:*` images to get all of these for free**
— msb derives the same agent-specific image naming convention as sbx when no
Expand Down Expand Up @@ -679,38 +677,33 @@ If the image requires registry auth, log in with your container tooling (e.g.
### Running OCI images inside the sandbox (podman)

Agents often need to run OCI images from inside the sandbox — `docker run` an
image, or bring up a `docker-compose.yaml`. The msb adapter guarantees this
capability the same way it guarantees the base-image contract: idempotently, no
matter what the base image brings.

The default image ships the Docker CLI, but msb's microVM init (`/init.krun`)
never starts `dockerd`, so the Docker socket is dead — and Docker's `overlay2`
storage driver cannot sit on the sandbox's already-overlay root without a
disk-backed data volume. Rather than retrofit the msb docker-in-docker recipe (a
daemon to start and keep alive across restarts, plus a per-sandbox disk-backed
volume), the adapter provisions **podman** at create time and aliases `docker` →
`podman`:

- **podman is daemonless** — no socket to start/poll, no restart lifecycle — uses
`fuse-overlayfs` on the overlay root (no disk-backed volume), and needs no
nested virtualization (containers are `runc`/`crun` processes, not VMs).
- It runs **rootful** via the agent's passwordless sudo, which avoids the
rootless prerequisites (`uidmap`, `passt`/pasta) a lean base lacks.
- A tiny `docker` → `podman` wrapper is placed in `/usr/local/bin` (ahead of
`/usr/bin`), so `docker run …` **and** `docker compose …` route to podman. The
base image's `/usr/bin/docker` is never modified. `docker compose` resolves to
`podman compose`, driven by the installed `podman-compose` provider — so
`docker-compose.yaml` files work. (The standalone `docker-compose` CLI is
deprecated in favour of the `docker compose` subcommand, so no separate
`docker-compose` binary is provided.)

The install uses the OS package mirror, which under the default balanced egress
baseline (ADR-0018) is already reachable — no extra net-rule needed. With
`ACQ_NETWORK_TIER=strict`, or a custom base whose egress is narrowed, the
mirror is unreachable and the step **fails soft** (a warning; provision
continues; OCI is simply unavailable). Turn the step off entirely with
`ACQ_MSB_ENSURE_OCI=0` (e.g. a base that bakes its own working engine), or point
`ACQ_MSB_PODMAN_PKGS` at a different package set / internal mirror. See ADR-0020.
image, or bring up a `docker-compose.yaml`. This capability is now an **opt-in
catalog kit**, not an msb adapter default.

Enable it through the catalog:

```bash
acq configure
# select: oci-engine
```

You can also apply it for one sandbox by passing the pinned kit ref through
`--kit`, or by exporting that same ref in `ACQ_EXTRA_KITS`:

```bash
acq run opencode . --kit 'git+https://github.com/GSA-TTS/agentic-coding-patterns.git#ref=f2227413df78dc5ef6580b5e29c59542dfe1f66a&dir=integrations/isolation/acq-kits/oci-engine'
```

The kit provisions **rootless podman** and aliases `docker` to `podman`, so
`docker run` and `docker compose` work inside the sandbox without a Docker daemon.
It is backend-neutral: the same catalog choice applies on sbx and msb.

This is a breaking change for msb users: sandboxes no longer get podman by
default. Existing sandboxes keep whatever was already installed, but new
sandboxes must opt into `oci-engine` if they need an in-sandbox container engine.
The old msb-only environment toggles for adapter provisioning are removed; use
`acq configure`, `ACQ_EXTRA_KITS`, or `--kit` instead. See ADR-0020 for the
superseded adapter-era decision and ADR-0031 for the catalog mechanism.

### Secrets

Expand Down
6 changes: 5 additions & 1 deletion docs/CONCEPTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: "acq Concepts"
description: "Backend-neutral concepts for working with acq sandboxes (workspaces, mounts, published ports)"
status: canonical
tier: 2
last_updated: "2026-09-30"
last_updated: "2026-10-03"
audience: "developers"
keywords: ["acq", "concepts", "workspace", "mount", "ports", "publish", "backend-neutral", "sbx", "msb"]
related_files: ["docs/howto/acq.md", "docs/BACKEND_GUIDE.md", "docs/adr/0010-acq-pluggable-backends.md", "docs/adr/0011-msb-backend-and-neutral-kits.md", "docs/adr/0034-host-port-selection-and-publish-override.md"]
Expand Down Expand Up @@ -265,6 +265,7 @@ flags on every run.
[x] git-ssh-sign SSH-based git commit signing … (always applied)
❯ [x] openchamber Browser UI for OpenCode alongside the terminal TUI
[ ] paseo Self-hosted Paseo browser web UI for coding agents
[ ] oci-engine Rootless podman for docker run / docker compose
```

- The **four built-in kits** (`zscaler-ca-certificate`, `usai-provider`,
Expand All @@ -276,6 +277,9 @@ flags on every run.
- At `acq create`, the picker is shown again **pre-populated with your saved
defaults**, so a single sandbox can enable or disable a kit without changing
the global default (the deviation is remembered for that sandbox).
- Select **`oci-engine`** when the sandbox needs `docker run` or
`docker compose`. It installs rootless podman inside the sandbox and is not
enabled by default.
- The **GitHub-token** preference only pre-answers the scoping prompt; the
fine-grained token is still minted per-sandbox (see
[`acq github-scope`](howto/acq.md)).
Expand Down
66 changes: 55 additions & 11 deletions docs/KNOWN_FAILURE_MODES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: "Known Failure Modes"
description: "Real-world failure patterns when using Docker SBX + USAi + agent frameworks"
status: canonical
tier: 2
last_updated: "2026-09-30"
last_updated: "2026-10-03"
audience: "developers"
keywords: ["debugging", "troubleshooting", "sbx", "usai", "failures"]
---
Expand Down Expand Up @@ -647,7 +647,7 @@ worked on sbx 0.35.0–0.37.x, where `sbx kit add` recreated the container with
augmented kit set while preserving state.

> **sbx 0.38 caveat.** On sbx >= 0.38, `sbx kit add` no longer applies
> startup-bearing kits mid-life (see [Section 35](#35-re-attach-heal-loop-warns-every-time-on-sbx-038--sbx-kit-add-refuses-startup-bearing-kits)),
> startup-bearing kits mid-life (see [Section 36](#36-re-attach-heal-loop-warns-every-time-on-sbx-038--sbx-kit-add-refuses-startup-bearing-kits)),
> and every built-in acq kit declares startup commands. In-place healing of the
> built-in bundle therefore does **not** work on 0.38+: to add or refresh the
> bundle you must recreate the sandbox (`acq rm && acq run`). acq detects the
Expand Down Expand Up @@ -1746,7 +1746,51 @@ acq exec <sandbox> -- sh /home/agent/openchamber-start.sh &

---

## 34. Git signing fails on msb: socat missing or msb < 0.6.9
## 34. `docker run` or `docker compose` Missing Inside a Sandbox

### Symptoms

- `docker run`, `docker compose`, or `podman` is not found inside a sandbox.
- On msb, a new sandbox no longer gets podman automatically.

### Root Cause

`oci-engine` is an opt-in catalog kit. acq no longer installs podman from the msb
adapter by default, and sbx/msb now use the same mechanism for in-sandbox OCI
support.

### Fix

Enable the kit for future sandboxes:

```bash
acq configure
# select: oci-engine
```

For a single sandbox, pass the pinned kit ref with `--kit` or include it in
`ACQ_EXTRA_KITS`:

```bash
acq run opencode . --kit 'git+https://github.com/GSA-TTS/agentic-coding-patterns.git#ref=f2227413df78dc5ef6580b5e29c59542dfe1f66a&dir=integrations/isolation/acq-kits/oci-engine'
```

Existing sandboxes that were created before this change keep whatever podman
state they already have, but new sandboxes require the opt-in kit unless the base
image already includes a working engine.

### Prevention / Status

- Breaking change in the `oci-engine` catalog migration. Covered by the
`acq configure` catalog tests, the configured-kit fresh-shell start
round-trip, the msb no-default-OCI regression test, and the dedicated live
`scripts/verify-backends --only msb --oci-only` path.
- ADR-0020 is superseded for the adapter-owned mechanism; ADR-0030 and ADR-0031
describe the kit/catalog path.

---

## 35. Git signing fails on msb: socat missing or msb < 0.6.9

### Symptoms

Expand Down Expand Up @@ -1866,7 +1910,7 @@ See [ADR-0021](adr/0021-msb-host-ssh-agent-forwarding-via-vsock.md)

---

## 35. Re-attach Heal Loop Warns Every Time on sbx 0.38 — `sbx kit add` Refuses Startup-Bearing Kits
## 36. Re-attach Heal Loop Warns Every Time on sbx 0.38 — `sbx kit add` Refuses Startup-Bearing Kits

### Symptoms

Expand Down Expand Up @@ -1956,7 +2000,7 @@ heal-loop cases).

---

## 36. msb Create-Time Published Port Returns Empty Response for a Loopback-Only Guest Service
## 37. msb Create-Time Published Port Returns Empty Response for a Loopback-Only Guest Service

### Symptoms

Expand Down Expand Up @@ -2028,7 +2072,7 @@ from inside the sandbox and can reach guest `127.0.0.1:6767`.

---

## 37. Commit signing fails in the sandbox: `user.signingKey needs to be set` / `No signature`
## 38. Commit signing fails in the sandbox: `user.signingKey needs to be set` / `No signature`

### Symptoms

Expand Down Expand Up @@ -2085,7 +2129,7 @@ Notes:
reachable, so a rebase with `SSH_AUTH_SOCK` set does not need a separate
`--amend -S` pass.

## 38. Spurious `M` (modified) diffs on scripts across the host/sandbox mount
## 39. Spurious `M` (modified) diffs on scripts across the host/sandbox mount

### Symptoms

Expand Down Expand Up @@ -2135,7 +2179,7 @@ amending the wrong branch.

---

## 39. Windows preview: `bash.exe` resolves to the WSL shim, WHP is not a feature flag, and the execution policy blocks scripts
## 40. Windows preview: `bash.exe` resolves to the WSL shim, WHP is not a feature flag, and the execution policy blocks scripts

### Symptoms

Expand Down Expand Up @@ -2208,7 +2252,7 @@ amending the wrong branch.

---

## 40. Recovering agent work reads the guest-writable scratch clone (residual risk)
## 41. Recovering agent work reads the guest-writable scratch clone (residual risk)

### Symptoms

Expand Down Expand Up @@ -2251,7 +2295,7 @@ an untrusted agent could write to.

---

## 41. A Required Check Backed by a `paths:`-Filtered Workflow Deadlocks Unrelated PRs
## 42. A Required Check Backed by a `paths:`-Filtered Workflow Deadlocks Unrelated PRs

### Symptoms

Expand Down Expand Up @@ -2319,7 +2363,7 @@ adding them to branch protection.

---

## 42. A Second Parallel Sandbox From the Same Kit Is Unreachable on Its Published Port (msb)
## 43. A Second Parallel Sandbox From the Same Kit Is Unreachable on Its Published Port (msb)

### Symptoms

Expand Down
Loading
Loading