feat: make AForge exec the default harness - #7
Merged
Conversation
…istry image The image pulled `ghcr.io/agent-field/aforge-v2:chat-v2-exec` and copied `/aforge` out of it. That package is not publicly pullable, so an out-of-the-box `docker compose up --build` failed for anyone without registry access. Replace it with a fetch stage that downloads the released binary over plain HTTPS from the public download host, decompresses it, and verifies the *decompressed* binary's SHA-256 against the release `checksums.txt` before it is copied into the runtime image. The verification is a hard build failure: an absent or mismatched checksum line aborts the build. `AFORGE_BASE_URL` and `AFORGE_VERSION` stay overridable build args, and docker-compose forwards both from the environment, so a mirror or a newer build can be selected without editing the Dockerfile. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The unreleased git SHA pin required `allow-direct-references` and a `git`-capable build environment, and it pinned an SDK that no consumer could resolve from an index. `agentfield>=0.1.129` is on PyPI and already ships the Python AForge harness provider (`agentfield/harness/providers/aforge.py`), which runs `aforge exec --json -w <root>` and accepts the `aforge_bin` field this agent sets on `HarnessConfig`. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add two behaviour tests: `CLOUDSECURITY_AFORGE_BIN`/`AFORGE_BIN` override the resolved binary path, and the pinned agentfield floor actually accepts the `provider="aforge"` + `aforge_bin=...` HarnessConfig this agent constructs — so dropping the SDK floor below the release that carries the AForge provider fails the suite instead of failing at runtime. Document `AFORGE_BASE_URL`/`AFORGE_VERSION` in the README, and correct the `AGENTFIELD_AFORGE_COMMAND` row: the shipped SDK always runs `aforge exec`, so that variable is forward-looking rather than a live switch. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
aforge-v2 cut its first semver release (v0.1.0), so the AFORGE_VERSION default moves off the build-<sha> coordinate onto the tag. Bumping the string is what busts the fetch layer's cache, so this is what actually pulls the released binary instead of restoring the stale one. Moves all four places the coordinate is written: the Dockerfile ARG, the docker-compose build arg fallback, the .env.example hint, and the README build-arg table and override example. The AgentField SDK pin is deliberately left alone — it bumps on its own release. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
0.1.130 is the first agentfield release cut after the aforge exec harness landed as the default provider. Raise the floor in both the package metadata and the runtime image so a fresh install and a fresh container build both resolve the release this agent is verified against. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…eld>=0.1.130 The "forward-looking / always runs exec" wording was written against 0.1.129. 0.1.130 reads AGENTFIELD_AFORGE_COMMAND (default `exec`, `do` opts into the routed workflow), so describe the real behaviour. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
AbirAbbas
marked this pull request as ready for review
August 18, 2026 02:28
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Make AForge the default CloudSecurity-AF harness and run it through
exec, withOpenCode retained as a configuration-only rollback.
Two things changed since the first draft, both aimed at making a clean checkout
build and run with no private access:
do
FROM ghcr.io/agent-field/aforge-v2:chat-v2-exec+COPY --from=aforge /aforge.That package is not publicly pullable, so
docker compose up --buildfailed foranyone without registry credentials. A fetch stage now downloads
${AFORGE_BASE_URL}/${AFORGE_VERSION}/aforge-linux-${TARGETARCH}.gz, gunzips it,and verifies the decompressed binary's SHA-256 against the release
checksums.txtbefore it is copied to/usr/local/bin/aforge.agentfield @ git+…@bfd34426(which also needed
[tool.hatch.metadata] allow-direct-references) is replacedby
agentfield>=0.1.129, the released SDK that already ships the Python AForgeharness provider.
Configuration
AFORGE_BASE_URLhttps://agentfield.ai/downloads/aforge<version>/aforge-linux-<arch>.gzand<version>/checksums.txtAFORGE_VERSIONv0.1.0Both are overridable via
--build-arg, anddocker-compose.ymlforwards them fromthe environment, so a mirror can be selected without editing the Dockerfile.
SDK pin: what works today and what does not
agentfield>=0.1.129supplies everything this agent actually depends on —SUPPORTED_PROVIDERSincludesaforge,HarnessConfighas anaforge_binfield,and the provider runs
aforge exec --json -w <root>. Two caveats to bump later:AGENTFIELD_AFORGE_COMMANDis a no-op on 0.1.129. The env var is set in theimage, in compose, and injected into the harness subprocess env, but the shipped
provider hardcodes the
execsubcommand — nothing reads the variable. It becomesa live switch only once feat(harness): make aforge the default provider across Python, Go, and TypeScript agentfield#905 is released. Keeping it wired
now means the rollback path costs no code change later.
--timeout, so AForge's own 15-minute wallapplies to each harness call (the SDK's outer kill is
AGENTFIELD_HARNESS_TIMEOUT_SECONDS, default 1800s). #905 adds explicit flagplumbing.
Exact lines to bump when the #905 release lands (same version string in both):
pyproject.toml:14—"agentfield>=0.1.129",Dockerfile:51—"agentfield>=0.1.129" \There is no Go node in this repo, so there is no
sdk/gopseudo-version to carry.Validation contract
Observable behaviours this change must exhibit:
docker build .succeeds with no registry credentials and nogitaccess to aprivate repo.
/usr/local/bin/aforgeis byte-identical to the publishedrelease artifact — a tampered or truncated download fails the build rather
than shipping.
aforgeis onPATHand executable as the non-rootcloudsecurityuser.OPENROUTER_API_KEYset, the agent resolves the AForge harness —provider
aforge,AforgeProvider, binary/usr/local/bin/aforge.HARNESS_PROVIDER=opencodestill resolvesOpenCodeProvider(rollback intact).inside the image.
/health.CLOUDSECURITY_AFORGE_BIN/AFORGE_BINoverride the resolved binary path.main.How it was verified
Built against a local mirror of the published layout (
--build-arg AFORGE_BASE_URL=…);the default value in the committed Dockerfile is the public host.
docker build→DONE, and the fetch stage loggedsha256sum -c→aforge: OK.Negative test: rebuilt the fetch stage against a mirror serving a byte-flipped
binary with the genuine
checksums.txt→aforge: FAILED/sha256sum: WARNING: 1 computed checksum did NOT match, build exit 1.docker run --rm <img> aforge --help→ exit 0, AForge usage banner.ls -l→-rwxr-xr-x … /usr/local/bin/aforge;in-image
sha256sum=61217a18…c79f5, matching the releasechecksums.txtline for
aforge-linux-amd64;id→uid=10001(cloudsecurity).In-container resolution with only
OPENROUTER_API_KEYset:resolved provider: aforge,resolved provider class: AforgeProvider,resolved aforge_bin: aforge -> /usr/local/bin/aforge.Same script with
HARNESS_PROVIDER=opencode→OpenCodeProvider.Live smoke inside the image, prompt
Reply with exactly OK:{"text":"OK","stop":"done","usage":{...},"turns":1,...}, exit 0.AIIntegrationConfig:is_error: False,returncode: 0,result text: 'OK'.In-image SDK version confirmed as
agentfield 0.1.129.docker run -d …thencurl /health→{"status":"healthy","node_id":"cloudsecurity",…}within 2s.
docker compose configresolves;AFORGE_BASE_URL/AFORGE_VERSIONoverridesflow through to the build args.
Gates (this repo has no CI; the
Developmentsection of the README definesthem). Run on Python 3.11 against
mainand this branch:mainpytest -q(ignoring the 2 modules that fail collection onmain)ruff check src testsmypy srcThe 4 extra passes are the AForge default/rollback/bin-override/SDK-contract
tests.
tests/test_graph_context.pyandtests/test_schemas.pyfail collectionon
maintoo (ResourceEdge/ResourceClustermissing fromschemas/recon.py, a file this PR does not touch); the 38 failures and themypycount are identical on both refs.Still draft — what un-drafts it
Two external things, both outside this repo:
https://agentfield.ai/downloads/aforge/v0.1.0/must actually serveaforge-linux-{amd64,arm64}.gzandchecksums.txt. The host is live andalready serves the older
build-<sha>coordinate; v0.1.0 is still a 404there. Until that publish lands, a default-args
docker buildcannot fetchthe binary. Un-draft check:
docker build .with no--build-argoverridessucceeds.
AGENTFIELD_AFORGE_COMMANDstops being decorative and the timeout is passed explicitly. Then bump the two
pin lines listed above to that release.
Neither blocks review of the code itself.
Follow-ups (not in scope here)
tests/test_graph_context.py/tests/test_schemas.pyfail collection onmain;tests/test_utils.pyprompt-template assertions andTestDepthProfile::test_prover_capsfail onmaintoo. Worth a separaterepair PR — this branch neither fixes nor worsens them.
soaked, dropping it is a meaningful image-size win.
🤖 Generated with Claude Code