claude-dev-env 8.13.0 → 8.14.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.
@@ -24,7 +24,7 @@ One warm advisor at the strongest tier this session can reach. This session is t
24
24
  ## Bind
25
25
 
26
26
  1. Name the session identity first (protocol **Host profiles**), then walk the model floor.
27
- 2. Claude: when `advisor` is in this session's tool list, the built-in advisor tool is the advisor. Spawn nothing and call `advisor()` at each consult point. Otherwise spawn or resume `pstack:poteto-agent` at `ADVISOR_EFFORT` (default low) with the advisor response contract in the prompt. When the bound model is out of usage, use the configured fallback at the same effort. Codex: use the native advisor path. Third-party: use the headless advisor path. When the host's walk fails, fail closed.
27
+ 2. Claude: when `advisor` is in this session's tool list, the built-in advisor tool is the advisor. Spawn nothing and call `advisor()` at each consult point. Otherwise spawn or resume `pstack:poteto-agent` at `ADVISOR_EFFORT` (default xhigh) with the advisor response contract in the prompt. When the bound model is out of usage, use the configured fallback at the same effort. Codex: use the native advisor path. Third-party: use the headless advisor path. When the host's walk fails, fail closed.
28
28
  3. Name the warm instance `team-advisor-agent` and keep its advisor response contract in every first prompt. When a native Codex subagent spawn is the advisor path and the spawn tool has a `flags` field, pass `flags: ["--advisor"]` with Astra and record `advisor_flag: passed`. A spawn that skips an offered flag is a failed bind. When the spawn tool has no `flags` field, as in `codex exec`, spawn `gpt-6-astra` plainly, record `advisor_flag: unavailable`, and treat it as bound.
29
29
  4. Skip the multi-consumer "who you are" opener. This session is the sole consumer.
30
30
  5. When the bind or reply path fails, fail closed and report to the user. On a third-party host, only the bound advisor issues ENDORSE / CORRECTION / PLAN / STOP.
@@ -18,10 +18,10 @@ The sections below hold the standing rules. Open a reference file at the moment
18
18
  | Moment | Open |
19
19
  |---|---|
20
20
  | Naming the session identity | [`reference/identity.md`](reference/identity.md): Claude, Codex, or neither |
21
- | Binding on a Claude host | [`reference/warm-up.md`](reference/warm-up.md): spawn fields, Fable token, charter |
21
+ | Binding on a Claude host | [`reference/warm-up.md`](reference/warm-up.md): spawn fields, Opus token, charter |
22
22
  | Binding on a Codex host | [`reference/identity.md`](reference/identity.md): in-session Astra spawn |
23
23
  | Binding from a third-party host | [`reference/third-party-bind.md`](reference/third-party-bind.md): CLI bind steps, fail-closed rule |
24
- | Fable is out of usage | [`reference/astra-rung.md`](reference/astra-rung.md): Astra fallback at shared effort |
24
+ | Opus is out of usage | [`reference/astra-rung.md`](reference/astra-rung.md): Astra fallback at shared effort |
25
25
  | Composing a consult | [`reference/consult-format.md`](reference/consult-format.md): packet, new-evidence and report-back rules |
26
26
  | Assembling an executor spawn prompt | [`reference/advisor-block.md`](reference/advisor-block.md): the paste parts |
27
27
  | Advisor drifts, dies, or the task pivots | [`reference/lifecycle.md`](reference/lifecycle.md): re-spawn and re-bind steps |
@@ -47,25 +47,25 @@ Mechanical override for scripts:
47
47
 
48
48
  ### Shared effort, any host
49
49
 
50
- Fable and Astra both read `ADVISOR_EFFORT` (`low`, `medium`, `high`, `xhigh`, `max`). Fable keeps its low default. Astra uses the policy default, Medium.
50
+ Opus and Astra both read `ADVISOR_EFFORT` (`low`, `medium`, `high`, `xhigh`, `max`). Opus keeps its xhigh default. Astra uses the policy default, Medium.
51
51
  Pass `--effort <level>` on the Astra helper to set effort for that Astra run.
52
- Pass `--effort <level>` on the Claude CLI bind for Fable. An unset or unrecognized Fable value uses `low`.
52
+ Pass `--effort <level>` on the Claude CLI bind for Opus. An unset or unrecognized Opus value uses `xhigh`.
53
53
 
54
54
  ### Astra rung
55
55
 
56
- On Claude and ThirdParty: when Fable is out of usage, bind Astra through the Codex helper.
56
+ On Claude and ThirdParty: when Opus is out of usage, bind Astra through the Codex helper.
57
57
  Open that attempt with `ADVISOR_ASTRA=1` (or `true` / `yes` / `on`) in the environment, or pass `--enable-astra` on the helper invocation.
58
- Flag off both ways: fail closed when Fable did not bind.
59
- Flag on: run the Codex preflight and bind per [`reference/astra-rung.md`](reference/astra-rung.md); a failed preflight fails closed when Fable did not bind.
58
+ Flag off both ways: fail closed when Opus did not bind.
59
+ Flag on: run the Codex preflight and bind per [`reference/astra-rung.md`](reference/astra-rung.md); a failed preflight fails closed when Opus did not bind.
60
60
 
61
61
  On Codex: Astra is the in-session default. The `ADVISOR_ASTRA` flag is not required. Fail closed when that spawn does not bind.
62
62
 
63
63
  ### Claude host
64
64
 
65
- When `advisor` is in the session's tool list, the built-in advisor tool is the advisor. The user turns it on with `/advisor`, the `advisorModel` setting, or `--advisor`. Spawn nothing and call `advisor()` at each consult point. The tool forwards the whole transcript, so a consult needs no packet. Its reply is free text, so the four signal words do not apply; weigh it per `docs/references/advisor-tool.md` **How to treat advice**. It is a server tool, so hooks and the spawn-walk log do not see it. A Fable or Opus 5 advisor returns an encrypted result that a log cannot read. When a readable record matters, use the warm agent below.
65
+ When `advisor` is in the session's tool list, the built-in advisor tool is the advisor. The user turns it on with `/advisor`, the `advisorModel` setting, or `--advisor`. Spawn nothing and call `advisor()` at each consult point. The tool forwards the whole transcript, so a consult needs no packet. Its reply is free text, so the four signal words do not apply; weigh it per `docs/references/advisor-tool.md` **How to treat advice**. It is a server tool, so hooks and the spawn-walk log do not see it. An Opus advisor returns an encrypted result that a log cannot read. When a readable record matters, use the warm agent below.
66
66
 
67
- When `advisor` is not in the tool list, use the **Model floor** ladder below (Fable first, then Astra when Fable is out of usage).
68
- Warm-up spawns `subagent_type: session-advisor` via the Agent tool for Fable; consults go through `SendMessage` to that warm agent. Astra uses the Codex helper.
67
+ When `advisor` is not in the tool list, use the **Model floor** ladder below (Opus first, then Astra when Opus is out of usage).
68
+ Warm-up spawns `subagent_type: session-advisor` via the Agent tool for Opus; consults go through `SendMessage` to that warm agent. Astra uses the Codex helper.
69
69
  Assemble and paste each executor's Advisor block per the **Advisor block** section.
70
70
 
71
71
  ### Codex host
@@ -73,14 +73,14 @@ Assemble and paste each executor's Advisor block per the **Advisor block** secti
73
73
  Spawn a native in-session Astra subagent at `resolve_codex_model_id("Astra")`.
74
74
  Walk `candidate_tiers = ["Astra"]`. Record `{tier: "Astra", result: "spawned"}` on success.
75
75
  **Fail closed:** when Astra does not bind, set `selected_tier = null` and a `fallback_reason`, report that the advisor is unreachable, and **stop**.
76
- Do not walk Fable on a Codex host. Consults stay in-session with that Astra subagent.
76
+ Do not walk Opus on a Codex host. Consults stay in-session with that Astra subagent.
77
77
  Assemble and paste each executor's Advisor block per the **Advisor block** section.
78
78
 
79
79
  ### Third-party host
80
80
 
81
- On a third-party (non-Claude, non-Codex) harness, the shared CLI Claude-chain is the one path to a Claude advisor: bind Fable through it, per [`reference/third-party-bind.md`](reference/third-party-bind.md).
81
+ On a third-party (non-Claude, non-Codex) harness, the shared CLI Claude-chain is the one path to a Claude advisor: bind Opus through it, per [`reference/third-party-bind.md`](reference/third-party-bind.md).
82
82
  The bound Claude session is the advisor; this third-party session stays the executor.
83
- Walk `candidate_tiers = ["Fable"]`. When Fable is out of usage, the Astra rung binds after Fable (`candidate_tiers = ["Fable", "Astra"]`).
83
+ Walk `candidate_tiers = ["Opus"]`. When Opus is out of usage, the Astra rung binds after Opus (`candidate_tiers = ["Opus", "Astra"]`).
84
84
  **Cursor Astra first shot:** when the walk reaches Astra (or the user asks for Astra), bind through `codex_astra_advisor.py --bind --enable-astra` on the first tool call (see the GOTCHA in [`reference/third-party-bind.md`](reference/third-party-bind.md)). Do not use the Agent tool, and do not hunt a probe path.
85
85
  **Fail closed:** when every candidate fails, set `selected_tier = null` and a `fallback_reason`, report that the advisor is unreachable, and **stop**. ENDORSE / CORRECTION / PLAN / STOP come only from a bound advisor.
86
86
  Executors report to the orchestrating session; that session consults the bound advisor and relays the four-signal reply.
@@ -88,26 +88,26 @@ Executors report to the orchestrating session; that session consults the bound a
88
88
  ## Model floor
89
89
 
90
90
  The built-in advisor tool sits outside this ladder. Claude Code and the API accept it only when the advisor is at least as capable as the main model, and that check is its floor.
91
- On Claude and ThirdParty the advisor ladder is `Fable` first, then Astra (flag-gated, Codex CLI) when Fable is out of usage.
91
+ On Claude and ThirdParty the advisor ladder is `Opus` first, then Astra (flag-gated, Codex CLI) when Opus is out of usage.
92
92
  On Codex the walk is Astra only, in-session.
93
93
  Opus is not an advisor candidate. `Sonnet` and `Haiku` are executor tiers only.
94
94
  Consumer `own_tier` is recorded on the spawn-walk log; it does not add Opus to the advisor walk.
95
95
  Tier names are canonical Title Case; the validator accepts any letter case and normalizes to Title Case.
96
- Try binds top-down. Fable resolves to the short model alias in [`reference/cli-chain.md`](reference/cli-chain.md); Astra resolves through `resolve_codex_model_id("Astra")` to `gpt-6-astra`.
96
+ Try binds top-down. Opus resolves to the short model alias in [`reference/cli-chain.md`](reference/cli-chain.md); Astra resolves through `resolve_codex_model_id("Astra")` to `gpt-6-astra`.
97
97
  The advisor is created at `selected_tier`, the first ladder tier that binds.
98
- When Fable fails on a Claude host, try Astra if the flag is on, else fail closed. The CLI chain is the Fable bind path on a third-party host and the Claude-host fallback for Fable; it does not bind Opus as advisor.
98
+ When Opus fails on a Claude host, try Astra if the flag is on, else fail closed. The CLI chain is the Opus bind path on a third-party host and the Claude-host fallback for Opus.
99
99
  On a Codex host a failed Astra spawn fails closed per **Host profiles → Codex host**.
100
- On a third-party host the CLI chain is already the primary path, so a failed Fable (and Astra, when enabled) walk fails closed per **Host profiles → Third-party host**.
100
+ On a third-party host the CLI chain is already the primary path, so a failed Opus (and Astra, when enabled) walk fails closed per **Host profiles → Third-party host**.
101
101
 
102
102
  Emit a structured spawn-walk log so the walk can be checked mechanically: [`reference/spawn-walk-log.md`](reference/spawn-walk-log.md).
103
103
  The validator checks ladder shape only; host policy sits on top.
104
104
 
105
- **Equal-tier pairings.** Bind Fable for an independent second pass on irreversible or security-sensitive work. The advisor is Fable or Astra.
105
+ **Equal-tier pairings.** Bind Opus for an independent second pass on irreversible or security-sensitive work. The advisor is Opus or Astra.
106
106
 
107
107
  ## Warm-up (once per session)
108
108
 
109
109
  On a **Claude host** with `advisor` in the tool list, skip the warm-up; the built-in tool needs none.
110
- On a **Claude host** without it, spawn `session-advisor` at the Fable alias with the charter as its prompt. When Fable is out of usage and the Astra rung is open, bind Astra through the Codex helper instead.
110
+ On a **Claude host** without it, spawn `session-advisor` at the Opus alias with the charter as its prompt. When Opus is out of usage and the Astra rung is open, bind Astra through the Codex helper instead.
111
111
  Full spawn fields and the charter template: [`reference/warm-up.md`](reference/warm-up.md).
112
112
 
113
113
  On a **Codex host**, spawn a native in-session Astra subagent with the same charter. Bind fields: [`reference/identity.md`](reference/identity.md) and [`reference/warm-up.md`](reference/warm-up.md).
@@ -26,7 +26,7 @@ Subagents inherit the session's advisor tool, so the executor calls it directly.
26
26
  ## Transport preamble for a third-party host
27
27
 
28
28
  > The orchestrating session owns a standing advisor for this run.
29
- > The advisor chain: Claude Fable, then Astra through the Codex CLI when Fable is out of usage and the Astra flag and its preflight open that rung. Fable uses its low default. Astra uses the policy default, Medium. When neither binds, there is no advisor.
29
+ > The advisor chain: Claude Opus, then Astra through the Codex CLI when Opus is out of usage and the Astra flag and its preflight open that rung. Opus uses its xhigh default. Astra uses the policy default, Medium. When neither binds, there is no advisor.
30
30
  > The orchestrating session is your one path to it: send each consult as a report to the session that assigned you, and it relays the advisor's reply.
31
31
 
32
32
  ## Shared core for every host
@@ -1,13 +1,13 @@
1
1
  # Astra rung
2
2
 
3
3
  Detail behind the **Host profiles → Astra rung** section of [`advisor-protocol.md`](../advisor-protocol.md).
4
- Open this when Fable is out of usage on a Claude or ThirdParty host and an Astra fallback bind is starting.
4
+ Open this when Opus is out of usage on a Claude or ThirdParty host and an Astra fallback bind is starting.
5
5
  On a Codex host, Astra is the in-session default. See [`identity.md`](identity.md).
6
6
 
7
7
  ## Flag
8
8
 
9
- `ADVISOR_ASTRA=1` (or `true` / `yes` / `on`) opens the Astra fallback after Fable is out of usage. Set the variable in the helper's process environment, or pass `--enable-astra` on the helper invocation. The CLI flag opens the rung for that run without touching the environment.
10
- Flag off both ways: fail closed when Fable did not bind.
9
+ `ADVISOR_ASTRA=1` (or `true` / `yes` / `on`) opens the Astra fallback after Opus is out of usage. Set the variable in the helper's process environment, or pass `--enable-astra` on the helper invocation. The CLI flag opens the rung for that run without touching the environment.
10
+ Flag off both ways: fail closed when Opus did not bind.
11
11
  A Windows `setx` write only updates the persisted user environment; only a process started after that write inherits the new value, so an already-running session either sets the flag in its own invoking process environment or passes `--enable-astra`.
12
12
 
13
13
  ## Effort
@@ -28,12 +28,12 @@ python ~/.claude/scripts/codex_account_choice.py choose
28
28
 
29
29
  The shared entry point is `~/.claude/_shared/advisor/scripts/codex_astra_advisor.py`. It runs the picker and owns Astra bind or resume parsing. Bind with `python ~/.claude/_shared/advisor/scripts/codex_astra_advisor.py --bind --enable-astra --cwd <repo-root>` and pipe the charter on stdin. Resume with `--resume <session_id>` and pipe the delta consult on stdin.
30
30
 
31
- The gate passes only when the picker exits 0 and answers `tier: normal` with a `codex_home` and a finite `percent_left`. The helper then runs Codex with `CODEX_HOME` set to that `codex_home`. A `luna` or `wait` answer fails closed when Fable did not bind.
31
+ The gate passes only when the picker exits 0 and answers `tier: normal` with a `codex_home` and a finite `percent_left`. The helper then runs Codex with `CODEX_HOME` set to that `codex_home`. A `luna` or `wait` answer fails closed when Opus did not bind.
32
32
 
33
33
  ## Branches
34
34
 
35
35
  **Preflight pass.** Bind one Codex CLI session at `gpt-6-astra` with `model_reasoning_effort` set from the policy-selected `ADVISOR_EFFORT` value, `--sandbox read-only`, and JSON output. The helper receives the standing-reviewer charter on stdin and returns only parsed ENDORSE / CORRECTION / PLAN / STOP guidance with a session ID.
36
36
 
37
- **Preflight fail.** A picker failure, non-zero exit, timeout, malformed answer, or a `luna` or `wait` tier fails closed when Fable did not bind.
37
+ **Preflight fail.** A picker failure, non-zero exit, timeout, malformed answer, or a `luna` or `wait` tier fails closed when Opus did not bind.
38
38
 
39
- The helper owns the Astra attempt and returns an explicit fallback result. The consuming advisor path owns the Fable bind. Apply the same gate to every Astra attempt, including resume.
39
+ The helper owns the Astra attempt and returns an explicit fallback result. The consuming advisor path owns the Opus bind. Apply the same gate to every Astra attempt, including resume.
@@ -10,18 +10,18 @@ Call `resolve_session_identity` from `$HOME/.claude/_shared/advisor/scripts/tier
10
10
  | Identity text | Host profile | Bind path |
11
11
  |---|---|---|
12
12
  | a `codex` token | Codex | In-session Astra spawn |
13
- | a `claude` token | Claude | In-session Fable spawn of `session-advisor` |
13
+ | a `claude` token | Claude | In-session Opus spawn of `session-advisor` |
14
14
  | any other identity | ThirdParty | Headless CLI chain |
15
15
 
16
16
  When both `codex` and `claude` tokens appear, Codex wins. Empty text is ThirdParty.
17
17
 
18
18
  ## Bind path
19
19
 
20
- **Claude.** Spawn `subagent_type: session-advisor` at Fable through the Agent tool. When Fable is out of usage, bind Astra through the Codex helper if `ADVISOR_ASTRA` is on. Fail closed when neither binds.
20
+ **Claude.** Spawn `subagent_type: session-advisor` at Opus through the Agent tool. When Opus is out of usage, bind Astra through the Codex helper if `ADVISOR_ASTRA` is on. Fail closed when neither binds.
21
21
 
22
- **Codex.** Spawn a native in-session Astra subagent at `resolve_codex_model_id("Astra")` (`gpt-6-astra`). Walk `candidate_tiers = ["Astra"]`. When the spawn tool has a `flags` field, pass `flags: ["--advisor"]` and record `fallback.advisor_flag: "passed"`. When it has none, as in `codex exec`, spawn `gpt-6-astra` plainly and record `fallback.advisor_flag: "unavailable"`. Both count as a bind. Record `{tier: "Astra", result: "spawned"}` on success. The `ADVISOR_ASTRA` flag is not required. Fail closed when Astra does not bind, or when the spawn skips a flag the host offers. Do not walk Fable on a Codex host.
22
+ **Codex.** Spawn a native in-session Astra subagent at `resolve_codex_model_id("Astra")` (`gpt-6-astra`). Walk `candidate_tiers = ["Astra"]`. When the spawn tool has a `flags` field, pass `flags: ["--advisor"]` and record `fallback.advisor_flag: "passed"`. When it has none, as in `codex exec`, spawn `gpt-6-astra` plainly and record `fallback.advisor_flag: "unavailable"`. Both count as a bind. Record `{tier: "Astra", result: "spawned"}` on success. The `ADVISOR_ASTRA` flag is not required. Fail closed when Astra does not bind, or when the spawn skips a flag the host offers. Do not walk Opus on a Codex host.
23
23
 
24
- **ThirdParty.** Bind Fable through the CLI Claude-chain. When Fable is out of usage, bind Astra through the Codex helper if `ADVISOR_ASTRA` is on. Fail closed when neither binds.
24
+ **ThirdParty.** Bind Opus through the CLI Claude-chain. When Opus is out of usage, bind Astra through the Codex helper if `ADVISOR_ASTRA` is on. Fail closed when neither binds.
25
25
 
26
26
  ## Mechanical override
27
27
 
@@ -22,6 +22,6 @@ Every other consumer reaches it by message alone; spawn, respawn, and shutdown b
22
22
 
23
23
  The orchestrating session owns the CLI advisor bind for the whole run: first bind, re-bind on drift or lost `session_id`, and fail-closed report when the bound path cannot serve.
24
24
 
25
- **Re-bind on drift.** If a reply shows a stale picture, the task pivots, or `--resume` fails after a usage-limit failover (session stores are per binary/account), re-bind Fable through `claude_chain_runner.py` with the charter plus a compact recap of consults so far.
26
- Capture the new `session_id`, and log a fresh Fable walk with `result: "cli"` on success, then Astra when that rung is open. An Astra re-bind uses `codex_astra_advisor.py --bind --enable-astra` with the same charter and recap, and records `result: "codex"` on success.
25
+ **Re-bind on drift.** If a reply shows a stale picture, the task pivots, or `--resume` fails after a usage-limit failover (session stores are per binary/account), re-bind Opus through `claude_chain_runner.py` with the charter plus a compact recap of consults so far.
26
+ Capture the new `session_id`, and log a fresh Opus walk with `result: "cli"` on success, then Astra when that rung is open. An Astra re-bind uses `codex_astra_advisor.py --bind --enable-astra` with the same charter and recap, and records `result: "codex"` on success.
27
27
  Executors keep reporting to the orchestrating session; advisor binding stays with that session alone.
@@ -6,10 +6,10 @@ Detail behind the **Model floor** section of [`advisor-protocol.md`](../advisor-
6
6
 
7
7
  Write the log as JSON with these field names:
8
8
 
9
- - `own_tier`: the consuming session's tier (recorded; it does not add Opus to the advisor walk).
9
+ - `own_tier`: the consuming session's tier.
10
10
  - `host_profile`: `Claude`, `Codex`, or `ThirdParty`. Omit to default to `Claude`.
11
- - `candidate_tiers`: on Claude and ThirdParty, Fable, plus Astra when `astra_enabled` is true. On Codex, Astra only.
12
- - `astra_enabled`: a boolean recorded before candidate selection. On Claude and ThirdParty, `true` adds Astra after Fable and `false` walks Fable alone. On Codex this flag does not change the walk.
11
+ - `candidate_tiers`: on Claude and ThirdParty, Opus, plus Astra when `astra_enabled` is true. On Codex, Astra only.
12
+ - `astra_enabled`: a boolean recorded before candidate selection. On Claude and ThirdParty, `true` adds Astra after Opus and `false` walks Opus alone. On Codex this flag does not change the walk.
13
13
  - `attempts`: one `{tier, result}` entry appended as each bind try happens. `result` is `codex` for an Astra helper bind, `spawned` for an in-session spawn (Claude Agent or Codex native Astra), `cli` for a CLI Claude-chain bind, or a failure reason such as `unavailable`.
14
14
  - `selected_tier`: the tier of the first successful bind (first `codex`, `spawned`, or `cli` entry), or `null` paired with a `fallback_reason` string when none bound.
15
15
  - `evidence`: the versioned reference, fallback, and consult record described in `docs/references/advisor-tool.md`. A reference status records optional path repair separately from bind status.
@@ -29,5 +29,5 @@ Exit code `1` means a ladder invariant failed.
29
29
  Exit code `2` means the path or JSON was unusable.
30
30
  The same checks are available in-process via `validate_model_tier_run(run)`.
31
31
 
32
- The validator checks ladder shape and validates `evidence` when it is present. On Claude and ThirdParty, Astra is attempted after Fable when `astra_enabled` is enabled, and `selected_tier: "Astra"` requires `result: "codex"`. On Codex, the walk is Astra only, and `result: "spawned"` or `result: "codex"` counts as success. A Codex success record uses `reply_path: "native"` and `advisor_flag: "passed"` or `advisor_flag: "unavailable"`. A missing `advisor_flag` or `advisor_flag: "omitted"` fails validation.
32
+ The validator checks ladder shape and validates `evidence` when it is present. On Claude and ThirdParty, Astra is attempted after Opus when `astra_enabled` is enabled, and `selected_tier: "Astra"` requires `result: "codex"`. On Codex, the walk is Astra only, and `result: "spawned"` or `result: "codex"` counts as success. A Codex success record uses `reply_path: "native"` and `advisor_flag: "passed"` or `advisor_flag: "unavailable"`. A missing `advisor_flag` or `advisor_flag: "omitted"` fails validation.
33
33
  Host policy sits on top of it. See the Model floor section of the protocol.
@@ -5,7 +5,7 @@ Open this when binding or re-binding the advisor from a third-party (non-Claude,
5
5
 
6
6
  ## GOTCHA: Cursor Astra first shot
7
7
 
8
- Cursor is a third-party host. When the walk reaches Astra (`ADVISOR_ASTRA=1` / `--enable-astra` after Fable is out of usage, or the user asks for Astra), bind Astra on the **first** tool call through the headless Codex helper. Do not use the Agent or Task tool, do not spawn Grok as a substitute, and do not search the filesystem for the Codex account picker.
8
+ Cursor is a third-party host. When the walk reaches Astra (`ADVISOR_ASTRA=1` / `--enable-astra` after Opus is out of usage, or the user asks for Astra), bind Astra on the **first** tool call through the headless Codex helper. Do not use the Agent or Task tool, do not spawn Grok as a substitute, and do not search the filesystem for the Codex account picker.
9
9
 
10
10
  ```
11
11
  python "$HOME/.claude/_shared/advisor/scripts/codex_astra_advisor.py" --bind --enable-astra --cwd <repo-root>
@@ -18,18 +18,18 @@ When the Astra flag is off, follow the Claude-chain steps below.
18
18
  ## Bind steps
19
19
 
20
20
  1. Name the session identity first (protocol **Host profiles**). This path is for a ThirdParty profile.
21
- 2. Walk `candidate_tiers = ["Fable"]`. When Fable is out of usage, the Astra rung ([`astra-rung.md`](astra-rung.md)) binds Astra after Fable (`candidate_tiers = ["Fable", "Astra"]`).
22
- 3. **CLI bind (primary path):** for Fable, pipe a charter file into:
21
+ 2. Walk `candidate_tiers = ["Opus"]`. When Opus is out of usage, the Astra rung ([`astra-rung.md`](astra-rung.md)) binds Astra after Opus (`candidate_tiers = ["Opus", "Astra"]`).
22
+ 3. **CLI bind (primary path):** for Opus, pipe a charter file into:
23
23
 
24
24
  ```
25
25
  python "$HOME/.claude/scripts/claude_chain_runner.py" --routing-mode ordered_account -- -p --model <alias> --effort <effort> --output-format json
26
26
  ```
27
27
 
28
- Use `--model fable --effort` with the value of `ADVISOR_EFFORT` (default `low`) on Fable.
28
+ Use `--model opus --effort` with the value of `ADVISOR_EFFORT` (default `xhigh`) on Opus.
29
29
  User-facing wording follows [`rules/asd-ste100-language.md`](../../../rules/asd-ste100-language.md).
30
30
  A root advisor bind uses `--routing-mode ordered_account`. Walk order, failover, and the `advisor_blocked` terminal status are in [`cli-chain.md`](cli-chain.md).
31
31
  4. Stop at the first successful bind.
32
- Record `{tier, result: "cli"}` for Fable or `{tier: "Astra", result: "codex"}` for the Astra helper, and set `selected_tier` to that tier.
32
+ Record `{tier, result: "cli"}` for Opus or `{tier: "Astra", result: "codex"}` for the Astra helper, and set `selected_tier` to that tier.
33
33
  Persist `session_id` from the JSON events (any event carries it; the runner also surfaces it on `ChainInvocationOutcome.session_id`; reply text is the `type == "result"` event's `.result` field).
34
34
  Run every bind and every later consult with cwd set to the repo root the work is for. Claude sessions are project-scoped by working directory.
35
35
  5. **Fail closed:** when every candidate fails (chain exhausted, `advisor_blocked`, or model unavailable), set `selected_tier = null` and a `fallback_reason`, report that the advisor is unreachable, and **stop**. ENDORSE / CORRECTION / PLAN / STOP come only from a bound advisor.
@@ -38,4 +38,4 @@ When the Astra flag is off, follow the Claude-chain steps below.
38
38
  ## Session model field
39
39
 
40
40
  Resolve a third-party session's own model field with `resolve_cli_model_id("ThirdParty")` → `third-party` when a host model alias is required.
41
- The **advisor** bind uses the Fable alias. Astra binds through the Codex helper.
41
+ The **advisor** bind uses the Opus alias. Astra binds through the Codex helper.
@@ -5,10 +5,10 @@ Open this when binding the warm advisor on a Claude host or a Codex host, and fo
5
5
 
6
6
  ## Spawn fields for a Claude host
7
7
 
8
- The consuming skill's session tries Fable first. Spawn with:
8
+ The consuming skill's session tries Opus first. Spawn with:
9
9
 
10
10
  - `subagent_type: session-advisor` (see [`agents/session-advisor.md`](../../../agents/session-advisor.md) for the full signal contract).
11
- - `model`: the short alias via `resolve_cli_model_id("Fable")` (alias table: [`cli-chain.md`](cli-chain.md)): `fable`. When Fable is out of usage and the Astra rung is open, continue with the Codex helper in [`astra-rung.md`](astra-rung.md) as the Astra fallback.
11
+ - `model`: the short alias via `resolve_cli_model_id("Opus")` (alias table: [`cli-chain.md`](cli-chain.md)): `opus`. When Opus is out of usage and the Astra rung is open, continue with the Codex helper in [`astra-rung.md`](astra-rung.md) as the Astra fallback.
12
12
  - `name`: a name the session and every consumer will use to reach it (e.g. `team-advisor-agent`).
13
13
  - `run_in_background: true`.
14
14
  - `prompt`: the charter below.
@@ -34,7 +34,7 @@ Spawn a native in-session Astra subagent at `resolve_codex_model_id("Astra")` (`
34
34
  When the spawn tool has a `flags` field, pass `flags: ["--advisor"]` and record `fallback.advisor_flag: "passed"`.
35
35
  When the spawn tool has no `flags` field, as in `codex exec`, spawn `gpt-6-astra` plainly, record `fallback.advisor_flag: "unavailable"`, and treat the advisor as bound.
36
36
  Record `{tier: "Astra", result: "spawned"}` on success. Fail closed when that spawn does not bind, or when it skips a flag the host offers.
37
- The `ADVISOR_ASTRA` flag is not required. Do not walk Fable. Consults stay in-session with that Astra subagent.
37
+ The `ADVISOR_ASTRA` flag is not required. Do not walk Opus. Consults stay in-session with that Astra subagent.
38
38
  Identity routing: [`identity.md`](identity.md).
39
39
 
40
40
  ## Third-party host
@@ -6,8 +6,8 @@ import json
6
6
  from pathlib import Path
7
7
 
8
8
  ADVISOR_MODEL_TIER: str = "Astra"
9
- ADVISOR_FALLBACK_TIER: str = "Fable"
10
- ADVISOR_FALLBACK_RESULT: str = "fable"
9
+ ADVISOR_FALLBACK_TIER: str = "Opus"
10
+ ADVISOR_FALLBACK_RESULT: str = "opus"
11
11
  ADVISOR_EFFORT_ENV_VAR: str = "ADVISOR_EFFORT"
12
12
  ADVISOR_ROUTING_TIMEOUT_SECONDS: int = 10
13
13
 
@@ -43,8 +43,8 @@ SESSION_IDENTITY_WORD_PATTERN: str = r"[a-z0-9]+"
43
43
  HOST_PROFILE_JSON_KEY: str = "host_profile"
44
44
 
45
45
  ALL_MODEL_TIERS: tuple[str, ...] = (
46
+ "Fable",
46
47
  ADVISOR_FALLBACK_TIER,
47
- "Opus",
48
48
  "Sonnet",
49
49
  "Haiku",
50
50
  )
@@ -58,8 +58,8 @@ ALL_KNOWN_TIER_NAMES: tuple[str, ...] = (
58
58
  ADVISOR_SENDMESSAGE_REPLY_WAIT_SECONDS: int = 120
59
59
 
60
60
  ALL_CLI_MODEL_ID_BY_TIER: dict[str, str] = {
61
- ADVISOR_FALLBACK_TIER: "fable",
62
- "Opus": "opus",
61
+ "Fable": "fable",
62
+ ADVISOR_FALLBACK_TIER: "opus",
63
63
  "Sonnet": "sonnet",
64
64
  "Haiku": "haiku",
65
65
  THIRD_PARTY_MODEL_TIER: "third-party",
@@ -7,17 +7,17 @@ This validator reads that log back and checks its invariants.
7
7
 
8
8
  ladder_walk = ModelTierRun(
9
9
  own_tier="Opus",
10
- candidate_tiers=["Fable"],
11
- attempts=[{"tier": "Fable", "result": "spawned"}],
12
- selected_tier="Fable",
10
+ candidate_tiers=["Opus"],
11
+ attempts=[{"tier": "Opus", "result": "spawned"}],
12
+ selected_tier="Opus",
13
13
  )
14
14
  validate_model_tier_run(ladder_walk) # ok: returns None, raises nothing
15
15
 
16
16
  cli_bind = ModelTierRun(
17
17
  own_tier="Opus",
18
- candidate_tiers=["Fable"],
19
- attempts=[{"tier": "Fable", "result": "cli"}],
20
- selected_tier="Fable",
18
+ candidate_tiers=["Opus"],
19
+ attempts=[{"tier": "Opus", "result": "cli"}],
20
+ selected_tier="Opus",
21
21
  )
22
22
  validate_model_tier_run(cli_bind) # ok: third-party-host CLI Claude-chain bind
23
23
 
@@ -330,10 +330,9 @@ def validate_model_tier_run(run: ModelTierRun) -> None:
330
330
  validate_model_tier_run(cli_bind) # ok: CLI Claude-chain bind
331
331
  validate_model_tier_run(broken_log) # flag: ModelTierRunError
332
332
 
333
- Candidate tiers are Fable, plus Astra when ``is_astra_enabled`` is true, on
333
+ Candidate tiers are Opus, plus Astra when ``is_astra_enabled`` is true, on
334
334
  Claude and ThirdParty hosts. A Codex host walks Astra only. Consumer
335
- ``own_tier`` is recorded and must be a known tier. It does not add Opus
336
- to the advisor walk. Tries walk that list in order. Early stop only
335
+ ``own_tier`` is recorded and must be a known tier. Tries walk that list in order. Early stop only
337
336
  after ``spawned``, ``cli``, or Astra ``codex`` (and Astra ``spawned`` on a
338
337
  Codex host). A null selected_tier requires a full walk plus
339
338
  fallback_reason.
@@ -218,19 +218,19 @@ def test_non_object_evidence_reports_the_same_message_at_validate_and_load(
218
218
  def test_clean_single_spawn_at_top_of_slice_passes() -> None:
219
219
  run = ModelTierRun(
220
220
  own_tier="Opus",
221
- candidate_tiers=["Fable"],
222
- attempts=[{"tier": "Fable", "result": "spawned"}],
223
- selected_tier="Fable",
221
+ candidate_tiers=["Opus"],
222
+ attempts=[{"tier": "Opus", "result": "spawned"}],
223
+ selected_tier="Opus",
224
224
  )
225
225
  assert validate_model_tier_run(run) is None
226
226
 
227
227
 
228
- def test_astra_codex_bind_succeeds_after_fable_when_enabled() -> None:
228
+ def test_astra_codex_bind_succeeds_after_opus_when_enabled() -> None:
229
229
  run = ModelTierRun(
230
230
  own_tier="Opus",
231
- candidate_tiers=["Fable", ADVISOR_MODEL_TIER],
231
+ candidate_tiers=["Opus", ADVISOR_MODEL_TIER],
232
232
  attempts=[
233
- {"tier": "Fable", "result": "unavailable"},
233
+ {"tier": "Opus", "result": "unavailable"},
234
234
  {"tier": ADVISOR_MODEL_TIER, "result": CODEX_BIND_SUCCESS_TOKEN},
235
235
  ],
236
236
  selected_tier=ADVISOR_MODEL_TIER,
@@ -239,12 +239,12 @@ def test_astra_codex_bind_succeeds_after_fable_when_enabled() -> None:
239
239
  assert validate_model_tier_run(run) is None
240
240
 
241
241
 
242
- def test_fable_success_with_astra_enabled_stops_before_astra() -> None:
242
+ def test_opus_success_with_astra_enabled_stops_before_astra() -> None:
243
243
  run = ModelTierRun(
244
244
  own_tier="Opus",
245
- candidate_tiers=["Fable", ADVISOR_MODEL_TIER],
246
- attempts=[{"tier": "Fable", "result": "spawned"}],
247
- selected_tier="Fable",
245
+ candidate_tiers=["Opus", ADVISOR_MODEL_TIER],
246
+ attempts=[{"tier": "Opus", "result": "spawned"}],
247
+ selected_tier="Opus",
248
248
  is_astra_enabled=True,
249
249
  )
250
250
  assert validate_model_tier_run(run) is None
@@ -253,7 +253,7 @@ def test_fable_success_with_astra_enabled_stops_before_astra() -> None:
253
253
  def test_astra_first_walk_raises_when_astra_is_enabled() -> None:
254
254
  run = ModelTierRun(
255
255
  own_tier="Opus",
256
- candidate_tiers=[ADVISOR_MODEL_TIER, "Fable"],
256
+ candidate_tiers=[ADVISOR_MODEL_TIER, "Opus"],
257
257
  attempts=[{"tier": ADVISOR_MODEL_TIER, "result": CODEX_BIND_SUCCESS_TOKEN}],
258
258
  selected_tier=ADVISOR_MODEL_TIER,
259
259
  is_astra_enabled=True,
@@ -262,12 +262,12 @@ def test_astra_first_walk_raises_when_astra_is_enabled() -> None:
262
262
  validate_model_tier_run(run)
263
263
 
264
264
 
265
- def test_astra_rung_follows_fable_on_third_party_cli_floor_when_enabled() -> None:
265
+ def test_astra_rung_follows_opus_on_third_party_cli_floor_when_enabled() -> None:
266
266
  run = ModelTierRun(
267
267
  own_tier="ThirdParty",
268
- candidate_tiers=["Fable", ADVISOR_MODEL_TIER],
268
+ candidate_tiers=["Opus", ADVISOR_MODEL_TIER],
269
269
  attempts=[
270
- {"tier": "Fable", "result": "unavailable"},
270
+ {"tier": "Opus", "result": "unavailable"},
271
271
  {"tier": ADVISOR_MODEL_TIER, "result": CODEX_BIND_SUCCESS_TOKEN},
272
272
  ],
273
273
  selected_tier=ADVISOR_MODEL_TIER,
@@ -281,9 +281,9 @@ def test_astra_rung_follows_fable_on_third_party_cli_floor_when_enabled() -> Non
281
281
  def test_astra_codex_result_requires_astra_candidate() -> None:
282
282
  run = ModelTierRun(
283
283
  own_tier="Opus",
284
- candidate_tiers=["Fable"],
285
- attempts=[{"tier": "Fable", "result": CODEX_BIND_SUCCESS_TOKEN}],
286
- selected_tier="Fable",
284
+ candidate_tiers=["Opus"],
285
+ attempts=[{"tier": "Opus", "result": CODEX_BIND_SUCCESS_TOKEN}],
286
+ selected_tier="Opus",
287
287
  )
288
288
  with pytest.raises(ModelTierRunError):
289
289
  validate_model_tier_run(run)
@@ -292,9 +292,9 @@ def test_astra_codex_result_requires_astra_candidate() -> None:
292
292
  def test_astra_spawned_result_does_not_count_as_codex_success() -> None:
293
293
  run = ModelTierRun(
294
294
  own_tier="Opus",
295
- candidate_tiers=["Fable", ADVISOR_MODEL_TIER],
295
+ candidate_tiers=["Opus", ADVISOR_MODEL_TIER],
296
296
  attempts=[
297
- {"tier": "Fable", "result": "unavailable"},
297
+ {"tier": "Opus", "result": "unavailable"},
298
298
  {"tier": ADVISOR_MODEL_TIER, "result": "spawned"},
299
299
  ],
300
300
  selected_tier=ADVISOR_MODEL_TIER,
@@ -304,13 +304,13 @@ def test_astra_spawned_result_does_not_count_as_codex_success() -> None:
304
304
  validate_model_tier_run(run)
305
305
 
306
306
 
307
- def test_exhausted_fable_walk_fails_closed() -> None:
307
+ def test_exhausted_opus_walk_fails_closed() -> None:
308
308
  run = ModelTierRun(
309
309
  own_tier="Opus",
310
- candidate_tiers=["Fable"],
311
- attempts=[{"tier": "Fable", "result": "unavailable"}],
310
+ candidate_tiers=["Opus"],
311
+ attempts=[{"tier": "Opus", "result": "unavailable"}],
312
312
  selected_tier=None,
313
- fallback_reason="Fable did not bind; no advisor",
313
+ fallback_reason="Opus did not bind; no advisor",
314
314
  )
315
315
  assert validate_model_tier_run(run) is None
316
316
 
@@ -318,8 +318,8 @@ def test_exhausted_fable_walk_fails_closed() -> None:
318
318
  def test_fully_exhausted_walk_with_fallback_reason_passes() -> None:
319
319
  run = ModelTierRun(
320
320
  own_tier="Opus",
321
- candidate_tiers=["Fable"],
322
- attempts=[{"tier": "Fable", "result": "unavailable"}],
321
+ candidate_tiers=["Opus"],
322
+ attempts=[{"tier": "Opus", "result": "unavailable"}],
323
323
  selected_tier=None,
324
324
  fallback_reason="every candidate tier failed",
325
325
  )
@@ -329,9 +329,9 @@ def test_fully_exhausted_walk_with_fallback_reason_passes() -> None:
329
329
  def test_opus_candidate_on_advisor_walk_raises() -> None:
330
330
  run = ModelTierRun(
331
331
  own_tier="Opus",
332
- candidate_tiers=["Fable", "Opus"],
333
- attempts=[{"tier": "Fable", "result": "spawned"}],
334
- selected_tier="Fable",
332
+ candidate_tiers=["Opus", "Opus"],
333
+ attempts=[{"tier": "Opus", "result": "spawned"}],
334
+ selected_tier="Opus",
335
335
  )
336
336
  with pytest.raises(ModelTierRunError):
337
337
  validate_model_tier_run(run)
@@ -340,7 +340,7 @@ def test_opus_candidate_on_advisor_walk_raises() -> None:
340
340
  def test_attempt_tier_outside_candidate_slice_raises() -> None:
341
341
  run = ModelTierRun(
342
342
  own_tier="Opus",
343
- candidate_tiers=["Fable"],
343
+ candidate_tiers=["Opus"],
344
344
  attempts=[{"tier": "Haiku", "result": "spawned"}],
345
345
  selected_tier="Haiku",
346
346
  )
@@ -351,10 +351,10 @@ def test_attempt_tier_outside_candidate_slice_raises() -> None:
351
351
  def test_attempts_out_of_ladder_order_raises() -> None:
352
352
  run = ModelTierRun(
353
353
  own_tier="Opus",
354
- candidate_tiers=["Fable", ADVISOR_MODEL_TIER],
354
+ candidate_tiers=["Opus", ADVISOR_MODEL_TIER],
355
355
  attempts=[
356
356
  {"tier": ADVISOR_MODEL_TIER, "result": CODEX_BIND_SUCCESS_TOKEN},
357
- {"tier": "Fable", "result": "unavailable"},
357
+ {"tier": "Opus", "result": "unavailable"},
358
358
  ],
359
359
  selected_tier=ADVISOR_MODEL_TIER,
360
360
  is_astra_enabled=True,
@@ -366,12 +366,12 @@ def test_attempts_out_of_ladder_order_raises() -> None:
366
366
  def test_selected_tier_not_first_spawned_attempt_raises() -> None:
367
367
  run = ModelTierRun(
368
368
  own_tier="Opus",
369
- candidate_tiers=["Fable", ADVISOR_MODEL_TIER],
369
+ candidate_tiers=["Opus", ADVISOR_MODEL_TIER],
370
370
  attempts=[
371
- {"tier": "Fable", "result": "unavailable"},
371
+ {"tier": "Opus", "result": "unavailable"},
372
372
  {"tier": ADVISOR_MODEL_TIER, "result": CODEX_BIND_SUCCESS_TOKEN},
373
373
  ],
374
- selected_tier="Fable",
374
+ selected_tier="Opus",
375
375
  is_astra_enabled=True,
376
376
  )
377
377
  with pytest.raises(
@@ -387,9 +387,9 @@ def test_selected_tier_not_first_spawned_attempt_raises() -> None:
387
387
  def test_exhausted_walk_with_non_null_selected_tier_raises() -> None:
388
388
  run = ModelTierRun(
389
389
  own_tier="Opus",
390
- candidate_tiers=["Fable"],
391
- attempts=[{"tier": "Fable", "result": "unavailable"}],
392
- selected_tier="Fable",
390
+ candidate_tiers=["Opus"],
391
+ attempts=[{"tier": "Opus", "result": "unavailable"}],
392
+ selected_tier="Opus",
393
393
  fallback_reason="every candidate tier failed",
394
394
  )
395
395
  with pytest.raises(ModelTierRunError):
@@ -399,8 +399,8 @@ def test_exhausted_walk_with_non_null_selected_tier_raises() -> None:
399
399
  def test_exhausted_walk_missing_fallback_reason_raises() -> None:
400
400
  run = ModelTierRun(
401
401
  own_tier="Opus",
402
- candidate_tiers=["Fable"],
403
- attempts=[{"tier": "Fable", "result": "unavailable"}],
402
+ candidate_tiers=["Opus"],
403
+ attempts=[{"tier": "Opus", "result": "unavailable"}],
404
404
  selected_tier=None,
405
405
  )
406
406
  with pytest.raises(ModelTierRunError):
@@ -421,7 +421,7 @@ def test_unknown_own_tier_raises() -> None:
421
421
  def test_empty_attempts_with_null_selected_tier_raises() -> None:
422
422
  run = ModelTierRun(
423
423
  own_tier="Opus",
424
- candidate_tiers=["Fable"],
424
+ candidate_tiers=["Opus"],
425
425
  attempts=[],
426
426
  selected_tier=None,
427
427
  fallback_reason="skipped straight to CLI fallback",
@@ -433,10 +433,10 @@ def test_empty_attempts_with_null_selected_tier_raises() -> None:
433
433
  def test_incomplete_fallback_walk_before_astra_raises() -> None:
434
434
  run = ModelTierRun(
435
435
  own_tier="Opus",
436
- candidate_tiers=["Fable", ADVISOR_MODEL_TIER],
437
- attempts=[{"tier": "Fable", "result": "unavailable"}],
436
+ candidate_tiers=["Opus", ADVISOR_MODEL_TIER],
437
+ attempts=[{"tier": "Opus", "result": "unavailable"}],
438
438
  selected_tier=None,
439
- fallback_reason="stopped after Fable without trying Astra",
439
+ fallback_reason="stopped after Opus without trying Astra",
440
440
  is_astra_enabled=True,
441
441
  )
442
442
  with pytest.raises(ModelTierRunError):
@@ -446,9 +446,9 @@ def test_incomplete_fallback_walk_before_astra_raises() -> None:
446
446
  def test_lowercase_own_tier_and_candidates_pass() -> None:
447
447
  run = ModelTierRun(
448
448
  own_tier="opus",
449
- candidate_tiers=["fable"],
450
- attempts=[{"tier": "fable", "result": "spawned"}],
451
- selected_tier="fable",
449
+ candidate_tiers=["opus"],
450
+ attempts=[{"tier": "opus", "result": "spawned"}],
451
+ selected_tier="opus",
452
452
  )
453
453
  assert validate_model_tier_run(run) is None
454
454
 
@@ -459,16 +459,16 @@ def test_cli_validates_json_log_file(tmp_path: Path) -> None:
459
459
  json.dumps(
460
460
  {
461
461
  "own_tier": "Opus",
462
- "candidate_tiers": ["Fable"],
463
- "attempts": [{"tier": "Fable", "result": "spawned"}],
464
- "selected_tier": "Fable",
462
+ "candidate_tiers": ["Opus"],
463
+ "attempts": [{"tier": "Opus", "result": "spawned"}],
464
+ "selected_tier": "Opus",
465
465
  }
466
466
  ),
467
467
  encoding="utf-8",
468
468
  )
469
469
  assert main([str(log_path)]) == 0
470
470
  loaded_run = load_model_tier_run_from_json_path(from_path=log_path)
471
- assert loaded_run.selected_tier == "Fable"
471
+ assert loaded_run.selected_tier == "Opus"
472
472
  assert loaded_run.host_profile == "Claude"
473
473
 
474
474
 
@@ -478,9 +478,9 @@ def test_cli_rejects_non_string_host_profile(tmp_path: Path) -> None:
478
478
  json.dumps(
479
479
  {
480
480
  "own_tier": "Opus",
481
- "candidate_tiers": ["Fable"],
482
- "attempts": [{"tier": "Fable", "result": "spawned"}],
483
- "selected_tier": "Fable",
481
+ "candidate_tiers": ["Opus"],
482
+ "attempts": [{"tier": "Opus", "result": "spawned"}],
483
+ "selected_tier": "Opus",
484
484
  "host_profile": 1,
485
485
  }
486
486
  ),
@@ -495,9 +495,9 @@ def test_cli_rejects_non_boolean_astra_enabled(tmp_path: Path) -> None:
495
495
  json.dumps(
496
496
  {
497
497
  "own_tier": "Opus",
498
- "candidate_tiers": ["Fable"],
499
- "attempts": [{"tier": "Fable", "result": "spawned"}],
500
- "selected_tier": "Fable",
498
+ "candidate_tiers": ["Opus"],
499
+ "attempts": [{"tier": "Opus", "result": "spawned"}],
500
+ "selected_tier": "Opus",
501
501
  "astra_enabled": "false",
502
502
  }
503
503
  ),
@@ -512,8 +512,8 @@ def test_cli_rejects_incomplete_fallback_log(tmp_path: Path) -> None:
512
512
  json.dumps(
513
513
  {
514
514
  "own_tier": "Opus",
515
- "candidate_tiers": ["Fable", "Astra"],
516
- "attempts": [{"tier": "Fable", "result": "unavailable"}],
515
+ "candidate_tiers": ["Opus", "Astra"],
516
+ "attempts": [{"tier": "Opus", "result": "unavailable"}],
517
517
  "selected_tier": None,
518
518
  "fallback_reason": "incomplete",
519
519
  "astra_enabled": True,
@@ -531,9 +531,9 @@ def test_cli_loads_astra_enabled_fallback_walk(tmp_path: Path) -> None:
531
531
  {
532
532
  "own_tier": "ThirdParty",
533
533
  "host_profile": "ThirdParty",
534
- "candidate_tiers": ["Fable", "Astra"],
534
+ "candidate_tiers": ["Opus", "Astra"],
535
535
  "attempts": [
536
- {"tier": "Fable", "result": "unavailable"},
536
+ {"tier": "Opus", "result": "unavailable"},
537
537
  {"tier": "Astra", "result": "codex"},
538
538
  ],
539
539
  "selected_tier": "Astra",
@@ -552,12 +552,12 @@ def test_cli_missing_path_returns_usage_exit_code() -> None:
552
552
  assert main([]) == 2
553
553
 
554
554
 
555
- def test_cli_bind_at_fable_passes() -> None:
555
+ def test_cli_bind_at_opus_passes() -> None:
556
556
  run = ModelTierRun(
557
557
  own_tier="Opus",
558
- candidate_tiers=["Fable"],
559
- attempts=[{"tier": "Fable", "result": "cli"}],
560
- selected_tier="Fable",
558
+ candidate_tiers=["Opus"],
559
+ attempts=[{"tier": "Opus", "result": "cli"}],
560
+ selected_tier="Opus",
561
561
  )
562
562
  assert validate_model_tier_run(run) is None
563
563
 
@@ -565,9 +565,9 @@ def test_cli_bind_at_fable_passes() -> None:
565
565
  def test_cli_bind_fallthrough_to_opus_raises() -> None:
566
566
  run = ModelTierRun(
567
567
  own_tier="Opus",
568
- candidate_tiers=["Fable", "Opus"],
568
+ candidate_tiers=["Opus", "Opus"],
569
569
  attempts=[
570
- {"tier": "Fable", "result": "unavailable"},
570
+ {"tier": "Opus", "result": "unavailable"},
571
571
  {"tier": "Opus", "result": "cli"},
572
572
  ],
573
573
  selected_tier="Opus",
@@ -576,12 +576,12 @@ def test_cli_bind_fallthrough_to_opus_raises() -> None:
576
576
  validate_model_tier_run(run)
577
577
 
578
578
 
579
- def test_third_party_own_tier_maps_to_fable_cli_bind_passes() -> None:
579
+ def test_third_party_own_tier_maps_to_opus_cli_bind_passes() -> None:
580
580
  run = ModelTierRun(
581
581
  own_tier="ThirdParty",
582
- candidate_tiers=["Fable"],
583
- attempts=[{"tier": "Fable", "result": "cli"}],
584
- selected_tier="Fable",
582
+ candidate_tiers=["Opus"],
583
+ attempts=[{"tier": "Opus", "result": "cli"}],
584
+ selected_tier="Opus",
585
585
  )
586
586
  assert validate_model_tier_run(run) is None
587
587
 
@@ -589,9 +589,9 @@ def test_third_party_own_tier_maps_to_fable_cli_bind_passes() -> None:
589
589
  def test_third_party_own_tier_lowercase_cli_bind_passes() -> None:
590
590
  run = ModelTierRun(
591
591
  own_tier="thirdparty",
592
- candidate_tiers=["fable"],
593
- attempts=[{"tier": "fable", "result": "cli"}],
594
- selected_tier="fable",
592
+ candidate_tiers=["opus"],
593
+ attempts=[{"tier": "opus", "result": "cli"}],
594
+ selected_tier="opus",
595
595
  )
596
596
  assert validate_model_tier_run(run) is None
597
597
 
@@ -599,9 +599,9 @@ def test_third_party_own_tier_lowercase_cli_bind_passes() -> None:
599
599
  def test_self_token_is_not_bind_success_raises() -> None:
600
600
  run = ModelTierRun(
601
601
  own_tier="Opus",
602
- candidate_tiers=["Fable"],
603
- attempts=[{"tier": "Fable", "result": "self"}],
604
- selected_tier="Fable",
602
+ candidate_tiers=["Opus"],
603
+ attempts=[{"tier": "Opus", "result": "self"}],
604
+ selected_tier="Opus",
605
605
  )
606
606
  with pytest.raises(ModelTierRunError):
607
607
  validate_model_tier_run(run)
@@ -610,9 +610,9 @@ def test_self_token_is_not_bind_success_raises() -> None:
610
610
  def test_third_party_self_token_is_not_bind_success_raises() -> None:
611
611
  run = ModelTierRun(
612
612
  own_tier="ThirdParty",
613
- candidate_tiers=["Fable"],
614
- attempts=[{"tier": "Fable", "result": "self"}],
615
- selected_tier="Fable",
613
+ candidate_tiers=["Opus"],
614
+ attempts=[{"tier": "Opus", "result": "self"}],
615
+ selected_tier="Opus",
616
616
  )
617
617
  with pytest.raises(ModelTierRunError):
618
618
  validate_model_tier_run(run)
@@ -632,8 +632,8 @@ def test_third_party_host_legacy_single_tier_self_bind_raises() -> None:
632
632
  def test_third_party_cli_exhausted_fail_closed_passes() -> None:
633
633
  run = ModelTierRun(
634
634
  own_tier="ThirdParty",
635
- candidate_tiers=["Fable"],
636
- attempts=[{"tier": "Fable", "result": "unavailable"}],
635
+ candidate_tiers=["Opus"],
636
+ attempts=[{"tier": "Opus", "result": "unavailable"}],
637
637
  selected_tier=None,
638
638
  fallback_reason=(
639
639
  "third-party host CLI Claude-chain exhausted; fail closed"
@@ -645,8 +645,8 @@ def test_third_party_cli_exhausted_fail_closed_passes() -> None:
645
645
  def test_third_party_cli_exhausted_without_fallback_reason_raises() -> None:
646
646
  run = ModelTierRun(
647
647
  own_tier="ThirdParty",
648
- candidate_tiers=["Fable"],
649
- attempts=[{"tier": "Fable", "result": "unavailable"}],
648
+ candidate_tiers=["Opus"],
649
+ attempts=[{"tier": "Opus", "result": "unavailable"}],
650
650
  selected_tier=None,
651
651
  )
652
652
  with pytest.raises(ModelTierRunError):
@@ -656,9 +656,9 @@ def test_third_party_cli_exhausted_without_fallback_reason_raises() -> None:
656
656
  def test_third_party_cli_selected_tier_mismatch_raises() -> None:
657
657
  run = ModelTierRun(
658
658
  own_tier="ThirdParty",
659
- candidate_tiers=["Fable"],
660
- attempts=[{"tier": "Fable", "result": "cli"}],
661
- selected_tier="Opus",
659
+ candidate_tiers=["Opus"],
660
+ attempts=[{"tier": "Opus", "result": "cli"}],
661
+ selected_tier="Sonnet",
662
662
  )
663
663
  with pytest.raises(ModelTierRunError):
664
664
  validate_model_tier_run(run)
@@ -667,9 +667,9 @@ def test_third_party_cli_selected_tier_mismatch_raises() -> None:
667
667
  def test_claude_host_self_token_is_not_spawn_success_raises() -> None:
668
668
  run = ModelTierRun(
669
669
  own_tier="Opus",
670
- candidate_tiers=["Fable"],
671
- attempts=[{"tier": "Fable", "result": "self"}],
672
- selected_tier="Fable",
670
+ candidate_tiers=["Opus"],
671
+ attempts=[{"tier": "Opus", "result": "self"}],
672
+ selected_tier="Opus",
673
673
  )
674
674
  with pytest.raises(ModelTierRunError):
675
675
  validate_model_tier_run(run)
@@ -699,10 +699,10 @@ def test_codex_host_astra_codex_token_counts_as_success() -> None:
699
699
  assert validate_model_tier_run(run) is None
700
700
 
701
701
 
702
- def test_codex_host_fable_then_astra_walk_raises() -> None:
702
+ def test_codex_host_opus_then_astra_walk_raises() -> None:
703
703
  run = ModelTierRun(
704
704
  own_tier="Opus",
705
- candidate_tiers=["Fable", ADVISOR_MODEL_TIER],
705
+ candidate_tiers=["Opus", ADVISOR_MODEL_TIER],
706
706
  attempts=[{"tier": ADVISOR_MODEL_TIER, "result": "spawned"}],
707
707
  selected_tier=ADVISOR_MODEL_TIER,
708
708
  is_astra_enabled=True,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-dev-env",
3
- "version": "8.13.0",
3
+ "version": "8.14.0",
4
4
  "description": "Claude Code development standards — rules, hooks, agents, commands, and skills",
5
5
  "type": "module",
6
6
  "bin": {