agent-bios 0.10.0 → 0.11.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.
package/DEPENDENCIES.md CHANGED
@@ -37,10 +37,10 @@ Concrete role-slot→model bindings live only in each guide's `Environment Bindi
37
37
 
38
38
  ## Referenced / optional — not required by the core repo
39
39
 
40
- - **ultracode-for-codex** (0.5.0) the `$ultracode-for-codex` Codex skill / CLI (Codex-backed, gpt). In cross-family review it is the **ultracode** route a **Claude** main dispatches (gpt review); a Codex main instead uses the **ultracode** capability, which is the `claude` backend itself run headless with the keyword `ultracode` in the prompt — that keyword is what opens the Workflow tool for the turn (`workflowKeywordTriggerEnabled`, default true, read in the installed 2.1.220 bundle). Required only when the ultracode/hybrid route is selected and the main is Claude.
41
- - **Cross-family review reviewers** — with `review_family=cross` (default), each main routes review to the opposite family. A Claude main dispatches gpt review via `$CODEX_HOME/bin/codex-run --profile hermetic` (and `codex-helm --mode review` for hybrid fan-out); a Codex main dispatches Claude review via the `claude` CLI (`claude -p --permission-mode plan` for native/onto, and, for the workflow-orchestration route, the same `claude` CLI headless with the keyword `ultracode` in the prompt — the keyword trigger is what the injected contract names, so this is the mechanism to follow). The reviewer command, resolved path, and opposite-family tier bindings are named in the launch contract; an absent or unauthenticated route degrades to same-family native (PROPOSED). `review_family=same` restores same-family review.
40
+ - **Deep review** — no separate tool on either side. The Codex-seat deep reviewer (`codex-exec`) is the `codex` CLI's own non-interactive exec mode: `codex exec -s read-only -m gpt-5.6-sol -c model_reasoning_effort="ultra"`, self-contained packet on stdin (`-s read-only`, `-c model_reasoning_effort` and `-c service_tier` verified against installed codex-cli 0.146.0; `-c service_tier="fast"` is the explicit faster, shallower opt-in; `-s read-only` enforces the promised sandbox ambient `~/.codex` config stays inherited, so the route is read-only but not hermetic). The Claude-seat deep reviewer (**ultracode**) is the `claude` backend itself run headless with the keyword `ultracode` in the prompt — that keyword is what opens the Workflow tool for the turn (`workflowKeywordTriggerEnabled`, default true, read in the installed 2.1.220 bundle). Personal or third-party reviewers register in the user-owned `review-methods.local.toml`, never in the shipped config.
41
+ - **Cross-family review reviewers** — with `review_family=cross` (default), each main routes review to the opposite family. A Claude main dispatches gpt review via `$CODEX_HOME/bin/codex-run --profile hermetic` (and `codex-helm --mode review` for review fan-out) plus the deep `codex exec` pass above; a Codex main dispatches Claude review via the `claude` CLI (`claude -p --permission-mode plan` for native, and, for the workflow-orchestration route, the same `claude` CLI headless with the keyword `ultracode` in the prompt — the keyword trigger is what the injected contract names, so this is the mechanism to follow). The reviewer command, resolved path, and opposite-family tier bindings are named in the launch contract; an absent or unauthenticated route degrades to same-family native (PROPOSED). `review_family=same` restores same-family review.
42
42
  - **codex-plugin-cc** (1.0.6; re-evaluated 2026-07-16) — spawns `codex app-server` with inherited env and no `--ignore-user-config`/`--profile`, so every run reads the real `~/.codex` (config.toml, auth, its MCP servers); it has no per-invocation hermetic reach, which is what makes it unfit as a **review** route: the reviewer would inherit the same config and AGENTS.md as the main, undercutting the independent lens `review_family=cross` exists to provide. The model *is* selectable (`--model`/`--effort`); what is dated is the bundled `gpt-5-4-prompting` skill, so passing a current model does not resolve it. **Not adopted**; `wrappers/codex-run.sh` is preferred for controlled reach. It does not touch Claude Code's `/code-review` (no `code-review.md`; it adds namespaced `/codex:*`), so it never made that route cross-family. Capability we lack and may still want independently: its opt-in `Stop` hook review gate.
43
- - **MCP servers** (onto, clickhouse, node_repl, …) — environment-specific; referenced by Environment Binding (VERIFIER-A; coding-staged guide's structured multi-lens review slot), not a core dependency. For cross-family review, agent-launch mounts `onto` and instructs the main to call `onto_review` with `llmOverride={provider,model}` (from `[hosts.*].onto_review`, an onto review-role registered pair) so onto runs the opposite family; onto's own model seats are not launcher-controllable, so the family is set per call.
43
+ - **MCP servers** (clickhouse, node_repl, …) — environment-specific; referenced by Environment Binding, not a core dependency. The launcher registers a stdio MCP server only for a user-registered capability whose offer declares the `mcp-stdio-v1` adapter; no shipped review method is MCP-backed.
44
44
  - **spreadsheet-processing** (skill) — referenced by the global spreadsheet rule; present in the author's Claude Code and Codex environments. If absent, the rule's inline fallback (plain tools/code + real Excel-engine validation) applies.
45
45
 
46
46
  ## Untracked — dependencies, but excluded by design
package/README.md CHANGED
@@ -95,7 +95,7 @@ agent-bios uninstall # remove deployed files and the zsh hook
95
95
 
96
96
  From a git clone, run `./install.sh install` directly (the same CLI). `install` respects `CLAUDE_CONFIG_DIR`, `CODEX_HOME`, `AGENT_LAUNCH_VENV`, and `ZDOTDIR`; `--dry-run` prints actions without changing anything. Deploy to **every active environment in one sitting** — a partial deploy leaves a shared global pointing at a guide some environment lacks; globals are English only. Replaced files are backed up under `~/.local/share/agent-bios/backups/<timestamp>/`, and the installed set is recorded in a manifest that `uninstall` consumes. Those copies are **a manual escape hatch, not a restore mechanism**: nothing reads them back, so recovering from one means copying files yourself. The supported paths are the ones `agent-bios help` prints — a clone rolls corpus content back to a registered version, an npm install rolls the whole package back by version — and `uninstall` emits one archive of everything it removed. The backups exist for the case those three do not cover: the exact bytes that were on disk before a particular install. The published npm package ships only the deploy set (never `settings.json`, `config.toml`, `ko/`, or `benchmarks/`).
97
97
 
98
- In a TTY, zero-argument `codex` or `claude` opens the launch preflight. Every arrow-key TUI selection screen keeps the complete current setup in a fixed top panel, followed by the highlighted option's description and then the option list. Move with Up/Down, select with Enter, use Esc to return to the previous menu, and use `q` to cancel; Esc at the mode root also cancels. Each tier's model is chosen from the host's configured catalog, or via **Other** to type any model id the backend accepts; that text input preserves values that start with `q`, so Esc or Ctrl-C cancels immediately there, while submitting `q` cancels after Enter. The Textual preflight reflows to the terminal size, so there is no fixed minimum geometry. The root menu picks a mode — **Software Engineer** (repo-scoped work that defers to the project's own AGENTS.md/CLAUDE.md: **Vanilla**, the bare CLI with no launch contract, tier bindings, or applied permissions, plus **Custom**; SE-specific review defaults arrive later), **Builder** (the tier presets: Balanced, Deep review, Fast batch, Solo with delegation off, plus Custom), **Session distill** — then a preset within it. Select **Custom** (in Software Engineer or Builder) to open a persistent settings hub for the main tier, review setup, host policy, and each tier binding. Every edit returns to that hub; **Start with these settings** is the final launch confirmation, **Save these settings globally and start** additionally persists the setup as a named preset (with host-scoped tier overrides) in your user config for reuse elsewhere, and **Exit without launching** cancels the launch. The rich preflight runs from a managed virtualenv (`launch/provision-venv.sh`, at `~/.local/share/agent-launch/venv`) that the launcher re-execs into on the interactive path; when that venv is unavailable, or the call is non-interactive, or `TERM` is `dumb`/unset, the launcher falls back to numbered prompts, where `b` is the back command. Backend command names are resolved from the calling environment's `PATH`; shell functions are not re-entered. Codex child bindings are materialized as session-selected agent configs under the user cache, while Claude receives model and effort in `--agents` JSON when delegation is enabled. Review runs cross-family by default (`review_family`, default `cross`; `same` restores today's same-family projection): because the main's tiers are one model family, every dispatchable review route — native, onto, and ultracode — runs on the opposite family. The exception is `slash-review`, the host's own built-in review command (`/code-review` on Claude, with `ultra` for its deep multi-agent pass; `/review` on Codex): it needs no dependency and always resolves, but being the main's own command it cannot be dispatched cross-family, so under `cross` it runs as the same-family floor and its verdicts are labeled PROPOSED. A Claude main dispatches gpt/codex review (native via the `codex-run` reviewer wrapper resolved under `$CODEX_HOME/bin`, onto via an `llmOverride` to the configured openai seat, ultracode via the `$ultracode-for-codex` Codex skill); a Codex main dispatches Anthropic/Claude review (native via `claude -p --permission-mode plan`, onto via an `llmOverride` to the anthropic seat, ultracode via the `claude` CLI headless with the keyword `ultracode` in the prompt, which is what opens Claude Code's dynamic workflow for that turn). The concrete reviewer command, resolved absolute path, `llmOverride`, and opposite-family tier bindings are named in the injected session-start contract; cross-family reviewers are dispatched as read-only subprocesses, not CLI-native subagents, since neither CLI hosts the other family as a native subagent. When a cross-family route is unavailable at launch or unauthenticated at use time it degrades to same-family native subagent review labeled PROPOSED (family collapse) rather than blocking; a requested non-none review with no cross-family route and no same-family fallback (delegation off) stays fail-closed. Review setup means configured/requested; this launcher does not claim that review completed, and unavailable runtimes such as Ultrawork are not offered until integrated.
98
+ In a TTY, zero-argument `codex` or `claude` opens the launch preflight. Every arrow-key TUI selection screen keeps the complete current setup in a fixed top panel, followed by the highlighted option's description and then the option list. Move with Up/Down, select with Enter, use Esc to return to the previous menu, and use `q` to cancel; Esc at the mode root also cancels. Each tier's model is chosen from the host's configured catalog, or via **Other** to type any model id the backend accepts; that text input preserves values that start with `q`, so Esc or Ctrl-C cancels immediately there, while submitting `q` cancels after Enter. The Textual preflight reflows to the terminal size, so there is no fixed minimum geometry. The root menu picks a mode — **Software Engineer** (repo-scoped work that defers to the project's own AGENTS.md/CLAUDE.md: **Vanilla**, the bare CLI with no launch contract, tier bindings, or applied permissions, plus **Custom**; SE-specific review defaults arrive later), **Builder** (the tier presets: Balanced, Deep review, Fast batch, Solo with delegation off, plus Custom), **Session distill** — then a preset within it. Select **Custom** (in Software Engineer or Builder) to open a persistent settings hub for the main tier, review setup, host policy, and each tier binding. Every edit returns to that hub; **Start with these settings** is the final launch confirmation, **Save these settings globally and start** additionally persists the setup as a named preset (with host-scoped tier overrides) in your user config for reuse elsewhere, and **Exit without launching** cancels the launch. The rich preflight runs from a managed virtualenv (`launch/provision-venv.sh`, at `~/.local/share/agent-launch/venv`) that the launcher re-execs into on the interactive path; when that venv is unavailable, or the call is non-interactive, or `TERM` is `dumb`/unset, the launcher falls back to numbered prompts, where `b` is the back command. Backend command names are resolved from the calling environment's `PATH`; shell functions are not re-entered. Codex child bindings are materialized as session-selected agent configs under the user cache, while Claude receives model and effort in `--agents` JSON when delegation is enabled. Review runs cross-family by default (`review_family`, default `cross`; `same` restores today's same-family projection): because the main's tiers are one model family, every dispatchable review route — native and the deep route — runs on the opposite family. The exception is `slash-review`, the host's own built-in review command (`/code-review` on Claude, with `ultra` for its deep multi-agent pass; `/review` on Codex): it needs no dependency and always resolves, but being the main's own command it cannot be dispatched cross-family, so under `cross` it runs as the same-family floor and its verdicts are labeled PROPOSED. A Claude main dispatches gpt/codex review (native via the `codex-run` reviewer wrapper resolved under `$CODEX_HOME/bin`, deep via plain `codex exec -m <frontier model> -c model_reasoning_effort="ultra"` with a self-contained packet on stdin `-c service_tier="fast"` is the explicit faster, shallower opt-in); a Codex main dispatches Anthropic/Claude review (native via `claude -p --permission-mode plan`, deep via the `claude` CLI headless with the keyword `ultracode` in the prompt, which is what opens Claude Code's dynamic workflow for that turn). The concrete reviewer command, resolved absolute path, and opposite-family tier bindings are named in the injected session-start contract; cross-family reviewers are dispatched as read-only subprocesses, not CLI-native subagents, since neither CLI hosts the other family as a native subagent. When a cross-family route is unavailable at launch or unauthenticated at use time it degrades to same-family native subagent review labeled PROPOSED (family collapse) rather than blocking; a requested non-none review with no cross-family route and no same-family fallback (delegation off) stays fail-closed. Review setup means configured/requested; this launcher does not claim that review completed, and unavailable runtimes such as Ultrawork are not offered until integrated.
99
99
 
100
100
  At the shell-wrapper boundary, every argument-bearing command (`codex exec ...`, `claude -p ...`) and every non-TTY invocation skips launch-profile projection and preserves caller arguments. The Claude direct path intentionally retains its wrapper default, `--dangerously-skip-permissions`. `codex --no-tui ...` / `claude --no-tui ...` explicitly take that direct path, and `AGENT_LAUNCH_TUI=0` disables zero-argument TUI interception for a process tree.
101
101
 
@@ -173,7 +173,7 @@ Write for the next agent and re-verification, not narrative. Required content:
173
173
 
174
174
  This is the human-readable projection of concrete models/tools; `launch/agent-launch.toml` is the machine launch authority and parity checks keep them aligned. Re-probe when the binding is older than ~8 weeks or a newer observable model/tool changes the surface. `agent-bios install` overwrites deployed bindings, so edit the repo copy.
175
175
 
176
- Binding (2026-07-25):
176
+ Binding (2026-08-10):
177
177
 
178
178
  | Slot | Binding | Notes |
179
179
  |---|---|---|
@@ -181,13 +181,13 @@ Binding (2026-07-25):
181
181
  | HELM | Claude Opus 5 (xhigh) · GPT-5.6 Sol (xhigh main; main Ultra requires explicit selection; bounded FRONTIER Ultra allowed) | standing main; Codex defaults bypass, explicit sandbox narrows |
182
182
  | WORKHORSE | Claude Opus 5 (medium) · GPT-5.6 Terra (high) | implementation and per-item judgment |
183
183
  | SWEEP | Claude Haiku 4.5 · GPT-5.6 Luna (low) | clear repeatable scans and mechanical work |
184
- | VERIFIER-A | onto-mcp review | logic/authority kind; tier units per funnel |
185
- | VERIFIER-B | `ultracode-for-codex` CLI v0.4.5 (Codex-backed; callable from Claude or Codex) | code/execution kind |
184
+ | VERIFIER-A | plain `codex exec` deep pass — GPT-5.6 Sol at ultra effort, packet on stdin (`-c service_tier="fast"` as explicit fast opt-in) | strongest single reader; cross-family from a Claude main |
185
+ | VERIFIER-B | Claude Code ultracode workflow (keyword-opened, many-agent) | code/execution kind; fan-out counterpart |
186
186
  | INDEPENDENT-PR-REVIEWER | Codex CLI | adversarial `gh pr diff` review |
187
187
  | Claude relocation | EnterWorktree, `/cd`, `--worktree`; resume is directory-scoped | verified 2.1.207 |
188
188
  | Codex relocation | `codex resume` (cwd-filtered; `--all` lifts), fork | verified 0.144.1 |
189
189
  | Claude teammate | named mailbox continuation; completed-agent message may cold-rerun on main model | keep resident; avoid completed resume |
190
- | Rate-limit fallback | OpenAI limited → VERIFIER-A on Anthropic; Claude limited → VERIFIER-B on Codex | record family collapse |
190
+ | Rate-limit fallback | OpenAI limited → VERIFIER-B (Anthropic workflow); Claude limited → VERIFIER-A (Codex exec) | record family collapse |
191
191
 
192
192
  Codex direct-drive (verified 0.144.1, 2026-07-12):
193
193
 
@@ -108,5 +108,5 @@ Binding (2026-07):
108
108
 
109
109
  | Slot | Binding | Notes |
110
110
  |---|---|---|
111
- | Structured multi-lens review | onto-mcp review (private MCP) | consumes/emits the severity contract defined in Review Loop |
111
+ | Structured multi-lens review | agent-launch review methods: isolated panel + Codex deep exec (`codex exec` at ultra effort) + Claude ultracode workflow | consumes/emits the severity contract defined in Review Loop; personal tools register in the user-owned `review-methods.local.toml` |
112
112
  | Subagent review | host CLI's native review mechanism | e.g. Claude Code `/code-review` or Agent-tool reviewers |
@@ -50,9 +50,9 @@ Run in order; each stage reads the previous stage's `out/`:
50
50
  2. `digest.py` — one secret-redacted digest per session with deterministic
51
51
  6-criteria signals. Screen ALL digests; triage orders, never drops.
52
52
  3. Provider-affine screening against the concatenated live baseline
53
- (CLAUDE.md + guides): `screen-claude.js` (Workflow) and
54
- `screen-codex.js` (ultracode). Novelty is judged against real baseline
55
- text, not memory.
53
+ (CLAUDE.md + guides): `screen-claude.js` (Claude sessions) and
54
+ `screen-codex.js` (Codex sessions), both dynamic-workflow scripts.
55
+ Novelty is judged against real baseline text, not memory.
56
56
  4. `consolidate.js` — dedup + independent novelty verification. Rank by
57
57
  strength (recurrence × materiality), never by self-reported confidence.
58
58
  5. `bundle_final.py` — tiered bundle. Merge new candidates into
@@ -173,7 +173,7 @@ Write for the next agent and re-verification, not narrative. Required content:
173
173
 
174
174
  This is the human-readable projection of concrete models/tools; `launch/agent-launch.toml` is the machine launch authority and parity checks keep them aligned. Re-probe when the binding is older than ~8 weeks or a newer observable model/tool changes the surface. `agent-bios install` overwrites deployed bindings, so edit the repo copy.
175
175
 
176
- Binding (2026-07-25):
176
+ Binding (2026-08-10):
177
177
 
178
178
  | Slot | Binding | Notes |
179
179
  |---|---|---|
@@ -181,13 +181,13 @@ Binding (2026-07-25):
181
181
  | HELM | Claude Opus 5 (xhigh) · GPT-5.6 Sol (xhigh main; main Ultra requires explicit selection; bounded FRONTIER Ultra allowed) | standing main; Codex defaults bypass, explicit sandbox narrows |
182
182
  | WORKHORSE | Claude Opus 5 (medium) · GPT-5.6 Terra (high) | implementation and per-item judgment |
183
183
  | SWEEP | Claude Haiku 4.5 · GPT-5.6 Luna (low) | clear repeatable scans and mechanical work |
184
- | VERIFIER-A | onto-mcp review | logic/authority kind; tier units per funnel |
185
- | VERIFIER-B | `ultracode-for-codex` CLI v0.4.5 (Codex-backed; callable from Claude or Codex) | code/execution kind |
184
+ | VERIFIER-A | plain `codex exec` deep pass — GPT-5.6 Sol at ultra effort, packet on stdin (`-c service_tier="fast"` as explicit fast opt-in) | strongest single reader; cross-family from a Claude main |
185
+ | VERIFIER-B | Claude Code ultracode workflow (keyword-opened, many-agent) | code/execution kind; fan-out counterpart |
186
186
  | INDEPENDENT-PR-REVIEWER | Codex CLI | adversarial `gh pr diff` review |
187
187
  | Claude relocation | EnterWorktree, `/cd`, `--worktree`; resume is directory-scoped | verified 2.1.207 |
188
188
  | Codex relocation | `codex resume` (cwd-filtered; `--all` lifts), fork | verified 0.144.1 |
189
189
  | Claude teammate | named mailbox continuation; completed-agent message may cold-rerun on main model | keep resident; avoid completed resume |
190
- | Rate-limit fallback | OpenAI limited → VERIFIER-A on Anthropic; Claude limited → VERIFIER-B on Codex | record family collapse |
190
+ | Rate-limit fallback | OpenAI limited → VERIFIER-B (Anthropic workflow); Claude limited → VERIFIER-A (Codex exec) | record family collapse |
191
191
 
192
192
  Codex direct-drive (verified 0.144.1, 2026-07-12):
193
193
 
@@ -108,5 +108,5 @@ Binding (2026-07):
108
108
 
109
109
  | Slot | Binding | Notes |
110
110
  |---|---|---|
111
- | Structured multi-lens review | onto-mcp review (private MCP) | consumes/emits the severity contract defined in Review Loop |
111
+ | Structured multi-lens review | agent-launch review methods: isolated panel + Codex deep exec (`codex exec` at ultra effort) + Claude ultracode workflow | consumes/emits the severity contract defined in Review Loop; personal tools register in the user-owned `review-methods.local.toml` |
112
112
  | Subagent review | host CLI's native review mechanism | e.g. Claude Code `/code-review` or Agent-tool reviewers |
@@ -50,9 +50,9 @@ Run in order; each stage reads the previous stage's `out/`:
50
50
  2. `digest.py` — one secret-redacted digest per session with deterministic
51
51
  6-criteria signals. Screen ALL digests; triage orders, never drops.
52
52
  3. Provider-affine screening against the concatenated live baseline
53
- (CLAUDE.md + guides): `screen-claude.js` (Workflow) and
54
- `screen-codex.js` (ultracode). Novelty is judged against real baseline
55
- text, not memory.
53
+ (CLAUDE.md + guides): `screen-claude.js` (Claude sessions) and
54
+ `screen-codex.js` (Codex sessions), both dynamic-workflow scripts.
55
+ Novelty is judged against real baseline text, not memory.
56
56
  4. `consolidate.js` — dedup + independent novelty verification. Rank by
57
57
  strength (recurrence × materiality), never by self-reported confidence.
58
58
  5. `bundle_final.py` — tiered bundle. Merge new candidates into
package/install.sh CHANGED
@@ -238,9 +238,15 @@ assemble_corpus() {
238
238
  for g in "$REPO"/codex/guides/*.md; do
239
239
  [ -f "$g" ] || continue
240
240
  dst="$CODEX_DIR/guides/$(basename "$g")"
241
- [ -f "$dst" ] && printf '%s\n' "$dst" >> "$MANIFEST"
241
+ # if-form, not `[ -f ] && printf`: when the alphabetically LAST guide is
242
+ # not deployed (a partial domain selection on a fresh machine), the
243
+ # compound's false status became the loop's, the loop's became the
244
+ # function's, and the install died silently right after ASSEMBLED —
245
+ # a latent first-user bug the I9 scenario exposed.
246
+ if [ -f "$dst" ]; then printf '%s\n' "$dst" >> "$MANIFEST"; fi
242
247
  done
243
248
  fi
249
+ return 0
244
250
  }
245
251
 
246
252
  add_zsh_hook() {
@@ -602,6 +608,13 @@ cmd_install() {
602
608
  deploy_file "$REPO/launch/agent-launch.toml" "$LAUNCH_DIR/profiles.toml"
603
609
  deploy_file "$REPO/launch/agent-launch.zsh" "$LAUNCH_DIR/shell.zsh"
604
610
  deploy_file "$REPO/launch/agent-launch.py" "$BIN_DIR/agent-launch" "+x"
611
+ # UI text catalogs: deploy-managed siblings of the config, one per language.
612
+ # The launcher resolves them from the config path, so the deployed home is
613
+ # $LAUNCH_DIR/i18n exactly as the checkout's is launch/i18n.
614
+ local lang
615
+ for lang in en ko ja; do
616
+ deploy_file "$REPO/launch/i18n/$lang.toml" "$LAUNCH_DIR/i18n/$lang.toml"
617
+ done
605
618
  log ""
606
619
  log "Optional dependencies (missing ones only degrade the routes that need them)..."
607
620
  handle_capabilities "$WITH" || exit 1
@@ -966,14 +979,44 @@ cmd_onboard() {
966
979
  fi
967
980
  DOMAINS_ARG="$sel"; DOMAINS_SET=1
968
981
  log "selection: ${sel:-<core+infra only>}"
969
- cmd_install
982
+ # Subshelled so a failing install can still record its outcome: the launcher's
983
+ # corpus checklist reads `last_apply` from corpus-status.json, and an exit with
984
+ # nothing recorded reads as "nothing happened". cmd_install's shell state stays
985
+ # in the subshell; everything after here uses only top-level globals.
986
+ local apply_rc=0
987
+ # NOT `( cmd_install ) || apply_rc=$?`: a command list that tests the subshell
988
+ # suppresses errexit for everything inside it, so an unguarded failure in
989
+ # cmd_install would run through to a zero return (probed on bash 3.2/5.x).
990
+ # Toggling -e around a STANDALONE subshell keeps errexit live inside while the
991
+ # outer shell survives to record the outcome.
992
+ set +e
993
+ ( set -e; cmd_install )
994
+ apply_rc=$?
995
+ set -e
996
+ if [ "$apply_rc" -ne 0 ]; then
997
+ python3 "$REPO/compose/corpus-state.py" record-apply \
998
+ --requested "$sel" --outcome install_failed >/dev/null 2>&1 || true
999
+ exit "$apply_rc"
1000
+ fi
970
1001
  log ""
971
1002
  log "Activation canary (proves the bundle loads in a live session)..."
972
1003
  if [ "$DRY_RUN" = 1 ]; then info "[dry-run] skip canary probe"; return; fi
973
- bash "$REPO/compose/canary.sh" || {
1004
+ local canary_rc=0
1005
+ bash "$REPO/compose/canary.sh" || canary_rc=$?
1006
+ if [ "$canary_rc" -ne 0 ]; then
1007
+ # rc=1 is a real probe that answered "not loading"; rc=3 is "could not
1008
+ # probe" (no CLI/auth). Both leave the apply unproven, so both record as
1009
+ # canary_failed — the tail carries which, so the panel's loud line does
1010
+ # not send the operator to debug imports over an auth problem.
1011
+ python3 "$REPO/compose/corpus-state.py" record-apply \
1012
+ --requested "$sel" --outcome canary_failed \
1013
+ --error-tail "canary exit $canary_rc$([ "$canary_rc" = 3 ] && printf ' (could not probe)')" \
1014
+ >/dev/null 2>&1 || true
974
1015
  log "ONBOARDING INCOMPLETE: the bundle is installed but not loading — fix the cause above and re-run: agent-bios verify"
975
1016
  exit 1
976
- }
1017
+ fi
1018
+ python3 "$REPO/compose/corpus-state.py" record-apply \
1019
+ --requested "$sel" --outcome applied >/dev/null 2>&1 || true
977
1020
  # The prune is authorized by the canary's proof, and cmd_install ran before the canary existed
978
1021
  # for this bundle rev — so it kept everything. Now that loading is proven, run it for real.
979
1022
  migrate_learnings