NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
Go modules · #688 by repository stars
Last release 3 days ago
05 Oct 2026
Ships on a steady schedule
a new release about every 9 days
Nearly every release is documented
notes for 57 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
11 months old
927 releases · first in 2025
One column per month.
security(deps): bump pytest to >=9.0.3 (CVE-2025-71176) by @AbirAbbas in https://github.com/Agent-Field/agentfield/pull/488
⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
# Staging binary (use --staging flag)
curl -fsSL https://agentfield.ai/install.sh | bash -s -- --staging
# Python SDK (prerelease - requires --pre flag)
pip install --pre agentfield
# TypeScript SDK
npm install @agentfield/sdk@next
VERSION=v0.1.137-rc.7 curl -fsSL https://agentfield.ai/install.sh | bash
Download the binary for your platform below, make it executable, and move it to your PATH.
agentfield-darwin-amd64agentfield-darwin-arm64agentfield-linux-amd64agentfield-linux-arm64af call rejecting valid input for optional reasoner params by @AbirAbbas in https://github.com/Agent-Field/agentfield/pull/610_current_status issue where status stuck on `S… by @DebanKsahu in https://github.com/Agent-Field/agentfield/pull/673af install by @AbirAbbas in https://github.com/Agent-Field/agentfield/pull/738Note truncated.
fix(control-plane): honor execution query filters
fix(control-plane): allow operator note reads
fix(control-plane): return persisted execution details
fix(control-plane): export traces to configured OTLP transport
docs(control-plane): document tracing configuration
fix(control-plane): use complete workflow reads for details
fix(control-plane): restore exact execution detail reads
chore(control-plane): tidy tracing dependencies
style(control-plane): format execution storage fixture
fix(control-plane): use exporter-specific OTLP defaults
docs(control-plane): clarify tracing startup failures
docs(control-plane): describe execution note operator reads (e38277a)
security(deps): bump pytest to >=9.0.3 (CVE-2025-71176) by @AbirAbbas in https://github.com/Agent-Field/agentfield/pull/488
⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
# Staging binary (use --staging flag)
curl -fsSL https://agentfield.ai/install.sh | bash -s -- --staging
# Python SDK (prerelease - requires --pre flag)
pip install --pre agentfield
# TypeScript SDK
npm install @agentfield/sdk@next
VERSION=v0.1.137-rc.6 curl -fsSL https://agentfield.ai/install.sh | bash
Download the binary for your platform below, make it executable, and move it to your PATH.
agentfield-darwin-amd64agentfield-darwin-arm64agentfield-linux-amd64agentfield-linux-arm64af call rejecting valid input for optional reasoner params by @AbirAbbas in https://github.com/Agent-Field/agentfield/pull/610_current_status issue where status stuck on `S… by @DebanKsahu in https://github.com/Agent-Field/agentfield/pull/673af install by @AbirAbbas in https://github.com/Agent-Field/agentfield/pull/738Note truncated.
feat(sdk): allow disabling structured log stdout mirroring
fix(sdk): treat AGENTFIELD_LOG_STDOUT like the SDK's other on-by-default flags
AGENTFIELD_LOG_STDOUT was parsed as == "true", so only the literal string
"true" kept the stdout mirror on. Every other value turned it off, including
values that are truthy everywhere else in the SDK (_TRUTHY_ENV_VALUES in
agent.py accepts 1/true/yes), a set-but-empty variable — what a bare
AGENTFIELD_LOG_STDOUT= in a Compose file or value: "" in a Kubernetes
manifest produces — and any typo. An operator who set the flag to 1 to keep
mirroring, or who left it empty, silently lost their structured log output.
Use the falsy-list convention already established by node_logs.logs_enabled() for on-by-default flags: 0/false/no/off disable, everything else keeps the default. The flag now fails towards keeping records visible.
Also move the docs entry out of "Control Plane (Server) > Logging" into "Agent Nodes > Python SDK agents" — the variable is read only by the Python SDK, so a server operator setting it would see no effect — and spell out the accepted values the way the neighbouring AGENTFIELD_DISABLE_IP_DETECTION entry does.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
fix(sdk): make structured stdout mirroring opt-in
Revert "fix(sdk): make structured stdout mirroring opt-in"
This reverts commit ff99fa92be41ab3955679826d954d06cb347e05d.
Co-authored-by: Abir Abbas abirabbas1998@gmail.com Co-authored-by: Claude Fable 5 noreply@anthropic.com (515ae55)
test(sdk): cover graceful shutdown contracts
fix(sdk/go): drain asynchronous executions on shutdown
fix(sdk/typescript): handle signals and drain executions
test(sdk/typescript): run shutdown parser contract in suite
docs(sdk): document shared graceful shutdown timeout
fix(sdk/go): unblock Serve after remote shutdown
fix(sdk/go): bound graceful shutdown drain
test(sdk/go): cover asynchronous shutdown drain
fix(sdk/typescript): cancel all executions on shutdown timeout
fix(sdk/typescript): exit after signal shutdown
fix(sdk/typescript): reuse shutdown promise
test(sdk/typescript): cover shutdown drain lifecycle
test(sdk/go): cover shutdown drain branches
chore: drop stray worker report from repo root
REPORT.md was an agent work-log artifact accidentally committed to the repository root; it is not project documentation and should not ship.
Lost while resolving the ENVIRONMENT_VARIABLES.md rebase conflict.
Moves the Go/TypeScript AGENTFIELD_SHUTDOWN_TIMEOUT section next to the other agent-node settings instead of the end of the file, and leaves the control-plane bullet untouched, so sibling PRs editing the same document merge in any order. Points at the Python SDK section for its equivalent.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
fix(ts-sdk): bound post-cancel drain wait
fix(ts-sdk): reject executions during shutdown
fix(go-sdk): make shutdown lease stop idempotent
docs: clarify graceful shutdown bound
Co-authored-by: Claude Fable 5 noreply@anthropic.com (9399409)
security(deps): bump pytest to >=9.0.3 (CVE-2025-71176) by @AbirAbbas in https://github.com/Agent-Field/agentfield/pull/488
⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
# Staging binary (use --staging flag)
curl -fsSL https://agentfield.ai/install.sh | bash -s -- --staging
# Python SDK (prerelease - requires --pre flag)
pip install --pre agentfield
# TypeScript SDK
npm install @agentfield/sdk@next
VERSION=v0.1.137-rc.5 curl -fsSL https://agentfield.ai/install.sh | bash
Download the binary for your platform below, make it executable, and move it to your PATH.
agentfield-darwin-amd64agentfield-darwin-arm64agentfield-linux-amd64agentfield-linux-arm64af call rejecting valid input for optional reasoner params by @AbirAbbas in https://github.com/Agent-Field/agentfield/pull/610_current_status issue where status stuck on `S… by @DebanKsahu in https://github.com/Agent-Field/agentfield/pull/673af install by @AbirAbbas in https://github.com/Agent-Field/agentfield/pull/738Note truncated.
fix(sdk/python): refresh dependency lock
ci(sdk/python): test Python 3.13 and lock drift
ci(sdk/python): add weekly LiteLLM canary
chore(sdk/python): relock after the #993 litellm marker split
Regenerates uv.lock on top of main now that PR #993 scopes the litellm !=1.97.0,<1.98.0 cap to python_version < '3.11'. The lock now carries both marker branches in requires-dist and passes uv lock --check, which the sdk-python workflow enforces from this PR.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Co-authored-by: Claude Fable 5 noreply@anthropic.com (0b39990)
security(deps): bump pytest to >=9.0.3 (CVE-2025-71176) by @AbirAbbas in https://github.com/Agent-Field/agentfield/pull/488
⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
# Staging binary (use --staging flag)
curl -fsSL https://agentfield.ai/install.sh | bash -s -- --staging
# Python SDK (prerelease - requires --pre flag)
pip install --pre agentfield
# TypeScript SDK
npm install @agentfield/sdk@next
VERSION=v0.1.137-rc.4 curl -fsSL https://agentfield.ai/install.sh | bash
Download the binary for your platform below, make it executable, and move it to your PATH.
agentfield-darwin-amd64agentfield-darwin-arm64agentfield-linux-amd64agentfield-linux-arm64af call rejecting valid input for optional reasoner params by @AbirAbbas in https://github.com/Agent-Field/agentfield/pull/610_current_status issue where status stuck on `S… by @DebanKsahu in https://github.com/Agent-Field/agentfield/pull/673af install by @AbirAbbas in https://github.com/Agent-Field/agentfield/pull/738Note truncated.
docs(control-plane): correct storage mode names
docs(api): document execution and restart contracts
docs(control-plane): describe live execution knobs
docs(kubernetes): add agent rollout guidance (f9ef7ba)
When storage.mode is postgres, payloads are already persisted inline in the execution record (input_payload / result_payload BYTEA columns). The FilePayloadStore was unconditionally writing them to disk as well, causing unbounded disk growth (~2GB/30d) and eventual pod eviction.
Fix: use a NopPayloadStore when mode is postgres. savePayload returns nil, so InputURI/ResultURI stay NULL - all read paths already prefer the inline columns and only fall back to URI when inline is empty. (fb9aa44)
Moving the OpenCode target to a native ~/.config/opencode/skills/<name> symlink leaves the marker block older af binaries appended to ~/.config/opencode/AGENTS.md behind forever: uninstallMarkerBlock is no longer reachable for this target, so nothing can remove it. Upgrading users end up with the native skill and the stale instructions — the AGENTS.md bloat #813 was actually about. Codex made the same migration in #910 and shipped removeLegacyMarkerBlock for exactly this reason.
Install (once the symlink is in place) and Uninstall (per catalog skill) now strip that block. The rules are deliberately stricter than the Codex helper, because the two files are not alike: Codex's AGENTS.override.md was created by af for itself, while ~/.config/opencode/AGENTS.md is written by the user and read by OpenCode. So a file holding no block of ours is never opened for writing — bytes and mtime stay exactly as the user left them — and the file is deleted only when removing our block is what emptied it. Reusing uninstallMarkerBlock verbatim would instead rewrite any AGENTS.md it can read (measured: a user file with no agentfield block goes 23 -> 21 bytes) and delete a deliberately empty one on every install.
Other tools' marker blocks and user prose on both sides of ours survive; a missing file is a no-op; read/write failures propagate, matching the target's existing Uninstall error contract.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
TestOpenCodeTargetUninstallRemovesCatalogEntries was the one OpenCode test that did not call withTempHome, so it built and tore down catalog entries in the home shared by the whole package instead of its own.
realHomeSnapshot also still only fingerprinted the old ~/.config/opencode/AGENTS.md. Now that OpenCode installs a directory of symlinks, add ~/.config/opencode/skills so the real-home pollution guard covers the path this target actually writes to.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
removeLegacyMarkerBlock called os.Remove/os.WriteFile/os.Rename directly while every other write path in the package goes through the reconcile* seams (reconcile.go), which exist precisely so a test can force a failure. The consequence was that its "remove", "write" and "rename into" branches could not be exercised at all: six lines that never ran once, and error strings that could ship wrongly wrapped without anything noticing.
Switch the four filesystem calls to reconcileReadFile/reconcileRemove/ reconcileWriteFile/reconcileRename and cover each failure through Uninstall, modelled on the reconciler's own rewrite-failure subtests.
Also drop legacyRulesPath's error return. It could only fail when TargetPath() fails, and both call sites have already proven TargetPath() succeeds before reaching it — so the branch was unreachable and told a reader about a failure mode that does not exist. It now takes the resolved skills root, which lets Uninstall use the TargetPath() result it was already computing and discarding instead of re-resolving it per skill.
No behaviour change: same files read, same files written, same errors returned.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Restores skillkit changes from a2762e14 (PR #947) dropped by the squash 9a14e21e.
fix(sdk): mark nested harness subprocesses
docs(harness): document depth guard and OpenCode limits
Documents AGENTFIELD_HARNESS_DEPTH and removes unsupported OpenCode tool and permission claims.
Co-authored-by: Claude Fable 5 noreply@anthropic.com (29c209f)
security(deps): bump pytest to >=9.0.3 (CVE-2025-71176) by @AbirAbbas in https://github.com/Agent-Field/agentfield/pull/488
⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
# Staging binary (use --staging flag)
curl -fsSL https://agentfield.ai/install.sh | bash -s -- --staging
# Python SDK (prerelease - requires --pre flag)
pip install --pre agentfield
# TypeScript SDK
npm install @agentfield/sdk@next
VERSION=v0.1.137-rc.3 curl -fsSL https://agentfield.ai/install.sh | bash
Download the binary for your platform below, make it executable, and move it to your PATH.
agentfield-darwin-amd64agentfield-darwin-arm64agentfield-linux-amd64agentfield-linux-arm64af call rejecting valid input for optional reasoner params by @AbirAbbas in https://github.com/Agent-Field/agentfield/pull/610_current_status issue where status stuck on `S… by @DebanKsahu in https://github.com/Agent-Field/agentfield/pull/673af install by @AbirAbbas in https://github.com/Agent-Field/agentfield/pull/738Note truncated.
Signed-off-by: ump45nose 52391318+ump45nose@users.noreply.github.com (e9710dc)
security(deps): bump pytest to >=9.0.3 (CVE-2025-71176) by @AbirAbbas in https://github.com/Agent-Field/agentfield/pull/488
⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
# Staging binary (use --staging flag)
curl -fsSL https://agentfield.ai/install.sh | bash -s -- --staging
# Python SDK (prerelease - requires --pre flag)
pip install --pre agentfield
# TypeScript SDK
npm install @agentfield/sdk@next
VERSION=v0.1.137-rc.2 curl -fsSL https://agentfield.ai/install.sh | bash
Download the binary for your platform below, make it executable, and move it to your PATH.
agentfield-darwin-amd64agentfield-darwin-arm64agentfield-linux-amd64agentfield-linux-arm64af call rejecting valid input for optional reasoner params by @AbirAbbas in https://github.com/Agent-Field/agentfield/pull/610_current_status issue where status stuck on `S… by @DebanKsahu in https://github.com/Agent-Field/agentfield/pull/673af install by @AbirAbbas in https://github.com/Agent-Field/agentfield/pull/738Note truncated.
Add Pi and OMP harness providers
Make OMP the default harness provider
Improve Pi and OMP harness coverage
address review comments on #913
Sweeps the OMP-as-default remnants left in non-conflicting files after the merge, and brings the Go Pi/OMP provider up to the Result.Model contract main added for aforge/opencode:
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Follow-up to the merge: three places still baked OMP (or an eagerly resolved default) into the no-configuration path, which the gates caught.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
The TypeScript pi/omp provider returned failures with neither failureType nor returnCode set, so callers could not tell a crash from an API error or an empty completion — the Go and Python pi providers both classify. Mirror their exact ladder: signal death -> crash, non-zero exit -> crash, a stopReason error/aborted on a clean exit -> api_error, a clean exit with no assistant text -> no_output, otherwise none. stderr is now ANSI-stripped and capped at 1000 chars like Go/Python. The catch path classifies a timeout distinctly from a crash.
runCli resolved code ?? 0, so a child killed by a signal looked like a
clean exit 0 and the "Process killed by signal N" branch was unreachable.
It now reports the negative signal number, matching Go's os/exec and
Python's asyncio subprocess.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
runner.ts bases the schema-output directory on projectDir ?? cwd, but only
pi/omp and aforge read projectDir — codex, gemini, opencode and claude used
options.cwd alone. { schema, projectDir, cwd, provider: 'codex' } therefore
wrote the instruction file into one directory and ran the CLI in another, so
the agent was told to write a file outside the root it could see.
Add a single resolveRoot() helper (projectDir -> project_dir -> cwd, the precedence every Python provider already uses) and route all six providers through it. This also fixes opencode's inverted ladder, which checked cwd first and then a snake_case project_dir key the TS options object never carries.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
af doctor --probe ran pi --print "Say OK" with the prompt positional and
stdin left at EOF, while all three SDK adapters run <bin> --print --mode json
and feed the prompt over stdin. The probe therefore exercised a different
surface than the harness does, so a healthy install could be reported as
empty or error.
The registry entry gains ProbeStdin; pi and omp now carry the adapters' exact flag set with the prompt on stdin, and runProbeCommand wires a strings.Reader in when a payload is present. Providers that take the prompt positionally keep a nil stdin, and the 60s probe bound is unchanged.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Verified against the real CLIs (pi 0.74.2, omp v18.0.7):
--approve, --auto-approve, --yolo,
-y, --approval-mode and --permission-mode each fail with
Error: Unknown option: <flag>, so the permission_mode="auto" branch made
every Pi auto-mode run die on argument parsing. Only OMP gets a flag now
(--auto-approve, which it does document).--tools is an enforced allowlist in both CLIs and is Pi's own documented
read-only mechanism ("Read-only mode (no file modifications possible):
pi --tools read,grep,find,ls -p ..."), so plan mode is genuinely read-only
with no approval flag. OMP's default tools.approvalMode is yolo, and even
always-ask auto-approves read-only tiers, so a read-only allowlist never
blocks on approval there either.Plan mode therefore keeps sending only the read-only allowlist. The flag set is now pinned by a test in each SDK that rejects every known approval-style flag, and the ground truth is recorded in a comment at each branch so it does not get "fixed" back.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
test_default_provider_is_aforge asserts the built-in default, but HarnessConfig.provider resolves through AGENTFIELD_HARNESS_PROVIDER, so the test failed on any machine that pins a harness provider in the environment. Every sibling test that asserts this default already clears the variable (test_harness_types.py, test_types.py, test_harness_defaults.py, test_harness_runner.py); this one did not.
Verified: AGENTFIELD_HARNESS_PROVIDER=codex pytest tests/test_harness_factory.py
now passes.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
--provider has no default: omitting it surveys every provider. In cobra
help, "(default)" reads as the flag's own default value, so annotating
aforge that way advertised behaviour the flag does not have. aforge is the
SDK's default harness provider, which is a different statement and belongs
in the SDK docs, not in this flag's help.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
The test body never asserted a default — it checks OMP's provider name, auth status, official install command and usability — but its name was residue from the reverted "OMP is the default provider" design. aforge is the default; this was the last OMP-default claim left in the tree.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
The two other README spots that enumerate harness providers already list pi and omp; the "Harness (Multi-turn Coding Agents)" table still stopped at opencode. aforge stays the zero-setup default, stated in the row above.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
The Pi-family event stream can carry several assistant message_end events. All three adapters took the assistant text last-writer-wins but kept the provider error first-writer-sticky: once any message_end reported stopReason "error" or "aborted", nothing cleared it. A run whose model call failed on an intermediate turn and then recovered was surfaced as failure_type=api_error with a stale message, its correct final answer discarded — and since api_error is transient, the runner burned a retry re-running the whole harness invocation.
Only the final message_end's stop reason decides now: every assistant message_end sets or clears the provider error. Nothing else about the parse changes, and no exit-code branch moves.
Fixed identically in Go, Python and TypeScript with a regression test in each, covering both error-then-recovery (clean run) and recovery-then-error (still an api_error).
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
resolveRoot() centralised the provider-side working-directory ladder (projectDir -> project_dir -> cwd), but the runner kept its own two-rung version that never looked at project_dir. resolveOptions copies overrides with Object.entries, so a JS caller's project_dir key does reach the providers: with { project_dir: P, cwd: C } the schema instruction file was created under C while the provider ran in P, and the harness was told to write its output to a path outside the directory it was running in. Before this branch that split existed for aforge alone; centralising the ladder had widened it to six providers.
The runner now calls resolveRoot on the resolved options, so the two ladders are identical by construction. Regression test covers the snake_case-only case; it fails if the line is reverted.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
ClaudeCodeProvider goes through @anthropic-ai/claude-agent-sdk rather than
cli.runCli, so the runner's provider matrix cannot reach it, and the existing
claude tests only ever passed cwd. Reverting claude.ts to the old
options.cwd line left the whole suite green.
Two tests close that: projectDir wins over a nested cwd, and an empty-string cwd now leaves the SDK option unset (resolveRoot skips empty strings, where the old code forwarded ''). Both fail against the reverted hunk.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
af doctor survey aforge, the default harness providerThe agentfield skill gates every use of app.harness() on af doctor
reporting harness_usable: true AND listing the chosen provider. doctor's
provider list never contained aforge, so on the default install — aforge
shipped with af, nothing else present — an agent following the skill
concluded the harness was unusable and refused to use the default provider.
This branch had made that worse by adding aforge to the skill's provider
union while leaving doctor's list alone.
Detection now reuses af harness doctor's spec table
(findHarnessProviderSpec + probeHarnessBinary) wherever a binary-backed spec
exists, so both doctors agree on what "installed" means. That matters for
aforge specifically: it answers version, not --version, and af aforge ensure installs it into $AGENTFIELD_HOME/bin, which the current shell's PATH
usually does not contain. claude-code has no binary in that table (it is the
pip-package wrapper) and keeps the plain PATH check.
--probe skips providers that declare no ProbeArgs, which is aforge alone:
every other probe is one trivial completion, whereas aforge's only one-shot
is a full coding-agent run with write access to the working directory, which
is not something a doctor command should start. af harness doctor reports
aforge's health.
Live-verified with a fake aforge in $HOME/.agentfield/bin and an empty PATH:
af doctor --json reports aforge available with its version, and
recommendation.harness_usable true / harness_providers ["aforge"];
af doctor --probe produces no aforge probe entry.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
--probe reporting a silently broken pi/omp install as okclassifyProbe decided "empty" purely by an empty stdout. That was correct
while pi/omp probed in plain --print text mode, but they now probe with
--print --mode json, and the CLI emits a {"type":"session",...} event
before any assistant output. stdout is therefore never blank and the probe
always fell through to "ok" — so an install that exits 0 with a parsed stream
and no assistant text, and one whose message reports stopReason "error", both
came back healthy. That negates the exact capability --probe's own help text
advertises, for the two providers this branch added.
Providers whose probe output is a JSON event stream are now marked JSONLStream, and their probes apply the SDK adapters' own success criterion: an assistant message_end carrying text, with the last assistant message_end's stop reason not "error"/"aborted" (a turn that errored and then recovered is not a failure, matching the adapter fix in this branch). An exit-0 stream error surfaces its message as the probe detail when stderr is silent. Plain text providers keep the previous rule unchanged.
Live-verified with fakes on PATH: an omp printing only
{"type":"session","id":"s1"} and exiting 0 now reports status "empty" where
it reported "ok" before; a pi printing a real assistant message_end still
reports "ok".
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
af doctor's aforge detection against a silent revertThe branch in buildDoctorReport that routes detection through the harness
doctor's spec table (findHarnessProviderSpec + probeHarnessBinary) is the
whole behavior of "fix(cli): make af doctor survey aforge, the default
harness provider" — it is what makes doctor ask aforge for version rather
than --version, and what makes it look in $AGENTFIELD_HOME/bin when the
binary is not on PATH. Replacing that branch with main's original
checkTool(h.Binary, "--version") left the entire internal/cli suite green,
so a future refactor could revert the fix without CI noticing.
TestBuildDoctorReport_AforgeDetectionUsesHarnessSpec drives buildDoctorReport with a shell-script aforge stub and covers both halves:
• installed only in $AGENTFIELD_HOME/bin with an empty PATH — doctor must
report it available, with the managed path and its version;
• on PATH but answering version only (non-zero on --version) — doctor
must still record the version.
Both subtests fail under the checkTool(h.Binary, "--version") mutation
(available:false / version:"" respectively), and the full
go test ./internal/cli/ -count=1 suite stays green.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Co-authored-by: Abir Abbas abirabbas1998@gmail.com Co-authored-by: Claude Fable 5 noreply@anthropic.com (44d63dc)
Your coding agent can read these notes before it upgrades. Set up the MCP server →