NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
Go modules · #688 by repository stars
Last release today
03 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
925 releases · first in 2025
One column per month.
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.110-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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.110-rc.3...v0.1.110-rc.4
The summary endpoint computed success_rate from calendar-today (UTC) executions only, returned 0 when nothing had run, and counted in-flight executions as failures. An idle system therefore showed a red 0% under a label claiming "last 24 hours".
Compute the rate over executions started in the rolling last-24h window, count only terminal executions in the denominator, and report 100 when none have finished - no completed runs means nothing has failed.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
The summary endpoint returns success_rate as a 0-100 percentage, but the dashboard multiplied it by 100 again before display. The test fixtures mirrored the same wrong 0-1 scale, so the tautology passed while a real server response would have rendered 9100%. Align the fixtures with the actual API contract.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Co-authored-by: Claude Fable 5 noreply@anthropic.com (623084e)
The Windows tray ignores PNG scale-factor representations (electron/electron#33044) and upscales the 16px bitmap on >100% displays, so make-icons.mjs now also emits one .ico per tray variant with 16/20/24/32/48 frames (20 covers the common 125% scaling). The PNGs stay for the Linux representation path.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Two fixes for the washed-out / blurry tray icon on Windows:
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Co-authored-by: Claude Fable 5 noreply@anthropic.com (6da0607)
Nothing published for this version
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.110-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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.110-rc.2...v0.1.110-rc.3
Bumps the uv group with 1 update in the /sdk/python directory: mcp.
Updates mcp from 1.27.0 to 1.28.1
updated-dependencies:
Signed-off-by: dependabot[bot] support@github.com Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> (75e942a)
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.110-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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.110-rc.1...v0.1.110-rc.2
Approvals could previously only be resolved through the HMAC-signed webhook (POST /api/v1/webhooks/approval-response), whose secret is held by the external approval service. Extract the resolution core (idempotency, state transitions, approval bookkeeping, events, agent callback) into webhookApprovalController.applyApprovalDecision and add POST /api/v1/executions/:execution_id/approval-response under the authenticated agentAPI group, so operators and CLIs holding an API key can approve/reject/request_changes directly. Webhook behavior is unchanged; 'expired' stays webhook-only since expiry is not an operator decision.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Add 'af agent exec pause|resume|cancel|restart|approval-status|approve' as thin wrappers over the existing /api/v1/executions/:execution_id/* endpoints, emitting the standard AgentResponse envelope with non-zero exit on error. approve wires --decision approved|rejected| request_changes [--reason] to the new authenticated approval-response endpoint.
proxyToServer now normalizes legacy string errors ({"error":"..."}, optionally with a sibling message) into the structured envelope error object {code,message,hint}, deriving the code from the HTTP status when the handler didn't provide one — so agents scripting against 'af agent' always get {ok:false,error:{...}} on failures.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Expose persisted execution lifecycle events (workflow_execution_events) through POST /api/v1/agentic/query as resource=events so agents can poll event history from a shell loop instead of consuming SSE. Queries require filters.execution_id (direct per-execution listing) or filters.run_id (fan-out over the run's execution records); results are sorted by emitted_at ascending with sequence tie-breaking, honor since/until RFC3339 bounds, and paginate with limit/offset (total is the pre-pagination count). No new persistence layer or storage interface methods — this composes the existing QueryExecutionRecords and ListWorkflowExecutionEvents queries.
CLI: 'af agent query -r events --execution-id X | --run-id Y' with a new --execution-id filter flag; help documents that this is a pollable snapshot of the SSE stream, not a live subscription.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Add a --json flag to af list, af install, af run, af stop, and af logs that emits the agent-mode {ok,data,error:{code,message,hint}} envelope on stdout with non-zero exit on error. Default human output is unchanged.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
The raw INSERT in storeWorkflowExecutionEventTx omitted recorded_at (the GORM model's autoCreateTime does not apply to raw SQL), leaving NULL in SQLite/Postgres. ListWorkflowExecutionEvents scanned the column into a non-nullable time.Time, so listing any stored event failed with 'unsupported Scan, storing driver.Value type <nil>'. Nothing exercised this listing path end-to-end until the agentic events query resource; the existing storage test masked the bug with a manual UPDATE of recorded_at before listing.
Write recorded_at in the INSERT and scan it through sql.NullTime, falling back to emitted_at for legacy NULL rows so old databases keep listing cleanly. Found via runtime verification of 'af agent query -r events' against a local control plane.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
structuredErrorFromString and defaultCodeForStatus were exercised only through subprocess exit-path tests, which record no coverage. Add direct table-driven tests so the patch-coverage gate sees these lines.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Register POST /api/v1/executions/:execution_id/approval-response in the agentic API catalog so 'af agent discover' surfaces the new resolution endpoint alongside the other approval routes.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
storeExecutionLogEntryTx — the single writer behind both StoreExecutionLogEntry and StoreExecutionLogEntries — omitted recorded_at from its raw INSERT, so every execution-log row landed NULL and every read silently took the legacy emitted_at fallback: the server-ingestion timestamp was never actually stored. It also stamped entry.RecordedAt only AFTER the insert, mutating the caller's struct with a value that never reached the database. This is the same bug this branch already fixed for workflow_execution_events (the GORM model's autoCreateTime does not apply to raw INSERTs); the sibling path was missed.
The default is now stamped before the query is built and recorded_at is bound explicitly, mirroring storeWorkflowExecutionEventTx. The regression test uses distinct emitted_at/recorded_at values so the NULL-read fallback cannot masquerade as persistence, and covers the batch path's zero-value stamping; it fails against the previous INSERT.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
The recorded_at-persistence fix (raw INSERT no longer leaves the column NULL) made the legacy assertion here fail: it expected the NULL-read fallback (recorded_at -> emitted_at) for a freshly stored entry. Give the entry an explicit RecordedAt and assert it round-trips; the NULL fallback branch is still covered by the forced-NULL UPDATE above.
Latent in the branch before the main merge - conflict state had kept full CI from running on the previous head.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Co-authored-by: Claude Fable 5 noreply@anthropic.com (cf29386)
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.110-rc.1 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.109...v0.1.110-rc.1
`bash curl -fsSL https://agentfield.ai/install.sh | bash `
curl -fsSL https://agentfield.ai/install.sh | bash
VERSION=v0.1.109 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.108...v0.1.109
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.109-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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.109-rc.6...v0.1.109-rc.7
Two beta-plan items ("Santosh's recommendations") for the sub-harness
flow, where a coding agent drives AgentField through af agent and the
agentfield-use skill:
Reasoner discovery at scale. With hundreds of reasoners installed
the brain must search, not list. New GET /api/v1/agentic/reasoners
?q=<free text>&agent=<id>&limit=<1..50> ranks reasoners with a
dependency-free BM25F-lite index built per request from the same
registration data discovery serves (id boost 3.0, tags 2.0, agent
1.5, metadata description 1.0; snake/kebab/camelCase-aware
tokenizer; deterministic tie-break). Each hit carries
invocation_target + agent_health so the brain dispatches with no
second lookup. CLI: af agent search "<text>" [--agent] [--limit].
Ambient machine-load metadata. Every agentic response now carries
meta.load = {running_agents, total_agents, active_executions,
cpu_cores, recommended_max_concurrent} via a load provider stamped
into respondOK (2s TTL cache; omitted silently on error — never
fails a response). recommended_max_concurrent = max(1, cores/2),
cores-based; memory-aware refinement noted as follow-up. The
af agent CLI already forwards server meta, so the driving agent
gets load data with zero extra round-trips.
The agentfield-use skill (v0.2.0 -> v0.3.0, embedded mirror synced) teaches both: search-first discovery past ~20 reasoners, and pacing — if active_executions >= recommended_max_concurrent, finish in-flight work before launching more.
Verified end-to-end on a live control plane with 78 registered reasoners: "review pull request" ranks pr-af-go:review_dimension / review on top, --agent filters, empty q -> structured missing_query, meta.load rides every response (16 cores -> recommendation 8).
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
CodeQL (go/uncontrolled-allocation-size) does not track the limit clamp through getIntQuery. Allocate at the constant max (50) instead - the loop still stops at the requested limit.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Co-authored-by: Claude Fable 5 noreply@anthropic.com (4db5244)
Bumps the npm_and_yarn group with 2 updates in the /desktop directory: electron and tar.
Updates electron from 33.4.11 to 39.8.5
Updates tar from 6.2.1 to 7.5.20
updated-dependencies:
Signed-off-by: dependabot[bot] support@github.com Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> (e04a84f)
Nothing published for this version
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.109-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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.109-rc.5...v0.1.109-rc.6
Docker-Desktop-style dashboard for non-technical users: shows control plane health (GET /health) and the locally installed agent nodes from ~/.agentfield/installed.yaml, cross-checked against GET /api/v1/nodes for a running/stopped/unknown badge per agent. Polls every 5s with a manual Refresh button and graceful empty states.
Electron + electron-vite + React + TypeScript, plain CSS. Secure
defaults: contextIsolation on, nodeIntegration off, sandboxed renderer,
single contextBridge API. All data access is isolated in
src/main/agentfield.ts with a marked seam to later swap the registry
read to af list -o json. 29 vitest unit tests cover registry parsing,
health mapping, and badge derivation.
Self-contained under desktop/ (own package.json); no packaging (electron-builder) yet, and the GUI is untested in this headless environment — typecheck, production build, and unit tests all pass.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Replaces the stale commented-out windows block with a real agentfield-windows-amd64 build mirroring the linux/darwin ones (goreleaser appends .exe on its own). Groundwork only: the release workflow's build matrix filters by --id and does not build this id yet; shipping the artifact needs a follow-up matrix entry (windows runner, or mingw-w64 on the linux runner for the CGO sqlite dependency).
Also modernizes archives.builds/format to ids/formats so
goreleaser check passes clean again (both were deprecated).
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
af stop used process.Signal(os.Interrupt) and a signal-0 probe, both
unsupported on Windows (and os.FindProcess always succeeds there, so
the liveness check was meaningless). Extract the two process operations
into build-tagged helpers: proc_unix.go keeps the existing SIGINT +
signal-0 behaviour; proc_windows.go uses taskkill for the graceful
request and a tasklist PID query for liveness.
stop.go changes are limited to swapping the two call sites and the now-unused syscall import. Windows paths are compile-verified only (GOOS=windows cross-build), not yet tested on a real Windows machine.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
af logs shelled out to tail(1), which does not exist on Windows. The
tail/follow commands now go through one tailCommand helper: unchanged
tail(1) invocations on Unix, PowerShell Get-Content -Tail (-Wait for
follow) on Windows, with proper single-quote escaping of the log path.
Windows path is compile-verified only, not yet run on a real machine.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Go agent nodes declare unix-style binary paths in their manifests
(entrypoint.start: bin/foo). On Windows the install-time go build -o
output now carries the conventional .exe extension, and the runner's
GoBinaryProgram resolves an extensionless start path to the built .exe
when present. No behaviour change on other platforms; windows path is
compile-verified only.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
The patch-coverage gate flagged the runtime.GOOS-gated windows branches (PowerShell tail construction in logs.go, .exe naming/resolution in gointerp.go) as untestable on linux CI. Extract each into a pure helper taking an explicit goos string — tailCommandArgs, withExeSuffixFor, goBinaryProgramFor — with the exported wrappers passing runtime.GOOS, so behavior is unchanged while both platform paths are unit-testable anywhere. Table-driven tests cover the windows tail command (incl. single-quote escaping), .exe suffixing, and the built-.exe fallback resolution; refactored regions now profile with zero uncovered blocks.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
control-plane/agentfield.yaml was a checked-in symlink to
config/agentfield.yaml. On Windows checkouts (core.symlinks=false, the
default) git materializes it as a plain text file containing the literal
target path, which Viper then finds via its . search path and fails to
parse: cannot unmarshal !!str config/... — a fatal error on every
af server run from the control-plane directory.
The symlink is redundant on every platform: both cmd/af and cmd/agentfield-server already search ./config and <execDir>/config, which resolve to the same file.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
The af binary only filled in DatabasePath/KVStorePath when storage.mode was absent entirely. A config file that sets mode: "local" while leaving the paths empty (which the repo's own sample config/agentfield.yaml does, and which af picks up automatically when running next to it) skipped the defaulting block and failed startup with "database path is empty".
Default the paths whenever the effective mode is local, mirroring cmd/agentfield-server which already had this shape. Found on Windows but platform-independent.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
exec.LookPath alone cannot pick a Python on Windows: stock machines ship Microsoft Store "app execution alias" stubs named python3.exe (and often python.exe) that resolve like real binaries but exit 9009 without running anything. resolveVenvInterpreter took the first PATH hit and only version-checked that one, so a node declaring requires-python failed with "no compatible interpreter" even when a perfectly good python was next in line. Verified live on Windows 11: python3 -> dead Store stub (exit 9009), python -> real 3.11.9, never consulted.
ambientPythonInterpreter now probes each candidate by actually running it (-c version query) and takes the first that answers. The candidate list gains "py", the Windows launcher: python.org installers register it even when "add python to PATH" is left unchecked (the default), where it is the only working entry. It does not exist on Unix, so probing it there is a no-op.
The legacy no-requires-python path in InstallPythonDependencies now uses the same probe instead of blindly running python3 -m venv and falling back, and fails with an actionable error listing the probed candidates when nothing on PATH runs.
Test stubs that previously only handled -m venv now answer the -c version probe, matching how real interpreters behave; the venv-creation-failure contracts now expect the earlier, more actionable error.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Spawned agents log through stdout/stderr redirected to a log file. On Windows, Python then encodes with the legacy ANSI code page (cp1252), which cannot represent the SDK's emoji log prefixes - every heartbeat flooded the log with UnicodeEncodeError tracebacks from the logging module. Verified live: with PYTHONUTF8=1 the same agent logs cleanly.
Applied in both spawn paths (services.buildProcessConfig, which backs af run, and the legacy packages runner). An explicit PYTHONUTF8 in the caller's environment wins. UTF-8 mode is a no-op where UTF-8 is already the default, so this is safe on every platform.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
dev_service.go is build-tagged !windows (Windows gets a stub service), but two pieces of its test surface were not:
Before this, go vet / go test of internal/core/services failed to compile on Windows. Also carries the one-line stub update from the interpreter-probe change (the fake python in coverage_additional_test.go now answers the -c version query); no other test logic changed.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
checkControlPlane treated any HTTP 200 from {baseUrl}/health as "healthy", so anything squatting on the popular default port lit the dashboard green. Found live on Windows: an unrelated dev server answering {"status":"alive"} on /health showed as a running control plane.
The probe now recognizes an AgentField control plane by its health payload shape (status: healthy|unhealthy, per routes_core.go). Anything else reachable on the port reports recognized: false with an explanatory error, renders as a yellow "Another service is on this port" state, and is excluded from the nodes cross-check so a foreign /api/v1/nodes response cannot corrupt agent badges.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Data layer growth behind the same single-snapshot IPC:
Install flow, with the af CLI as the single contract:
af install <source>, sanitizes
ANSI/spinner output into displayable lines, and streams them to the
renderer over agentfield:install-progress. The renderer only ever sends
catalog names over IPC; unknown names are refused, raw sources never
reach a shell. A missing af CLI degrades to an actionable message.Verified live on Windows: installed SWE-AF from the app end-to-end — including uv provisioning Python 3.12.13 because the node requires >=3.12 and the ambient interpreter is 3.11 (the interpreter-probing fix working in production).
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Native-feeling chrome:
Layout: left sidebar (Dashboard / Agents / Activity / Install + a control-plane status pill pinned at the bottom), right content view. The Dashboard leads with stat tiles (agents running, executing now, runs today vs yesterday, success rate) over a recent-activity list; Agents and Activity render as clean row panels; Install streams per-row progress.
macOS-specific chrome is behind platform guards and still needs one smoke run on a real Mac; everything else verified live on Windows.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
npm run dist produces DMG+zip on macOS and a one-click NSIS installer
on Windows into release/ (git-ignored); npm run dist:dir for a quick
unpacked smoke. electron-builder is pinned to v25 — v26 requires
require(ESM) support (Node 20.19+/22.12+) that older Node 22 lacks.
Unsigned for now, default Electron icon; signing/notarization and a real icon come before distribution. Verified on Windows: the packaged AgentField.exe boots and opens its window.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Replace the default Electron icon everywhere. scripts/make-icons.mjs renders the brand mark (the exact outlined "af" + dot paths from the web UI logo, so no font dependency) via an offscreen Electron window into:
Outputs are committed (npm run icons regenerates), resources/** now
ships inside the app package, and desktop/build is un-ignored for
exactly the two icon files the root .gitignore would otherwise drop.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Tray (Windows/Linux only — macOS has af-tray, installed with AgentField itself): a status glyph whose brand dot goes gold while the control plane runs, tooltip + disabled menu row naming the state (running / unhealthy / port-in-use / stopped), Open AgentField / Open web UI / Quit. Closing the window now hides to the tray, Docker-Desktop style; presentation logic is pure in tray-model.ts and unit-tested. If tray creation fails (some Linux desktops) the app logs why and keeps classic quit-on-close.
Deep links: the app registers the agentfield:// scheme (declared for
macOS via electron-builder protocols, HKCU-registered at runtime on
Windows) and holds the single-instance lock — a relaunch or an
agentfield://dashboard|agents|activity|install URL focuses the running
app and switches it to that view. Parsing is pure in shared/deeplink.ts
(unit-tested); the view union now lives there as the one canonical list.
Verified live on Windows (packaged build): deep link cold-open, deep link into a tray-resident app, view switching, single-instance focus, close-to-tray, and the port-in-use state against a foreign service squatting on 8080.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
The macOS menu-bar tray now prefers the AgentField desktop app when it
is installed: every "open" action first tries the agentfield:// deep
link for the equivalent view (dashboard/agents/activity) and falls back
to the web UI in the browser. Detection is the deep link itself —
open agentfield://… exits non-zero fast when nothing registered the
scheme, so there is no separate probe to drift. Page→view mapping and
the browser fallback are pure helpers in shared.go with contract tests;
the darwin file only gains the two-line try/fallback.
assets/appicon.icns was a renamed 512px PNG, not an ICNS container — Finder/dock could show a generic icon. It is now a real icns (PNG members at 32…1024 on Apple's grid), generated by the same desktop/scripts/make-icons.mjs that produces the desktop app's icons, so both apps wear the same mark.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Replacing the icon and context menu on every 5s poll churns native tray APIs for nothing and can dismiss a menu the user has open on Windows.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Swept the org: a repo is installable iff it has agentfield-package.yaml
at its root (the manifest af install requires) — that held for four of
fifteen repos, and the catalog now carries all of them: swe-planner
(SWE-AF), pr-af, sec-af, and cloudsecurity-af, each keyed by its
manifest name: so installed-state detection keeps working. The sweep
rule is documented at the top of catalog.ts for the next addition.
Required secrets (e.g. OPENROUTER_API_KEY) are resolved at af run
time, not install time, so installs from the app stream cleanly and
setup prompts happen where a terminal exists.
Verified in the packaged app: all four render, swe-planner shows Installed ✓.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Agents view: Start / Stop / Restart per row, shelling out to the af CLI
(af run / af stop; restart is stop-then-run — the CLI has no restart
verb). Names are validated against installed.yaml before anything is
spawned; the renderer only ever sends names.
Settings view: open at login (OS login item, packaged builds only — launches hidden with --hidden, tray-only), start the control plane automatically, and per-agent auto-start switches. Persisted to settings.json in userData, normalized on load so hand-edits and old shapes can't break the app.
Autostart on every launch (src/main/autostart.ts, planning pure and
unit-tested): spawn af server detached (logs to
~/.agentfield/logs/control-plane.log, same file macOS launchd uses) only
when nothing answers on the port — never over a live control plane or a
foreign service — then start the selected agents. Agents whose registry
entry went stale (running with no control-plane presence, e.g. after a
reboot; Windows never reconciles that live) are restarted, not skipped.
The point: agents are already answering when Claude/Codex/anything
queries them — nobody has to start a server first.
Also fixes a deep-link race this surfaced: a link that cold-starts the app pushed the view at did-finish-load, before React subscribed, and got dropped. The renderer now announces readiness and collects the pending view (agentfield:renderer-ready), so agentfield://settings into a hidden app lands on Settings.
Verified live on Windows (packaged build): start/restart/stop from the UI (badge, port, registry all agree), settings round-trip, login-item registration with --hidden, hidden tray-only launch, autostart bringing a stopped agent up on relaunch, and the port-in-use guard skipping the control-plane start while a foreign service owns 8080.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Non-technical users install ONLY the desktop app and get all of
AgentField: the package now carries the af CLI (extraResources from
vendor/, staged by npm run bundle-cli or the release pipeline).
Every launch resolves which af to drive (src/main/cli.ts):
managed (~/.agentfield/bin — the same location the curl installer uses,
so the two installers converge instead of double-installing) → PATH →
bundled. A copy older than MIN_AF_VERSION is skipped — the app runs on
its bundled CLI meanwhile, and Settings grows an "AgentField CLI" card
showing version + source with an Update button that installs the
bundled copy into the managed location (never over a newer one; dev
builds are trusted). With no CLI anywhere, first launch auto-provisions
~/.agentfield/bin (agentfield + af alias, curl-installer naming), copes
with a running binary via rename-aside, and registers the Windows user
PATH so terminals get af too.
Launches also run af skill install --non-interactive (Settings toggle,
default on) so detected coding agents — Claude Code, Codex, Gemini … —
always know how to use AgentField; skillkit's state file makes this
idempotent and shared with the curl installer.
Verified live on Windows from a simulated fresh machine (no managed copy, no PATH af): first launch provisioned both binaries, registered the user PATH, installed the skill into ~/.claude/skills, resolved to the managed copy, and drove agent start/stop through it.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Two blind spots closed:
The desktop app had no CI at all — its tests only ever ran on a dev machine. New desktop.yml runs typecheck, vitest, and an unsigned electron-builder package on macos-14 and windows-latest (a stub in vendor/ validates the bundled-CLI extraResources wiring), so the platform-guarded chrome and packaging config prove out on both ship targets per PR.
cmd/af-tray's darwin implementation is CGO code that Linux CI never compiles (it builds the !darwin stub, and the CGO_ENABLED=0 matrix can't touch it) — a type error in tray_darwin.go would only surface at release time. control-plane.yml grows a macos-14 job that builds and vets the tray, wired into required-checks.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
The embedded skill catalog gains a second skill. The existing agentfield
skill teaches BUILDING multi-agent systems; agentfield-use teaches USING
the agents already installed on this machine: control-plane health check,
capability discovery (with the colon-vs-dot invocation_target gotcha),
sync/async execution + polling/SSE, session headers, failure triage
(including af secrets set for missing keys), the af CLI ops cheat
sheet, and the VC-chain audit trail. Grounded in the verified HTTP
surface — it deliberately omits endpoints that don't exist (e.g. a
GET /api/v1/executions list).
Skill struct gains a per-skill Trigger sentence so marker-block targets route build requests and use requests to the right SKILL.md; install.sh and the catalog test cover both skills.
Also fixes a real resolution gap both runner paths shared: a manifest declaring ONLY require_one_of groups (no required/optional lists) skipped env resolution entirely, so nothing was injected and an unsatisfied group never errored. The emptiness guard now includes RequireOneOf, with a regression test.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Closes the sharpest install-to-running gap: a catalog install whose manifest requires API keys used to hit a guaranteed "missing required environment variables" failure on Start, with no in-app fix.
af run decrypts into the agent process: af secrets ls parsed
for key presence (values never leave the store), af secrets set
with the value piped over stdin (never argv), af secrets rm per
scope. Writes go to the manifest-declared scope and are validated
against the manifest regex; the renderer can only name declared vars.Live-verified on a packaged Windows build against SWE-AF's real manifest: chip/gating, set → encrypted global store, group satisfaction clearing the chip, revoke emptying the store, and agentfield-use landing in ~/.claude/skills on boot. 13 new unit tests (103 total).
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Caught by the first real end-to-end run on Windows (live control plane,
swe-planner + smoke-agent): af run smoke-agent was assigned port 8001
while swe-planner was actively listening there, reported "started
successfully" (its readiness poll got swe-planner's 200 and even printed
swe-planner's reasoner list), and the control plane then routed
smoke-agent executions into swe-planner — agent error 404.
Two root causes, both fixed in the port manager and both run paths:
Port probing used a bind-only check. On Windows a probe bind can succeed while another process holds a non-exclusive listener on the same port (no SO_EXCLUSIVEADDRUSE — reproduced against a live uvicorn agent: net.Listen on :8001/127.0.0.1:8001/0.0.0.0:8001 all "FREE" while netstat shows LISTENING). Availability now also dial-probes: anything accepting a connection means the port is taken.
waitForAgentNode accepted any HTTP 200 on the port. It now reads the health payload's node_id and refuses a response from a different node ("port 8001 is answering health checks as "swe-planner", not "smoke-agent""). Payloads without node_id (custom healthchecks) and empty expectations skip the check.
Re-ran the live collision after the fix: smoke-agent correctly lands on 8002, registers, and an async demo_echo execution through the control plane succeeds in 6ms.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Caught by the first real LLM-backed SWE-AF run on Windows (OpenRouter + opencode runtime), which peeled three layers off the same onion:
run_cli spawned providers with create_subprocess_exec, whose
CreateProcess does no PATHEXT resolution — npm-installed CLIs
(opencode, codex, gemini) exist on Windows PATH only as .cmd shims,
so every call died with FileNotFoundError ("OpenCode binary not
found") even though the shell finds the command. cmd[0] is now
resolved via shutil.which on Windows.
With the shim found, the prompt-as-positional-argv convention hit cmd.exe's ~8k command-line cap ("The command line is too long.") on any real prompt. opencode reads the prompt from stdin when the positional arg is absent, so on Windows the provider now hands the prompt to run_cli's new input_text, which pipes it to the child's stdin (fed concurrently with the stdout/stderr drains to stay deadlock-free). POSIX keeps the battle-tested argv path.
run_cli's watchdog kill path called os.killpg, which does not exist on Windows (AttributeError escaped the except clause) — now guarded with hasattr and falling through to proc.kill().
After these, a full swe-planner.plan run on Windows succeeded end to end: 10 minutes of multi-role LLM work through the control plane, PRD + architecture + sprint issues written to disk.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
The dashboard tile rendered the API's raw float (57.894736842…%, overflowing the tile). Now rounded to a whole percent and colored as a reinforcement of the number: green ≥90, yellow ≥60, red below — using the existing status palette vars, so light/dark both work.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Secrets in af's store are global by default — one key shared by every agent that declares it, and users can add keys the CLI way that no installed agent's manifest mentions. The per-agent Keys editor showed a sliver of that world and revoked with only a tooltip's warning.
af secrets ls, global scope first, each annotated with
the installed agents whose manifests declare it ("used by
swe-planner" / "not declared by any installed agent"). Values never
leave the store.Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Repos ship several installable nodes side by side (pr-af has a Python root and a Go port under go/), but the installer could only find one manifest per repo — findPackageRoot walks to the FIRST agentfield-package.yaml and stops.
af install <repo>//<subdir>[@ref] installs the subdirectory's
package: ParseGitURL learns the // selector (the scheme's own //
is skipped; composes with @ref), and InstallFromGit resolves the
manifest exactly there — no walking, escape-guarded. Registry stays
keyed by manifest name, so root and subdir nodes coexist.af uninstall now also removes the node's node-scoped secrets file
(secrets/<name>.enc) — useless without the node; the shared global
scope is untouched. New SecretStore.DeleteScope refuses global.Verified live on Windows: pr-af-go installed from https://github.com/Agent-Field/pr-af//go (clone -> subdir resolve -> go build at install -> 17 reasoners registered), then uninstalled with zero residue. swe-planner-go same cycle (30 reasoners) via Agent-Field/SWE-AF#96, which ships that repo's go manifest.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
af uninstall --force — names validated against the registry.Live-verified on Windows: both Go nodes installed, ran (17 and 30 reasoners registered on a live control plane), and uninstalled with zero residue.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Go SDK nodes (swe-planner-go, pr-af-go) reported health_status "unknown" forever while running and serving traffic. Root cause, in four parts:
StatusManager held starting→active as a "pending" transition instead of completing it, so State stayed "starting" and persisted as health "unknown" even as the same update set lifecycle "ready". The Go SDK renews its status lease every 2 minutes — exactly MaxTransitionTime — so every renewal re-created the pending transition right before the timeout sweeper could force-complete it. A state claim always arrives with direct evidence (ready lease renewal, heartbeat, health check result), so handleStateTransition now completes immediately. (This was also behind the intermittent Python-node "unknown" wedge: its plain heartbeats don't reset the transition, so it usually escaped via the 2-minute sweeper — Go nodes never did.)
Only POST /heartbeat enrolled a node in HTTP health monitoring. Nodes whose keep-alive is the status lease (PATCH /nodes/:id/status — the Go SDK) were never polled. NodeStatusLeaseHandler now registers them with the HealthMonitor; serverless nodes stay excluded (no /status to poll).
HealthMonitor.RegisterAgent reset the tracked status to "unknown" on every call, and it is called on every DB-updating heartbeat. It is now idempotent for an unchanged BaseURL; a moved agent restarts tracking.
needsReconciliation had no rule for the wedged shape itself: health "unknown" with a fresh heartbeat past the startup grace period. The reconciler now sweeps such rows to active, unwedging rows left behind by pre-fix control planes without requiring a server restart.
Live-verified on Windows: a fresh af stop && af run swe-planner-go cycle
now reaches health "active" within 5 seconds; before the fix the same flow
sat at "unknown" for 100+ minutes.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
On Windows the opencode CLI on PATH is an npm .cmd shim that CreateProcess routes through cmd.exe, whose ~8k command-line cap real prompts blow straight through ("The command line is too long."). The Go harness passed the prompt as a positional arg, so every call whose prompt embedded diff context died at spawn — and schema retries, which append more text, could never recover. The observable failure was silent and severe: pr-af-go on Windows "completed" reviews with zero dimensions planned, empty LLM fields, and a confident "Safe to merge — 0 findings" verdict manufactured from mechanical parsing alone (every failed call was downgraded to "0 findings for this dimension").
opencode reads the prompt from stdin when the positional arg is absent, so on Windows the prompt now goes over stdin — mirroring the Python SDK's _prompt_via_stdin fix (harness/providers/opencode.py). POSIX keeps the battle-tested positional-arg path. The provider's injectable runCLI seam moves from RunCLI to RunCLIWithStdin (which already existed for the claude provider).
Verified live on Windows 11: pre-fix, a pr-af-go review of a 335-line PR produced a false-clean (plan.dimensions null); post-fix the same review runs its dimension reviewers with prompts delivered over stdin (argv ends at the model flag). TestOpenCodePromptDelivery pins both delivery paths; the harness suite shows no new failures against the pre-existing Windows baseline (22 fixture/path-separator failures unrelated to this change, green on Linux CI).
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
af run resolved only manifest-declared user_environment variables, so a
secret stored with af secrets set KEY --node <name> that the manifest didn't
declare was silently never injected — the store accepted it, af secrets ls
showed it, and the node never saw it. Hit live while trying to raise
AGENTFIELD_HARNESS_IDLE_SECONDS for a node: the override "took" twice with no
effect before the cause surfaced.
Node-scoped secrets are explicit per-node intent, so EnvResolver.Resolve now overlays them even when undeclared. Precedence is preserved: declared variables keep their full chain, process environment still wins for undeclared keys, and GLOBAL secrets stay manifest-driven — a shared key never leaks into nodes that don't declare it.
af secrets set --node also now prints when the value takes effect
("Applies on next start: af stop <name> && af run <name>") — env is decrypted
into the process at spawn time only, and nothing previously said so.
Three regression tests pin the new behavior (inject, global containment, process-env precedence).
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
New desktop-installers job in release.yml: after the GitHub release is created, macos-14 builds the DMG + zip (Apple Silicon) and windows-latest builds the NSIS .exe (x64), and both attach to the same release the CLI binaries land on — staging (RC prereleases) and production alike, so users download whichever installer they want.
Each installer carries an af CLI built from the release commit with
-tags "embedded sqlite_fts5" (bundle-cli full — parity with
build-single-binary.sh), so the installed app is fully self-contained on a
fresh machine: web UI embedded, FTS search working, no separate CLI install.
The desktop version is stamped from the release version before packaging so
installer filenames and the About dialog follow the release rather than the
static package.json version. Windows guards CGO with a mingw fallback
install; packaging stays unsigned (CSC_IDENTITY_AUTO_DISCOVERY=false) until
signing/notarization lands.
NSIS artifactName loses its spaces (AgentField-Setup-<version>.exe) so release asset names are clean URLs.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Four Agents/Activity view improvements from live use:
No more running<->unknown flicker. The badge treated "node absent from GET /api/v1/nodes" as unknown, but that endpoint default-filters to health=active — any one-poll health dip (busy node, post-restart unknown, late lease renewal) removed the node from the list and flipped the badge. The snapshot now fetches ?show_all=true and keeps id -> health_status: registration presence (stable) proves a running registry entry is live regardless of momentary health; health only matters for stopped entries, where an ACTIVE node contradicts the registry. Stopped nodes staying registered as inactive/unknown still badge as plain Stopped. Truth-table test extended to the health-aware contract.
Failed runs surface their error. /api/ui/v2/workflow-runs already carries root_error_message; it now rides ExecutionSummary.errorMessage and renders under failed/timeout activity rows (full text in the tooltip).
Running states animate. Live activity rows show a spinning ring instead of the word "running"; running agents' status dots pulse like live runs.
Deep links into the web UI. New guarded IPC (agentfield:open-web-ui) opens control-plane pages in the browser — absolute-path-only, joined server-side to the known base URL, so the renderer cannot target arbitrary sites. Agents rows get "Web UI" while running; every activity row (running, succeeded, or failed) gets a hover affordance to its /ui/runs/<run_id> detail page.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Installed catalog entries gain an Update action next to Uninstall. It maps
to af install <source> --force (the CLI's reinstall-in-place), so the
registry entry and the agent's secrets survive — unlike an
uninstall+install round trip, which deletes node-scoped secrets. The flow
restores the agent's previous run state: a running agent is stopped first
(Windows locks running executables, so the binary could not be replaced
otherwise) and restarted after a successful update; a stopped agent stays
stopped. A failed update says exactly what state it left behind ("was
stopped and has not been restarted").
Phase markers (Stopping…/Updating…/Restarting…) ride the existing install progress channel, and update shares the install mutex so the two can't interleave. The install view now also shows success messages ("pr-af-go updated and restarted"), not just failures.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
The "Installed ✓" chip next to Update/Uninstall crowded the actions column. The title itself now carries the state — green name with a small tick — and the actions column is just buttons.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Callers had no way to ask "what is running right now": GET /api/v1/executions and /executions/active were 404, batch-status needs execution IDs the caller must have tracked, and the data lived only on the UI-internal /api/ui/v2/workflow-runs. Live-tested tonight with three concurrent agent runs, the answer required scraping the UI API.
GET /api/v1/executions/active returns every run with at least one
non-terminal execution: run_id, root execution, target agent.reasoner,
active/total execution counts, full status_counts, started_at and
latest_activity (the wedge tell — active>0 with stale latest_activity
means a run is likely dead, not working). Filters: agent_id, session_id,
limit. af ps is the CLI face of the same endpoint.
Storage: ExecutionFilter.ActiveOnly filters runs AFTER aggregation (HAVING on the active-count) so a surviving run's terminal children still show in status_counts — a Status="running" pre-filter both loses those rows and misses queued-only runs. AgentNodeID now also applies to QueryRunSummaries; the agentic query surface always accepted the filter but silently ignored it.
Also fixes the auth-level hole that made agentic discover useless on default installs: with no API key configured, the middleware never set auth_level, so getAuthLevel fell back to "public" and FilterByAuth hid every api_key endpoint — discover returned zero results for every query in local mode. No-auth callers now get api_key level, matching their actual access.
agentfield-use skill 0.1.0 → 0.2.0, rewritten from tonight's fresh-agent test findings: no-jq discovery fallback (fresh Windows boxes), corrected discovery-lists-inactive-agents claim (filter health_status=="active"), concurrency guidance (fire async calls together, ~3-4 heavy runs per node), af ps / executions/active, batch-status result-size warning (terminal entries embed full payloads — never pass through argv), and a wedge protocol: stale latest_activity + quiet logs → cancel-tree (NOT plain cancel, which orphans children) → restart agent → re-submit.
Test flake fix: workflow_execution_events_test asserted CompletedAt.After(StartedAt), which fails when both events land within one coarse timer tick (Windows ~15ms); now asserts !Before.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
CodeQL (go/uncontrolled-allocation-size, 3 high) flagged the result slice/map pre-allocations in QueryRunSummaries: their capacity is filter.Limit, which flows straight from request input, so a single call with limit=1<<30 would try to allocate gigabytes before reading a row. The allocations predate this PR (#46) — the scanner surfaced them here because this branch touched the function.
Every live caller already clamps its page size (UI ≤200, agentic ≤100, af ps ≤200), but the storage layer now enforces its own ceiling (maxRunSummaryLimit=1000) instead of trusting callers. Regression test issues the query with Limit=math.MaxInt32.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
CodeQL still flagged the three allocations after the previous clamp: it does not treat reassignment-style clamps (x = max when x > max) as sanitizers — the identical clamps in every HTTP caller were being ignored the same way. Instead of arguing with the guard recognizer, sever the flow: capacity now derives from totalRuns (the query's own COUNT, not caller input) clamped to maxRunSummaryLimit. Semantically better too — never reserve more than the query can return.
The limit clamp stays; it bounds the SQL LIMIT itself.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
A "running" registry entry outlives reboots and crashes, and stop treated it as fact: os.FindProcess/kill on the recorded PID, /shutdown to the recorded port, no verification that either still belongs to the agent. After a reboot that meant (a) a dead PID errored out BEFORE the registry was reset, so stop-then-start flows — the desktop restart button and login autostart both abort when stop fails — wedged permanently, and (b) a reused PID or port could get an unrelated process signalled or shut down.
Stop now verifies before it acts: a dead PID reconciles the record to "stopped" and succeeds; a recorded port whose /health answers as a DIFFERENT node marks the whole record stale and signals nothing (the live PID is almost certainly reused); a process that exits between the aliveness check and the kill (os.ErrProcessDone) counts as stopped. The identity probe reuses the packages.HealthNodeID/NodeIDsEquivalent helpers introduced for start readiness.
Tests: dead-PID reconciliation (cross-platform via test-binary re-exec), foreign-node port never receives /shutdown and its process survives, and the two ops assertions that had encoded the old error behavior now assert reconciliation. Existing shutdown-path tests grew /health handlers for the new probe.
Found by an independent pre-merge review (Codex).
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Two gaps between the endpoint's documented contract ("every run with a non-terminal execution, with complete per-run status counts") and the SQL:
The active set was running/pending/queued/waiting — but paused and unknown are canonical non-terminal statuses too. A pause-wedged run (the exact failure this surface exists to expose) would vanish from af ps. The ActiveOnly HAVING clause now matches types.IsTerminalExecutionStatus; the handler's active_executions is computed from status_counts the same way, deliberately leaving the aggregation's narrower pre-existing ActiveExecutions column alone — the UI's status derivation still depends on it.
The agent_id filter was a row-level WHERE applied before GROUP BY, so a cross-agent run lost other agents' rows from its counts, lost its root fields when the root ran elsewhere, and disappeared entirely when its only execution on the filtered agent was already terminal. It is now run-level membership (run_id IN (...)): every run that touched the agent, aggregated over ALL of its rows.
Tests cover a paused-only run and a cross-agent run whose agent-filtered result keeps complete counts and the foreign root.
Found by an independent pre-merge review (Codex).
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
The release pipeline bundled an UNSTAMPED af: bundle-cli.mjs ran plain
go build, so every shipped binary answered Version: dev. The app
trusts unparseable versions and prefers the managed copy, so the first
launch provisioned a dev binary into ~/.agentfield/bin that would win
over every future release forever — no min-version gate, and Settings
could never offer an update (both sides must be parseable). Upgrades
were structurally broken.
git describe --tags → dev fallback.af server is pinned to port 8080 — the port the app
polls. Without it a config-file custom port made the server bind
elsewhere while the app spun on 8080 forever. Custom-port/authed
control planes remain unsupported by the app (documented follow-up).Found by an independent pre-merge review (Codex).
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Users should never have to re-download the app from the releases page by hand. The public repo's releases feed is the update channel: packaged builds poll /releases/latest shortly after launch and every 4 hours (stable releases only — RC prereleases never surface; an RC install IS offered the stable build of its own version once it lands, via a prerelease-aware version compare), and a newer release shows an "Update available" banner across the top of the window plus a Settings → App updates card.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
CodeQL (js/incomplete-url-substring-sanitization) flagged the updater tests' fake fetch for routing on includes('api.github.com'). It is a stub, not sanitization, but hostname comparison is the canonical safe pattern and costs nothing.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
A macOS app launched from Finder/Dock inherits launchd's minimal PATH (/usr/bin:/bin:/usr/sbin:/sbin), not the user's shell PATH. The af CLI itself still resolved (absolute paths), but everything af shells out to — go, uv, python3, claude, codex — was unfindable, killing installs, runs, and skill sync on a normal double-click launch. Windows never surfaced this: GUI apps inherit the full user PATH there.
New main/env.ts resolves the real PATH once per launch (login shell probed with sentinel markers and a 3s cap, merged with process.env.PATH and the well-known bin dirs, deduped in that priority order; win32 passes through untouched) and every child spawn now uses childEnv(). The version probe in cli.ts and the secrets CLI runner are wired here; the remaining spawn sites ride with their own commits.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
The updater polled the monorepo's /releases/latest and offered any newer tag as an app update. But that release train also ships CLI-only releases (wheels, goreleaser binaries, af-tray) — v0.1.108 has no desktop installer at all — so every fresh install saw a phantom 'Update available' whose only action was a 'View release' browser link, the manual flow in-app updates exist to replace. Same on Windows and macOS.
A release is now only an app update when it carries this platform's installer asset; the browser fallback and its 'View release' label are gone. macOS asset selection is arch-aware (exact -arm64/-x64 match → suffix-less universal → any .dmg; .blockmap never matches), and shell.openPath's error-string result — it never rejects — is checked and routed to status.error instead of being dropped.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Once af-tray installs its launchd agents, two owners could start the control plane: the app's detached 'af server' spawn and launchd's ai.agentfield.server (RunAtLoad + KeepAlive={SuccessfulExit:false}). On a net-new first launch the app spawns first, then the tray installs, and launchd's copy fails against the held resources and relaunch-loops every ~10s for the whole session (observed live: runs climbing, last exit 1).
startControlPlane now probes launchctl for the server agent on darwin and kickstarts it when loaded — one owner, launchd — falling back to the original direct spawn when the agent is absent (pre-tray first launch) or kickstart fails. Spawns inherit the resolved user PATH (main/env.ts). The other half of the fix — the server exiting clean when a healthy control plane already answers — lands control-plane-side.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
A desktop-app-only install had no menu-bar icon: af-tray only shipped via the curl installer. The app now carries af-tray (bundle-cli builds it into vendor/ on darwin, stamped like the CLI) and provisions it the way it provisions af: staged into ~/.agentfield/bin/af-tray — the managed location both installers converge on — then 'af-tray install' builds the ~/Applications bundle and launchd agents.
Re-staging is version-gated via 'af-tray version' (dev-stamped copies are trusted, mirroring cli.ts), and 'af-tray install' only runs when the binary changed or its launchd agent isn't loaded — install reloads launchd via bootout+bootstrap and would blink the tray on every launch otherwise. A new macOS-only Settings toggle ('Show the menu bar icon', default on) drives it; off runs 'af-tray uninstall'. Pure logic in tray-companion.ts, DI'd and unit-tested.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
The Install view gains an 'Install from repository' box: paste https://github.com/<owner>/<repo> (or the //subdir selector form) and the app runs 'af install <source>' with the same streamed progress, mutex, and registry convergence as catalog installs. Both platforms.
This deliberately relaxes the renderer-sends-catalog-names-only rule for exactly one channel; the compensating control is strict main-process shape validation (parseRepoSource): https://github.com/ prefix required, owner/ repo/subdir character classes with no leading dashes, no whitespace, query strings, fragments, or .. traversal — an accepted value can never read as a CLI flag. 23 accept/reject cases in tests.
Also unwraps the af CLI's zerolog JSON error lines into their human message before display — an install failure now reads 'invalid package structure: …' instead of a wall of raw JSON.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Wiring and the remaining macOS fixes, verified on a real Mac (the README's 'needs one smoke run' debt is paid):
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Under a supervisor, a second 'agentfield server' racing an incumbent is not an error — the desired state (control plane up) is already true. But startup died non-zero on whichever shared resource it hit first (in local mode that's the BoltDB file lock during storage init, well before the port bind), and af-tray's launchd agent uses KeepAlive={SuccessfulExit:false}: non-zero exit meant a relaunch loop, throttled ~10s, for as long as the incumbent lived. Observed live on a net-new install where the desktop app started the server before the tray's launchd agent was bootstrapped.
New startguard: on any server create/start failure, probe /health (2s cap) and accept only AgentField's payload shape — status healthy plus non-empty version and checks, so a foreign 200 on the port is rejected. A healthy incumbent logs 'control plane already running on port N — nothing to do' and exits 0, which SuccessfulExit:false correctly reads as a clean stop. Everything else keeps the non-zero exit. Both entry points (af server and agentfield-server) guard both their create and start paths.
Verified live: with the launchd server healthy on :8080, a second 'af server --open=false' fails storage init, logs the honest line, exit 0.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
GET /api/v1/executions/active?session_id=X drove the documented wedge heuristic, but for any run doing its work in local child calls it reported active=1, total=1, latest_activity frozen at dispatch for the whole run — observed across a real 27-minute pr-af-go.review whose executions table held 21 progressively-updated rows the entire time.
Root cause: workflow execution events carry no session_id, so child rows persist with it empty; only the dispatch-path root has one. The SessionID filter in QueryRunSummaries applied at the ROW level, dropping every session-less child before the GROUP BY and collapsing each run to its root — whose updated_at only moves on completion. The filter now
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.109-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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.109-rc.3...v0.1.109-rc.5
feat(harness): add Python provider preflight (#685)
fix(harness): restore Python 3.10 CI compatibility
fix(harness): align claude-code doctor spec with Python SDK, trim doc, KeyError fallback
Address the three unresolved review threads on #756:
docs/harness-providers.md: drop the TypeScript/Go doctor examples — those APIs (agent.harnessDoctor, harness.Doctor) do not exist yet. Document the Python SDK + af CLI surface that actually ships and note TS/Go as planned follow-ups of #685.
control-plane/internal/cli/harness_doctor.go: the claude-code row now
mirrors the Python doctor (_doctor.py::_claude_health). It probes a Python
interpreter for the claude_agent_sdk pip package (which bundles its own
CLI) instead of looking for a global claude binary, and hints
pip install 'agentfield[harness-claude]' instead of npm. Interpreter
candidates (python3/python/py) are run-probed so dead launcher stubs are
skipped; issues are wrapper_not_installed / python_not_found.
sdk/python/agentfield/harness/_availability.py: provider_unavailable() falls back to a generic ProviderSpec via .get() so providers without a PROVIDER_SPECS entry (claude-code, or any future provider) raise the helpful HarnessProviderUnavailable instead of a bare KeyError. Regression test added for both provider_unavailable and ensure_cli_available.
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 (ea8aaad)
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.109-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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.109-rc.2...v0.1.109-rc.4
Add optional scope/scope_id kwargs to app.memory.set/get/delete so the developer-facing MemoryInterface matches what humans and LLMs naturally guess (app.memory.set(key, data, scope="global")) and mirrors the TypeScript SDK, which already accepts scope positionally. scope=None keeps today's hierarchical behavior unchanged; explicit scopes route to the existing accessor clients. Invalid scopes raise a ValueError listing valid scopes; non-global scopes without a scope_id raise a clear ValueError.
No general memory search endpoint exists on the control plane (only /api/v1/memory/vector/search, already exposed as similarity_search), so the README's advertised app.memory.search(...) is corrected to similarity_search and the scope names are corrected from 'agent/run' to 'actor/workflow'.
fix(memory): allow context-derived explicit scopes
fix(memory): derive event history scope ids
feat(sdk-python): extend scope kwargs to memory.similarity_search
Finish the memory-scope DX work for #712: the developer-facing MemoryInterface.similarity_search now accepts the same optional scope/scope_id kwargs as set/get/delete, dispatching through the shared _resolve_scope_target helper. This matches the TypeScript SDK, whose searchVector already takes scope/scopeId options. scope=None keeps today's behavior exactly.
Also loosen ScopedMemoryClient/ScopedMemoryEventClient scope_id type hints to Optional[str] - the context-derived explicit-scope path passes None by design - and apply ruff format to memory_events.py.
Verified end-to-end against a local control plane (local mode): set/get/delete with scope kwargs across global/session/workflow, hierarchical get, accessor-style reads, context-derived scope ids, similarity_search with scope="global", and ValueError on invalid scopes.
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 (31a90f2)
Implement the foundation layer for the TypeScript SDK trigger system, bringing it to parity with the Python SDK's triggers.py.
New files:
Modified files:
Tests:
Fixes #509
The control plane's ReasonerDefinition.accepts_webhook is typed as *string ("true" / "false" / "warn") and rejects bool literals with a 400. This was causing POST /api/v1/nodes/register to fail with:
json: cannot unmarshal bool into Go struct field ReasonerDefinition.reasoners.accepts_webhook of type string
Fix: emit "true" string when triggers are present, omit field (omitempty) when no triggers are declared — matching the Python SDK normalization in agent.py lines 914-926.
Address review feedback:
Replace the hardcoded 2-state webhook opt-in (accepts_webhook="true" only when triggers exist, otherwise absent) with the Python SDK's 3-state model:
Adds tests for explicit false-with-triggers (opt-out), explicit true, explicit 'warn' overriding the auto-set, default-with-triggers auto opt-in, trigger-less "warn" default, and string-typed serialization in the registration payload.
Resolves review thread on PR #743.
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 (8c08186)
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.109-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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.109-rc.2...v0.1.109-rc.3
Newer OpenAI models (o1, o3, gpt-4o, gpt-4.x) dropped support for the legacy max_tokens parameter in favor of max_completion_tokens. The Go SDK was always emitting max_tokens, causing the output-length cap to be silently ignored.
Changes:
Closes #441
Co-authored-by: Copilot Autofix powered by AI 175728472+Copilot@users.noreply.github.com
Address reviewer feedback:
Address review feedback on #724:
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Co-authored-by: Copilot Autofix powered by AI 175728472+Copilot@users.noreply.github.com Co-authored-by: Abir Abbas abirabbas1998@gmail.com Co-authored-by: Claude Fable 5 noreply@anthropic.com (99f3e9f)
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.109-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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.109-rc.1...v0.1.109-rc.2
A reasoner calling a CLI harness provider could wedge silently forever:
stuck 'running' with no child process, no logs, and a healthy event loop.
Root-caused from a production swe-planner run that sat 26 minutes in that
state: run_cli's finally block ended with a bare await proc.wait(), which
parks indefinitely in two real situations —
Fix:
taskkill /F /T on Windows as the killpg analog so
kills reach the whole tree (also guards os.killpg with hasattr — it
does not exist on Windows).Tests: unit regressions for the lost-notification recovery and kill-on-cancellation, plus a real-subprocess regression where a grandchild holds the pipes — run_cli must conclude in bounded time on every platform.
Co-authored-by: Claude Fable 5 noreply@anthropic.com (45a4d4d)
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.109-rc.1 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.108...v0.1.109-rc.1
On Windows the opencode CLI on PATH is an npm .cmd shim that CreateProcess routes through cmd.exe, whose ~8k command-line cap real prompts blow straight through ("The command line is too long."). The Go harness passed the prompt as a positional arg, so every call whose prompt embedded diff context died at spawn — and schema retries, which append more text, could never recover. The observable failure was silent and severe: pr-af-go on Windows "completed" reviews with zero dimensions planned, empty LLM fields, and a confident "Safe to merge — 0 findings" verdict manufactured from mechanical parsing alone (every failed call was downgraded to "0 findings for this dimension").
opencode reads the prompt from stdin when the positional arg is absent, so on Windows the prompt now goes over stdin — mirroring the Python SDK's _prompt_via_stdin fix (harness/providers/opencode.py). POSIX keeps the battle-tested positional-arg path. The provider's injectable runCLI seam moves from RunCLI to RunCLIWithStdin (which already existed for the claude provider).
Verified live on Windows 11: pre-fix, a pr-af-go review of a 335-line PR produced a false-clean (plan.dimensions null); post-fix the same review runs its dimension reviewers with prompts delivered over stdin (argv ends at the model flag). TestOpenCodePromptDelivery pins both delivery paths; the harness suite shows no new failures against the pre-existing Windows baseline (22 fixture/path-separator failures unrelated to this change, green on Linux CI).
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Provider CLIs in JSON mode emit events only at completion boundaries —
opencode's run --format json writes a text event when a part carries
time.end, never token-by-token — so one long reasoning completion over a
large context is minutes of legitimate stdout silence. At 120s the watchdog
routinely killed healthy runs on slower models (observed live: pr-af-go
reviews on deepseek-v4-pro died with "CLI command made no progress for 120s"
at 8-19 minutes into otherwise-progressing pipelines, while chatty
tool-calling models like kimi-k2.5 sailed through because every tool_use
event reset the window).
300s tolerates a long single completion while still catching genuine hangs. AGENTFIELD_HARNESS_IDLE_SECONDS still overrides in both SDKs; <= 0 still disables. Go and Python defaults move together to keep parity.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Co-authored-by: Claude Fable 5 noreply@anthropic.com (8f0e350)
Nothing published for this version
`bash curl -fsSL https://agentfield.ai/install.sh | bash `
curl -fsSL https://agentfield.ai/install.sh | bash
VERSION=v0.1.108 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.107...v0.1.108
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.108-rc.1 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.107...v0.1.108-rc.1
Add a --path flag to af install so a single repository can ship more than
one installable agent node (e.g. a Python node at the root and a Go port under
go/). By default af install finds the first agentfield-package.yaml root-first;
with --path <subdir> it installs the node whose manifest lives at
<root>/<subdir>/agentfield-package.yaml, and that subtree becomes the package
root that is copied to ~/.agentfield/packages/<name>.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Behavior-driven tests derived from the --path validation contract:
af install --path <subdir> selects the subdir node,
bare install installs the root node, a missing/absolute/escaping --path errors
and leaves the registry unmutated.Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Add a "One repo, many nodes: --path" section to the agent-node install guide covering git and local sources, @ref composition, the relative-path/escape rules, and that a bare install is unchanged. Add a --path row to the lifecycle reference table.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
The claude provider appended the prompt as a trailing positional after repeated --allowedTools flags; claude CLI 2.1.x treats --allowedTools as variadic and swallows the positional, so every tool-passing call exited 1 with 'Input must be provided'. The prompt now flows through stdin (RunCLIWithStdin), which --print reads natively; codex/opencode/ gemini were inspected and are unaffected. Verified against the real CLI via a gated integration test.
Note() posted to {base}/executions/note without the /api/v1 prefix, 404ing on the control plane (route registered under the /api/v1 group) and silently dropping every progress note; existing tests masked it by baking /api/v1 into the base URL, contrary to the SDK-wide bare-base contract.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com (cherry picked from commit 7c6f11e1c89a55e4a9959901b6b866d482519c3a)
Agent.Call was a synchronous POST /execute/{target} bounded by the 15s CallTimeout http.Client default, killing any caller whose child reasoner worked longer. It now mirrors the Python SDK: submit via /execute/async/{target}, then poll the execution record with Python-parity pacing (0.25s doubling to 4s, jittered), CallTimeout bounding each request rather than the overall wait, ctx-cancellable, lineage headers on submit and polls so DAG parentage is unchanged.
The claude provider now uses --output-format stream-json --verbose: per-event output keeps the CLI idle watchdog fed during long silent turns (plain json emitted nothing until completion, so >120s turns were SIGKILLed), and the terminal result event carries the same fields including total_cost_usd. Real 2.1.191 capture committed as a fixture; ctx cancellation now kills the whole CLI process group.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com (cherry picked from commit 18c3f3eaf5aab18667c08e23c5836b38ff739e36)
Adds tests closing the patch-coverage gap on PR #746's async-submit Agent.Call rewrite and the claudecode stdin/stream-json changes.
agent_call_coverage_test.go (package agent) exercises the error/edge branches of Call's submit + poll loop that the happy-path tests miss:
claudecode_defaultrunner_test.go covers the runCLI == nil fallback in ClaudeCodeProvider.Execute via a struct-literal provider (bypassing NewClaudeCodeProvider) driving the real default runner.
Lifts sdk-go patch coverage from 61% to 98% (agent.go 98.29%, claudecode.go 100%), clearing the 80% min_patch gate. Tests only; no production code changed.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com (cherry picked from commit 5b763d872751309c0b72ebd90f48626cfbdf9692)
Port the codex harness patch behaviors into the Go codex provider so it matches the Python reference (runtime/codex_harness_patch.py):
-m <model> (was ignored entirely; SWE-AF resolves gpt-5.5 vs
gpt-5.3-codex by auth mode and the value must reach the CLI).--skip-git-repo-check so the harness runs outside a git repo.--full-auto with the permission->sandbox mapping:
"auto" -> --dangerously-bypass-approvals-and-sandbox; read-only /
workspace-write / danger-full-access -> --sandbox <mode>; else
--sandbox workspace-write.Schema plumbing uses a schemaAware interface the runner detects: the runner owns the strict-schema rewrite (codexStrictJSONSchema, ported from _codex_strict_json_schema), writes it, hands the provider the deterministic paths, and swaps in a codex-native prompt suffix while claude/opencode keep the Write-tool suffix. Options gains no schema field.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
ParseAndValidate was unmarshal-only, so output missing required fields, carrying invalid enum values, or (with additionalProperties:false) extra fields passed silently and the schema-retry loop never fired.
Add validateAgainstSchema (github.com/santhosh-tekuri/jsonschema/v5) and run it at every parse-success point in handleSchemaWithRetry — after the initial ParseAndValidate/TryParseFromText and inside each retry iteration — so a validation failure sets err and the EXISTING retry branch fires (schemaMaxRetries default 2 preserved). Validation applies only when both a destination struct and a schema are provided; uncompilable schemas skip validation (return nil) so there is no regression versus unmarshal-only.
This makes map-schema harness calls stricter than before; callers control strictness through the schema they pass.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Port the Python opencode provider behaviors (providers/opencode.py):
--format json and parse the JSONL event stream: recover the final
assistant text (extract_final_text parity), sum per-step cost from
step_finish events (nil when none report a cost, distinguishing
"unknown" from "$0.00"), and count turns as one per step_start, falling
back to tool_use events.Non-JSON stdout still falls back to trimmed raw text, so older opencode versions keep working.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Add a native ReasonerFailed error type (Message / Result / ErrorDetails) so a reasoner that ran but failed can report status=failed WITHOUT discarding its structured outcome — mirroring the Python SDK's ReasonerFailed exception.
In executeReasonerAsync's error branch, detect it via errors.As and attach payload["result"] / payload["error_details"] (only when non-nil) so the single 5x-retried status post carries the result atomically; the control plane stores the result regardless of terminal status. The two sync HTTP paths (handleExecute / handleReasoner) mirror this by carrying the result/details onto their error response. A plain error synthesizes neither key.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
The async submit+poll Agent.Call path (introduced earlier on this branch) failed a call the instant a single HTTP request to the control plane failed. Real-world testing exposed the impact: two ~hour-long SWE-AF builds died at ~55 minutes when the CP briefly went slow under system load — one timed-out status poll ("context deadline exceeded while awaiting headers") aborted calls that had been running for 30+ minutes, and a slow submit POST likewise killed a call before the request could be confirmed accepted.
Poll resilience: a transient poll failure (transport error/timeout, 408/429, or 5xx) no longer fails the call. Consecutive failures are retried with exponential backoff (capped at 15s) for a configurable window of UNBROKEN failure — default 5 minutes — after which the call fails with a clear "control plane unreachable for Xs" error instead of the raw first error. A single successful poll resets the window. A 404 on a just-submitted execution (the CP can lag before the row is queryable) is retried within a shorter bounded window, then fails with a distinct not-found message. Permanent 4xx (auth, bad request) still abort immediately.
Submit safety: re-POSTing execute/async is NOT idempotent (a duplicate would double-run a coder), so the submit is retried ONLY on errors that prove the request never reached the server — dial/DNS/connection-refused, detected by inspecting the error chain (syscall.ECONNREFUSED, net.DNSError, dial-phase net.OpError). Ambiguous failures (a timeout awaiting headers — the request may already have been accepted) are never blind-retried; instead the submit client timeout is raised substantially (default 120s) so a slow-but-healthy CP does not abort an accepted request, and the call fails with a clear message if it still times out.
Config: three env knobs following the AGENTFIELD_* integer-seconds convention, read once and cached on the agent — AGENTFIELD_CALL_POLL_TIMEOUT_SECONDS (60), AGENTFIELD_CALL_RETRY_WINDOW_SECONDS (300), AGENTFIELD_CALL_SUBMIT_TIMEOUT_SECONDS (120) — with dedicated submit/poll HTTP clients so these timeouts don't affect other client traffic. Each retried failure is logged at warn via the existing structured-log seam (call.outbound.submit_retry / call.outbound.poll_retry) with attempt count and elapsed window so operators see degradation without the call dying.
The Python SDK's async Call path (_submit_execution_sync / _await_execution_sync) uses bare requests with raise_for_status() and no transient retry, so it shares this fragility; this change improves on it.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Extends the async-Call test suite for the submit/poll resilience change:
Existing branch tests updated for the new semantics: submit/poll now use the dedicated call clients; a persistent poll transport error is retried to the unreachable-window error; a permanent poll status uses 403 (5xx is now retried). Also checks previously-unchecked json.Encode returns and switches to tagged switches so golangci-lint is clean on the branch delta.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
The Call() and Config.CallTimeout doc comments still claimed CallTimeout bounds the async submit and each status poll. That is no longer true: the Call path now uses dedicated submit/poll HTTP clients bounded by AGENTFIELD_CALL_SUBMIT_TIMEOUT_SECONDS / AGENTFIELD_CALL_POLL_TIMEOUT_SECONDS, with transient failures retried within AGENTFIELD_CALL_RETRY_WINDOW_SECONDS. Update both comments so the documented timeout semantics match the code.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Co-authored-by: Claude Fable 5 noreply@anthropic.com (a995105)
Nothing published for this version
`bash curl -fsSL https://agentfield.ai/install.sh | bash `
curl -fsSL https://agentfield.ai/install.sh | bash
VERSION=v0.1.107 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.106...v0.1.107
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.107-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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.107-rc.2...v0.1.107-rc.3
PackageMetadata gains an explicit language field with go.mod detection fallback (additive to config v1; Python manifests unchanged). entrypoint.build compiles the node at install time via a resolved Go toolchain (pyinterp-style discovery with actionable missing/too-old errors); af run launches the built binary with identical port, healthcheck, secret, and env semantics. Out-of-tree replace directives are refused with vendoring guidance, with an AGENTFIELD_GO_REPLACE override for dev installs. Service-layer install/start paths route through the shared dispatcher so both code paths stay in lockstep.
Co-authored-by: Claude Fable 5 noreply@anthropic.com (10cfe8a)
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.107-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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.107-rc.1...v0.1.107-rc.2
Parity with the Python SDK's Agent.pause(): PauseManager registers a pending approval before client.RequestApproval transitions the execution to waiting, then blocks until the control plane's /webhooks/approval callback resolves it (or expiry/cancellation). Route matches the Python agent_server path and the CP's notifyApprovalCallback payload; exempted from origin/DID middleware like other CP-to-worker notifications. PauseClock intentionally not ported: the Go SDK has no execution watchdog to discount.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Metrics/Result gain CostUSD (*float64, nil = unknown) extracted from Claude's JSON output with Python's cost_usd-or-total_cost_usd semantics and accumulated across retries including failed attempts. Options gains SchemaMode (single/incremental/auto): auto engages on the compact-encoded schema crossing the large-schema token threshold, with the incremental prompt suffix, per-field failure diagnosis, and followup prompts ported byte-verbatim from the Python SDK. Non-Claude providers report nil cost (Python parity when litellm is unavailable).
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Co-authored-by: Claude Fable 5 noreply@anthropic.com (cbe40d4)
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.107-rc.1 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.106...v0.1.107-rc.1
Bumps the go_modules group with 1 update in the /control-plane directory: golang.org/x/crypto.
Updates golang.org/x/crypto from 0.51.0 to 0.52.0
updated-dependencies:
Signed-off-by: dependabot[bot] support@github.com Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Abir Abbas abirabbas1998@gmail.com (d179bb6)
The generic_hmac source and the approval webhook handler accepted any timestamp without checking freshness, allowing captured signatures to be replayed indefinitely.
Changes:
Note: the original issue also mentioned plaintext secret storage, but the codebase has since been refactored to use SecretEnvVar (env var names stored, secrets read from environment at request time), so that part is already resolved.
Closes #65
Address maintainer review feedback: the timestamp was verified for freshness but not included in the signed payload, so an attacker could rewrite the timestamp header to 'now' and replay the original body+signature pair unchanged.
Now when timestamp_header is configured, the HMAC is computed over '<timestamp>.<body>' (Stripe-style) instead of bare body. A forged fresh timestamp invalidates the signature, making replay impossible.
Also adds:
Co-authored-by: Abir Abbas abirabbas1998@gmail.com (a507eed)
`bash curl -fsSL https://agentfield.ai/install.sh | bash `
curl -fsSL https://agentfield.ai/install.sh | bash
VERSION=v0.1.106 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 install by @AbirAbbas in https://github.com/Agent-Field/agentfield/pull/738Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.105...v0.1.106
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.106-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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.106-rc.1...v0.1.106-rc.2
Enhance the macOS menu-bar tray beyond a bare running/stopped indicator:
All parsing/summary/formatting/key-storage logic lives in the build-tag-free shared.go so it unit-tests on Linux CI; the systray event loop and osascript dialogs stay in the _darwin file. fleet_test.go covers node parsing, online/skill counting, the 200/401/403/500/unreachable status mapping, header/proxy X-API-Key behavior, env-vs-file key precedence (0600), and the row/headline/sort formatting.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
Redesign the tray menu around the feedback that it was crowded, colorless, and hard to tell online from offline:
ps (the Prometheus /metrics endpoint
only exports Go heap, which understates the real footprint). Each row
hides itself when it has nothing to show.New pure helpers (agentsHeadline, agentLine, successLine, perfLine, enterKeyTitle, parse/fetchExecStats) live in the tag-free shared.go and are unit-tested on Linux CI; serverMemoryMB (ps-based RSS) is darwin-only.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
The install converge step used kickstart -k, which cannot re-exec a
launchd agent across a binary whose code signature changed. Every
rebuild/upgrade produces a new ad-hoc cdhash, so on a real upgrade launchd
rejects the relaunch with EX_CONFIG (78) — "spawn failed" — and the tray
(and potentially the server) dies until the next login.
Replace the bootstrap-then-kickstart-k dance with reloadAgent: bootout (ignored if not loaded), bootstrap with a short retry loop to ride out bootout's async teardown, then a plain kickstart to ensure it's running now. This lands cleanly on the new bytes every time, and also fixes the long-standing caveat that plist-content changes weren't hot-reloaded.
Verified across an A→B upgrade with distinct cdhashes plus repeated installs: tray and server both stay running, server healthy, no EX_CONFIG.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
Address the feedback that rows were still cramming multiple facts:
Helpers renamed/split accordingly (statusLine, metricSuccess, metricResponse, metricMemory) and remain pure + unit-tested on Linux CI.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
Swap the emoji prefixes for real monochrome menu icons, so the tray looks native rather than "vibecoded":
Assets live in assets/icons/ with a LICENSE.md crediting Lucide. Total footprint is ~6 KB for all twelve PNGs. Embeds are darwin-only (menu_icons_darwin.go); Linux CI cross-build and all unit tests still pass.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
The stats were disabled menu items, which macOS renders in a hard-to-read dim gray; enabling them plainly would make them look like clickable actions with no action. Resolve the tension by making them genuine links: each stat row is now enabled (full-contrast, legible) and opens the dashboard view it summarizes —
Success / Response -> /ui/executions Memory -> /ui/dashboard Agents "Open …" -> /ui/agents
So the full-contrast text is honest rather than misleading. Adds uiPageURL (pure, tested) and an openURL helper.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
Color each stat's icon green / yellow / red by a benchmark, so health reads at a glance (NSMenu won't let us color the row text, so the icon carries it):
Success green ≥60% · yellow 30–59% · red <30% Response green ≤100ms · yellow ≤500ms · red >500ms Memory green <1GB · yellow <2GB · red ≥2GB
No data → the neutral monochrome (template) icon. Green/yellow/red variants of circle-check, gauge and cpu are rendered from the same Lucide sources (ISC) and applied as regular colored images; the thresholds and level-mapping (successLevel/responseLevel/memoryLevel) are pure and unit-tested at every boundary.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
Co-authored-by: Claude Opus 4.8 noreply@anthropic.com (95d54ac)
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.106-rc.1 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 install by @AbirAbbas in https://github.com/Agent-Field/agentfield/pull/738Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.105...v0.1.106-rc.1
Adds af-tray, a small separate binary that puts an AgentField icon in
the macOS menu bar. It polls the control plane's public /health endpoint
to show running/stopped status, opens the dashboard, and drives the
control-plane lifecycle (start/stop/restart/start-at-login) via launchd —
the tray is a controller of an OS service, not a supervisor.
Design/isolation:
curl | bash update force-restarts a stale tray/server onto the new
binary with nothing manual.Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
On macOS (production channel) the installer now fetches the separate
agentfield-tray-<arch> binary and delegates .app-bundle + launchd setup
to af-tray install (mirroring how the skill install is delegated to the
binary). Best-effort throughout: a missing/failed tray never fails the
overall install, and it is never fetched on Linux/headless/container hosts.
Opt out with --no-tray or TRAY_MODE=none.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Adds goreleaser build targets for agentfield-tray-darwin-{amd64,arm64} (CGO on, macOS only) and includes them in the release matrix on the macos-14 runner so the Cocoa/CGO link happens on a real macOS host. The binaries are named to match the existing agentfield-* asset convention, so the flatten/checksum/upload steps pick them up automatically.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Splits the CLI dispatch out of main() into a testable run([]string) int and adds unit tests for it plus the non-darwin stubs and the shared helpers (serverBinaryPath fallbacks, writeFileAtomic error paths). This lifts the control-plane patch coverage on the af-tray files from 66% to ~85%, above the 80% patch-coverage gate. The darwin-only files are not measured on the Linux coverage run; the systray loop / launchctl calls remain covered only by the on-device build.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Co-authored-by: Claude Opus 4.8 (1M context) noreply@anthropic.com (e2bf705)
af install <repo-url> (#738)Add an install snippet to the 'Built With AgentField' section: with a control
plane running, any first-party node (swe-planner, sec-af, cloudsecurity, pr-af)
installs with one af install <github-url> command, prompts once for shared
secrets, and its reasoners become callable. Links to docs/installing-agent-nodes.md.
Co-authored-by: Claude Opus 4.8 (1M context) noreply@anthropic.com (d9569d1)
`bash curl -fsSL https://agentfield.ai/install.sh | bash `
curl -fsSL https://agentfield.ai/install.sh | bash
VERSION=v0.1.105 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.104...v0.1.105
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.105-rc.1 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.104...v0.1.105-rc.1
af run <node> intermittently failed with 'agent node did not become ready
within 10s' — worst for import-heavy nodes like pr-af. Root cause is a
check-then-exec race between the runner and the SDK:
Fix (regression-safe, gated):
python -m <node>.app, manual PORT=...), the old
lenient auto-bump behavior is unchanged — no regression.Verified: with the patched control plane + SDK, all four reference nodes (swe-planner, cloudsecurity-af, sec-af, pr-af) start on their assigned ports and pass health; pr-af — previously failing almost every run — now binds its assigned port every time.
Co-authored-by: Claude Opus 4.8 (1M context) noreply@anthropic.com (23d9086)
`bash curl -fsSL https://agentfield.ai/install.sh | bash `
curl -fsSL https://agentfield.ai/install.sh | bash
VERSION=v0.1.104 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.103...v0.1.104
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.104-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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.104-rc.1...v0.1.104-rc.2
When a command failed at runtime — e.g. af run <node> hitting a
readiness timeout — cobra printed the full usage/help block (flags,
global flags, etc.) after the error. Usage text is meant for
mis-invocation, not runtime failures, so it was pure noise on top of the
actual error the user cares about.
Set SilenceUsage on the root command (cobra suppresses the usage block for any subcommand when the root has this set). The error itself still propagates — main.go surfaces it — so nothing is hidden; only the irrelevant usage wall is gone. Genuine bad-invocation errors (wrong arg count, unknown flag) still print their concise error message.
Co-authored-by: Claude Opus 4.8 (1M context) noreply@anthropic.com (fac34e1)
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.104-rc.1 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.103...v0.1.104-rc.1
The embedded Knowledge Base article ("observability/webhooks") and the
machine-readable API catalog both advertised
GET/POST/DELETE /api/v1/settings/webhooks, which is not a registered
route and 404s on the server (the Smart404 handler confirms
"/api/v1/settings/webhooks does not exist"). The real endpoint is the
singleton GET/POST/DELETE /api/v1/settings/observability-webhook
(plus /status, /redrive, /dlq), registered in
registerObservabilityRoutes.
Both surfaces are served to users/agents (public KB article endpoint and the /discover + .well-known/ai-catalog.json catalog), so the wrong paths were externally visible.
Changes:
X-AgentField-Signature: sha256=<hex> HMAC signing (when a secret is
set) and the lifecycle events it fires on, and clarify that this
outbound observability webhook is distinct from the inbound,
HMAC-signed approval webhook (POST /api/v1/webhooks/approval-response)./settings/webhooks entries with
the seven real /settings/observability-webhook* endpoints.Verified live: all documented paths now resolve (200), the dead path is gone from the served KB, and the corrected KB/catalog match the router.
Co-authored-by: Claude Opus 4.8 (1M context) noreply@anthropic.com (06f9110)
`bash curl -fsSL https://agentfield.ai/install.sh | bash `
curl -fsSL https://agentfield.ai/install.sh | bash
VERSION=v0.1.103 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.102...v0.1.103
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.103-rc.1 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.102...v0.1.103-rc.1
When an interactive af run/af install hits an unsatisfied
require_one_of group, the old flow prompted for each option in sequence
and told the user to "fill in one, leave the rest blank" — so to use
OpenRouter you had to know to press Enter past the Anthropic prompt.
Nobody could tell how to select. It also listed options as
ANTHROPIC_API_KEY | OPENROUTER_API_KEY, which reads poorly.
Now a group with two or more options renders a numbered menu (each option on its own line with its description), reads a single selection, and prompts only for the chosen provider. A single-option group still prompts directly. All user-facing option enumerations join with "or" instead of "|" (menu prompt "Enter 1 or 2 …", and the missing-env error).
Adds a PromptLine method to the Prompter interface (echoed line read for the selection) with a stdin-swap test, and menu contract tests covering select/retry/skip/exhaust/blank/single-option paths.
Co-authored-by: Claude Opus 4.8 (1M context) noreply@anthropic.com (c07b197)
`bash curl -fsSL https://agentfield.ai/install.sh | bash `
curl -fsSL https://agentfield.ai/install.sh | bash
VERSION=v0.1.102 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.101...v0.1.102
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.102-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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.102-rc.2...v0.1.102-rc.3
Add a config_version field to the agent-node manifest so the control plane can read it as the format evolves without locking authors into whatever shape shipped the day they wrote it. It is distinct from the node's own version: (release semver); config_version is the schema version.
ParsePackageMetadata now does a version-dependent read: an absent value is v0 (the legacy, pre-versioning format, read leniently), the current version is v1, and a manifest declaring a version newer than CurrentConfigVersion is refused with an "upgrade AgentField" error rather than silently mis-parsed. The "v" prefix is optional/case-insensitive; malformed values fail loudly.
Bump policy: config_version bumps only for BREAKING format changes (a field renamed/removed or its shape changed). Additive optional fields (e.g. the existing require_one_of) do not bump it.
Tests:
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Explain config_version in the agent-node install guide and the coding-agent CLI reference: what it is (schema version, distinct from the node's release version:), that absent means v0, that v1 is current, and the bump policy (breaking changes only — additive fields don't bump). Add a version table and link Agent-Field/SWE-AF's manifest as a real example to copy from. Mirror the CLI-reference change into the embedded skill_data copy.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Tell agents authoring/reading agentfield-package.yaml about config_version: the single reader (packages.ParsePackageMetadata), the bump policy, and that the golden-fixture suite is the spec they must maintain (grow the current fixture for additive fields; add a net-new fixture for a net-new version).
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Co-authored-by: Claude Opus 4.8 (1M context) noreply@anthropic.com (315f732)
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.102-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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.102-rc.1...v0.1.102-rc.2
Relocate the shared ui package out of internal/cli so non-cli packages (e.g. internal/packages, which prints install progress) can render with the same styled primitives without a cli->packages layering inversion. No behaviour change; only the import path moves.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
The git install path routed user-facing text through the JSON logger, so the terminal showed raw {"level":"info",...\u001b[..m} lines mixed with the spinners. Print those directly instead, and render the completion as a bordered success panel (name/version + source/location). Two more fixes to the flow:
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Extract the post-install source label and success panel into pure installSourceLabel / installSummaryPanel helpers so the styled completion is unit-tested (the surrounding InstallFromGit needs a real clone). Add spinner lifecycle tests for the non-TTY path and a clearLine test.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Co-authored-by: Claude Opus 4.8 (1M context) noreply@anthropic.com (2c4d446)
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.102-rc.1 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.101...v0.1.102-rc.1
Ports the control-plane pause/resume mechanism to the TypeScript SDK (closes the gap tracked in #726, where it existed only in the Python SDK).
Three layers:
Async-execution dispatch (on by default, asyncExecution config to opt out):
a reasoner dispatched by the control plane (carrying X-Execution-ID) is
acknowledged immediately with 202 Accepted and run detached; its terminal
status is delivered out-of-band via POST /executions/{id}/status. This
frees the dispatch connection so a reasoner can wait far longer than the
control plane's synchronous dispatch ceiling. A watchdog (pause-aware
active-time budget) guarantees a terminal status even if a reasoner hangs.
Pause primitive: ctx.pause() / Agent.pause() transition the execution to
WAITING via request-approval and block on a promise resolved by the always-on
POST /webhooks/approval route when the control plane delivers the decision.
Returns an ApprovalResult; times out to { decision: 'expired' } rather
than throwing. Backed by a PauseManager + PauseClock (new src/agent/pause.ts).
Multi-hop propagation: the remote call() path now submits async and polls
for the result, and when an awaited child enters WAITING it pushes the
caller's own execution to WAITING via notifyAwaiterStatus — so ancestors
don't time out while a descendant legitimately waits.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Adds planWithPause, which uses the high-level ctx.pause() primitive
alongside the existing low-level ApprovalClient demo, so the example shows both
the parity API and the manual polling approach.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
The functional test test_ts_agent invokes the reasoner via the legacy
synchronous endpoint POST /api/v1/reasoners/{node}.{reasoner}, which forwards
the agent's HTTP response verbatim and cannot handle a 202. With async dispatch
gated only on X-Execution-ID, the agent 202-acked there and the caller got the
{status:"processing"} marker instead of the result.
Gate async dispatch on BOTH X-Execution-ID and X-Run-ID. X-Run-ID is set
only by the control plane's async-aware callAgent path (workflow execute,
execute/async, agent-to-agent calls, triggers) — all of which wait for the
out-of-band /status result. The legacy sync invoke endpoint omits X-Run-ID
for long-running agents, so the agent now runs synchronously and returns the
result inline there, while pause/async continues to work on the execute paths.
Verified live: the legacy endpoint returns the inline echo result again, and a pause submitted via execute/async still reaches WAITING and resumes to succeeded. Adds a regression test for the X-Execution-ID-without-X-Run-ID case.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Co-authored-by: Claude Opus 4.8 (1M context) noreply@anthropic.com (1e11e82)
`bash curl -fsSL https://agentfield.ai/install.sh | bash `
curl -fsSL https://agentfield.ai/install.sh | bash
VERSION=v0.1.101 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.100...v0.1.101
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.101-rc.1 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.100...v0.1.101-rc.1
Introduce internal/cli/ui: a small lipgloss-based toolkit (bordered panels, column tables, status badges, key/value blocks) so CLI commands share one consistent, styled look. Palette matches the existing af init flow. lipgloss and bubbletea are already dependencies, so this adds no new modules.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Replace the ad-hoc printf output of af list and af secrets ls with bordered
ui tables: status badges (● running / ○ stopped), aligned columns, sorted rows,
and framed empty states. Update the two list assertions to the new header text.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Co-authored-by: Claude Opus 4.8 (1M context) noreply@anthropic.com (726e211)
`bash curl -fsSL https://agentfield.ai/install.sh | bash `
curl -fsSL https://agentfield.ai/install.sh | bash
VERSION=v0.1.100 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.99...v0.1.100
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.100-rc.1 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.99...v0.1.100-rc.1
Agent-node manifests could only mark each variable independently required or optional. Nodes that accept alternatives — e.g. SWE-AF works with either an Anthropic key OR an OpenRouter key — had no way to say "at least one of these"; you had to over-require one provider or make both optional and fail at runtime.
Add a require_one_of section: a list of groups, each satisfied when at least
one of its options resolves (env / secret store / default). On af run, an
unsatisfied group prompts the user to fill in one option (leaving the rest
blank), validating and persisting it encrypted like any required secret; a
non-interactive session errors naming the alternatives instead of failing inside
the node. af install surfaces unsatisfied groups the same way it does required
vars. Required / require_one_of / optional compose in one manifest.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Add unit coverage for the require_one_of paths flagged by the patch-coverage gate: the install-time group warnings in both checkEnvironmentVariables copies, envGroupSatisfied, and the group store-read / persist / combined-missing error branches. Also propagate store-read errors from resolveGroupFromSources so a group option's store failure aborts the resolve, consistent with required and optional variables.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Co-authored-by: Claude Opus 4.8 (1M context) noreply@anthropic.com (468caf0)
`bash curl -fsSL https://agentfield.ai/install.sh | bash `
curl -fsSL https://agentfield.ai/install.sh | bash
VERSION=v0.1.99 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.98...v0.1.99
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.99-rc.1 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.98...v0.1.99-rc.1
af install built each node's venv with whatever python3 was on PATH and
let pip enforce the package's requires-python. A node pinning
requires-python = ">=3.12" on a host whose python3 is 3.10 failed with a raw
pip ... requires a different Python trace and no path forward.
Add resolveVenvInterpreter: read requires-python from pyproject.toml and, when the ambient interpreter doesn't satisfy it, provision a compatible one via uv (auto-downloads a standalone build) or discover a matching pyenv-installed version — otherwise fail with an actionable error naming the required and found versions. No declared constraint keeps the legacy python3->python fallback, so existing behavior is unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Wire resolveVenvInterpreter into InstallPythonDependencies so a node's venv is created with an interpreter that satisfies its requires-python, provisioning one when the ambient python is too old instead of failing later in pip.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Co-authored-by: Claude Opus 4.8 (1M context) noreply@anthropic.com (086b0e0)
`bash curl -fsSL https://agentfield.ai/install.sh | bash `
curl -fsSL https://agentfield.ai/install.sh | bash
VERSION=v0.1.98 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.97...v0.1.98
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.98-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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.98-rc.3...v0.1.98-rc.4
A deployment_type:"serverless" node is a pull-registered, stateless HTTP handler - the same request/response contract AWS Lambda (via a Function URL), Cloud Run, Cloud Functions 2nd gen, and Fly.io all speak. That means the same Go reasoner should drop into any of them with zero SDK changes, but four real gaps broke that promise for a first-time adopter:
Closes Agent-Field/agentfield#718. (e16987a)
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.98-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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.98-rc.2...v0.1.98-rc.3
Fix(sdk): GLM-5.2 context limits + reasoning-model empty-output retry (#722)
_MODEL_CONTEXT_LIMITS: add openrouter/z-ai/glm-5.2 and z-ai/glm-5.2 at 131072. Absent entries fell back to 10,192 tokens and the trimmer cut 68% of large prompts (verified live: whole context blocks dropped).
AgentAI.ai: when parsed structured output is empty/default-only AND the response carries reasoning_content (reasoning model spent the whole completion budget on hidden reasoning), retry once with max_tokens doubled instead of silently returning the empty instance.
Co-authored-by: Abir Abbas abirabbas1998@gmail.com (0f9cc60)
agent.New() hardcoded a 15s timeout on the http.Client used for every outbound call the agent makes as a client (cross-agent Call(), the control-plane memory backend). Any reasoner chained behind Call() that legitimately takes longer - most visibly a reasoning-model-backed reasoner doing search + a large max_tokens "thinking" response - fails the caller with a client-side context-deadline-exceeded error while the callee keeps running and completes successfully on its own, with no way to fix it from the caller's config.
Adds Config.CallTimeout, defaulting to the existing 15s when unset so this is not a behavior change for anyone not hitting the issue.
Fixes Agent-Field/agentfield#720.
Co-authored-by: Abir Abbas abirabbas1998@gmail.com (5fa2057)
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.98-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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.98-rc.1...v0.1.98-rc.2
The SSEHandler deferred header flush until the first event, causing clients to hang on connection when no events matched immediately.
Changes:
Closes #358 (e0e8337)
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.98-rc.1 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.97...v0.1.98-rc.1
Replace the select{} no-op with real signal handling and HTTP server drain so SIGTERM during rolling deploys no longer kills in-flight requests.
Changes:
Closes #427
Co-authored-by: santoshkumarradha instrument.santosh@gmail.com (6c6c195)
`bash curl -fsSL https://agentfield.ai/install.sh | bash `
curl -fsSL https://agentfield.ai/install.sh | bash
VERSION=v0.1.97 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.96...v0.1.97
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.97-rc.8 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.97-rc.7...v0.1.97-rc.8
feat(cli): af share exports self-contained run artifact (DAG, timeline, bundle v1)
fix(share): hide cost UI entirely when cost data is unavailable
feat(share): workflow share export endpoint + UI share button
Add GET /api/ui/v1/workflows/{workflow_id}/share returning the same
self-contained offline HTML artifact as af share, as an attachment
(run-<id>.html, text/html). Supports ?redact=1.
The share bundle/template package moves from internal/cli/share to internal/share so both the CLI and the new handler import it. The handler builds the bundle directly from the storage layer (the same execution records the DAG and execution-details UI handlers read), resolving payloads from the payload store when stored by URI — no internal HTTP round-trip and no per-execution fan-out.
UI: a native Share button in the run detail action row (matching the Export provenance button style, Share2 icon from lucide-react) and a Share item in the runs-list lifecycle kebab menu. Both download via an authenticated fetch + anchor, honouring Content-Disposition.
af share <id> --public now publishes to agentfield.ai and prints the
returned permalink (https://agentfield.ai/share/<token>) instead of erroring
when AGENTFIELD_SHARE_URL is unset. Point that variable at a self-hosted
share server to publish there instead.
test(web): cover run share menu action
fix(share): avoid script escape preallocation overflow
test(share): cover artifact export paths (6f17fac)
The CLI harness runner in all three SDKs blocked until the child exited and read output only at the end, so it could not apply a no-progress watchdog. A stalled opencode/OpenRouter streaming call froze the run up to the wall-clock cap (default 1800s) while holding a concurrency-semaphore slot.
Python (sdk/python/agentfield/harness/_cli.py):
Go (sdk/go/harness/cli.go, cli_unix.go, cli_windows.go):
TypeScript (sdk/typescript/src/harness/cli.ts):
All return shapes are unchanged, so JSONL parsing downstream is unaffected. Adds idle-watchdog and fast-command tests in each SDK.
The .ai() path raised TimeoutError on the asyncio safety-net timeout with no retry (rate-limit retry only covers 429/503). A stalled OpenRouter connection therefore failed the reasoner outright. Add a timeout-retry layer that reissues the call on a fresh client pool (the pool is already reset on timeout), bounded by AGENTFIELD_AI_TIMEOUT_RETRIES (default 2, 0 disables). Applies to both the plain and tool-loop .ai paths. Existing deadlock-recovery tests run with retries disabled; added tests cover the retry-recovers and retry-exhausts cases.
The .ai() timeout-retry now also covers transient provider glitches: a malformed 'Unable to get json response', a 5xx, or a dropped connection are retried on a fresh client pool, while permanent client errors (bad request, auth, model-not-found, unsupported-schema) propagate immediately. Observed live with glm-5.2 returning a garbage whitespace body that failed a reasoner outright. (05ae9eb)
fix python sdk decorator metadata duplication
preserve stacked reasoner metadata
unwrap reasoners for code origin
honor outer reasoner trigger opt in
honor staged trigger opt in
keep agent reasoner metadata local
fix(sdk-python): apply EventTrigger transform on canonical reasoner form (#693)
The decorator-dedup refactor moved trigger merging into
resolve_reasoner_metadata but stopped stamping _reasoner_triggers on the
stored handler. As a result the runtime path (_execute_reasoner_endpoint)
read no bindings for the canonical @app.reasoner(triggers=[EventTrigger( ..., transform=fn)]) form on a plain handler, so the declared transform
was silently skipped and the handler received the raw event payload.
Rather than re-stamping the function (which the PR deliberately dropped: bound methods reject setattr, and a shared function object registered on two agents would leak triggers between them), thread the merged bindings through _execute_reasoner_endpoint via the registration closure. This keeps the PR's agent-local metadata intent while restoring transform application at dispatch time.
Adds a regression test that drives the real route -> envelope unwrap -> _execute_reasoner_endpoint path and asserts the handler receives the transformed object.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Co-authored-by: Santosh santosh@agentfield.ai Co-authored-by: Abir Abbas abirabbas1998@gmail.com Co-authored-by: Claude Opus 4.8 (1M context) noreply@anthropic.com (91d8f67)
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.97-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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.97-rc.6...v0.1.97-rc.7
Ref: #589 Signed-off-by: Jay sallomondiei@gmail.com
fix: replace stub with real regression test for OpenRouter video download auth
test(#589): relocate regression test into sdk/python/tests so CI collects it
The regression test for #589 was committed at repo-root tests/test_issue_589.py. The sdk-python CI workflow only triggers on sdk/python/**, so the test never ran, and 'import agentfield' does not resolve from repo root. Move it under sdk/python/tests/ where CI collects it and the package import resolves. Also drop an unused 'import os' flagged by ruff.
Refs #703, #589
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Signed-off-by: Jay sallomondiei@gmail.com Co-authored-by: Claude Opus 4.8 (1M context) noreply@anthropic.com (7b6f4b8)
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.97-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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.97-rc.5...v0.1.97-rc.6
Adds the foundation for making 'af install'/'af run' usable for real agent nodes (which start via 'python -m pkg.app' and have no top-level main.py):
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Local end-to-end verification revealed the CLI's install/run path goes through internal/core/services (DefaultPackageService/DefaultAgentService), which duplicated — and so bypassed — the fixes previously made in internal/packages. 'af install' on an entrypoint-only node still failed with 'main.py not found', and 'af run' still exported only AGENTFIELD_SERVER_URL and loaded plaintext .env.
Verified end-to-end: install entrypoint-only node -> missing-secret errors cleanly -> af secrets set -> af run injects AGENTFIELD_SERVER + the stored secret + manifest default into the process (confirmed via the node's env dump).
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Local multi-agent verification showed a port collision: dependencies were started after the parent allocated its port, so the parent's port (not yet bound) was handed out again to a dependency, which then failed to bind. Move dependency startup ahead of port allocation so each dependency fully binds its own port first.
Verified end-to-end against a live local control plane: 'af run greeter-node' auto-starts its dependency echo-node (distinct ports 8002/8003), both register, both reasoners execute through the control plane, and an already-running dependency is left untouched (same PID).
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Unit tests for resolveNodeRef, installedNames, installNodeDependencies (skip-already-installed), and startNodeDependencies (not-installed warning + already-running skip) in both the service and packages layers — covering the new patch lines and pinning the behaviors verified end-to-end.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
End-to-end install testing against the published node repos surfaced two gaps:
Verified: all five published node repos now install from their GitHub URLs; a pyproject node (sec-af) builds its venv and 'pip install .' succeeds, with sec_af + agentfield importable from the node's venv. (Nodes that declare requires-python >=3.11 need a matching interpreter on PATH — pip reports this clearly.) Tests updated for the new validation contract; new unit tests cover the pyproject branch and entrypoint-accepting findPackageRoot.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
The coverage-summary check was failing the patch-coverage gate: touched lines in the af-node-install feature sat at 59% vs the 80% floor in .coverage-gate.toml. This adds behavior-focused Go tests for the previously untested error and lifecycle paths:
af secrets set/ls/rm command tree
(global + node scope, stdin value, empty-value rejection, idempotent
remove) — previously had no test file.Patch coverage on touched lines: 59% -> 81% (gate passes at the 80% floor). No production code changed; tests only.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Co-authored-by: Claude Opus 4.8 (1M context) noreply@anthropic.com (753cba7)
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.97-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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.97-rc.4...v0.1.97-rc.5
Add logging configuration (level + redact_payloads) to control what execution data appears in structured log events and the internal event bus.
Changes:
Closes #560
The structured-log payload redaction added in #701 gated execution
input/result/context data behind redactPayloads. Those branches were only
exercised on their redact-enabled default, leaving the opt-out paths uncovered
and dropping control-plane patch coverage below the 80% floor.
Adds behavior tests that subscribe to the execution event bus and assert the observable contract: input/result/context payloads are omitted from published events when redaction is enabled (the safe default) and present only when an operator explicitly disables it. Covers completeExecution, failExecution, completeReplayHit, handleStatusUpdate, and the event-context path.
Patch coverage on touched lines: 68% -> 93%. Additive only; does not weaken the redaction logic.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Co-authored-by: Abir Abbas abirabbas1998@gmail.com Co-authored-by: Claude Opus 4.8 (1M context) noreply@anthropic.com (841459b)
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.97-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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.97-rc.3...v0.1.97-rc.4
Salvage of the safe, zero-regression subset of #618. Removes genuinely dead code only:
Deliberately EXCLUDES the regression-inducing parts of the original PR: the /admin/public-key alias removal (breaks all-SDK offline VC verification), node lifecycle + /actions/claim endpoints, legacy reasoner execute endpoints, the broken root compose.yaml, and storage-mode/telemetry config flips.
Validation: go build/vet clean; go test ./... green (control-plane); web-ui npm build clean; web-ui coverage 84.78% (baseline 84.79%, floor 84.0).
Co-authored-by pocesar via original PR #618.
Co-authored-by: Abir Abbas abirabbas1998@gmail.com Co-authored-by: Claude Opus 4.8 (1M context) noreply@anthropic.com (615baa6)
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.97-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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.97-rc.2...v0.1.97-rc.3
AgentFieldClient constructed its default async_config with AsyncConfig(), ignoring AGENTFIELD_ASYNC_* environment overrides that Agent already honors. Initialize the default from AsyncConfig.from_environment() so client-level async behavior can be tuned via env vars, while preserving any explicitly passed async_config unchanged. Adds regression coverage for both paths.
Fixes #621. Supersedes #632 (original change by liuzemei / neooosky); re-authored here so it can land without the outstanding CLA signature.
Co-authored-by: Claude Opus 4.8 (1M context) noreply@anthropic.com (04756b8)
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.97-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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.97-rc.1...v0.1.97-rc.2
Bumps the go_modules group with 1 update in the /control-plane directory: golang.org/x/net.
Updates golang.org/x/net from 0.52.0 to 0.55.0
updated-dependencies:
Signed-off-by: dependabot[bot] support@github.com Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> (bd5f8cc)
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.97-rc.1 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.96...v0.1.97-rc.1
feat(skill): add mental-models layer to agentfield skill
feat(skill): rework thinking layer into generative orchestration theory
The skill taught rules and a pattern vocabulary; an agent reading it could imitate reference builds but not derive an orchestration for a problem that looks like neither security auditing nor contract review. Patterns are outputs of thinking, not inputs.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
The thinking-layer rework edited skills/agentfield/ (source of truth) but the binary embeds skill_data/agentfield/. Sync the mirror (adds mental-models.md, updates SKILL.md and references) and bump the catalog version 0.4.0 -> 0.5.0 so existing installs pick up the change on af skill install/update instead of being skipped as already-current.
Co-authored-by: Claude Opus 4.8 noreply@anthropic.com (76fdf5e)
Docs: credit integrations packs in comparison table (linked partial mark) (a709524)
Docs: sharpen vs-frameworks pitch (concede row, plain-words rows, second-caller rule) (2ea7c67)
Docs: scale-first README rewrite (fan-out hero sample, how-it-scales section, tutorial blog cards) (859174f)
Nothing published for this version
`bash curl -fsSL https://agentfield.ai/install.sh | bash `
curl -fsSL https://agentfield.ai/install.sh | bash
VERSION=v0.1.96 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.95...v0.1.96
> ⚠️ This is a staging/pre-release version for testing. Not recommended for production use.
⚠️ 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.96-rc.1 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.95...v0.1.96-rc.1
The async execution handler records an execution as succeeded whenever the
reasoner returns a value — it never inspects the result. A reasoner whose own
payload says success: False (e.g. a build that completed zero issues and
merged nothing) therefore surfaces as green, which is easy to act on
incorrectly.
Add ReasonerFailed, raised inside a reasoner to report that the work ran but
failed. The handler maps it to status="failed" while still posting the
structured result, so the control plane (which stores the result payload
regardless of terminal status) keeps the rich outcome — debt, DAG state, any
PR opened — instead of just a bare error string. error_details is carried
through the existing generic path.
Refs Agent-Field/SWE-AF#82 (Gap 2, SDK half).
Co-authored-by: Claude Opus 4.8 (1M context) noreply@anthropic.com (491460d)
`bash curl -fsSL https://agentfield.ai/install.sh | bash `
curl -fsSL https://agentfield.ai/install.sh | bash
VERSION=v0.1.95 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-arm64Full Changelog: https://github.com/Agent-Field/agentfield/compare/v0.1.94...v0.1.95
Your coding agent can read these notes before it upgrades. Set up the MCP server →