Skip to content

Releases: quant-risk/radiant-harness

v3.7.13: phase redirect --purge + great-grandchildren pid tree + fleet status --html

Choose a tag to compare

@quant-risk quant-risk released this 30 Jun 17:36

v3.7.13 — phase redirect --purge + great-grandchildren pid tree + fleet status --html

Three backlog items closed in one sprint.

Added

  • radiant phase redirect --purge=<ticket-id> — explicit cleanup of stale follow redirect without nuking state dir. Removes ONLY redirect.json for the named ticket; spec, tasks, other redirects untouched. Exits 1 on missing file so CI / lints catch accidental purges. --list + --purge mutually exclusive.
  • Nested pid tree — great-grandchildren layerPidTree gains GreatGrandchildrenPids + GreatGrandchildrenAlive + GreatGrandchildrenCount. New .pid.great-grandchildren sidecar. refreshChildTreeSidecars writes all 3 sidecars (children + grandchildren + great-grandchildren) in a single pgrep pass. Crashed-evidence string in Coordinator.Status() includes great-grandchildren counts.
  • radiant fleet status <run-id> --html — self-contained HTML report with visual nested pid tree (parent → child → grandchild → great-grandchild) in Unicode box-drawing glyphs inside <pre>. Color-coded by liveness (alive=green, dead=red, vacuous=muted). --html-out=<path> writes to disk. No external CSS / JS / CDN — renders offline in any browser or mail client. HTML escape enforced (XSS defense).

Tests

11 new tests pin the contract (4 CLI redirect purge, 6 fleet status HTML, 7 pidtree great-grandchildren). 32/32 packages pass. Backward compatible — all existing tests still green.

Process-learnings

  • pidAlive + sentinel 16777215 (above pid_max on every reasonable host) is the test pattern for great-grandchildren alive-counting.
  • TaskPidTree early-returns on empty children sidecar; great-grandchildren are not read when children is empty (matches reality: no children = no descendants possible).
  • purgeFollowRedirectW (writer-injecting form) is the testable shape; cobra subcommand uses purgeFollowRedirect (hardcoded stdout/stderr) wrapper.
  • FormatStatusHTML is offline-safe by construction (no http(s):// URLs, no @import, no <script src=>).
  • HTML escape is mandatory — fleet goal / title / evidence may contain operator-supplied strings; the & < > " ' replacer handles XSS via injected metadata.

v3.7.12 — phase redirect --list + phase follow + grandchildren pid tree

Choose a tag to compare

@quant-risk quant-risk released this 30 Jun 16:38

"## v3.7.12 — phase redirect --list + phase follow + grandchildren pid tree\n\nThree backlog items closed in one sprint:\n\n### A. radiant phase redirect --list\n\nNew flag on the existing redirect subcommand. Scans .radiant-harness/state/possess-*/ for redirect.json files and emits either a formatted table (default — columns: OLD, NEXT, CREATED_AT, PATH) or NDJSON (--list --json, one object per line). Skips corrupt files silently (defense against operator-edited files with bad JSON) and skips non-possess-* directories.\n\n\n$ radiant phase redirect --list\nOLD NEXT CREATED_AT PATH\n--------------------------------------------------------------------------------\nv3711-A-real v3711-B-real 2026-06-30T15:33Z .radiant-harness/state/possess-v3711-A-real/redirect.json\n2 redirect(s) in /tmp/watch-test/.radiant-harness/state\n\n\n### B. radiant phase follow <anchor-ticket-id>\n\nAlias for radiant phase watch --follow=<ticket> with the anchor as a positional argument (easier to type + tab-complete in a shell). Reuses the same flag set as watchCmd (--interval, --max-poll, --json, --on-change-exit). Semantics byte-identical to --follow=<anchor> on the watch command.\n\n\n$ radiant phase follow 04b82c5a2f19ab36 --interval=5s\n$ radiant phase follow 04b82c5a2f19ab36 --on-change-exit --max-poll=30s\n$ radiant phase follow 04b82c5a2f19ab36 --json | jq -c .status\n\n\n### C. Recursive pid tree — grandchildren\n\nPidTree struct now exposes GrandchildrenPids + GrandchildrenAlive + GrandchildrenCount in addition to the v3.7.10 Children* fields. New helpers readGrandchildrenPids + writeGrandchildrenPids provide the on-disk format (newline-separated integers at .radiant-harness/fleet/pids/agent-<...>.pid.grandchildren). refreshChildAndGrandchildrenSidecars writes both sidecars on each refresh. Coordinator.Status() enriches the crashed-evidence string:\n\n\nagent pid 12345 not alive; 2 children recorded, 1 still alive; 5 grandchildren recorded, 3 still alive\n\n\n### Tests\n\n13 new tests pin the contract (100% PASS):\n- 6 CLI tests in cmd/radiant/v3_7_12_cli_test.go: --list empty/with-entries/JSON/corrupt-skip/non-possess-skip, follow help + state-read\n- 7 pidtree tests in internal/fleet/pidtree_grandchildren_test.go: GC all-alive / GC dead / no GC sidecar / write-read roundtrip / path layout / refresh writes both / grandchild found\n\ngo test ./... PASS (32/32 packages)\n\n### Backlog (v3.7.13)\n\n- Real CI host reproducing fleet cross-process need (still gated)\n- Per-task nested-pid-tree dashboard HTML report\n- radiant phase redirect --purge=<ticket> for explicit cleanup\n- Recursive fleet pid tree (great-grandchildren)\n"

v3.7.11 — --on-change-exit + --follow + docs/HOSTS.md

Choose a tag to compare

@quant-risk quant-risk released this 30 Jun 15:57

"## v3.7.11 — --on-change-exit, --follow, docs/HOSTS.md\n\nThree backlog items closed — observability + offline docs for the async opt-in matrix shipped in v3.7.10.\n\n### A. radiant phase watch --on-change-exit\n\nExit 0 immediately after the FIRST change observed AFTER the initial snapshot. Useful for "wait until anything changes" notifications without a full watch. Combine with --max-poll to bound the wait window (--on-change-exit --max-poll=30s).\n\n### B. radiant phase watch --follow=<anchor> + radiant phase redirect <old> <new>\n\n--follow=<anchor> tracks the anchor ticket's state initially. When a redirect.json appears at .radiant-harness/state/possess-<anchor>/redirect.json with a {next_ticket: \"...\"} payload, the watch transparently switches to the new ticket's state.json.\n\nradiant phase redirect <old-ticket> <new-ticket> is the new subcommand that writes the redirect.json (atomic write, RFC3339 created_at timestamp for forensics).\n\nUse case: resume re-dispatches with a NEW ticket id; the operator wants to keep watching without manually updating the CLI invocation.\n\n### C. docs/HOSTS.md (new)\n\nOffline-readable per-host opt-in matrix for all 13 Light-mode hosts + the "no agent detected" case. Documents how/when/when-not-to opt in, how to verify, and governance rules for flipping verdicts. Companion to radiant doctor --async-host (which already shipped in v3.7.10).\n\n### Tests\n\n9 new tests pin the contract (100% PASS):\n- on-change-exit transition/max-poll semantics (exits 0/1)\n- redirect.json file format (write/read round-trip, missing/corrupt handling, RFC3339 payload shape)\n- follow redirect detection mid-watch\n\ngo test ./... PASS (32/32 packages)\n\n### Backlog (v3.7.12)\n\n- Real CI host reproducing fleet cross-process need (still gated)\n- radiant phase redirect --list\n- radiant phase follow alias\n- Recursive fleet pid tree (grandchildren)\n"

v3.7.10 — --watch + nested pid tree + async-host opt-in matrix

Choose a tag to compare

@quant-risk quant-risk released this 30 Jun 15:28

"## v3.7.10 — --watch, nested pid tree, async-host opt-in matrix\n\nThree backlog items closed in one sprint, all observability/lifecycle:\n\n### A. radiant phase watch <task-id> CLI\n\nNew CLI namespace under radiant phase. Polls the persisted possessState and re-emits the phase summary only when (status, current_phase, subprocess_alive, subprocess_pid) changes. Exits 0 when the run reaches a terminal state (done / cancelled / error / crashed); exits 1 after --max-poll elapses; exits 130 on SIGINT/SIGTERM (clean Ctrl-C handling). --json emits one structured object per change in NDJSON format.\n\nCompanion to MCP radiant_phase_status for hosts that want streaming without round-tripping through the MCP transport (which does not stream).\n\n### B. Per-task nested pid tree\n\nTaskLive.tree field exposes parent_alive + children_pids + children_alive + child_count so a host can distinguish "parent died cleanly" from "parent died; N helpers orphaned". Dispatcher.spawnAgent spawns a refreshChildPidsLoop goroutine that pgrep -P's the parent every 5s and writes the children sidecar at .radiant-harness/fleet/pids/agent-<...>.pid.children.\n\n### C. Async-subprocess opt-in matrix + diagnostic\n\nTwo CLI flags on radiant mcp serve:\n- --async-subprocess (loop async subprocess)\n- --fleet-async-subprocess (fleet async subprocess)\n\nPrecedence: CLI flag > env var > default off. radiant doctor --async-host (v3.7.10+) scores all 13 known hosts — only Hermes is currently flagged RecommendAsync=true (TUI gates tool-call completion on subprocess exit); the rest default to inline. Exits non-zero when a recommendation is unmade so CI/lint can catch regressions.\n\n### Tests\n\n22 new tests pin the contract (100% PASS):\n- internal/fleet/pidtree_test.go (13): pid sidecar roundtrip, refresh loop lifecycle, parent/children liveness combinations\n- cmd/radiant/v3_7_10_test.go (9): phase watch terminal/max-poll/JSON/no-reemit semantics, status CLI shape, doctor exit-code contract, envBool parsing\n\ngo test ./... PASS (32/32 packages)\n\n### Backlog (v3.7.11)\n\n- --watch --on-change-exit flag — exit on FIRST change after initial snapshot\n- --follow=<ticket> — follow another ticket after a re-dispatch\n- Per-host opt-in matrix in docs/HOSTS.md for offline reading\n- Real CI host reproducing fleet cross-process need (still gated)"

v3.7.9 — Fleet async primitives (parity with loop)

Choose a tag to compare

@quant-risk quant-risk released this 30 Jun 14:52

Fleet async primitives — parity with loop (A+B+C)

Three layers combined in one release:

A. MCP wrappers

  • radiant_fleet_status(run_id, workdir?) — returns structured FleetStatus JSON with task counts, per-task liveness, dispatcher liveness, conflict list, raw JSON dump, and automatic next-step hint
  • radiant_fleet_resume(run_id, workdir?, model?, auto_route?) — wraps Dispatcher.ResumeAll so hosts can drive the fleet from the MCP wire (no shell-out)

B. Liveness probe

  • Coordinator.WithLivenessDir(workdir) — opt-in
  • FleetStatus gains DispatcherAlive + DispatcherPid + TaskLiveness map
  • TaskCrashed lifecycle: tasks the store considers assigned but whose pid file points at a dead process escalate to TaskCrashed (parity with v3.7.8 loop phaseStatusSummary crashed branch)
  • Store.CrashTask(taskID, evidence) persists the crashed state cross-process

C. Subprocess gate

  • DispatchConfig.AsyncSubprocess + DispatchConfig.Workdir
  • When enabled, RunAll forks radiant fleet-async-runner <run-id> and returns immediately (parity with v3.7.7 loop async-runner)
  • Inline remains the default; opt-in via RADIANT_FLEET_ASYNC_SUBPROCESS=1

Pid files (always-on)

  • Per-task: .radiant-harness/fleet/pids/agent-<runID>-<taskID>.pid — written by spawnAgent before cmd.Start, removed via defer after cmd.Wait
  • Per-dispatcher: .radiant-harness/fleet/pids/dispatcher-<runID>.pid — written by the fleet-async-runner on boot
  • sanitizePidComponent defends against path traversal in run/task IDs

Tests

  • 22 new tests pin the contract (10 pidfile + 5 coordinator + 7 MCP)
  • go test ./... PASS (32/32 packages, 0 FAIL)
  • make audit-docs PASS (46 refs / 57 cmds)
  • make audit-skills PASS (6 hint map / 69 bundled skills)

Backlog (v3.7.10)

  • Real host opt-in for RADIANT_FLEET_ASYNC_SUBPROCESS=1 (gated by reproduction)
  • --watch flag for radiant_phase_status
  • Per-task nested pid tracking (recursive liveness)

v3.7.8 — Async gate pid/liveness probe

Choose a tag to compare

@quant-risk quant-risk released this 30 Jun 14:18

[3.7.8] — 2026-06-30 — Async gate pid/liveness probe

radiant_phase_status now cross-references the persisted
subprocess pid against the running OS process list, so a host
agent can tell the difference between "the phase is still
running" and "the subprocess crashed without writing an error".

Changed

  • phaseStatusSummary (returned in radiant_phase_status MCP
    response) gains two additive fields populated from
    .radiant-harness/pids/<ticket>.pid:
    • subprocess_alive (bool) — kill -0 on the recorded pid.
    • subprocess_pid (int) — the recorded pid itself.
  • Status escalation: when the recorded phase is in_progress
    but subprocess_alive=false, status moves from in_progress
    to crashed and the next-step line tells the host to re-call
    mcp__radiant__run_gate(phase=...) to resume from where the
    crash happened.
  • Next-step annotation when alive: in_progress runs that have
    a live subprocess now show subprocess pid=N alive — last polled at <RFC3339> so the operator can confirm the child is
    actually running.
  • Format helper (content[1].text) gains a subprocess: line
    when a pid is recorded (pid=N alive / pid=N dead).
  • No wire-format change for existing callers: the new fields are
    omitempty, so older consumers that JSON-parse
    content[0].text or the existing summary fields keep working
    unchanged.

Why this matters

The subprocess path shipped in v3.7.7 (opt-in via
RADIANT_ASYNC_SUBPROCESS=1) spawns a child radiant async-runner per phase and tracks it via a pid file. Without a
liveness check, a crashed child looks identical to a slow one
— the host sees in_progress indefinitely and never knows to
re-call the gate. v3.7.8 closes that gap by reading the pid
file and doing kill -0 on every phase_status call.

Verified

  • cmd_mcp_possess_test.go::TestPhaseStatusSummary_* 7/7 PASS:
    • DoneRunShape, MidRunShape, ErrorShape,
      CancelledShape (existing, v3.7.6) — unchanged behaviour.
    • SubprocessAlive (NEW) — pid file pointing at the test
      process; SubprocessAlive=true, Status stays in_progress,
      NextStep mentions the live pid.
    • SubprocessCrashed (NEW) — pid file pointing at a stale
      pid (16777215, above pid_max on Linux/macOS);
      SubprocessAlive=false, Status escalates to crashed,
      NextStep instructs re-call run_gate.
    • NoPidFile (NEW) — no pid file written; SubprocessAlive=
      false, SubprocessPid=0, Status stays in_progress (no
      false-positive crashed on the default inline path).
  • go test ./cmd/radiant ./internal/... PASS.
  • ./scripts/run.sh PASS, 8/8 + 2 SKIP doctor.

Migration

No migration required. subprocess_alive and subprocess_pid
are additive on the summary JSON. Hosts that don't care about
subprocess liveness keep working unchanged.

Install

```bash
curl -fsSL https://raw.githubusercontent.com/quant-risk/radiant-harness/main/install.sh | bash
```

Or pin v3.7.8:

```bash
curl -fsSL https://raw.githubusercontent.com/quant-risk/radiant-harness/main/install.sh | RADIANT_VERSION=3.7.8 bash
```

Cross-platform binaries

OS Arch File
Linux amd64 radiant-linux-amd64
Linux arm64 radiant-linux-arm64
macOS amd64 radiant-darwin-amd64
macOS arm64 radiant-darwin-arm64
Windows amd64 radiant-windows-amd64.exe
Windows arm64 radiant-windows-arm64.exe

Verify with `shasum -a 256 -c SHA256SUMS` against `dist/SHA256SUMS`.

v3.7.7 — Subprocess-backed async gate primitives

Choose a tag to compare

@quant-risk quant-risk released this 30 Jun 13:33

[3.7.7] — 2026-06-30 — Subprocess-backed async gate primitives

The async gate primitives (radiant_possess_async +
radiant_run_gate) ship two execution paths in v3.7.7. The inline
path is unchanged; the new subprocess path is opt-in via
RADIANT_ASYNC_SUBPROCESS=1 and forks a radiant async-runner
child process so phases can outlive the parent's tool-call window.

Added

  • radiant async-runner --phase=<p> --ticket=<id> --workdir=<w> --task=<task> — the worker subcommand. Validates args, writes
    .radiant-harness/pids/<ticket>.pid on entry, delegates to the
    same selfDriven<Phase> helpers the inline path uses, removes
    the pid file on exit. Hidden from --help; gated by
    RADIANT_INTERNAL=1 so a fresh shell can't trigger it.
  • subprocessAsyncGate + subprocessPossessAsync — implementations
    of internal/possess.AsyncGate and internal/possess.PossessAsync
    that fork radiant async-runner via os/exec. Selected via
    RADIANT_ASYNC_SUBPROCESS=1; the inline path is the default.
  • RADIANT_BIN env var honored by asyncRunnerSelfPath — tests
    point the subprocess at a one-time-built binary (rather than
    the test binary, which would deadlock).
  • selectedPossessAsync() + selectedAsyncGate() helpers in
    cmd_mcp_possess_async.go — single source of truth for the
    inline-vs-subprocess selection; both mcpPossessAsync and
    mcpRunGate route through them.

Why subprocess mode is opt-in, not the default

The inline path closes the synchronous-host deadlock today
(Hermes TUI) because the self-driven phases complete in
<500 ms before the tool call returns. A subprocess fork adds
~50 ms of overhead and the management machinery (pid files,
kill -0 liveness, crash recovery) is only worth paying for
when a real host need reproduces. Per
docs/PROPOSAL-v3.7.2-async-primitives.md § v3.7.6 update,
subprocess mode is wired but not the default — turn it on
when a sampling-backed sync-host or fleet cross-process worktree
need reproduces. The inline path stays the default to keep
existing deployments unchanged.

Crash recovery

The subprocess path writes state.json after each phase
(identical to the inline path), so a crash mid-Execute is
recoverable: the next mcp__radiant__run_gate call observes
execute is already in_progress and resumes from there. The
pid file is best-effort cleanup on exit; a stale pid file
indicates "this ticket was running" for operator-side diagnosis
and is not relied on for correctness.

Verified

  • cmd_async_runner_test.go 5/5 PASS:
    • TestSubprocessAsync_DiscoveryRunsInChild — subprocess
      gate Spawn lands state.json with discover=done.
    • TestSubprocessAsync_FourPhasesEndToEnd — full 4-phase
      possess_async through the subprocess path lands the
      canonical scaffold (spec.md / tasks.md / scripts/run.sh).
    • TestSubprocessAsync_PidFileLifecycle — write/read/remove
      semantics of the pid file helpers.
    • TestSubprocessAsync_CrashRecovery — planted in_progress
      state.json resumes correctly on next run_gate call.
    • TestSubprocessAsync_SpawnsChildProcess — direct
      invocation of radiant async-runner as a real subprocess.
  • go test ./cmd/radiant/... PASS.
  • ./scripts/run.sh PASS (8/8 + 2 SKIP doctor).
  • Build clean; make audit-docs PASS.

Migration

No migration required. Subprocess mode is opt-in. Set
RADIANT_ASYNC_SUBPROCESS=1 in the radiant mcp serve
process to enable; unset (or omit) to keep the inline path.

Install

curl -fsSL https://raw.githubusercontent.com/quant-risk/radiant-harness/main/install.sh | bash

Or pin v3.7.7 explicitly:

curl -fsSL https://raw.githubusercontent.com/quant-risk/radiant-harness/main/install.sh | RADIANT_VERSION=3.7.7 bash

Enable subprocess mode (opt-in)

The inline path is unchanged. To turn on the subprocess-backed
gate primitives, set RADIANT_ASYNC_SUBPROCESS=1 in the
radiant mcp serve process.

Cross-platform binaries

OS Arch File
Linux amd64 radiant-linux-amd64
Linux arm64 radiant-linux-arm64
macOS amd64 radiant-darwin-amd64
macOS arm64 radiant-darwin-arm64
Windows amd64 radiant-windows-amd64.exe
Windows arm64 radiant-windows-arm64.exe

Verify with shasum -a 256 -c SHA256SUMS against dist/SHA256SUMS.

v3.7.6 — Consolidation: status UX, host matrix, doc/backlog cleanup

Choose a tag to compare

@quant-risk quant-risk released this 30 Jun 11:55

[3.7.6] — 2026-06-30 — Consolidation: status UX, host matrix, doc/backlog cleanup

v3.7.6 is a consolidation release. It ships the v3.7.3-v3.7.5 backlog
of doc/backlog cleanups (the three commits 913f7d3, cec74bc,
9fe13cf since v3.7.5), tightens the radiant_phase_status contract
so a host agent can resume a run without re-parsing state.json,
extends the cross-agent install matrix to include Google Gemini CLI
(13th host), and turns scripts/run.sh into a single-call validation
entrypoint that exercises the full install/test/audit matrix.

No sampling-loop behaviour changed. No MCP wire format changed. The
summary field on radiant_phase_status is additive — older callers
that JSON-parse content[0].text keep working unchanged.

Highlights

  • radiant_phase_status returns a structured summary. The
    v3.7.6 response carries result.summary with status,
    current_phase, next_step, resume_command, pending_files,
    pending_marker_count, last_gate, and a compact per-phase map.
    The raw state.json dump is still present in content[0].text for
    backwards compatibility. This closes the "host agent has to read
    state.json itself to know whether to retry" gap that v3.7.2 left
    open. Five new contract tests pin the four phases × {done,
    in_progress, error, cancelled} matrix.
  • Google Gemini CLI added to the host matrix. setup-mcp --agent=gemini writes ~/.gemini/settings.json (user) or
    ./.gemini/settings.json (project) with the standard
    mcpServers JSON shape — same as Claude/Cursor. Detection
    signal: GEMINI_CLI, GEMINI_PROJECT_ROOT, GEMINI_API_KEY.
    Restart hint: relaunch gemini-cli. The 12-agent matrix in
    scripts/host-agent-matrix.json is now 13; make test-agents
    asserts all 13 sandbox installs.
  • scripts/run.sh is the canonical validation entrypoint.
    v3.7.6 extends the previous 4-command script to cover the full
    matrix: mcp self-test, doctor, doctor --mcp (both
    informational when no host is wired), go test ./cmd/radiant ./internal/..., go test ./..., audit-docs, audit-skills,
    audit-install, test-agents, test-dropin. Doctor is
    surfaced as SKIP (not FAIL) in a fresh shell, so the script
    is reliable from CI and from inside a host session.
  • radiant_run_gate + radiant_possess_async documented.
    AGENTS-FOR-TASKS.md § MCP tools now lists all 6 primitives
    (was 4 — radiant_run_gate and radiant_possess_async were
    on the wire but missing from the docs table).
  • External MenuFlex case spec removed. Commit 913f7d3
    the user-case spec did not belong in the harness repo. The
    removal is recorded for audit; nothing else in the repo
    referenced the case.
  • Backlog consolidation. Commit cec74bc consolidates the
    docs (docs/ROADMAP.md, docs/STATE.md, docs/PROPOSAL-v3.7.2-async-primitives.md)
    and closes the placeholder spec/doc open work into explicit
    status records. Commit 9fe13cf documents the final validation
    pass.
  • Async subprocess deferred. The v3.7.2 PROPOSAL called for a
    real background subprocess for radiant_possess_async. The
    current implementation runs phases synchronously in-process
    (the offline self-driven path is already short — typical run is
    <500 ms, so a subprocess adds little). v3.7.6 keeps the existing
    inline path and adds a follow-up spec for the cases that would
    justify a real subprocess (long-running Claude Code sampling
    loops, cross-process worktree ops).

Changed

  • internal/hostdetect/hostdetect.go: added AgentGeminiCLI constant
    • signature (GEMINI_CLI/GEMINI_PROJECT_ROOT/GEMINI_API_KEY env,
      gemini/gemini-cli parent binaries, SupportsSampling=true).
  • cmd/radiant/cmd_doctor.go::mcpConfigPath + probeRadiantEntry:
    added gemini-cli case → ~/.gemini/settings.json with the
    standard mcpServers JSON shape.
  • cmd/radiant/cmd_setup_mcp.go::mcpConfigFor: added gemini case
    using the existing mergeMCPJSON helper (same JSON layout as
    Claude/Cursor). Updated the unknown-agent error message.
  • cmd/radiant/cmd_mcp_runtime.go::mcpPhaseStatus: returns
    result.summary (structured phaseStatusSummary + a rich text
    block in content[1].text) alongside the raw state dump.
  • scripts/host-agent-matrix.json: 13th agent row for gemini.
  • scripts/run.sh: rewritten as a fail-collecting matrix; doctor
    steps surfaced as SKIP, real gates (audit-install, test-agents,
    test-dropin, full go test ./...) now exercised.
  • AGENTS-FOR-TASKS.md: MCP tools table now lists all 6
    primitives with parameters and a sync-host alternative
    workflow. Agent list includes gemini.
  • INSTALL.md + README.md: agent table updated to 13 entries
    with the Gemini row + detect signal.

Added

  • cmd/radiant/cmd_mcp_runtime.go: phaseStatusSummary,
    phaseMini, phaseGateSummary types + buildPhaseStatusSummary
    • formatPhaseStatusSummary + extractLastGate helpers.
  • cmd/radiant/cmd_mcp_possess_test.go: 5 new tests pinning the
    v3.7.6 contract (TestPhaseStatusSummary_DoneRunShape,
    TestPhaseStatusSummary_MidRunShape,
    TestPhaseStatusSummary_ErrorShape,
    TestPhaseStatusSummary_CancelledShape,
    TestMCPPhaseStatus_ReturnsSummaryField).
  • internal/hostdetect/hostdetect_test.go::TestDetect_GeminiCLI.

Verified

  • ./scripts/run.sh PASS (8 PASS, 2 SKIP — doctor + doctor --mcp
    in a host-less shell are correctly informational, not failures).
  • make audit-install PASS (canonical curl | bash path will
    PASS once v3.7.6 is published — the SKIP in the validation
    above was because the local tree was 3 commits ahead of v3.7.5).
  • make test-agents PASS (13/13 agents simulated install).
  • make test-dropin PASS against v3.7.6.
  • go test ./cmd/radiant ./internal/... PASS.
  • go test ./... PASS (full module).
  • radiant mcp self-test PASS, exposes 6 MCP tools.
  • Build clean (go vet ./... clean, go build ./... clean).

Migration

No migration required. The summary field on
radiant_phase_status is additive; older callers that JSON-parse
content[0].text keep working unchanged. Hosts that key off
the raw state.json shape continue to see the same fields.

Hosts running v3.7.6 inside a Gemini CLI session: run
radiant setup-mcp --agent=gemini --global once, then relaunch gemini-cli for the MCP server entry to land.

Install

curl -fsSL https://raw.githubusercontent.com/quant-risk/radiant-harness/main/install.sh | bash

Or pin v3.7.6 explicitly:

curl -fsSL https://raw.githubusercontent.com/quant-risk/radiant-harness/main/install.sh | RADIANT_VERSION=3.7.6 bash

Cross-platform binaries

OS Arch File
Linux amd64 radiant-linux-amd64
Linux arm64 radiant-linux-arm64
macOS amd64 radiant-darwin-amd64
macOS arm64 radiant-darwin-arm64
Windows amd64 radiant-windows-amd64.exe
Windows arm64 radiant-windows-arm64.exe

Verify with shasum -a 256 -c SHA256SUMS against dist/SHA256SUMS.

v3.7.5: documented drop-in self-driven E2E

Choose a tag to compare

@quant-risk quant-risk released this 30 Jun 10:51
  • Publishes the current HEAD that includes the automated drop-in self-driven E2E test and documentation.\n- Keeps the v3.7.4 binary behavior: MCP radiant_possess returns Self-driven handoff on non-sampling hosts.\n- Includes cross-platform binaries and SHA256SUMS for install.sh latest-release installs.\n\nValidation before release:\n- make test-dropin\n- go test ./...\n- radiant mcp self-test

v3.7.4: drop-in self-driven Codex handoff

Choose a tag to compare

@quant-risk quant-risk released this 30 Jun 09:34
  • Makes the public drop-in flow work for hosts without MCP sampling by returning a clear Self-driven handoff from radiant_possess.\n- Updates README/INSTALL/install.sh language so agents use mcp__radiant__possess and continue with native tools when sampling is unavailable.\n- Includes cross-platform binaries and SHA256SUMS for install.sh latest-release installs.\n\nValidation:\n- go test ./...\n- radiant mcp self-test\n- make audit-install