Skip to content

feat: make AForge exec the default harness - #7

Merged
AbirAbbas merged 7 commits into
mainfrom
agent/aforge-exec-default
Aug 18, 2026
Merged

feat: make AForge exec the default harness#7
AbirAbbas merged 7 commits into
mainfrom
agent/aforge-exec-default

Conversation

@AbirAbbas

@AbirAbbas AbirAbbas commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Status update — agentfield v0.1.130 is released; this PR is ready

Everything below the line was written against the 0.1.129 pin and is kept for history. What is true on the current head:

  • Pins bumped: agentfield>=0.1.130 in pyproject.toml and the Dockerfile.
  • "What does not work today" resolved: 0.1.130 reads AGENTFIELD_AFORGE_COMMAND (exec default), passes --timeout/--turns. README wording updated.
  • Live verification (real OpenRouter key, default provider): image built with default args from agentfield.ai + PyPI (aforge v0.1.0, agentfield 0.1.130); node registered on a fresh agentfield/control-plane:latest; cloudsecurity.run_network_hunter on a 3-resource terraform dir found the 0.0.0.0/0 SSH security group at the right line (3 findings), 40 s, <$0.05; .aforge/trace/1.trace.log written; live argv aforge exec --json -w … --timeout 1795 --turns 50 --context-fill 60 --completion-reserve 65536 --model … --plan-model …. Code default with all provider env unset = aforge; HARNESS_PROVIDER / CLOUDSECURITY_PROVIDER=claude-code flip it. Tests: same failure set as main (pre-existing rot in tests/test_utils.py etc.), +4 new passing config tests.
  • Un-draft preconditions met (site live, 0.1.130 on PyPI).

Summary

Make AForge the default CloudSecurity-AF harness and run it through exec, with
OpenCode 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:

  • The AForge CLI is downloaded, not pulled from a registry. The image used to
    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 --build failed for
    anyone 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.txt before it is copied to /usr/local/bin/aforge.
  • The SDK is pinned to a released PyPI version. agentfield @ git+…@bfd34426
    (which also needed [tool.hatch.metadata] allow-direct-references) is replaced
    by agentfield>=0.1.129, the released SDK that already ships the Python AForge
    harness provider.

Configuration

Build arg Default Purpose
AFORGE_BASE_URL https://agentfield.ai/downloads/aforge Download host serving <version>/aforge-linux-<arch>.gz and <version>/checksums.txt
AFORGE_VERSION v0.1.0 Released AForge version to install

Both are overridable via --build-arg, and docker-compose.yml forwards them from
the environment, so a mirror can be selected without editing the Dockerfile.

SDK pin: what works today and what does not

agentfield>=0.1.129 supplies everything this agent actually depends on —
SUPPORTED_PROVIDERS includes aforge, HarnessConfig has an aforge_bin field,
and the provider runs aforge exec --json -w <root>. Two caveats to bump later:

  • AGENTFIELD_AFORGE_COMMAND is a no-op on 0.1.129. The env var is set in the
    image, in compose, and injected into the harness subprocess env, but the shipped
    provider hardcodes the exec subcommand — nothing reads the variable. It becomes
    a 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.
  • 0.1.129's provider passes no --timeout, so AForge's own 15-minute wall
    applies to each harness call (the SDK's outer kill is
    AGENTFIELD_HARNESS_TIMEOUT_SECONDS, default 1800s). #905 adds explicit flag
    plumbing.

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/go pseudo-version to carry.

Validation contract

Observable behaviours this change must exhibit:

  1. docker build . succeeds with no registry credentials and no git access to a
    private repo.
  2. The installed /usr/local/bin/aforge is byte-identical to the published
    release artifact — a tampered or truncated download fails the build rather
    than shipping.
  3. aforge is on PATH and executable as the non-root cloudsecurity user.
  4. With only OPENROUTER_API_KEY set, the agent resolves the AForge harness —
    provider aforge, AforgeProvider, binary /usr/local/bin/aforge.
  5. HARNESS_PROVIDER=opencode still resolves OpenCodeProvider (rollback intact).
  6. A real harness call through the SDK's AForge provider returns model output from
    inside the image.
  7. The container still boots and serves /health.
  8. CLOUDSECURITY_AFORGE_BIN / AFORGE_BIN override the resolved binary path.
  9. The test suite and lint/type gates are no worse than 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.

  1. docker buildDONE, and the fetch stage logged sha256sum -caforge: OK.

  2. Negative test: rebuilt the fetch stage against a mirror serving a byte-flipped
    binary with the genuine checksums.txtaforge: FAILED /
    sha256sum: WARNING: 1 computed checksum did NOT match, build exit 1.

  3. 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 release checksums.txt
    line for aforge-linux-amd64; iduid=10001(cloudsecurity).

  4. In-container resolution with only OPENROUTER_API_KEY set:
    resolved provider: aforge, resolved provider class: AforgeProvider,
    resolved aforge_bin: aforge -> /usr/local/bin/aforge.

  5. Same script with HARNESS_PROVIDER=opencodeOpenCodeProvider.

  6. Live smoke inside the image, prompt Reply with exactly OK:

    • raw CLI: {"text":"OK","stop":"done","usage":{...},"turns":1,...}, exit 0.
    • through the SDK provider built from this repo's AIIntegrationConfig:
      is_error: False, returncode: 0, result text: 'OK'.
      In-image SDK version confirmed as agentfield 0.1.129.
  7. docker run -d … then curl /health{"status":"healthy","node_id":"cloudsecurity",…}
    within 2s.

  8. docker compose config resolves; AFORGE_BASE_URL/AFORGE_VERSION overrides
    flow through to the build args.

  9. Gates (this repo has no CI; the Development section of the README defines
    them). Run on Python 3.11 against main and this branch:

    gate main this branch
    pytest -q (ignoring the 2 modules that fail collection on main) 38 failed, 32 passed 38 failed, 36 passed
    ruff check src tests 110 errors 109 errors
    mypy src 33 errors 33 errors

    The 4 extra passes are the AForge default/rollback/bin-override/SDK-contract
    tests. tests/test_graph_context.py and tests/test_schemas.py fail collection
    on main too (ResourceEdge / ResourceCluster missing from
    schemas/recon.py, a file this PR does not touch); the 38 failures and the
    mypy count are identical on both refs.

Still draft — what un-drafts it

Two external things, both outside this repo:

  1. https://agentfield.ai/downloads/aforge/v0.1.0/ must actually serve
    aforge-linux-{amd64,arm64}.gz and checksums.txt. The host is live and
    already serves the older build-<sha> coordinate; v0.1.0 is still a 404
    there. Until that publish lands, a default-args docker build cannot fetch
    the binary. Un-draft check: docker build . with no --build-arg overrides
    succeeds.
  2. feat(harness): make aforge the default provider across Python, Go, and TypeScript agentfield#905 must be released so AGENTFIELD_AFORGE_COMMAND
    stops 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.py fail collection on main;
    tests/test_utils.py prompt-template assertions and
    TestDepthProfile::test_prover_caps fail on main too. Worth a separate
    repair PR — this branch neither fixes nor worsens them.
  • The runtime image still installs OpenCode (~the rollback path). Once AForge has
    soaked, dropping it is a meaningful image-size win.

🤖 Generated with Claude Code

AbirAbbas and others added 6 commits August 17, 2026 11:08
…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
AbirAbbas marked this pull request as ready for review August 18, 2026 02:28
@AbirAbbas
AbirAbbas merged commit 266a849 into main Aug 18, 2026
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.

1 participant