Repository navigation
Use kits to install agents on a devenv-enabled base image #473
Copy link
Copy link
Closed
8 / 88 of 8 issues completedClosed
8 / 88 of 8 issues completed
Copy link
Labels
enhancementNew feature or requestNew feature or request
Description
Context
A Slack discussion on 2026-09-15 converged on a possible architecture simplification for acq: stop relying on base images that already contain specific coding agents, and instead use a generic devenv-enabled base image plus agent kits.
The relevant base-image work is in GSA-TTS/agentic-coding-patterns: GSA-TTS/agentic-coding-patterns#395. That pattern is not necessarily NixOS. It layers Nix single-user, devenv, and direnv onto a parametrized BASE_IMAGE, which keeps Ubuntu-like images viable while still giving us Nix/devenv/direnv behavior.
Proposed direction
- Have
acqdepend on a generic devenv-enabled, agent-less base image contract. - Move agent install, config, and startup knowledge into agent kits.
- Treat OpenCode, Pi, Goose, Prime Agent, and future harnesses as tools supplied by kits rather than baked into base images or core
acqlogic. - Keep
acqresponsible for backend lifecycle, credentials, mounts, network, and kit orchestration. - Let
acq run <agent> <workspace>infer the corresponding agent kit when one is not explicitly supplied. - Treat
shellas the likely special case because it is not an agent harness. - Consider extracting podman setup into a default OCI engine kit, rather than keeping OCI engine installation embedded in an adapter.
Layering model
User / control plane
CLI, Agor-like UI, future Factory UI
Normalized session API
acq today, possibly split later
Harness adapter layer
OpenCode, Pi, Goose, Prime Agent, future agents
Environment / capability layer
kits + devenv
Sandbox control layer
acq lifecycle, credentials, network, mounts
Backends
msb, sbx
Generic devenv-enabled base
parametrized BASE_IMAGE + Nix single-user + devenv + direnv
Open questions for discussion
- Does
acqrundevenv up,devenv shell,direnv allow, or a combination? - Which declarations belong at create time versus run or attach time?
- What exact neutral schema should agent kits use for entrypoints, startup steps, files, env, volumes, and egress?
- How should security-sensitive merge conflicts work when built-in, team, and personal kits overlap?
- Should
usai-providerremain one agent-aware kit, or should provider-format translation live inside each agent kit? - Should rootless podman setup move into an OCI engine kit that is part of the default kit set?
- What minimum contract should
acqrequire from a bring-your-ownBASE_IMAGEorACQ_IMAGE? - How should personal dotfiles be represented: devenv config, a personal kit, a mounted volume, or explicit copy-in?
- What current
acq run opencode .behavior must remain stable during migration?
Discussion goal
Use this issue and the proposed ADR draft to align before implementation. The immediate goal is not to implement the refactor, but to agree on the architecture, vocabulary, and migration path.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request
Activity
basiliskus commentedon Sep 15, 2026
The architecture-level feedback (install pinning, activation contract, create-time vs run-time and a
resources:field, supervision models, usai-provider, BYO image contract, egress merge) is on the ADR PR: #474 (comment). Four of the open questions here are not covered there, and the login.gov data team runs a concrete answer to the first one.Personal dotfiles: a personal kit, and the drop-in hook belongs in the base contract. We already run this shape: a personal kit under
ACQ_EXTRA_KITSthat ships config files (files[]), installs the user's tools with a pinnednix profile installstartup step, and drops shell snippets into~/.rc.d/that the team kit wires into bash and zsh. Weighing the alternatives from that experience: devenv config is per-project, so it is the wrong layer for per-user preferences; a mounted host dotfiles directory assumes host paths and host-installed tools that the guest does not have; explicit copy-in is what a kit'sfiles[]already is. The one gap: the~/.rc.dwiring lives in our team kit today, so a personal kit only works when that team kit is present. That hook should move into the base-image contract or a built-in neutral kit.Agent kit inference: built-in bundle only, visible, and overridable.
acq run opencode .should resolve the agent kit by name match against the built-in bundle, never against extra kits (otherwise a team or personal kit namedopencodesilently becomes the agent).acq kit lsor the create output should print which kit was selected, and an explicit--kitwins.shellselects nothing.OCI engine kit: yes, but optional and not in the default bundle. Moving rootless podman out of the msb adapter is right. Keeping it out of the default set matters: it is a create-time install plus egress for every sandbox, and kits like ours never need it.
Behavior that must stay stable during migration. From the team kit's side the load-bearing contract is:
--clonesemantics with theACQ_CLONE/ACQ_WORKSPACEguest markers (ADR-0027); startup steps re-applied on every run on msb;ACQ_EXTRA_KITSlocal paths applied after the built-in bundle;acq exec/acq shelllanding in the primary repo with a login shell;ACQ_IMAGEas the image override; andvolumes:mounted at boot before any exec. Ourscripts/verifyasserts each of these against a real--clonesandbox on the active backend, so it can serve as a regression check while the refactor lands.docs(adr): incorporate review feedback on agent-kit/devenv layering
mogul commentedon Sep 16, 2026
Status: moving from ADR discussion into incremental implementation
Radiating intent: we are going to start moving the engineering work forward from ADR-0030 with the understanding that the cost of rework is relatively low if later comments materially change the ADR. Comments are still welcome, but comments that affect sequencing or architecture are most useful sooner rather than later.
The implementation will proceed as small deliverables. Unresolved questions stay deferred until the last responsible moment before a concrete increment needs the answer.
Increment Roadmap
Baseline substrate update in patterns
Track the devenv 2.x image/substrate work in devenv image: adopt devenv 2.x and revisit size, startup, and generation agentic-coding-patterns#418. Quickstart implementation should consume that output rather than duplicate it.
Agent-kit metadata and inference
feat(agent-kits): add built-in agent kit metadata and inference #479 defines the first
acq-side increment: built-in-bundle-only agent kit inference, visible selected kit, explicit override, andshellas no-agent-kit.Migration gate for OpenCode stability
test(migration): gate the OpenCode agent-kit migration #480 defines the regression gate and sequencing needed to preserve current
acq run opencode .behavior while behavior moves into kits.Provider facts versus agent rendering
feat(provider): split USAi provider facts from agent config rendering #481 splits
usai-providerinto neutral provider facts while each agent kit renders its native config.Neutral shell drop-in hook for personal kits
feat(kits): add neutral shell rc.d hook for personal kits #482 moves the
~/.rc.dhook out of team-specific behavior and into the base contract or a built-in neutral kit.Human-owned devenv/direnv activation
feat(devenv): implement human-owned activation contract #478 implements the activation contract: surface trust/activation actions, do not auto-approve by default, and allow only explicit
ACQ_opt-in for non-interactive use.OpenCode agent kit
feat(opencode): move OpenCode install and entrypoint into an agent kit #485 moves OpenCode install and entrypoint ownership into a content-pinned agent kit.
Optional OCI engine kit
feat(oci): extract rootless podman into optional OCI engine kit #483 extracts rootless podman into an explicit optional OCI engine kit, preserving ADR-0020 security decisions.
Bring-your-own image contract
feat(images): define and verify the devenv BYO image contract #484 defines and verifies the minimum image contract, including
/nix, devenv major, direnv/shell hook behavior, and diagnostics.Guest sizing follow-up
#475 remains separate from the devenv adoption story and tracks neutral CPU/memory resource vocabulary.
Deferred to Last Responsible Moment
acq run opencode .cutover sequence is deferred to the migration-gate increment.~/.rc.dhook belongs in the base image or a built-in neutral kit is deferred until implementation can compare the blast radius.Orchestration Protocol
mogul commentedon Sep 17, 2026
Implementation status after sandbox recovery
The earlier sandbox was torn down, so the previous “review queue” state should be treated as stale. I reconstructed the durable state from Git/worktrees and rebased the local work on current
origin/mainbefore continuing.Current durable state:
refactor/acq-devenv-base-imageis the integration branch for Use kits to install agents on a devenv-enabled base image #473.test(migration): gate opencode agent-kit migration.test/bats/140-opencode-migration-gate.bats, documenting the migration-sensitive contract indocs/BACKEND_GUIDE.md, and updatingscripts/verify-backendsas the live sequencing gate.Verification known from the pre-teardown session for the migration-gate increment:
./scripts/test-acq-bats test/bats/140-opencode-migration-gate.bats./scripts/test-acq-bats test/bats/35-image-override.bats test/bats/116-clone-option.bats test/bats/110-volumes.bats test/bats/30-dispatch-routing.bats test/bats/70-msb-backend.bats test/bats/140-opencode-migration-gate.batsnpm run lint:mdgit diff --checkResidual risk / re-verification needed:
./scripts/verify-backends --only sbxand--only msbstill require a sandbox-capable host and real backend setup.test/bats/90-sbx-startup-kit.bats; if it still reproduces, it should stay out of scope for this increment unless it blocks the migration work.Next implementation step:
--kitoverride, andshellselecting no agent kit.[-]Discuss agent kits on a devenv-enabled base image[/-][+]Use kits to install agents on a devenv-enabled base image[/+]mogul commentedon Sep 17, 2026
Implementation update
Rebased the local #473 work on current
origin/main, refreshed the stale status comment after sandbox recovery, and continued the next increment using the orchestration protocol from this issue.Current integration branch:
refactor/acq-devenv-base-imageNew commits on top of the migration gate:
e61520b feat(agent-kits): infer built-in agent kit metadataa3f3437 test(agent-kits): cover enabled built-in kit selectionf58b04c fix(agent-kits): preserve recorded agent for kit refreshImplemented for #479:
opencodewhile keeping application deferred until the pinned built-in bundle actually ships an enabled agent kit.shellas the no-agent-kit case.--kithigher precedence than implicit inference.ACQ_EXTRA_KITSout of inference; extras are still appended after selected built-ins and before CLI kits.acq run opencode .behavior.Verification:
bash -n acq acq.backends/agents.sh acq.backends/common.sh acq.backends/msb.sh acq.backends/sbx.shgit diff --check./scripts/test-acq-bats test/bats/30-dispatch-routing.bats test/bats/36-agent-catalog.bats test/bats/50-kit-list-completeness.bats test/bats/74-msb-restart-durability.bats test/bats/85-kit-provenance.bats test/bats/95-kit-ref-persistence.bats test/bats/140-opencode-migration-gate.bats(106/106)npm run lint:mdKnown residual:
./scripts/test-acq-bats test/bats/90-sbx-startup-kit.batsstill has the pre-existing unrelated failure inheal(sbx): the playbook stale-probe uses the AGENTS.md footprint, not .git; the newagent-kit-heal(sbx): forced refresh includes recorded agent kitcase in that file passes../scripts/verify-backends) was not run in this session because it requires a sandbox-capable host/backend setup.Cleanup:
agent-kit-scout,neutral-rcd-hook,robust-vampirebat, andreview-opencode-migration-gate.opencode-migration-gatecould not be removed viagit worktree removebecause initialized submodules are present; left it untouched rather than forcing removal.1 remaining item
mogul commentedon Sep 17, 2026
Epic Status: ADR-0030 Implementation
Current integration branch:
refactor/acq-devenv-base-imageLatest pushed commit:
0f6a6b8 chore(shellcheck): document optional kit-list argumentSummary
refactor/acq-devenv-base-image; sub-issues remain open until the PR/branch landsLanded on Branch
test/bats/140-opencode-migration-gate.bats; updateddocs/BACKEND_GUIDE.md; updatedscripts/verify-backendsso migration behavior is explicitly gatedopencode;shellselects no agent kit; explicit--kitsuppresses inference;ACQ_EXTRA_KITScannot drive inference; recorded-agent provenance supports future heal/refreshopencodekit.envrcand devenv markers; default behavior advises only;ACQ_ACTIVATE_PROJECT_ENV=1opts into already-approveddirenv export; internal helper/probe execs are protected; SBX/MSB review fixes landeddevenv shell; current opt-in only usesdirenv exportwhen.envrcexistsUSAI_PROVIDER_*fallback defaults; routed SBX/MSB default USAi binding through them; preserved explicit--host/--envprecedence; ADR-0030 now defines provider-facts artifact contractusai-providerartifact once available at the pinned refBacklog
/nix, devenv major, direnv/shell hook, and workspacedevenv.nixconcerns; no checks landedACQ_IMAGE/BASE_IMAGEonce substrate details are stableresources:CPU/memory vocabulary independentlyCommit Map
0791da3,5ca2efc,5f07235,f7ce258,52a17c7,77ee43dafter rebasec62f24dafter rebase2ec7810,4fc7b26,b61916fafter rebase823de9a,97d00a5after rebase31d0588,77ee43dafter rebasee21779d,0f6a6b8Verification
bash -n acq acq.backends/agents.sh acq.backends/common.sh acq.backends/msb.sh acq.backends/sbx.shprintf %s\\n acq acq.backends/*.sh scripts/test-acq-lib.sh scripts/test-acq-bats test/bats/*.bats test/bats/helper.bash | xargs -r -n8 shellcheck --severity=warningnpm run lint:mdgit diff --check HEAD./scripts/test-acq-bats test/bats/50-kit-list-completeness.bats test/bats/30-dispatch-routing.bats test/bats/72-msb-agent-user.bats test/bats/140-opencode-migration-gate.bats(99/99)Known Residuals
./scripts/verify-backendshas not been run in this session because it requires a sandbox-capable backend hosttest/bats/90-sbx-startup-kit.batsstill has the pre-existing failure inheal(sbx): the playbook stale-probe uses the AGENTS.md footprint, not .gitmogul commentedon Sep 17, 2026
Quickstart-side progress update
New pushed commit on
refactor/acq-devenv-base-image:c8150e3 feat(provider): load usai facts artifactprovider-facts/usai.env-style metadata, with fallback behavior preservedUpdated #481 Status
acq_provider_facts_load FILEparses staticKEY=VALUEdata; it does not source or eval the fileUSAI_PROVIDER_BIND_HOSTSwhile preserving explicit--host/--envsidecar precedenceusai-providerkit ref; removing/demoting fallback defaults once the patterns-side artifact existsVerification
bash -n acq.backends/common.sh acq.backends/sbx.sh acq.backends/msb.shgit diff --check./scripts/test-acq-bats test/bats/50-kit-list-completeness.bats test/bats/40-secret-set.bats test/bats/71-msb-provision-secrets.bats test/bats/77-usai-rotate.bats test/bats/30-dispatch-routing.bats98/98)mogul commentedon Sep 17, 2026
Quickstart-side progress update
New pushed commit on
refactor/acq-devenv-base-image:08a00b4 feat(provider): load facts from usai kitprovider-facts/usai.envfrom the pinnedusai-providerkit, preserving fallback defaults when absent and failing closed when present-but-invalidUpdated #481 Status
c8150e3: parsesKEY=VALUEfacts as data, not shellc8150e3: validates schema, provider id, host/bind hosts, HTTPS URLs, and env var names08a00b4:acqtries the pinnedUSAI_KITartifact after backend resolutionVerification
bash -n acq.backends/common.sh acq.backends/sbx.sh acq.backends/msb.shgit diff --check./scripts/test-acq-bats test/bats/50-kit-list-completeness.bats test/bats/40-secret-set.bats test/bats/71-msb-provision-secrets.bats test/bats/77-usai-rotate.bats test/bats/30-dispatch-routing.bats101/101)mogul commentedon Sep 17, 2026
Quickstart-side progress update
New pushed commit on
refactor/acq-devenv-base-image:2982ba5 feat(kits): source neutral rc snippets~/.rc.d/*.shhook contract in the acq-owned login profile bridgeUpdated #482 Status
~/.rc.d/*.sh.profilebridgedirenv allow; does not duplicateACQ_ACTIVATE_PROJECT_ENVbehaviorVerification
bash -n acq.backends/msb.sh test/bats/72-msb-agent-user.batsgit diff --check./scripts/test-acq-bats test/bats/72-msb-agent-user.bats test/bats/140-opencode-migration-gate.bats50/50)mogul commentedon Sep 18, 2026
Quickstart-side progress update
New pushed commit on
refactor/acq-devenv-base-image:932a8b7 test(kits): cover neutral rc snippet deliveryfiles:payloads can deliver~/.rc.d/*.shsnippetsUpdated #482 Status
2982ba5: sources~/.rc.d/*.shfor bash/zsh login shells932a8b7: neutral kitfiles/home/agent/.rc.d/*.shmaterializes into sbx-v2 kit payloads932a8b7: neutral kit files copy to/home/agent/.rc.d/*.shand the rc.d tree is chowned to agentVerification
9/9)Known residual: full
test/bats/90-sbx-startup-kit.batsstill has the unrelated stale-probe/git-identity failure; the new SBX rc.d case passes.mogul commentedon Sep 18, 2026
Quickstart-side progress update
New pushed commit on
refactor/acq-devenv-base-image:0439013 feat(images): add non-enforcing contract doctoracq doctor NAMEdiagnostics for ADR-0030 BYO/devenv image contract checks on existing sandboxesUpdated #484 Status
acq doctor NAMEinspects an existing sandbox; bareacq doctorbehavior is preservedacq_backend_doctor_sandboxhooksHOME, agent user,/nix,nix,devenv,direnv,/home/agentwritability, best-effort passwordless sudo probe,~/.rc.d, shell startup hook referencedevenvversion floors; create-time hard enforcement; live backend validationVerification
./scripts/test-acq-bats test/bats/65-doctor-image-contract.bats test/bats/60-help.bats25/25)bash -n acq acq.backends/common.sh acq.backends/msb.sh acq.backends/sbx.sh scripts/test-acq-lib.sh test/bats/65-doctor-image-contract.batsgit diff --checkmogul commentedon Sep 18, 2026
Quickstart-side progress update
New pushed commit on
refactor/acq-devenv-base-image:9be74d3 feat(agent-kits): validate built-in agent artifactsUpdated #485 Status
spec.yaml, expected kit name, and directagent.name/agent.entrypointmetadataopencoderemains disabled by default; current migration gate stays stable--kitstill suppresses implicit built-in agent-kit inferenceVerification
./test/vendor/bats-core/bin/bats test/bats/140-opencode-migration-gate.bats test/bats/85-kit-provenance.bats test/bats/50-kit-list-completeness.bats test/bats/30-dispatch-routing.bats93/93)bash -n acq acq.backends/common.sh acq.backends/agents.sh acq.backends/kit-translate.shgit diff --checkmogul commentedon Sep 21, 2026
Quickstart-side progress update
Continued the ADR-0030 work on
refactor/acq-devenv-base-image(draft PR #474), focused on the quickstart-side work that has no patterns-substrate dependency while the devenv 2.x image, USAi facts artifact, and OpenCode agent kit are still unpublished.CI is green again on the epic branch
The draft PR was red on
Pre-commitandbash 3.2 compat(the offline bats suite). Fixed and merged currentmain:4bcca99 test(agent-kits): fix sbx heal test flake and agent-kit refresh gated946f27 feat(oci): add opt-in OCI-engine capability kit selectionc889723 Merge origin/mainacq.backends/msb.shconflict (Windows path-form/_acq_msb_cliwrapping from #463/#464 vs. the epic'sACQ_ACTIVATE_PROJECT_ENVactivation logic — both preserved)Root causes fixed:
agent-kit-heal(sbx): forced refresh includes recorded agent kitbroke when the selection gate tightened fromacq_agent_builtin_kit_enabledtoacq_agent_builtin_kit_ready(validated artifact). OpenCode enablement is deferred until the pinned patterns bundle ships a valid opencode agent kit, so the test now stubs readiness offline to exercise the refresh path without falsely enabling OpenCode.heal(sbx): the playbook stale-probe uses the AGENTS.md footprint, not .gitpassed in CI but failed on hosts with a configured git identity (which injects a git-identity kit-add). Neutralized the git identity in the probe subshell, matching the same fix on fix(acq): use sandbox workspace for github scoping #476.All four PR checks (
Pre-commit,bash 3.2 compat,PR Lint,Markdown Quality) are now green atc889723.#483 (OCI engine kit) — first increment landed
Implemented the quickstart-side, opt-in selection + allowlisting + tests for an
oci-enginecapability kit, off by default (ACQ_ENABLE_OCI_KIT) and gated on a readiness probe of the pinned patterns ref. Because the patterns kit body is unpublished, opting in currently no-ops with a single notice; the msb adapter's_acq_msb_ensure_ociprovisioning is untouched and remains the active OCI mechanism. Details, verification, and the deferred/sequenced follow-ups are tracked on #483.Decisions confirmed this session
agentic-coding-patterns, not quickstart. This quickstart increment only wires selection/allowlisting/tests; the patterns kit is a separate PR (the trigger that flips readiness to true).Still blocked on patterns substrate (unchanged)
#481fallback-removal,#484version floors, and#485OpenCode enablement remain deferred pending the patterns-side devenv 2.x image,provider-facts/usai.envartifact, and OpenCode agent kit.mogul commentedon Sep 24, 2026
Quickstart-side progress update
Continued the ADR-0030 work on
refactor/acq-devenv-base-image/ draft PR #474.Latest pushed commits:
59d10f0 feat(kits): wire neutral rc snippets892a183origin/maininto the integration branch and resolves the verifier header conflict, keeping the ADR-0030 gate language and the current sbx>= 0.39.0floor9a82061 feat(kits): harden pending kit gatesUpdated scope tracking
#474 now has a fully qualified
Closes:line for #478, #479, #480, #481, #482, #483, #484, and #485.#475 has been removed from the PR closure scope and remains a separate resource-sizing track.
What landed since the prior #473 update
acq_login_profile_rc_blocknow drives both msb and sbx; sbx installs the bridge through post-createsbx execafter an exec-readiness wait; tests now execute the generated block and verify deterministic byte-order sourcingoci-enginecapability kit is not misclassified as an agent kit during sbx forced refresh; msb suppresses adapter-owned podman provisioning only when the OCI kit is actually selected and fetched for that provisionacq doctor NAMEdiagnostics now report available tool versions and separate the missing~/.rc.ddirectory warning from the missing shell-startup-hook warning, while remaining non-enforcingacq run opencode .behaviorCurrent patterns dependencies
Verification
./scripts/test-acq-bats597/597)./scripts/test-acq-bats test/bats/66-oci-engine-kit.bats test/bats/71-msb-provision-secrets.bats test/bats/65-doctor-image-contract.bats test/bats/140-opencode-migration-gate.bats test/bats/90-sbx-startup-kit.bats70/70)bash -n acq acq.backends/agents.sh acq.backends/common.sh acq.backends/msb.sh acq.backends/sbx.sh scripts/test-acq-lib.sh scripts/test-acq-bats test/bats/helper.bash test/bats/65-doctor-image-contract.bats test/bats/66-oci-engine-kit.bats test/bats/71-msb-provision-secrets.bats test/bats/140-opencode-migration-gate.bats test/bats/90-sbx-startup-kit.bats scripts/verify-backendsprintf '%s\n' acq acq.backends/*.sh scripts/test-acq-lib.sh scripts/test-acq-bats test/bats/*.bats test/bats/helper.bash scripts/verify-backends | xargs -r -n8 shellcheck --severity=warninggit diff --checknpm run lint:md0issues)Residual risk: live
./scripts/verify-backendswas not run in this session because it requires a sandbox-capable host/backend setup.feat(schema): add optional agent block to hybrid/v1 kit schema (#454)
feat(acq-kits): add opencode agent-harness kit (SHA-pinned release bi…
mogul commentedon Oct 6, 2026
Shipped in v4.0.0
The devenv-base / agent-kit migration tracked by this issue is implemented, released, and verified end-to-end on both backends.
Release: https://github.com/GSA-TTS/agentic-coding-quickstart/releases/tag/v4.0.0
Patterns pin: agentic-coding-patterns v1.12.0 (
56d1f5f49ef928f50e61aa64a93d618b3d21c415)What landed
Core migration arrived in #474, with the capability/agent-kit layer completed by #549 and the shared markdownlint fix factored out to #548.
opencodeagent kit.opencode-aifrom npm.oci-enginecatalog kit; adapter-owned MSB OCI auto-install and unconditional device grants retired.provider-facts/usai.env), with a transitional fallback.~/.rc.d/*.shshell-snippet contract, bridged on both msb and sbx.Breaking changes (see v4.0.0 notes)
oci-engineviaacq configure,--kit, orACQ_EXTRA_KITS.oci-engine.Verification
scripts/verify-backendson the release branch: msb 15/0/1, sbx 10/0/1 (the single skips are the no-GitHub-token playbook fetch).Closed by this work
#478, #479, #480, #481, #482, #483, #484, #485, #505.
Deliberately out of scope / tracked separately
Closing this umbrella issue as the migration is shipped in v4.0.0.