Skip to content

feat: named per-repo toolchain image variants - #10

Merged
devzeebo merged 7 commits into
mainfrom
feat/toolchain-image-variants
Aug 30, 2026
Merged

feat: named per-repo toolchain image variants#10
devzeebo merged 7 commits into
mainfrom
feat/toolchain-image-variants

Conversation

@devzeebo

Copy link
Copy Markdown
Collaborator

Summary

  • Adds buildToolchainImage(variant, { agent, dockerfileRelative, ... }) to bake a content/repo-hashed layer on top of the agent image and register it by name
  • Lets tests select that layer with agent({ name, variant }) (no tag plumbing); image remains a mutually exclusive escape hatch
  • Persists the variant registry under /tmp/.agent-gwt/… so vitest globalSetup is visible to test workers; documents the pattern in the README

Closes #5

Test plan

  • pnpm lint && pnpm test
  • In a consumer repo, add a Dockerfile FROM agent-gwt/cursor-cli:local, call buildToolchainImage("node18", …) from vitest globalSetup, and run agent({ name: "cursor", variant: "node18" })
  • Confirm changing the Dockerfile rebuilds (new tag) and an unchanged Dockerfile reuses the cached image
  • Confirm omitting variant still uses the stock agent image; unknown variant / both image+variant error clearly

Allow consumers to build a per-repo content-hashed layer on the agent
image and select it via agent({ variant }) without threading tags
through every test (#5).

@devzeebo devzeebo left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review (issue #5)

Named variant + buildToolchainImage is the right consumer API, and the vitest worker registry problem is real. I would not merge yet: skip-if-present plus a Dockerfile-only hash can serve a stale image, and the on-disk registry is a racy read-modify-write.

(Posted as a comment review — GitHub blocks REQUEST_CHANGES on your own PR.)

Blockers

  1. Incomplete invalidate key — tag ignores parent image ID and build-context files (COPY/ADD). See inline on build-toolchain-image.ts.
  2. variants.json lost updates — shared read→mutate→write under parallel registration / this repo’s parallel specs. See inline.

Should fix

  1. FROM is docs-only; not tied to options.agent (easy footgun: agent: "claude" + Cursor FROM).
  2. ensureDockerImage and agentRunError (unchanged in this PR) still only hint buildAgentImage when a pruned toolchain tag is usually a buildToolchainImage miss — please update those messages in this PR or a follow-up.
  3. Image digest uses packageRoot; registry path uses process.cwd() — document or align.

Nit

  • c59f101 (.codegraph/ gitignore) is unrelated to #5 — prefer a separate commit/PR.
  • Tmp root is .agent-gwt while workspaces use .agents-gwt.
  • Prefer one file per variant key (or lock + atomic write) over a single JSON blob.

What’s solid

  • variant vs image mutual exclusion and clear unknown-variant errors
  • Disk bridge for vitest globalSetup → workers
  • Reuse of buildDockerImage memoization for the Docker side
  • GWT coverage for tag identity / Dockerfile change / skip-if-present
  • README example folds buildAgentImage into buildToolchainImage

Comment thread src/agents/build-toolchain-image.ts Outdated
Comment thread src/agents/build-toolchain-image.ts Outdated
Comment thread src/agents/build-toolchain-image.ts Outdated
Comment thread src/agents/build-toolchain-image.ts
Comment thread src/agents/build-toolchain-image.ts Outdated
Comment thread src/given/agent.ts
Comment thread README.md Outdated
Comment thread src/given/agent.spec.ts Outdated
Comment thread .gitignore
Include parent image ID in the digest, force docker rebuilds, pass
AGENT_IMAGE as a build-arg with FROM validation, and use per-key
registry files under the packageRoot digest. Update missing-image
hints and README caveats; drop the unrelated .codegraph gitignore.
@devzeebo

Copy link
Copy Markdown
Collaborator Author

Addressed the review on this PR:

  • Digest / staleness: parent image ID is part of the tag digest; toolchain builds always run docker build (force: true)
  • Registry races: one file per variant under /tmp/.agents-gwt/toolchains/<packageRootDigest>/ (atomic rename)
  • FROM footgun: --build-arg AGENT_IMAGE=… + validation of the first FROM
  • Hints: ensureDockerImage / agentRunError mention buildToolchainImage where relevant
  • Specs: withAspect for reset/cleanup; reverted unrelated .codegraph gitignore

@devzeebo devzeebo left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up review (1a98dbb)

Prior blockers look addressed. Nice work — this is in much better shape.

Resolved

  • Parent image ID in the digest + force: true (Dockerfile/COPY/ADD + parent rebuilds)
  • Per-key registry files under packageRoot digest, atomic write+rename, shared .agents-gwt tmp root
  • AGENT_IMAGE build-arg + FROM validation; README example/caveats
  • ensureDockerImage / agentRunError toolchain hints
  • Unrelated .codegraph gitignore dropped; agent.spec mocks resolve (no shared-registry flake)
  • Tests for parent-id change, force rebuild, FROM mismatch

CI is green. Remaining items are smaller — see inline. I would not block merge on them, but the variant filename collision is worth fixing before this gets wide use.

Comment thread src/agents/build-toolchain-image.ts Outdated
Comment thread src/agents/build-toolchain-image.spec.ts
Comment thread src/agents/build-toolchain-image.ts
Comment thread src/agents/build-toolchain-image.ts
Use a digest of agent::variant for on-disk filenames so variants cannot
collide, clear temp packageRoot registries in aspect hooks, note
first-FROM-only validation, and cover force/buildArgs on buildDockerImage.
@devzeebo
devzeebo merged commit a640e57 into main Aug 30, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Per-repo Docker toolchain layers on the agent image

1 participant