@staix/agent-hub 0.18.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +4 -4
  3. package/docs/agent-notes/README.md +6 -0
  4. package/docs/agent-notes/adapters.md +13 -10
  5. package/docs/agent-notes/bus.md +1 -1
  6. package/docs/agent-notes/daemon.md +11 -4
  7. package/docs/agent-notes/local-worker.md +3 -1
  8. package/docs/agent-notes/tasks.md +6 -1
  9. package/docs/agent-notes/tests.md +8 -4
  10. package/docs/dogfood.md +13 -4
  11. package/docs/memory.md +1 -1
  12. package/docs/operations.md +98 -28
  13. package/docs/quickstart.md +13 -5
  14. package/docs/sdlc.md +12 -0
  15. package/docs/security.md +24 -15
  16. package/docs/smoke.md +3 -3
  17. package/docs/specs/2026-09-19-agent-hub-design.md +101 -8
  18. package/docs/verification/2026-10-25-remote-docker-transport.md +10 -0
  19. package/docs/verification/2026-10-26-agy-1.4.7.md +69 -0
  20. package/docs/verification/2026-10-26-claude-implementer-2.1.310.md +69 -0
  21. package/docs/verification/2026-10-26-headless-claude-shell-context.md +62 -0
  22. package/docs/verification/2026-10-26-jcode-0.99.1.md +49 -0
  23. package/docs/verification/2026-10-26-kimi-232-reviewer-compat.md +53 -0
  24. package/docs/verification/2026-10-26-pi-140-compat.md +41 -0
  25. package/docs/verification/2026-10-26-qwen-0261-acp.md +60 -0
  26. package/docs/verification/2026-10-27-0.19.0.md +86 -0
  27. package/docs/verification/2026-10-27-0.20.0.md +75 -0
  28. package/docs/verification/claude-permission-transport-native.py +187 -0
  29. package/docs/verification/claude-shell-wrapper-host.ts +20 -0
  30. package/docs/verification/claude-shell-wrapper-native.py +145 -0
  31. package/docs/verification/pi-140-model-free.ts +57 -0
  32. package/docs/verification/pi-140-native.mjs +21 -0
  33. package/docs/verified.json +25 -17
  34. package/package.json +2 -2
  35. package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
  36. package/plugins/agent-hub/server.js +373 -72
  37. package/src/adapters/acp.ts +8 -0
  38. package/src/adapters/agy/entry.ts +1 -1
  39. package/src/adapters/channel-peer.ts +7 -5
  40. package/src/adapters/claude-channel.ts +7 -3
  41. package/src/adapters/claude-implementer.ts +6 -3
  42. package/src/adapters/codex-appserver.ts +11 -1
  43. package/src/adapters/compat.ts +32 -18
  44. package/src/adapters/conformance/enrollment.ts +4 -4
  45. package/src/adapters/conformance/factories.ts +2 -1
  46. package/src/adapters/conformance/fakes/pi-rpc.ts +1 -0
  47. package/src/adapters/conformance/kit.ts +10 -0
  48. package/src/adapters/definitions/builtin-metadata.ts +2 -2
  49. package/src/adapters/definitions/native-factories.ts +7 -2
  50. package/src/adapters/definitions/reviewer-variants.ts +2 -2
  51. package/src/adapters/local-worker.ts +2 -0
  52. package/src/adapters/pi.ts +46 -3
  53. package/src/adapters/qwen-dual.ts +25 -0
  54. package/src/adapters/registry-types.ts +6 -2
  55. package/src/adapters/registry.ts +1 -0
  56. package/src/adapters/reviewer-print.ts +1 -0
  57. package/src/cli/agents.ts +69 -7
  58. package/src/cli/claude-shell-wrapper.ts +54 -0
  59. package/src/cli/main.ts +30 -24
  60. package/src/cli/output.ts +4 -0
  61. package/src/hub/agent-drift.ts +61 -0
  62. package/src/hub/board.ts +14 -2
  63. package/src/hub/check-runner.ts +148 -18
  64. package/src/hub/ci-watch.ts +140 -0
  65. package/src/hub/claude-launch-proof.ts +67 -2
  66. package/src/hub/claude-shell-wrapper.ts +349 -0
  67. package/src/hub/config-apply.ts +2 -2
  68. package/src/hub/config-edit.ts +2 -2
  69. package/src/hub/config-tier.ts +2 -2
  70. package/src/hub/config-trust.ts +1 -0
  71. package/src/hub/daemon.ts +282 -113
  72. package/src/hub/host-executable.ts +20 -1
  73. package/src/hub/instances.ts +18 -2
  74. package/src/hub/lifecycle.ts +1 -1
  75. package/src/hub/operational-authority.ts +7 -0
  76. package/src/hub/operational-view.ts +6 -10
  77. package/src/hub/peers.ts +34 -0
  78. package/src/hub/read-only-shell-proof.ts +7 -6
  79. package/src/hub/review-scope.ts +13 -0
  80. package/src/hub/sdlc-metrics.ts +6 -4
  81. package/src/hub/settings.ts +1 -0
  82. package/src/hub/task-shell-command.ts +85 -0
  83. package/src/hub/task-shell-default.ts +79 -0
  84. package/src/hub/task-shell-proof.ts +171 -0
  85. package/src/hub/task-shell-sandbox.ts +61 -0
  86. package/src/hub/tasks.ts +274 -16
  87. package/src/local/deny.ts +112 -11
  88. package/src/local/sandbox.ts +70 -29
  89. package/src/local/shell-environment.ts +10 -0
  90. package/src/ui/index.html +1 -0
@@ -0,0 +1,69 @@
1
+ # Antigravity 1.4.7 T0 re-run (#843 AC5)
2
+
3
+ Date: 2026-10-26. Refs #843. The account-free legs behind the 1.4.2 verification ([P1 T0 receipt](2026-10-19-agy-p1-t0.md)) were repeated on the installed `agy 1.4.7`, following the 1.4.3 re-run ([1.4.3 receipt](2026-10-21-agy-1.4.3-t0.md)). Every account-free leg passed, so 1.4.7 is added to agy `verified` in `src/adapters/compat.ts` in the same change. 1.4.3 stays an unverified, warned patch.
4
+
5
+ ## Environment and isolation
6
+
7
+ - Observed CLI version: `agy 1.4.7`, from `--version`, exit 0.
8
+ - Executable SHA-256: `b7a13e53c9f49921692676ef8edc2e60ceb67064c00bc732d9a364ec3ad75b32` (the person's `~/.local/bin/agy`, 192171376 bytes, modified 2026-10-24). It was hashed before the first run and after the last and did not change; agy self-updates, so this is the exact binary these results belong to.
9
+ - Bun 1.4.3 ran the probes, the plugin MCP server and the hook scripts. The 1.4.2 receipt used Bun 1.4.2; as in the 1.4.3 receipt this is a second variable that is not separated from the agy change. Host macOS 27.0.1 arm64.
10
+ - Every run used a new temporary HOME with its own `.gemini`, workspace and temporary directory, an explicit environment, the Seatbelt profile from `src/local/sandbox.ts` denying the person's home except the executable, and a loopback Gemini protocol fixture. No real account or cloud model call is part of this receipt. The scratch hub had memory, inference, snapshots and auto-start disabled and explicit agy roster admission.
11
+ - The per-user temporary directory (`getconf DARWIN_USER_TEMP_DIR`) was used as `TMPDIR`. A first actual-hub run with the agent's scratch directory (under the person's home, so inside the Seatbelt deny) loaded no plugin hooks and made no MCP call; it is the same setup mistake the 1.4.3 receipt records, it is not execution evidence and is not used below.
12
+ - SHA-256 of the person's Gemini CLI files (`antigravity-cli/settings.json`, `config/config.json`, `config/mcp_config.json` and the legacy `settings.json`) taken before the first run and after the last run are equal; `config/import_manifest.json` is absent on this machine. The probes' own before and after hash was equal on every completed run, no owned process was left running, the scratch hub stopped and every temporary root was removed.
13
+ - The probe scripts are copies of the 1.4.3 receipt's adapted scripts (`actual-hub-adapted.ts`, `native-hooks.ts`, `tui-actual.ts`), re-pointed at a clean worktree of main. The originals were not edited. The only changes are the output path, the Bun path, an `agySha256` field, a native-read tool name chosen from what the model-facing declarations list, and a normal-close step in the TUI copy (below). Raw bounded receipts and scripts remain in the local scratch workspace; they are not public artifacts.
14
+
15
+ ## CLI surface (fresh HOME, no session)
16
+
17
+ | Item | 1.4.7 observation | vs 1.4.3 |
18
+ | --- | --- | --- |
19
+ | `--version` | prints `1.4.7`, exit 0 | same (new number) |
20
+ | `--help` flags | `--add-dir`, `--agent`, `--continue`/`-c`, `--conversation`, `--dangerously-skip-permissions`, `--disable-slash-commands`, `--effort`, `--input-format`, `--json-schema`, `--log-file`, `--mode`, `--model`, `--new-project`, `--output-format`, `--print`/`-p`, `--print-timeout`, `--project`, `--prompt`, `--prompt-interactive`/`-i`, `--remote-control`, `--sandbox`; no `--new` | every flag the hub relies on or refuses is still defined; `--agent`, `--effort`, `--json-schema`, `--model`, `--project`, `--remote-control` and `--sandbox` are listed, none is passed or enabled by the launcher |
21
+ | `--acp` | exit 2, `flags provided but not defined: -acp`; no ACP subcommand | same. Refusal of the tested flag only |
22
+ | `--new` | exit 2, `flags provided but not defined: -new` | same |
23
+ | subcommands | `agent`, `agents`, `changelog`, `help`, `install`, `mcp`, `mic-serve`, `models`, `plugin`, `plugins`, `remote-control`, `update` | no ACP subcommand |
24
+ | `agy mcp list` | `No MCP servers configured.` while the workspace plugin is loaded | same |
25
+
26
+ ## Plugin MCP and hook contract (print mode, loopback fixture)
27
+
28
+ Actual scratch-hub run (`hub_inbox` through the shipped bundle and the workspace plugin), probe adapted exactly as for 1.4.3:
29
+
30
+ - Exit 0, empty stderr. `call_mcp_tool` was called once with `ServerName` `agent-hub_agent-hub`, `ToolName` `hub_inbox`; the random nonce held only in the scratch bus preface appeared in the following fixture-provider request (`nonceInModelRequest` true, 3 provider requests, 1 MCP call). Native output SHA-256 `751fc6590c1341b5fc1c195c051caa7556e51bf1c9e825257935a6cffaa6734b`.
31
+ - All six hooks ran from the plugin-local `.agents/plugins/agent-hub/hooks.json` with no project-level or global hook file: `SessionStart`, `PreInvocation`, `PreToolUse`, `PostToolUse`, `PostInvocation`, `Stop`.
32
+ - The `init` event still lists 60 tools and `permission_mode: request-review`.
33
+
34
+ Native hook contract run (two hub MCP calls and one native read, fixture MCP server):
35
+
36
+ | Item | 1.4.7 observation | vs 1.4.3 |
37
+ | --- | --- | --- |
38
+ | Plugin discovery | `.agents/plugins/agent-hub/` loaded without install or global write; MCP log `server/discover`, `initialize`, `notifications/initialized`, `tools/list`, `tools/call`, `tools/call` | same |
39
+ | Hook stdin shared fields | `SessionStart`: `artifactDirectoryPath`, `conversationId`, `lastUserInput`, `modelName`, `transcriptPath`, `workspacePaths`; `PreInvocation` and `PostInvocation` add `initialNumSteps` and `invocationNum` | same |
40
+ | Tool hook stdin | `toolCall: { name, args }`; `PostToolUse` has an empty `error` on success | same shape |
41
+ | Native read | `read_file` with `Path`, `StartLine`, `EndLine` | same as 1.4.3 (1.4.2: `view_file` with `AbsolutePath`). The hub's decoder already classifies both |
42
+ | `call_mcp_tool` arguments | `ServerName`, `ToolName`, `Arguments`, no `toolSummary` or `toolAction` | same as 1.4.3 |
43
+ | Model-facing declarations | 15 tools: `ask_question`, `call_mcp_tool`, `define_subagent`, `edit_file`, `invoke_subagent`, `list_resources`, `manage_subagents`, `manage_task`, `read_file`, `read_resource`, `run_command`, `schedule`, `search_web`, `send_message`, `write_file` | same set as 1.4.3 |
44
+ | `Stop` | `executionNum` 0, `terminationReason` `NO_TOOL_CALL`, `error` empty, `fullyIdle` true | same |
45
+ | `injectSteps` | `SessionStart` and `PreInvocation` `ephemeralMessage` accepted | same |
46
+ | Tool hook matcher | tool hooks ran with `matcher: ".*"` and a nested `hooks` array | same |
47
+
48
+ ## Interactive TUI and its normal close
49
+
50
+ The same PTY probe as the 1.4.3 receipt ran the interactive TUI under the Seatbelt profile and fixture. Fresh-HOME onboarding was answered with the same key presses (Enter, Down, Right, Enter, Enter).
51
+
52
+ - **Two prompts**: the plugin MCP server attached lazily on the first prompt, exactly as on 1.4.3. Provider requests carried 0, 12, 15 and 15 tools; `call_mcp_tool` was absent from the first agent request (12 tools) and present from the second (15). `hub_inbox` was called once, the nonce reached the fixture provider, and `PreToolUse` and `PostToolUse` fired for the MCP call. A single-prompt run (0 and 12 tools, no MCP call) shows the same first-turn gap. The hub's launch notice ("hub tools appear from the second turn") remains accurate.
53
+ - **Normal close**: after the last answer the probe typed `/exit` and Enter. The agy process exited on its own with code 0, with no signal sent (`signalFallbackNeeded` false), and printed its resume line. The scratch hub then stopped and the temporary root was removed; no probe process remained.
54
+ - The close here is agy's own exit and the probe's cleanup. It is not the hub launcher's `ahub agy` cleanup of the three managed plugin files and its socket detach; that launcher leg needs the person's daemon and account and stays below.
55
+
56
+ ## Hub-side check
57
+
58
+ `agyVersionGate` and the decoder were not changed. `decodeAgyHook` already classifies `read_file(Path, StartLine, EndLine)` as a read (covered by `test/agy-hooks.test.ts`), and the version gate reads `COMPAT.agy`. A new test pins `verified` and the verdicts: 1.4.7 verified, 1.4.3 and 1.4.8 inside the 1.4 line but unverified, 1.5.0 refused.
59
+
60
+ ## Not verified
61
+
62
+ - A real account, a real model turn and agy's own permission prompts. The fixture provider replays fixed tool calls, so this receipt proves the transport, plugin, hook and decoder contract, not how a real model uses the hub tools.
63
+ - The person's `ahub agy` launch against a running compatible daemon: managed three-file plugin write, pull-only attach, `hub_inbox` and `hub_send` through the real TUI, and the launcher's own close cleanup. That is the live leg in `docs/smoke.md` "Antigravity P1", pending until the person runs it.
64
+ - Permission prompt mappings, whether pre-tool `allow` overrides a native approval, `Stop` continuation and post-invocation termination overrides. The peer stays unmanaged.
65
+ - The IDE form and the Linux build.
66
+
67
+ ## Decision
68
+
69
+ All account-free legs passed on `agy 1.4.7` (SHA-256 above), so `1.4.7` joins `verified` for agy. The accepted line (1.4.0 up to, not including, 1.5.0) is unchanged. Another 1.4.x patch still launches with the unverified warning, and the person may trust an exact version with `ahub agents trust`.
@@ -0,0 +1,69 @@
1
+ # Claude Code 2.1.310 headless implementer permission-transport receipt
2
+
3
+ Date: 2026-10-26. Scope: #843 AC5, task #507. This repeats the model-free procedure of [the 2.1.309 receipt](2026-10-23-headless-claude-permissions.md) on the installed Claude Code 2.1.310, with 2.1.309 run through the same producer as a control.
4
+
5
+ | Native version | Binary SHA-256 |
6
+ | --- | --- |
7
+ | Claude Code 2.1.309 (control) | `5eadc0009cdcdbc0d06e58110d7b2baf88ced6088b1c33a60a21217fe410619c` |
8
+ | Claude Code 2.1.310 | `ffb64331bc0ee1b69efb7c2c428bd3ab516bc31b75bf60886b356c97c1c25ffd` |
9
+
10
+ The 2.1.309 hash is the one the 2026-10-23 receipt records, so the control is the same binary that receipt certified.
11
+
12
+ ## Upstream changes since 2.1.309
13
+
14
+ Read from the upstream [CHANGELOG](https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md): 2.1.310 lists 26 items, and most are VSCode, cloud-session, Claude Tag and Code Review admin fixes that this hub's `claude -p` child never runs. The ones that touch permissions, MCP or hooks:
15
+
16
+ - **Monitor tool now available when telemetry or nonessential traffic is disabled** (matters). In this run the native init tool inventory grew from 28 tools on 2.1.309 to 29 on 2.1.310, the one difference being `Monitor`. The producer sets `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1`; the hub's own child does not set it, and a repeat of the Monitor probe below without that variable on 2.1.310 reached `Monitor` and the host prompt the same way, so availability here does not depend on it. It is a deferred tool: it is not in the request's tool list and has to be loaded through `ToolSearch` first, which a model can do. A probe that did this on 2.1.310 reached the host permission prompt for `Monitor` with the same `tool_name`, `input` and `tool_use_id` shape as `Bash`, and a deny reply stopped it (no process started, tool result an error, one permission denial). 2.1.309 answered the same attempt with "No such tool available: Monitor". So a new native tool now reaches `hub_permission_request`, which then sees `tool_name: "Monitor"`. See "Monitor" below.
17
+ - **Windows PreToolUse and PermissionRequest hooks no longer let a call through when Git Bash is missing** (does not matter on macOS and Linux; the receipt's hook-failure legs are the equivalent check here and pass).
18
+ - **MCP tool call that times out in a non-interactive session while the server's elicitation is unanswered now tells the model no answer came** (touches MCP error text only). The transport legs below, MCP error, disconnect and pending, are unchanged in outcome.
19
+ - **File read permission prompts show where a symbolic link leads** (a prompt rendering change; the hub's prompt tool receives the same arguments).
20
+ - **Auto mode prompt text**: the hub never uses auto mode (`--permission-mode default`).
21
+ - **Compaction, memory, tmux and Linux sandbox warnings, gateway retry of the `effort` beta and mid-conversation system messages**: no permission, MCP or hook contract.
22
+
23
+ Nothing in 2.1.310 changes `--permission-prompts host`, `--permission-prompt-tool`, `--setting-sources`, `--strict-mcp-config` or hook semantics, and none of the 26 items says so. This reading is of the changelog text, not of the binary's source, which is not public.
24
+
25
+ ## Method
26
+
27
+ The producer [claude-permission-transport-native.py](claude-permission-transport-native.py) ran both installed native binaries with an isolated HOME and `CLAUDE_CONFIG_DIR`, a disposable work directory, a fixture stdio MCP server, an empty settings-source selection and fixture settings. A loopback HTTP server supplied a synthetic model-protocol response requesting one `Write` and, after the tool result, a completion. The launch used the hub's own flags: `-p --output-format stream-json --verbose --strict-mcp-config --mcp-config … --setting-sources '' --settings … --permission-mode default --permission-prompts host --permission-prompt-tool mcp__fixture__approve`. No `--bare`, `acceptEdits`, `dontAsk` or `bypassPermissions` was used. The API key in the child's environment was the literal string `synthetic-probe-not-a-credential`, pointing at the loopback server. No account, provider, login or model inference was involved, and each native child ran in its own process group, which was stopped and confirmed empty after every case. Each binary's SHA-256 was identical before and after.
28
+
29
+ The 2.1.309 driver the earlier receipt hashed (`173c108f…`) was a temporary local diagnostic that was not kept, and no copy was found. This producer is therefore new, written against that receipt's case table and reusing the loopback provider and process-group handling of the wrapper producer added by PR #857. Because it is new, it was first run on 2.1.309, where it had to reproduce the 2026-10-23 table before its 2.1.310 result meant anything. It did, on all nine cases. An early run of it failed `allow` and `hook-allow` on both binaries identically because the producer asserted `is_error` was `false`; native stream-json omits the key on success. The assertion was corrected to check `is_error is True` only for failures, and the producer was rerun in full.
30
+
31
+ ## Results
32
+
33
+ All nine cases passed on both binaries (18 of 18), with identical outcomes:
34
+
35
+ | Fixture case | 2.1.309 (control) | 2.1.310 |
36
+ | --- | --- | --- |
37
+ | Prompt tool allows the Write | 1 MCP permission call; file written | same |
38
+ | Prompt tool denies | no write; 1 permission denial | same |
39
+ | Prompt tool missing from MCP inventory | no write; 0 MCP calls; native exit 1 | same |
40
+ | PreToolUse command exits 1, prompt tool denies | hook decides nothing; 1 MCP call; no write | same |
41
+ | PreToolUse command exits 1, prompt tool allows | hook decides nothing; 1 MCP call; file written | same |
42
+ | MCP permission request returns a JSON-RPC error | no write; tool-result error | same |
43
+ | MCP server disconnects during permission request | no write; tool-result error | same |
44
+ | MCP permission reply remains pending | no write before the external 25 s owned-group stop; native internal timeout not established | same |
45
+ | Simulated approval deadline returns deny after 100 ms | 1 MCP call; no write; native exit 0; 1 permission denial | same |
46
+
47
+ Each call's permission arguments were exactly `tool_name: "Write"`, the original `input` object and `tool_use_id`. Native exit codes, MCP call counts and write/no-write outcomes matched the 2026-10-23 table on 2.1.309, and the 2.1.310 column matched the 2.1.309 column row for row.
48
+
49
+ ### Monitor
50
+
51
+ The 2.1.310 inventory difference is the only behavioural difference this run found, and it is a new tool name, not a changed contract. A separate one-off probe (not part of the producer, retained with the evidence) loaded `Monitor` through `ToolSearch` and called it with a write command, then with `echo`, on 2.1.310. The write command reached the host permission prompt once and a deny reply prevented it. The read-only `echo` made no permission call on either `Monitor` or `Bash`, which matches native auto-allow of read-only commands rather than a bypass. This probe covers only that one deny and one read-only path. It does not prove that every `Monitor` form (long-running sources, persistent watches) asks, that approval of one `Monitor` call authorises no later one, or how the hub's `hub_permission_request` renders and decides a `tool_name` other than `Bash`. The host-side rendering is generic (`permissionPayload` accepts any tool name), so nothing in the hub depends on the name being `Bash`, but this receipt does not claim a hub-side `Monitor` fixture. That is a follow-up if `Monitor` is to be allowed in a task child, and the hub's `--allowedTools` list names only the hub's own MCP tools.
52
+
53
+ ## Ceilings
54
+
55
+ The result certifies the permission transport on this binary and version, as the 2.1.309 receipt did for 2.1.309. It does not certify real provider authentication, a real model's tool selection, a person's approval interaction, every native tool type (`Monitor` is covered only as stated above), native internal permission timeout, or filesystem sandbox isolation. The pending case was bounded externally. The host shell wrapper procedure of #845 is a separate receipt added by PR #857, which ran on 2.1.309 and 2.1.310 and states that a version upgrade repeats both; this receipt is the transport half. The exact-head package gate, daemon integration and CI are recorded in the PR, and this document claims none of them. Native version admission and the per-start binary fence remain runtime checks; this dated receipt is evidence for the supported contract, not a per-start receipt gate.
56
+
57
+ The MCP wire still does not authenticate that a schema-valid permission call came from native dispatch, as the 2.1.309 receipt says; a person's fresh allow-once for the original arguments remains required for either path.
58
+
59
+ ## Evidence
60
+
61
+ Kept outside the repository in `scratchpad/temp/agent-hub-507-run4` (the final full run of the committed producer), with the earlier runs beside it: `agent-hub-507-run1` (the failed first producer), `run2` and `run3` (identical results from the producer before a review fix gave each binary its own indexed output directory, so two binaries with the same file name no longer collide):
62
+
63
+ | Item | SHA-256 |
64
+ | --- | --- |
65
+ | `claude-permission-transport-native.py` (the committed producer) | `b3f39acce1eb3713a5f01191702f1f217d704039d3a86452c6dfd311cb274efe` |
66
+ | `receipt.json` of the final run (18 cases, `certified: true`, `account: false`, `inference: false`) | `edefd6d7e18dd28a22ad63489c51db0e9636586dadedc686738b0ff89b5113e9` |
67
+ | Monitor one-off probe | `1ebd2ff6b4b8a587b212cde221d035d0a0d37e24d6acdef37dce55d7a71111d8` |
68
+
69
+ The run retains each case's native stdout and stderr, the MCP permission records, and the request tool schemas. The host used Python 3 and the installed binaries; no Bun is involved in this producer.
@@ -0,0 +1,62 @@
1
+ # Headless Claude host shell wrapper receipt
2
+
3
+ Date: 2026-10-26. Scope: #845 AC6-AC8. A fresh model-free native run passed on both binaries below.
4
+
5
+ | Native version | Binary SHA-256 |
6
+ | --- | --- |
7
+ | Claude Code 2.1.309 | `5eadc0009cdcdbc0d06e58110d7b2baf88ced6088b1c33a60a21217fe410619c` |
8
+ | Claude Code 2.1.310 | `ffb64331bc0ee1b69efb7c2c428bd3ab516bc31b75bf60886b356c97c1c25ffd` |
9
+
10
+ ## Method
11
+
12
+ The installed native binaries ran sequentially with isolated HOME and CLAUDE_CONFIG_DIR directories, empty settings sources, explicit fixture settings asking for Bash, a strict fixture MCP inventory and a deterministic loopback provider. The provider supplied Bash calls and a final completion response. No personal authentication files, real provider request, account or model inference was used. Each native case had an external 25-second deadline. Native leaders were reaped, remaining live group members were checked, and the host fixture shut down the production wrapper through its owned cleanup path. Binary hashes were unchanged after every case.
13
+
14
+ The producers are [claude-shell-wrapper-native.py](claude-shell-wrapper-native.py) and [claude-shell-wrapper-host.ts](claude-shell-wrapper-host.ts). The host fixture imports the actual `HostShellWrapper` and fixed CLI entry from production source. It supplies synthetic task, generation and branch bindings and a current-root predicate; it does not simulate a real task-board assignment or certify the daemon's authorization policy. Real daemon fixtures separately cover task/child/root/branch, mode, privacy and action-policy admission.
15
+
16
+ For each version, the control ran `cd sub && pwd` followed by `pwd`, returning the original input in both permission replies. Both outputs named `sub`, demonstrating persistent native shell cwd. The wrapper case first performed the same `cd`, then requested `pwd` twice. Both later permission replies returned fresh `updatedInput` objects containing the same issued fixed-wrapper command and single-use ticket. The selected host executable, outside the worktree, printed its identity, cwd and environment fields and incremented an effect counter. Root and executable paths included spaces and apostrophes.
17
+
18
+ Native HOME, PATH and cwd differed from the host execution context. Native `GIT_DIR` and `RIPGREP_CONFIG_PATH` were injected with poison paths. The actual target received the host's fixed PATH/HOME/LANG/TERM and peer identity, with its owned command TMPDIR. Helper startup uses fixed private HOME/cwd, config and dotenv suppression. The host supervisor receives exact target argv/env over private fd4 rather than shell interpolation or argv serialization, and preserves the target environment without adding shell variables.
19
+
20
+ ## Native observations
21
+
22
+ | Leg | 2.1.309 | 2.1.310 |
23
+ | --- | --- | --- |
24
+ | Persistent-shell control reports `sub` twice | pass | pass |
25
+ | Fresh rewritten input executes the fixed root after the earlier `cd` | pass | pass |
26
+ | Target identity equals the absolute host-selected executable | pass | pass |
27
+ | Injected native GIT_DIR and RIPGREP_CONFIG_PATH are absent | pass | pass |
28
+ | Target HOME/PATH/TERM and peer identity equal the host fixture values | pass | pass |
29
+ | Owned TMPDIR replaces native state | pass | pass |
30
+ | Same ticket's second execution returns the fixed refusal and native tool error | pass | pass |
31
+ | Effect counter remains exactly 1 after replay | pass | pass |
32
+ | Spaces and apostrophes in root/executable paths | pass | pass |
33
+ | Native exit 0, host stopped, no remaining live native group members | pass | pass |
34
+ | Binary unchanged across the case | pass | pass |
35
+
36
+ All four cases passed. Each control made three loopback requests and two MCP permission calls; each wrapper case made four requests and three permission calls. The verifier requires exact original native permission arguments and exact rewritten replies. Successful output comes from native stream-json `tool_use_result.stdout`, with the corresponding tool-result block equal to that stdout, empty stderr and no interruption. Replay must be a native error containing the fixed refusal, and the counter must still be 1. Provider-facing text with native system reminders is not treated as raw command output.
37
+
38
+ ## Reproduction and retained evidence
39
+
40
+ Run from the repository with explicit installed binary paths and a new private output directory:
41
+
42
+ ```sh
43
+ python3 docs/verification/claude-shell-wrapper-native.py NEW_OUTPUT --bun ABSOLUTE_BUN --claude INSTALLED_2.1.309 --claude INSTALLED_2.1.310
44
+ ```
45
+
46
+ The successful local diagnostic directory is `claude513-wrapper-native-20261026-r1`. It retains native stdout/stderr, exact MCP request/reply records, loopback request bodies, the host fixture diagnostics and `receipt.json`. No actual account credentials are in those fixtures. The framework used host Bun 1.4.3; separate Linux fixtures exercised the same wrapper on pinned Bun 1.4.2. Package and CI evidence remain separate.
47
+
48
+ | Artifact | SHA-256 |
49
+ | --- | --- |
50
+ | Native producer | `ecf818acd4b4d42db87416a83dc3f5d2dfbfff3a07c70915fabd25abd8ed2649` |
51
+ | Host fixture | `616e6711e392f0eee7e3fa1c7bdc47a537dfa86bcc8ffb30e549ca94e5a71cef` |
52
+ | Production wrapper service | `a573956e9c408546aa618afe6b776932fb0d5dd462c089e02993e2629adaf675` |
53
+ | Fixed CLI wrapper | `8ff56514a6e3f25bce0784775d396df199b58b1b93f55ad0e8747bbc729d2fd8` |
54
+ | Four-case receipt JSON | `3db74019a71be0b556d88e21b8273da93e1fdbeace200190e1a5c801a23b6ea8` |
55
+
56
+ The earlier direct-rewrite diagnostic and its initial provider-text parsing failure are preserved in this document's Git history and retained raw artifacts. This receipt uses a fresh run of the strict structured-output verifier, not a restamp of that earlier failed producer result.
57
+
58
+ ## Host fixtures and ceilings
59
+
60
+ Mac fixtures separately passed the existing #816 Seatbelt recursive-deny boundary, profile/read-only-data mutation refusal and actual environment parity against `sandboxedExec`. The sandbox source remains byte-identical to its accepted baseline. Current host policy requires the local-worker Seatbelt profile plus all-Git-metadata denial for read-only and check/test/build grants; unsupported hosts ask. Closed hardened host Git add/commit/push and gh remain outside it. This native transport fixture does not exercise those privileged Git mutators; their helper/config and authorization regressions are separate. Additional daemon fixtures cover a model-written test that cannot read the live control token or SSH key even when the canonical checkout is readable. These authorization fixtures are separate from this generic native wrapper fixture. Portable fixtures cover binary fd output, numeric status, expiry/replay/quotas, helper config/env isolation, current proof/root/argv/env mutation, cancellation, deadline, disconnection and descendant pipe cleanup. Task and daemon fixtures cover persistent branch binding, action-policy asks, unchanged ask behavior and old-client protocol refusal.
61
+
62
+ The [earlier permission transport receipt](2026-10-23-headless-claude-permissions.md) remains evidence for its original allow/deny/error/hook cases. A native version upgrade repeats both this wrapper procedure and the original permission-transport procedure before extending the verified set. This wrapper receipt adds no version to COMPAT and does not prove real provider authentication, model tool selection, task-session resume, a person's approval interaction or isolation of the entire native Claude process. The executable task-code profile is host policy verified separately by Darwin fixtures. It is not a runtime receipt gate. Native version admission and binary fencing remain required. Exact-head package gate and CI results are recorded separately in the PR handoff.
@@ -0,0 +1,49 @@
1
+ # Jcode 0.99.1 receipt (#843 AC5)
2
+
3
+ Date: 2026-10-26. Refs #843. Installed release build, read through `--quiet version --json`: `semver` 0.99.1, `version` `v0.99.1 (7206efd0c)`, from [1jehuang/jcode](https://github.com/1jehuang/jcode) tag v0.99.1 (published 2026-10-22). Host macOS arm64, Bun 1.4.3.
4
+
5
+ This repeats the ACP, serve and MCP contract legs of [the 0.98.1 receipt](2026-10-19-jcode-0.98.1.md) and the 0.99.0 steering check. Every leg passed, so 0.99.1 is added to jcode `verified` in `src/adapters/compat.ts` in the same change.
6
+
7
+ ## Isolation
8
+
9
+ - Every process ran under an isolated `HOME` and `JCODE_HOME` (fresh directories under `/tmp/ahub-jc0991`, an empty `mcp.json`, no credentials, no account), with `JCODE_NO_TELEMETRY=1` and `JCODE_DISABLE_CLAUDE_MCP=1` as the adapter sets them. The real `~/.jcode` was never the home.
10
+ - SHA-256 of the four real config files that sit directly in `~/.jcode` (`auth.json`, `auth-refresh-state.json`, `config.toml` and `mcp.json`) was taken before the first leg and compared after the last: unchanged.
11
+ - The probes built every argv with the adapter's own `jcodeCommand` and spawned `serve` with `JCODE_SOCKET` and `JCODE_READY_FD=3` the way `JcodePeer` does. After each run `pgrep` found no process whose command line named the sandbox, and no telemetry file was written into the isolated home.
12
+
13
+ ## Contract legs (idle server, no model)
14
+
15
+ - **serve** with the adapter's socket name `j.sock`: ready on the private socket in 102 to 104 ms across two runs. It leaves `j-debug.sock`, `j.sock.hash`, `j.sock.server.json` and `j.sock.daemon.lock` beside it, and the server info file carries `argv`, `debug_socket_path`, `idle_timeout_secs`, `owner_pid`, `pid`, `ppid`, `schema_version`, `scope`, `socket_path` and `started_at`. The process group is gone after SIGTERM.
16
+ - **ACP** (`acp --mcp-tools eager` against the same private server):
17
+ - `initialize`: `protocolVersion` 1, `agentInfo` `{ name: "jcode", title: "Jcode", version: "0.99.1" }`, `loadSession: true`, `authMethods: []`.
18
+ - `session/new` returns `configOptions`, `models` and `sessionId`.
19
+ - `session/load` returns `configOptions` and `models` only, with no `sessionId`. The restored identity stays unproven, so `requireLoadSessionEcho` and the withheld automatic recovery are unchanged.
20
+ - `session/set_mode` and `session/request_permission` are still `Unsupported ACP method`, as on 0.98.1.
21
+ - **MCP**: a project `.jcode/mcp.json` entry that names no peer was started by the eager ACP child, and its environment held exactly `AGENTHUB_PEER_ID` and `AGENTHUB_LAUNCH_ID` from the owned process environment (values set on the `acp` child by the probe), nothing from the entry itself.
22
+ - **Telemetry**: with the adapter's `JCODE_NO_TELEMETRY=1` no telemetry file appeared in the isolated home.
23
+
24
+ ## Steering leg (the 0.99.0 check, now on a running turn)
25
+
26
+ The 0.99.0 check was established on an idle session. This receipt also exercises it on a running turn, still with no account: the isolated home holds one `openai-compatible` profile `fakegw` (added with `jcode provider add ... --no-api-key`, written only into the isolated `config.toml`) pointing at a local server on `127.0.0.1:18999` that streams a slow, fixed reply and records each request it receives. No real provider, key or model was involved.
27
+
28
+ - `serve` and `acp` were started with the adapter's argv carrying `--model fake-model --provider-profile fakegw`, a session was created and `session/prompt` started a turn.
29
+ - While that turn streamed, a second client on the private socket ran the same steps as `nativeSteer`: `ping` listed `soft_interrupt_ids` in `capabilities`, `subscribe` with `target_session_id` joined the same session (no new session), `state` reported `is_processing: true`, `soft_interrupt` with `urgent: false` was acknowledged.
30
+ - The prompt then ended with `end_turn`, not `cancelled`. The local server saw two requests. The first held only the original prompt. The second held the original prompt, the assistant text streamed so far and the steer text as a new user message, so the steer was injected at the end of the running response and the turn was not cancelled, as the adapter's comment on `nativeSteer` states.
31
+ - The idle variant (the same ping, subscribe and state steps against an idle session, run in the contract legs above) reports `is_processing: false`, which `nativeSteer` refuses with "the session has no running turn" without sending anything. That refusal is read from the adapter's source; the probe sent no steer to an idle session.
32
+
33
+ ## Source comparison v0.99.0..v0.99.1
34
+
35
+ 232 commits, 300 files, read only through the GitHub compare API (nothing built).
36
+
37
+ - Protocol (`crates/jcode-protocol`): additions only. `SwarmMemberRuntime` gains four optional fields, `Request::PersistSession` is new, and a swarm send can be refused for a non-coordinator. No existing request, field or `soft_interrupt_ids` capability was removed or renamed.
38
+ - MCP (`tool/mcp.rs`): the model-facing `mcp_search` and `mcp_call` tools become internal aliases of `mcp action=search` and `mcp action=call`. The hub's configuration and its injected tools never name those tools, so nothing here changes the owned MCP set.
39
+ - No change under the ACP, socket-name or `JCODE_READY_FD` paths was found among the files read; the fixes listed in the release notes (OpenAI schema, TUI recovery from a vanished server, configured model for fresh sessions, stale daemon token recovery) are native behavior behind the same contract.
40
+
41
+ ## Not verified
42
+
43
+ - A real account, provider or model, and a model turn that calls a hub tool through the project MCP entry, as in every earlier jcode receipt. The steering leg proves delivery to the provider request, not how a real model reacts to it.
44
+ - The TUI form (`jcode --resume`), covered separately for 0.98.1 in [the TUI receipt](2026-10-20-jcode-tui-0.98.1.md), was not repeated.
45
+ - A second instance running beside the base peer, and Linux or Intel macOS builds.
46
+
47
+ ## Decision
48
+
49
+ All legs passed, so `0.99.1` joins `verified` for jcode. The accepted range (0.98.0 up to, not including, 1.0.0) is unchanged. A failed leg on a later release would have meant no bump, as the task requires.
@@ -0,0 +1,53 @@
1
+ # Kimi 2.3.2 fresh-reviewer compatibility receipt
2
+
3
+ ## Scope and identity
4
+
5
+ This #843 (AC5, task #508) receipt repeats the model-free 2.3.1 procedure (`2026-10-25-kimi-231-reviewer-compat.md`) on the installed Kimi 2.3.2. No real account, provider inference, personal configuration, native login, credential refresh or personal machine trust was used or changed. As for 2.3.1 the result is a version verification only: no `kimi-review` instance is declared, and Kimi stays a pull-only TUI peer. The reviewer remains off until a project declares one.
6
+
7
+ | Artifact | Binding |
8
+ | --- | --- |
9
+ | Kimi native macOS arm64 executable | version `2.3.2`; SHA-256 `d84a94c7d73405283a279348d2de78abbf31d2b1f7c92a8d739eeb40cf2a2f9f` |
10
+ | Kimi source | tag `@moonshot-ai/kimi-code@2.3.2`, commit [`b8dd3a134060c6e80ba4a1659335cd63b68483f2`](https://github.com/MoonshotAI/kimi-code/tree/b8dd3a134060c6e80ba4a1659335cd63b68483f2) |
11
+
12
+ ## What changed since 2.3.1
13
+
14
+ Five commits (`684bae9e..b8dd3a13`, 22 files, 2.3.1 to 2.3.2): a test change that isolates cloud config in the TUI message-flow tests (e79422aa), "leave swarm mode to the user" (c9a48369), "launch subagents only on explicit request" (fd2e2c7e), a changeset wording fix (00e7007a) and the release (b8dd3a13). Read for reviewer-isolation impact:
15
+
16
+ - **Tools, MCP, config, trust and session code:** none of the 22 changed files touches tool registration, the MCP client or its config, `trustEnv.ts`, `workspaceMcpConfigService.ts`, session locks, the agent-file loader, the provider or OAuth code, or `--skills-dir`. The files are prompt text (`agent.md`, `system.md`, `enter-plan-mode.md`, `exit-reminder.md`, `agent-swarm.md`), the swarm service, the swarm tool, one profile description string, a transcript fold, docs and tests.
17
+ - **Swarm and subagents:** `AgentSwarmService.enter('tool')` now throws `Only the user can turn on swarm mode.`, `AgentSwarmTool` returns a fixed error result while swarm mode is off, and the system prompt tells the model not to launch subagents unless asked. This narrows what a model can start and does not widen any tool. The reviewer agent file already declares `subagents: []` and exactly two tools; the receipt's `prepare` leg asserts both on 2.3.2.
18
+ - **Profiles:** `profiles.ts` changes only the `whenToUse` string of the `explore` profile. The reviewer does not use that profile.
19
+
20
+ The probe sets `KIMI_CODE_TRUST_WORKSPACE` in the host environment as a decoy and asserts it is absent from the launch environment, as for 2.3.1.
21
+
22
+ ## Results
23
+
24
+ The 2.3.1 producer was copied with only the version, source commit, output paths and the decoy comment changed (`diff` of the two producers shows exactly those lines). It ran against an isolated HOME and a synthetic native `KIMI_CODE_HOME` (managed `kimi` provider, invented access-only OAuth record, device identity). The native print leg redirected only the managed provider endpoint and its scoped synthetic OAuth slot to a loopback fixed-response server, which performs no inference (`modelInferenceCalls: 0`).
25
+
26
+ | Leg | Fixture trust run | Verified run (no trust) |
27
+ | --- | --- | --- |
28
+ | `kimiReviewerBackend.prepare` (private config, exact two-tool agent, empty skills, replace env, `current()`, version `2.3.2`) | pass | pass (`fixtureTrustOnly: false`, with `assessVersion("kimi-review", "2.3.2", [])` asserted `verified`) |
29
+ | Task-bound MCP: exactly `hub_review` and `hub_task_show`; other task id, third tool and missing auth refused; revocation refuses reads | pass | pass |
30
+ | Native exact-two-tools: 4 requests, every inventory exactly the two hub names, both calls reached the host, injected `Write` refused, marker `unchanged` | pass | pass |
31
+ | Native positive control: `Write` added to the agent; inventory includes it, marker written (2 requests) | pass | pass |
32
+ | Trust-env decoy absent from the launch environment | pass | pass |
33
+ | Cleanup of owned groups and temporary trees | pass | pass |
34
+
35
+ The verified run was made with `2.3.2` already in the local `verified` list and no trust record. Before and after both runs, the SHA-256 of the real `~/.kimi-code` `config.toml`, `mcp.json` and `device_id` and a digest over every file in `credentials/` and `oauth/` were identical.
36
+
37
+ One environment note, not a Kimi finding: the producer first refused with `private cwd ancestor contains ambient configuration` because this machine's agent shell exported `TMPDIR` under `~/.jcode/scratch`, whose ancestor `~` holds a real `.kimi-code`. That is the reviewer backend's own isolation check working. Both recorded runs used the macOS default temporary root (`/var/folders/.../T/`), which has no ambient marker among its ancestors.
38
+
39
+ The producer ran with Bun 1.4.3 (the installed one). The hub code it exercises is plain TypeScript with no bundle step.
40
+
41
+ ## Not verified
42
+
43
+ A real-account review, attached-TUI coexistence during a review, OAuth refresh under a real token, review quality, token usage and quota behaviour remain unverified, as for 2.3.1. No future version or compatible line is inferred.
44
+
45
+ ## Evidence
46
+
47
+ Kept outside the repository in `scratchpad/temp/agent-hub-508`:
48
+
49
+ | Item | SHA-256 |
50
+ | --- | --- |
51
+ | `kimi-probe.ts` | `fa09ab4bfeb42becc0c87d1a959e7756082267906ba4aec4f50772ebda57d242` |
52
+ | `kimi-native-result.json` (fixture trust) | `098bb78f287de48c2772c89f3d0f7db3e93031d97614ecbe1b61bca17be5ba9e` |
53
+ | `kimi-verified-result.json` (no trust) | `4338c63103523585703c2b8b958a8ff92a0199fde668e169355abe8a5e06ce35` |
@@ -0,0 +1,41 @@
1
+ # Pi 1.4.0 model-free compatibility receipt
2
+
3
+ ## Identity and scope
4
+
5
+ - Issue #843 AC2, task #505. Initial source baseline: `991df88ffbe89497278082ad2e3b485d83b3b8b4` plus this PR; the native producer passed again after rebasing onto `9279711666d3ba2f01e83bfca65c6e7e12afdb94` with the exact agent-mem 0.9.1 pin.
6
+ - Native launcher: `~/.pi/agent/bin/pi`, managed package `@earendil-works/pi-coding-agent` version `1.4.0`.
7
+ - Native `dist/cli.js` SHA-256: `8189b66abc4f9f431dbb70941dcba690d76d040de1fbfff212886be35a53639d`.
8
+ - Measured on macOS arm64 with Bun 1.4.3 and Node 26.12.0 on 2026-10-26.
9
+ - Each native run uses an empty temporary HOME and `PI_CODING_AGENT_DIR`, a temporary cwd/session directory, and an environment containing only PATH, those isolated paths and invented loopback bridge settings. No account, real token, prompt, inference or personal trust entry is used.
10
+
11
+ ## Results
12
+
13
+ | Leg | Result | Evidence |
14
+ | --- | --- | --- |
15
+ | Native identity | pass | Isolated launcher `--version` returned exactly `1.4.0`, exit 0, empty stderr; package name/version checked independently. |
16
+ | Real CLI extension load and RPC session identity | pass | Native launcher in `--mode rpc`, `--no-builtin-tools`, `--no-skills`, `--no-prompt-templates`, `--no-extensions --extension <hub extension>`; `get_state` returned success, nonempty session id/file, messageCount 0, no pending messages; real extension emitted session_start/session_shutdown. |
17
+ | Installed SDK extension registration | pass | Pi 1.4.0's real `DefaultResourceLoader` and `createAgentSession` loaded this checkout's extension, bound its session context and registered exactly `compat_probe` as an active tool. No builtin tools were enabled. |
18
+ | Managed tool callback and receipt replay | pass | The native SDK's registered tool callback was invoked directly, without an agent prompt. It posted session/call ids to the isolated bridge using the real `PiToolReceipts`; two identical calls returned identical success with exactly one effect. |
19
+ | Failed tool result | pass | A distinct bridge fixture denial returned `failed: true`; the real extension returned `isError: true`. The fixture denial tests result propagation, not the host's authorization policy. |
20
+ | Host permission modes | pass (host fixtures) | `test/permission-modes.test.ts`, "Pi mode grants edits once, keeps shell on the console, and ask restores the console path": 1 pass, 12 assertions. ask-when-needed grants managed edits and asks for an unproven shell; never-ask changes approval frequency; ask restores the prompt. `test/pi-compat.test.ts` separately confirms read-only is refused by the production factory before a native probe. These modes remain host-owned; the launch adds no native permission-mode flag. |
21
+ | Version admission and launch paths | pass (host fixtures) | Exact verified/refused/trusted verdicts; headless, TUI, daemon peer_start and auto-start all reach `createPi` and refuse a fabricated 9.9.9 with `ahub agents trust pi 9.9.9`. A source guard confines production PiPeer construction to this registry factory. |
22
+ | Provider requests | pass | Zero requests reached the loopback provider endpoint; no prompt was submitted. Native and SDK stderr were empty. |
23
+
24
+ The SDK callback leg does not claim model-generated tool dispatch. Host mode fixtures use a synthetic Pi transport and loopback model metadata, independently of the native SDK leg. Their distinction is intentional: Pi supplies the extension API; the hub supplies authorization and durable receipts.
25
+
26
+ ## Repeat
27
+
28
+ The producer asserts package identity, native version, extension registration, RPC identity, replay effect count, failed-result propagation and zero provider requests. It retains its isolated temporary directory for inspection and prints no personal data.
29
+
30
+ ```sh
31
+ bun docs/verification/pi-140-model-free.ts "$HOME/.pi/agent/bin/pi" "$HOME/.pi/agent/install/releases/1.4.0/node_modules/@earendil-works/pi-coding-agent"
32
+ env -u AGENTHUB_HOME -u AGENTHUB_PROJECT_DIR -u AGENTHUB_STATE_DIR bun test test/pi-compat.test.ts test/compat.test.ts
33
+ env -u AGENTHUB_HOME -u AGENTHUB_PROJECT_DIR -u AGENTHUB_STATE_DIR bun test test/permission-modes.test.ts --test-name-pattern 'Pi mode grants'
34
+ ```
35
+
36
+ Native producer result: `pi 1.4.0 model-free receipt: PASS`. The host compatibility/path suite passed (31 tests), followed by the added native-error impersonation regression (1 test); host Pi mode test: 1 pass, 0 fail.
37
+
38
+ ## Not verified
39
+
40
+ - Account-backed inference, a model-generated tool request, a real provider's quota behavior and interactive TUI coexistence are unverified. They need a separately authorized live leg; this receipt makes no such claim.
41
+ - No other Pi release or compatible semver line is inferred. The COMPAT entry has no `line`; person trust lifts only the exact version refusal and leaves host permissions and receipt checks intact.
@@ -0,0 +1,60 @@
1
+ # Qwen Code 0.26.1 ACP receipt (#843 AC5)
2
+
3
+ Date: 2026-10-26. Refs #843. Installed npm release `@qwen-code/qwen-code` 0.26.1. This repeats the Qwen legs of [the 0.26.0 receipt](2026-10-22-kimi-qwen-compat.md) — native ACP identity, mode ids, permission callbacks, all without a model — on 0.26.1, and says whether the two ACP fixes in the 0.26.1 release notes change the hub contract. Every leg passed, so 0.26.1 is added to the `qwen` entry's `verified` in `src/adapters/compat.ts` in the same change.
4
+
5
+ ## Installed artifact
6
+
7
+ Package root `~/.local/share/fnm/node-versions/v24.18.1/installation/lib/node_modules/@qwen-code/qwen-code`. npm `dist.integrity` `sha512-4kpIzrlrgmawivim0yCZjr1AP5cfHTanyL7eL1g2R8WYU6QDBq7j9fiAye7REXL4EEXkRIq45D7+ngTw5n3GqQ==`, `gitHead` `b475278c4a300acebe6cfc990a9e1b1d18819bfc`. SHA-256 of `cli-entry.js` `113efe4104a9fc66f507d34bfd6abbd896ceb77de47f4b468a0825a327fdc6a5`; SHA-256 of `chunks/acpAgent-6HTF6TM6.js` (the chunk holding the ACP agent and the permission emitters) `1171efba62467d7578a332a0c1bb1a313c336c69efd400d0b860252734a1cf14`.
8
+
9
+ ## Isolation
10
+
11
+ - Every process ran under an isolated `HOME` and cwd (fresh directories under `/tmp/ahub-509-qwen-evidence`), with `--auth-type openai --model fixture-model --openai-base-url http://127.0.0.1:9/v1 --telemetry=false`, so nothing could reach a real account or provider. The real `~/.qwen` was never the home.
12
+ - A preload guard blocked every outbound connection attempt and counted them: the native run made 6 attempts (telemetry/update-check paths), all refused, 0 connected; the permission fixture made none.
13
+ - After each run the process group was verified gone (`groupGone` true after SIGTERM, `leaderExit` -15). No session transcript was written into the real home.
14
+
15
+ ## Leg 1: native ACP identity and mode ids (idle, no model)
16
+
17
+ Spawned `qwen --acp` (the production adapter argv is `["qwen","--acp"]`; the probe added `--bare --advisor off` and the fixture auth args) with 0 prompts sent:
18
+
19
+ - `initialize`: `protocolVersion` 1, `agentInfo` `{ name: "qwen-code", title: "Qwen Code", version: "0.26.1" }` — the identity `qwenNativeIdentity` checks. `authMethods` offers the `openai` terminal method only. `capabilities`: `loadSession`, image and audio and embedded-context prompt content, session list and resume, MCP `sse` and `http`.
20
+ - `session/new` returned session `9c73767d-a12c-4a84-a330-8f49b94c3fd9`, `modes` advertising `default`, `plan`, `auto-edit`, `auto`, `yolo` with `currentModeId` `default`, and `configOptions` for mode and model (the fixture model only). The hub's `QWEN_MODE_IDS` (ask → `default`, ask-when-needed → `auto-edit`, never-ask → `yolo`; `auto` and `plan` stay unmapped) is a subset of what 0.26.1 advertises, unchanged from 0.26.0.
21
+ - The cycle `default` → `auto-edit` → `yolo` → `default` through `session/set_mode` succeeded (ids 3–6 each `result: {}`). Each switch now also arrives as an extra `qwen/notify/session/mode-update` notification (`{ v: 1, sessionId, currentModeId }`, 4 in all, one per switch). The hub ignores unknown notifications, so this changes nothing in the contract; the 0.26.0 receipt recorded the same accompaniment.
22
+
23
+ ## Leg 2: permission callbacks (real installed code, no model)
24
+
25
+ The native permission path was exercised against the real installed chunk, not a reimplementation: a scratch copy of `chunks/acpAgent-6HTF6TM6.js` that only added exports (`SubAgentTracker`, `toPermissionOptions`, `resolvePermissionOutcome`, `ToolCallEmitter`) was written beside the chunk inside the package's `chunks/` directory (relative `./chunk-*.js` imports resolve only there), the real `SubAgentTracker.createApprovalHandler` was driven with synthetic client/tool/event ports, and the scratch copy was removed from the shared package afterwards (verified: none left).
26
+
27
+ - An MCP tool-call request produced a native `session/request_permission` with exactly the option set the hub's `answerPermission` selects from: `proceed_always_project` and `proceed_always_user` (`allow_always`), `proceed_once` named "Allow" (`allow_once`), `cancel` named "Reject" (`reject_once`).
28
+ - The Allow turn responded `proceed_once`; the cancellation turn responded `cancel`; both got the empty result the handler expects. An unoffered option was refused with `Permission response selected unoffered option: not-offered`. That error text changed from 0.26.0's `invalid option` wording; the hub only ever selects an option the request announced, so this is not a contract change.
29
+ - While a request was pending, the parent tool call received `tool_call_update` progress with "Waiting for permission: hub_task_show (agent-hub MCP Server)" — the same turn-pinned progress the hub surfaces.
30
+
31
+ ## The two 0.26.1 ACP fixes
32
+
33
+ The 0.26.1 release notes list exactly two APR-tagged ACP fixes (checked against the GitHub release and the installed chunk):
34
+
35
+ - **#15279 — stop blanking replay App html that cannot reclaim bytes.** This is the MCP App replay HTML path (`blankReplayedMcpAppHtml`). The hub's Qwen adapter never uses replay App html, so this changes nothing for the hub contract.
36
+ - **#15346 — refuse an edit whose arguments were cut off or arrived incomplete.** The native `runTool` now refuses Edit-kind calls whose arguments hit `MAX_TOKENS` or arrived incomplete, before PreToolUse and before the permission request, with codes `output_truncated` / `invalid_tool_params` and `executionStatus: "not_started"` (both code strings verified present in the installed chunk). The hub already refuses to let a cut payload buy a session-wide grant (`answerPermission` marks any raw input over 600 chars `[cut, N chars]` and withholds the allow_always options on it; an explicit allow_once is still answered), so this strengthens the same protection from the native side, arriving to the hub as an ordinary tool failure. It does not change the contract.
37
+
38
+ Verdict: neither fix changes the hub contract, and no leg failed, so the bump is allowed.
39
+
40
+ ## Not verified
41
+
42
+ - A permission turn reached by a real model call, a real login or account, and a real provider — as in every earlier Qwen receipt. Leg 2 drives the real handler through synthetic ports, which proves the callback shapes, not a model's behavior.
43
+ - Linux and Intel macOS builds. The 0.26.0→0.26.1 diff review was the release notes plus the two fix code paths in the installed chunk, not a full source diff.
44
+
45
+ ## Decision
46
+
47
+ All legs passed, so `0.26.1` joins `verified` for `qwen`; the `qwen-dual` entry (a different contract, receipted at [2026-10-25-qwen-dual-output-t0.md](2026-10-25-qwen-dual-output-t0.md)) is unchanged. A failed leg would have meant no bump, as the task requires.
48
+
49
+ Host validation: gate `scripts/check.sh --changed` on the PR head — see the PR.
50
+
51
+ Evidence fingerprints (producers and result JSONs, SHA-256):
52
+
53
+ | Item | SHA-256 |
54
+ | --- | --- |
55
+ | `qwen-acp-probe.py` | `b6e98f172dad31d3d7dedbcbeaf52788f28326073d16c0bb34caa297b095f7eb` |
56
+ | `native-result.json` | `b361b27acda4b85636271491d37e1dcb83ddc363581f129298622c57e4431d06` |
57
+ | `permission-fixture.mjs` | `63566432a965172dfad46fd5453dd554eda24fbafc8bcfea2419ab7890cd65ff` |
58
+ | `permission-result.json` | `97c639a4fb887681e0554a613f4dd8c131ff242d9c3b77e25d28d9e558178493` |
59
+ | `build-scratch-copy.py` | `1c2e7221a734c63183a065e39dd5d9c01f0ba5c95b82a5be03a1e09af2c7e375` |
60
+ | scratch copy `ahub509-native-permission-exports.mjs` | `85102aec216e363c645295225bddcd881424c4b59b5639366abe083c3b577d9a` |
@@ -0,0 +1,86 @@
1
+ # 0.19.0 release verification
2
+
3
+ This record covers release preparation and source review. It claims no installation, no running-hub upgrade to 0.19.0 and no live TUI launch.
4
+
5
+ ## Candidate
6
+
7
+ Version 0.19.0, built from merged main 08590801 (25 commits since v0.18.0, 8 of them `feat`). The release commits carry the version, the CHANGELOG section, the bundle (plugin 0.19.0, built with the pinned Bun 1.4.2 and the worktree's own frozen `node_modules`; against main the bundle differs only in its version string), the document corrections and the stamps. Control protocol stays 16; `@staix/agent-mem` is pinned at 0.10.0.
8
+
9
+ What changed (see `CHANGELOG.md` for the full list):
10
+ - Host-wrapper shell grants for the headless Claude implementer in `ask-when-needed`, with code gates confined away from project Git metadata (#845: #857).
11
+ - Code-only review scope and evidence-only verdicts (#852: #853); optional `model` for the headless Claude implementer (#844: #848).
12
+ - Agent CLI drift: a daily public-source watch and a planner notice for unverified installed versions (#849, #855); a native version gate for Pi (#843: #847); new verified versions for agy, Jcode, kimi-review, headless Qwen and claude-implementer (#850, #851, #856, #858, #859).
13
+ - Planner work-ready notices (#785: #842) and the lockfile-keyed dependency volume for the remote runner (#793: #846).
14
+ - Sandbox protection for submodule git dirs and `config.worktree` (#862, #866), the Qwen background-task notice fix (#861), conductor error preservation (#812: #839).
15
+ - CI: the suite watchdog stops on lost progress (#516: #870) and CI admission retries a transient GitHub 5xx or 429 (#872: #873).
16
+
17
+ ## Reviews
18
+
19
+ Every PR below merged after its hub review, with bot review threads answered and exact-head CI green at merge (the conductor read it). The review counts are the GitHub reviews each PR carries.
20
+
21
+ | PR | Merge | GitHub reviews |
22
+ | --- | --- | --- |
23
+ | #839 (#812) | 050bdf88 | 2 |
24
+ | #840 | 991df88f | 2 |
25
+ | #841 | 92797116 | 2 |
26
+ | #842 (#785) | 01bc6c13 | 2 |
27
+ | #846 (#793) | 94d71ab1 | 4 |
28
+ | #847 (#843) | 6651da46 | 2 |
29
+ | #848 (#844) | 99f3534c | 6 |
30
+ | #849 | bbfd4adc | 5 |
31
+ | #850 (#843) | cbbe23bd | 2 |
32
+ | #851 (#843) | 0431abff | 1 |
33
+ | #853 (#852) | 4f52cbd4 | 4 |
34
+ | #854 (#515) | 661eb9a1 | 2 |
35
+ | #855 | 58525a1b | 5 |
36
+ | #856 (#843) | 21fb4a56 | 2 |
37
+ | #857 (#845) | 1ad9b7c7 | 2 |
38
+ | #858 (#843) | d64e787e | 4 |
39
+ | #859 (#843) | 671e9f90 | 2 |
40
+ | #860 (#843) | a7c815cb | 2 |
41
+ | #861 | 3e08dee2 | 2 |
42
+ | #862 | 3cfefa05 | 4 |
43
+ | #866 (#865) | e02aa141 | 4 |
44
+ | #868 (#867) | 125e82f1 | 2 |
45
+ | #870 (#516) | 8ea5d00b | 4 |
46
+ | #871 | ae22bb1b | 2 |
47
+ | #873 (#872) | 08590801 | 5 |
48
+
49
+ Two merges were bound to a hub approval at an earlier head of the same change: #870 (hub task #516 approved at f8ee3e52, merged at d5e16a3c, a rebase onto main with only CHANGELOG context differing) and #873 (hub task #525 approved at a159cc37, merged at 44344f23 after `gh pr update-branch` merged main into it). Each merge was pinned with `--match-head-commit` to the head whose CI was green. #857's first macOS leg and three #873 macOS runs were killed by the pre-#870 1440 s total budget or hit the `test/path-policy.test.ts` hardlink flake below; none of those failures was in the changed code.
50
+
51
+ ## Document review
52
+
53
+ Fourteen documents were stale against the 0.18.0 stamps (af22ee0d). Each was rechecked against `git log af22ee0d..HEAD` (through #873) over its stamped paths and the source, by four parallel recheck passes (one per document group) and then read by the conductor before committing. Most features had been documented by the PR that introduced them; the corrections are the gaps those PRs left.
54
+
55
+ | Document | Result | Checked claims and correction |
56
+ | --- | --- | --- |
57
+ | `src/cli/help.ts` | no change | 050bdf88 changes error handling only; no command, subcommand or flag was added or removed since the stamp. Flags in `main.ts`, `launch.ts` and the native entries match the help rows both ways; `test/help.test.ts` passes. |
58
+ | `README.md` | corrected | Status 0.19.0, control protocol 16; the CLI version paragraph names the planner drift notice (#855); the verification link points to this report. |
59
+ | `docs/quickstart.md` | corrected | Install pin `v0.19.0`; a new "Upgrading to 0.19.0" section (Pi gate, drift notice, newly verified versions, implementer shell grants and `model`, review scope, planner notices, dependency volume, sandbox, agent-mem 0.10.0). |
60
+ | `docs/operations.md` | corrected | Header and protocol table name 0.19.0. Added: the Pi version gate (#847), Pi and the headless Claude implementer in the gated-CLI list, planner work-ready notices (#842), the Qwen background-task notice (#861), Qwen 0.26.1, Jcode 0.99.1 and kimi-review 2.3.2 receipts. Corrected: the local-worker sandbox said submodule git dirs under `.git/modules/` were not covered; #862 and #866 cover them. |
61
+ | `docs/security.md` | corrected | `ask-when-needed` names the implementer's host-wrapper grants (#857); the local-worker sandbox bullet describes the #862/#866 modules-tree rules and drops the removed refs/logs exemption; agent-mem pin 0.10.0; conductor operations audited as refused only on an authority refusal (#839); `review_scope` in tier 3 (#853); the version policy lists the implementer, the Qwen dual-output TUI and Pi; Qwen 0.26.1, Jcode 0.99.1 and the claude-implementer 2.1.310 receipt. |
62
+ | `docs/agent-notes/adapters.md` | corrected | `instances.modelSelect` in the fixed-builtin list and the `--model` argv rule (#848); `OperationalAuthorityError` only from an authority fence (#839); the Pi version gate (#847); compat `receipt` (#849); agy 1.4.7 (#851). Scope gains the #845 shell-wrapper files. |
63
+ | `docs/agent-notes/local-worker.md` | corrected | `config.worktree` beside `config`, the linked-worktree pattern rules, and the removed refs/logs residual (#862, #866); the host wrapper reuses `profile()` and must change with `sandboxedExec` (#857). |
64
+ | `docs/agent-notes/tests.md` | corrected | Scope gains `scripts/progress-tee.sh` (#870); the CI admission retry bound for a 429 or 5xx (#873); Pi fakes must answer `--version` (#847); daemon tests with a GitHub origin and a headless implementer pass `shellDefaultBranchProbe` (#857). History moved to the notes README. |
65
+ | `docs/agent-notes/tasks.md` | corrected | Scope gains `review-scope.ts`, `sdlc-merge.ts`, `sdlc-mirror.ts`; the planner work-ready notice rule (#842); `Tasks.bindShellBranch` as a board writer (#857). Review-scope history moved to the notes README. |
66
+ | `docs/agent-notes/daemon.md` | corrected | Conductor operational refusals (#839); scope gains `agent-drift.ts` and `cli/agents.ts` (#855); validation of instance `model` and `review_scope` (#848, #853). |
67
+ | `docs/agent-notes/README.md` | corrected | Background for the 0.19.0 rules (#852 classifier history, #843 fixtures, #516 watchdog). |
68
+ | `docs/agent-notes/benchmarks.md` | no change | The benchmark driver builds `PiPeer` directly, so the #847 preflight does not apply; #862/#866 are covered by the existing `profile()` change rule. |
69
+ | `docs/agent-notes/budget.md` | no change | No budget path changed; the headless implementer still uses `budget.account: "claude"`. |
70
+ | `docs/agent-notes/bus.md` | no change | No `bus.ts` change; the new notices use the existing publish and withdraw paths. |
71
+
72
+ Also corrected, outside the stamped set: `AGENTS.md` area-note path lists (the #845, #852, #855 and #870 files), and `docs/memory.md` named agent-mem pin 0.8.0 and now says 0.10.0.
73
+
74
+ ## Checks
75
+
76
+ - `node scripts/check-docs.mjs --require-fresh`: `docs: OK (0 stale documents)` at the stamp commit; every stamp names bc8a7f25, a commit of this branch.
77
+ - `bun x tsc --noEmit` clean; `bun scripts/build.mjs --check` clean (bundle built with the pinned Bun 1.4.2); `node scripts/check-package.mjs`: `package: OK (573 files, @staix/agent-hub@0.19.0)`.
78
+ - `test/help.test.ts`, `test/check-docs.test.ts` and `test/ci-reuse.test.ts`: 132 pass, 0 fail.
79
+ - The full `scripts/check.sh` was not run locally (host load was above the workspace heavy-work threshold); the release PR's exact-head CI on Ubuntu and macOS is the full gate, and the PR names its run.
80
+
81
+ ## Known gaps, not blocking
82
+
83
+ - The recheck was done by recheck passes reading source and commits, then the conductor; the reviewer of this PR is the independent check on it.
84
+ - No running hub has been upgraded to 0.19.0 here. The implementer shell grants, the drift notice and the Pi gate are source and fixture tested; their live receipts follow the upgrade.
85
+ - Flaky tests seen while preparing this release: `test/path-policy.test.ts` "read-only managed writes ... refuse hardlink aliases (#259)" on hosted macOS (realpath of a hardlink returned the other name), and `test/memory-code-head-684.test.ts` "#367 cached HEAD proof" (hub fail note d13a75e3).
86
+ - Follow-up candidate: the hub's `shell branch bound` history entry (#857) is not in `QUIET_EVENTS` in `src/hub/tasks.ts`, so it may count as a non-quiet entry in checks that read history.