Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .agents/plugins/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
{
"name": "case-solvers",
"source": { "source": "local", "path": "./plugins/case-solvers" },
"version": "2.24.0",
"version": "2.24.1",
"policy": { "installation": "AVAILABLE", "authentication": "ON_USE" },
"category": "Productivity"
},
Expand Down
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"name": "case-solvers",
"source": "./plugins/case-solvers",
"description": "A bd-backed, parallel-capable workflow: /case authors stories/epics in Beads, /refine revises a story, /board shows the backlog, /solve implements one in an isolated worktree, /evaluate merges after human review, /orchestrate automates the solve-review-land loop for a whole epic behind one final PR. Requires the bd (Beads) CLI.",
"version": "2.24.0",
"version": "2.24.1",
"author": { "name": "nadiar", "email": "codex@nadiar.id" },
"license": "MIT",
"category": "workflow",
Expand Down
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,25 @@ versions (shown in parentheses where relevant).

## [Unreleased]

## [2.24.1] - 2026-07-20

Plugin & marketplace entry `case-solvers` `2.24.0` → `2.24.1`. `/case` (`2.10.0` → `2.10.1`),
`/refine` (`1.9.0` → `1.9.1`), `/orchestrate` (`1.5.0` → `1.5.1`), `/solve` (`1.7.0` → `1.7.1`),
`/evaluate` (`1.14.0` → `1.14.1`).

**Changed: the shared model-tiers map no longer inlines reviewer-pinning into skills that never use
it.** `shared/model-tiers.md` bundled two things — **Tier classification** (needed by all five
skills, which each classify their own model) and **Reviewer pinning by host** (consumed only by
`/evaluate`) — and inlined the whole bundle into every skill. That put ~30 lines of `/evaluate`-voiced
reviewer-pinning instructions ("`/evaluate`'s request-changes path must…") into `/case`, `/refine`,
`/solve`, and `/orchestrate`, where they were both dead weight and addressed to the wrong skill.

The shared block now carries **Tier classification only**, still synced into all five skills by
`tests/model-tiers-sync.sh`. **Reviewer pinning by host** moved into `skills/evaluate/SKILL.md` as
native prose — `/evaluate` is its sole consumer, and its step 4b.1 already points at it — and the
redundant host table was dropped in favor of the capability-keyed branch list it duplicated. No
behavior change: the pinning logic is identical, just relocated and de-duplicated.

## [2.24.0] - 2026-07-20

Plugin & marketplace entry `case-solvers` `2.23.1` → `2.24.0`. `/case` (`2.9.1` → `2.10.0`),
Expand Down
2 changes: 1 addition & 1 deletion plugins/case-solvers/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
"name": "case-solvers",
"displayName": "Case Solvers",
"version": "2.24.0",
"version": "2.24.1",
"description": "A bd-backed, parallel-capable coding workflow: /case (planning model) authors stories/epics in Beads and /refine revises them, /board renders the backlog, /solve (budget model) implements one in an isolated git worktree, /evaluate merges it after human review, /orchestrate (planning model) automates the solve-review-land loop for a whole epic behind one final PR. Dependency-aware; bd stays hidden behind the commands. Requires the bd (Beads) CLI.",
"author": { "name": "nadiar", "email": "codex@nadiar.id" },
"homepage": "https://github.com/codxse/case-solvers",
Expand Down
2 changes: 1 addition & 1 deletion plugins/case-solvers/.codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "case-solvers",
"version": "2.24.0+codex.20260720202018",
"version": "2.24.1+codex.20260720211527",
"description": "A bd-backed, parallel-capable coding workflow: /case (frontier model) authors stories/epics in Beads and /refine revises them, /board renders the backlog, /solve (any model tier) implements one in an isolated git worktree, /evaluate merges it after human review, /orchestrate (frontier model) automates the solve-review-land loop for a whole epic behind one final PR. Dependency-aware; bd stays hidden behind the commands. Requires the bd (Beads) CLI.",
"author": {
"name": "nadiar",
Expand Down
39 changes: 4 additions & 35 deletions plugins/case-solvers/shared/model-tiers.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Model Tiers — shared by all case-solvers skills

The model-tier map for the whole plugin: which model IDs are **budget** vs **planning**, and how
each host pins a frontier reviewer. Every skill classifies its own model from its ID by the rules
below; `/evaluate` additionally uses the host map to pin its reviewer. The rules are identical
across skills, so they are written once, here.
The model-tier classification for the whole plugin: which model IDs are **budget** vs **planning**.
Every skill classifies its own model from its ID by the rules below — the rules are identical across
skills, so they are written once, here. (Reviewer pinning — how `/evaluate` picks a frontier
reviewer — has a single consumer and lives natively in `skills/evaluate/SKILL.md`, not here.)

**This file is the single source of truth, but it is not read at runtime.** Everything below
`BEGIN SHARED` is inlined verbatim into a `Model Tiers` section of each SKILL.md by
Expand Down Expand Up @@ -38,35 +38,4 @@ model (`/case`, `/refine`, `/orchestrate`) proceeds only on `planning` and stops
`unsure`; a skill that merely notes its tier (`/solve`) treats `planning` as frontier and the rest as
budget.

## Reviewer pinning by host

`/evaluate`'s request-changes path must run its review pass on a **frontier** reviewer, regardless of
what model `/evaluate` itself runs on (it carries no model gate). How the reviewer's model is pinned
depends on what the host can do. Detect the host from the session's model ID:

| Host | Session model ID | Reviewer pin |
|---|---|---|
| **Claude Code** (native) | a Claude marker (`opus`/`sonnet`/`haiku`/`fable`/`mythos`) | the shipped reviewer agents — `case-reviewer` (cheapest frontier) / `case-reviewer-strong` (strongest); the pin lives in the agent definition |
| **Codex** (native) | a GPT-5 marker (`gpt-5…`) | the shipped reviewer agents (TOMLs copied into `.codex/agents/`); same two rungs, pinned to Codex's base / strongest GPT-5-class |
| **Custom host** (e.g. a router) | neither native marker, but classifies as **planning** (e.g. `qwen3.8-max-preview`) | a general subagent pinned to the **session's own model ID** — the host accepts literal IDs; one frontier tier |
| **None of the above** | budget / `unsure`, and no usable native agents | **stop** — no frontier reviewer can be pinned |

Take the first branch that applies:

1. **Native host that lists the shipped reviewer agents** (session model carries a Claude or GPT-5
marker, and the host lists `case-reviewer`/`case-reviewer-strong`) → use the agents; the pin lives
in the definition and is enforced by the harness. Two-tier cost-keying and the same-class step-up
apply (the roster offers a cheapest and a strongest rung).
2. **Else the session model classifies as planning** (a custom frontier host) → spawn a general
subagent pinned to the **session's own model ID**. One frontier tier — cost-keying and the
same-class step-up both point at it; the rule degrades to a single pin, it never errors.
3. **Else** → **stop** and tell the user no frontier reviewer can be pinned.

Rules that bind every branch:
- **Never pin or inherit a budget ID**, and never run the review inline on `/evaluate`'s own model
instead of spawning a subagent. No frontier model to pin → stop; do not fall back to a budget
reviewer.
- **Spawn anonymously — never pass a `name`**: named teammates can't be spawned from inside another
agent, and nothing needs to address the reviewer after it reports.

<!-- END SHARED -->
33 changes: 1 addition & 32 deletions plugins/case-solvers/skills/case/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: case
description: 'Author one bd story, or decompose a large goal into an epic, on a planning model. Authoring only — view the board with /board, revise an existing story with /refine. Use when the user asks to open/file a case, put a problem or goal "to a case", or write a new story or epic — e.g. "let''s put our problem to a case".'
version: 2.10.0
version: 2.10.1
argument-hint: '<description>'
user-invocable: true
---
Expand Down Expand Up @@ -52,37 +52,6 @@ model (`/case`, `/refine`, `/orchestrate`) proceeds only on `planning` and stops
`unsure`; a skill that merely notes its tier (`/solve`) treats `planning` as frontier and the rest as
budget.

## Reviewer pinning by host

`/evaluate`'s request-changes path must run its review pass on a **frontier** reviewer, regardless of
what model `/evaluate` itself runs on (it carries no model gate). How the reviewer's model is pinned
depends on what the host can do. Detect the host from the session's model ID:

| Host | Session model ID | Reviewer pin |
|---|---|---|
| **Claude Code** (native) | a Claude marker (`opus`/`sonnet`/`haiku`/`fable`/`mythos`) | the shipped reviewer agents — `case-reviewer` (cheapest frontier) / `case-reviewer-strong` (strongest); the pin lives in the agent definition |
| **Codex** (native) | a GPT-5 marker (`gpt-5…`) | the shipped reviewer agents (TOMLs copied into `.codex/agents/`); same two rungs, pinned to Codex's base / strongest GPT-5-class |
| **Custom host** (e.g. a router) | neither native marker, but classifies as **planning** (e.g. `qwen3.8-max-preview`) | a general subagent pinned to the **session's own model ID** — the host accepts literal IDs; one frontier tier |
| **None of the above** | budget / `unsure`, and no usable native agents | **stop** — no frontier reviewer can be pinned |

Take the first branch that applies:

1. **Native host that lists the shipped reviewer agents** (session model carries a Claude or GPT-5
marker, and the host lists `case-reviewer`/`case-reviewer-strong`) → use the agents; the pin lives
in the definition and is enforced by the harness. Two-tier cost-keying and the same-class step-up
apply (the roster offers a cheapest and a strongest rung).
2. **Else the session model classifies as planning** (a custom frontier host) → spawn a general
subagent pinned to the **session's own model ID**. One frontier tier — cost-keying and the
same-class step-up both point at it; the rule degrades to a single pin, it never errors.
3. **Else** → **stop** and tell the user no frontier reviewer can be pinned.

Rules that bind every branch:
- **Never pin or inherit a budget ID**, and never run the review inline on `/evaluate`'s own model
instead of spawning a subagent. No frontier model to pin → stop; do not fall back to a budget
reviewer.
- **Spawn anonymously — never pass a `name`**: named teammates can't be spawned from inside another
agent, and nothing needs to address the reviewer after it reports.

<!-- END SHARED -->

<!-- END GENERATED -->
Expand Down
38 changes: 16 additions & 22 deletions plugins/case-solvers/skills/evaluate/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: evaluate
description: 'Human review gate for a needs-review story by id: opens its branch diff in VSCode, then enacts the verdict — approve (land it on the branch it was forked from — `main`, `master`, or a feature branch — close, unblock dependents) or request changes. Request changes spawns a frontier-pinned subagent (pinned per host — the strongest reviewer agent on a native Claude/Codex host, the session''s own model ID on a custom frontier host; under --unattended the pin keys off the solver-<tier> label of the story — cheapest frontier model for budget/medium stories, strongest for frontier — never the ambient model) that runs /code-review and applies the fixes in place, shows you the applied diff, and amends bd/<id> only after you confirm; a wrong contract instead routes to /refine. --approve lands it on its base branch without opening the diff; --review [effort] runs the code-review pass straight away (default high); either can add --unattended, for /orchestrate driving an unattended run onto a provisional epic branch — never for a human approving straight to master/main: on --review it auto-applies without the amend-confirm, on --approve it also self-resolves an otherwise-ambiguous merge conflict (recording the reasoning) instead of asking, unless the resolution would force tests red or drop an AC, where it aborts and stalls the story instead of landing broken code; --note <text> steers the review and/or annotates the story.'
version: 1.14.0
version: 1.14.1
argument-hint: '[<story-id>] [--approve [--unattended]] [--review [effort] [--unattended]] [--note <text>]'
disable-model-invocation: false
user-invocable: true
Expand Down Expand Up @@ -39,29 +39,27 @@ model (`/case`, `/refine`, `/orchestrate`) proceeds only on `planning` and stops
`unsure`; a skill that merely notes its tier (`/solve`) treats `planning` as frontier and the rest as
budget.

## Reviewer pinning by host
<!-- END SHARED -->

`/evaluate`'s request-changes path must run its review pass on a **frontier** reviewer, regardless of
what model `/evaluate` itself runs on (it carries no model gate). How the reviewer's model is pinned
depends on what the host can do. Detect the host from the session's model ID:
<!-- END GENERATED -->

| Host | Session model ID | Reviewer pin |
|---|---|---|
| **Claude Code** (native) | a Claude marker (`opus`/`sonnet`/`haiku`/`fable`/`mythos`) | the shipped reviewer agents — `case-reviewer` (cheapest frontier) / `case-reviewer-strong` (strongest); the pin lives in the agent definition |
| **Codex** (native) | a GPT-5 marker (`gpt-5…`) | the shipped reviewer agents (TOMLs copied into `.codex/agents/`); same two rungs, pinned to Codex's base / strongest GPT-5-class |
| **Custom host** (e.g. a router) | neither native marker, but classifies as **planning** (e.g. `qwen3.8-max-preview`) | a general subagent pinned to the **session's own model ID** — the host accepts literal IDs; one frontier tier |
| **None of the above** | budget / `unsure`, and no usable native agents | **stop** — no frontier reviewer can be pinned |
## Reviewer pinning by host

Take the first branch that applies:
`/evaluate`'s request-changes path must run its review pass on a **frontier** reviewer, regardless of
what model `/evaluate` itself runs on (it carries no model gate). How the reviewer is pinned keys off
what the host can do — not an enumerated host list. Take the first branch that applies:

1. **Native host that lists the shipped reviewer agents** (session model carries a Claude or GPT-5
marker, and the host lists `case-reviewer`/`case-reviewer-strong`) → use the agents; the pin lives
in the definition and is enforced by the harness. Two-tier cost-keying and the same-class step-up
apply (the roster offers a cheapest and a strongest rung).
2. **Else the session model classifies as planning** (a custom frontier host) → spawn a general
subagent pinned to the **session's own model ID**. One frontier tier — cost-keying and the
same-class step-up both point at it; the rule degrades to a single pin, it never errors.
3. **Else** → **stop** and tell the user no frontier reviewer can be pinned.
apply — the roster offers a cheapest frontier rung (`case-reviewer`) and a strongest
(`case-reviewer-strong`).
2. **Else the session model classifies as planning** (a custom frontier host, e.g.
`qwen3.8-max-preview`) → spawn a general subagent pinned to the **session's own model ID** — the
host accepts literal IDs. One frontier tier: cost-keying and the same-class step-up both point at
it; the rule degrades to a single pin, it never errors.
3. **Else** (budget / `unsure`, no usable native agents) → **stop** and tell the user no frontier
reviewer can be pinned.

Rules that bind every branch:
- **Never pin or inherit a budget ID**, and never run the review inline on `/evaluate`'s own model
Expand All @@ -70,10 +68,6 @@ Rules that bind every branch:
- **Spawn anonymously — never pass a `name`**: named teammates can't be spawned from inside another
agent, and nothing needs to address the reviewer after it reports.

<!-- END SHARED -->

<!-- END GENERATED -->

## Environment Guard — Run First

- `.beads/` absent → tell the user to `/case <description>` first. Stop.
Expand Down Expand Up @@ -128,7 +122,7 @@ If `--note <text>` was supplied, record it as a `bd comment` now (before asking
Ask which kind of change, because they route differently:

- **Implementation needs work (most common)** → the contract is fine, the code isn't. Don't bounce the story back to `/solve`; fix it in place by delegating the review to a **frontier model**:
1. **Spawn the review-and-apply as a subagent and pin its model to a frontier tier explicitly — never inherit the ambient model.** `/evaluate` carries no model gate, so if you don't set the model the subagent inherits whatever `/evaluate` is running on — often a budget model like `haiku` — which is exactly the failure this step exists to prevent. Pinning is **mandatory**, not best-effort. Pick the pin from the **Reviewer pinning by host** map in the Model Tiers section above — take the first branch that applies:
1. **Spawn the review-and-apply as a subagent and pin its model to a frontier tier explicitly — never inherit the ambient model.** `/evaluate` carries no model gate, so if you don't set the model the subagent inherits whatever `/evaluate` is running on — often a budget model like `haiku` — which is exactly the failure this step exists to prevent. Pinning is **mandatory**, not best-effort. Pick the pin from the **Reviewer pinning by host** section above — take the first branch that applies:
- **Native host that lists the shipped reviewer agents** (session model carries a Claude or GPT-5 marker, and the host lists `case-reviewer`/`case-reviewer-strong`) → use the agents; the model pin then lives in the definition and is enforced by the harness, not by this prose. The plugin ships them as agent definitions for both hosts (`agents/<name>.md` on Claude Code, auto-discovered and listed host-namespaced, e.g. `case-solvers:case-reviewer`; `agents/<name>.toml` on Codex, copied into `.codex/agents/` per the README). Default to **`case-reviewer-strong`** (the interactive flow's reviewer).
- **Custom frontier host** (session model is neither native marker but classifies as **planning**, e.g. `qwen3.8-max-preview`) → spawn a general subagent pinned to the **session's own model ID** — the host accepts literal IDs, so `Agent(subagent_type: "general-purpose", model: "<session model ID>", prompt: …)`. One frontier tier.
- **Neither** → **stop** and tell the user no frontier reviewer can be pinned — do not fall back to a budget reviewer.
Expand Down
Loading
Loading