@caddis/cli 0.2.0 → 0.2.2

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/README.md CHANGED
@@ -121,6 +121,21 @@ caddis update --extras # add extras to an existing install
121
121
  The first run. Detects, shows exactly what it is about to run, asks, then installs. `--yes` skips
122
122
  the prompt for CI.
123
123
 
124
+ ### Removing caddis
125
+
126
+ **There is no `caddis remove`.** This CLI installs and updates; it never uninstalls. Removal goes
127
+ through each agent's own command — the same principle as everything else here:
128
+
129
+ ```bash
130
+ claude plugin uninstall caddis@caddis # Claude Code
131
+ claude plugin uninstall caddis-extras@caddis
132
+ agy plugin uninstall caddis # agy
133
+ agy plugin uninstall caddis-extras
134
+ ```
135
+
136
+ `npm uninstall -g @caddis/cli` removes **only this CLI**, not the caddis plugins it installed into
137
+ your agents. Uninstall those first if you want caddis gone entirely.
138
+
124
139
  ---
125
140
 
126
141
  ## Flags
@@ -34,11 +34,9 @@ import os
34
34
  import re
35
35
  import sys
36
36
 
37
- # Functional identity, mirrored from scripts/claudster_config.py. Read order: the current dir first,
38
- # the pre-rename dir as a one-version fallback.
39
- _ARTIFACT_DIRS = (".caddis", ".claudster")
37
+ # Functional identity, mirrored from scripts/claudster_config.py.
38
+ _ARTIFACT_DIR = ".caddis"
40
39
  _ENV_PREFIX = "CADDIS"
41
- _LEGACY_ENV_PREFIX = "CLAUDSTER"
42
40
 
43
41
  # ── protected-path rules (write → deny) ──────────────────────────────────────
44
42
  _SECRET_BASENAMES = {"id_rsa", "id_dsa", "id_ecdsa", "id_ed25519", "credentials",
@@ -221,12 +219,9 @@ _TRUTHY = {"1", "true", "yes", "on"}
221
219
 
222
220
 
223
221
  def _config_path(root: str) -> str | None:
224
- """The repo's ``config.toml`` — ``.caddis`` preferred, legacy ``.claudster`` as fallback."""
225
- for name in _ARTIFACT_DIRS:
226
- cfg = os.path.join(str(root), name, "config.toml")
227
- if os.path.isfile(cfg):
228
- return cfg
229
- return None
222
+ """The repo's ``.caddis/config.toml``, or ``None`` if it doesn't exist."""
223
+ cfg = os.path.join(str(root), _ARTIFACT_DIR, "config.toml")
224
+ return cfg if os.path.isfile(cfg) else None
230
225
 
231
226
 
232
227
  def _load_guard_config(root: str) -> dict:
@@ -253,11 +248,8 @@ def guard_disabled(root: str) -> bool:
253
248
  """True when the guard is turned off entirely (all tiers bypassed).
254
249
 
255
250
  Precedence: the env var wins (global); otherwise the per-repo `[guard]` table — `enabled = false`
256
- or `mode = "off"`. Any parse problem → not disabled (fail safe). CADDIS_GUARD_DISABLED is the
257
- current name; the pre-rename CLAUDSTER_GUARD_DISABLED is read only when the new name is unset."""
258
- _disabled = os.environ.get(f"{_ENV_PREFIX}_GUARD_DISABLED")
259
- if _disabled is None:
260
- _disabled = os.environ.get(f"{_LEGACY_ENV_PREFIX}_GUARD_DISABLED", "")
251
+ or `mode = "off"`. Any parse problem → not disabled (fail safe). Env var: CADDIS_GUARD_DISABLED."""
252
+ _disabled = os.environ.get(f"{_ENV_PREFIX}_GUARD_DISABLED", "")
261
253
  if _disabled.strip().lower() in _TRUTHY:
262
254
  return True
263
255
  section = _load_guard_config(root)
@@ -271,11 +263,8 @@ def guard_disabled(root: str) -> bool:
271
263
  def deny_only(root: str) -> bool:
272
264
  """True when the guard keeps DENY (silent hard-block) but suppresses the ASK tier (ask -> allow =
273
265
  silence), so it NEVER prompts — for autonomous / no-prompt workflows that still want a catastrophe
274
- net. Env `CADDIS_GUARD_MODE=deny-only` (`CLAUDSTER_GUARD_MODE` fallback); config `[guard] mode =
275
- "deny-only"`. Read silently."""
276
- _mode = os.environ.get(f"{_ENV_PREFIX}_GUARD_MODE")
277
- if _mode is None:
278
- _mode = os.environ.get(f"{_LEGACY_ENV_PREFIX}_GUARD_MODE", "")
266
+ net. Env `CADDIS_GUARD_MODE=deny-only`; config `[guard] mode = "deny-only"`. Read silently."""
267
+ _mode = os.environ.get(f"{_ENV_PREFIX}_GUARD_MODE", "")
279
268
  if _mode.strip().lower() == "deny-only":
280
269
  return True
281
270
  section = _load_guard_config(root)
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "caddis",
3
- "version": "1.3.39",
3
+ "version": "1.3.41",
4
4
  "description": "caddis — agent-agnostic dev harness as an Antigravity (agy) plugin: TDD skills + commands, single-sourced with the Claude Code plugin."
5
5
  }
@@ -2,8 +2,8 @@
2
2
  """caddis `session_end` hook for agy (Antigravity) — Stop event.
3
3
 
4
4
  Ports claude-harness/hooks/session_end.py to agy's contract. On Stop, appends ONE session-end record to
5
- the workspace's usage log (`<workspace>/.caddis/usage-log.jsonl`, or `.claudster/` if the repo still lives
6
- there). Self-contained (the agy bundle does not ship claudster_config.py), stdlib-only, and fully defensive:
5
+ the workspace's usage log (`<workspace>/.caddis/usage-log.jsonl`). Self-contained (the agy bundle does not
6
+ ship claudster_config.py), stdlib-only, and fully defensive:
7
7
  a Stop hook must never fail the turn, and must not print a non-JSON line to stdout (agy parses Stop-hook
8
8
  stdout as a `{"decision":…}` object — a stray string trips its "unsupported hook decision" path). So this
9
9
  does a pure side effect and prints NOTHING.
@@ -19,11 +19,6 @@ from datetime import datetime, timezone
19
19
 
20
20
 
21
21
  def _artifact_root(root: str) -> str:
22
- """Write where the repo lives: prefer .caddis, keep .claudster if that's what the repo has."""
23
- for name in (".caddis", ".claudster"):
24
- path = os.path.join(str(root), name)
25
- if os.path.isdir(path):
26
- return path
27
22
  return os.path.join(str(root), ".caddis")
28
23
 
29
24
 
@@ -12,7 +12,7 @@ complement to `/caddis:code-review`, not a replacement.
12
12
 
13
13
  ## Prerequisite (one-time)
14
14
  A provider key must be resolvable. Precedence: `REVIEW_API_KEY` > the provider's own env var
15
- (`DEEPSEEK_API_KEY` / `GLM_API_KEY`) > `OSS_API_KEY` > the keys file (`~/.claudster/keys.env`,
15
+ (`DEEPSEEK_API_KEY` / `GLM_API_KEY`) > `OSS_API_KEY` > the keys file (`~/.caddis/keys.env`,
16
16
  overridable via `CADDIS_KEYS_FILE`). If your keys file is populated, no env setup is needed.
17
17
  Details: the `coding/cross-review` skill and the **Providers & keys** guide.
18
18
 
@@ -92,6 +92,15 @@ A tier can be served by an OSS provider instead of Anthropic (cheat sheet:
92
92
  (Claude or GLM implemented) or `--provider glm` / a Claude `code-reviewer` pass (DeepSeek-adjacent
93
93
  work). Never same-vendor.
94
94
 
95
+ ### Flag high-risk phases (`risk:` — a marker, not a mechanism)
96
+ Each phase may carry **`risk: normal|high`** (default `normal` — omit the line unless the phase is
97
+ `high`), meaning only "this is a phase where a wrong answer is expensive" — security/authz, a
98
+ correctness-critical algorithm, an ambiguous spec, or an irreversible change. It is **inert**: it
99
+ selects no model, spawns no agents, and implies no fan-out — it exists so the executor can decide **at
100
+ runtime** whether an extra cross-check is worth it. Do not emit orchestration, lane fan-out, or
101
+ `Workflow` scripts from this command; the runtime decision rules and the intent→model map live in one
102
+ place, the `agent-orchestration` skill's *Multi-model fan-out* section.
103
+
95
104
  ## Step 3 — Write the plan to `.caddis/plans/<feature-slug>.md`
96
105
 
97
106
  Create `.caddis/plans/` if it doesn't exist.
@@ -127,6 +136,7 @@ Creating Model: <model-id>
127
136
  **Model:** <tier> (`/model <alias>`) — <one-line rationale tied to this phase's difficulty>
128
137
  **Lane:** claude — this session | glm-headless — `claude-glm -p "/caddis:implement <this plan's path> — Phase 1 only"`
129
138
  **Session:** continue | **fresh** (start a new session for this phase — note why: lane change / heavy context)
139
+ **Risk:** high — token-verification seam; a wrong answer here is a silent auth bypass *(omit this line when normal)*
130
140
  **Goal:** <one sentence>
131
141
  **Touches:** `<files>`
132
142
  **TDD:**
@@ -46,8 +46,8 @@ plan A on the workstream stack — so its exact resume point survives and `/resu
46
46
  > per-branch file automatically when it exists, then `.caddis/relay.md`, then the legacy
47
47
  > `.claude/relay/<branch>.md` and root `relay.md` (back-compat during the migration).
48
48
  >
49
- > **Write where the repo lives:** if this repo still has a `.claudster/` (and no `.caddis/`), write
50
- > the relay THERE — don't create a second artifact dir. `/caddis:migrate-dir` converts the repo.
49
+ > A repo still on the pre-rename `.claudster/` won't see this relay until it's converted —
50
+ > `/caddis:migrate-dir` does that.
51
51
 
52
52
  ```markdown
53
53
  # Relay — <feature>
@@ -46,8 +46,9 @@ surface the `[DOC-MAP]` "read the index first" pointer for future sessions in th
46
46
 
47
47
  ## KB note format (OKF-lite — mandatory for every new note)
48
48
 
49
- Every new `.caddis/kb/*.md` note starts with this frontmatter block (`type` is required;
50
- the rest recommended). `DOC-MAP.md` is the index, not a note — it stays frontmatter-free:
49
+ Every new `.caddis/kb/*.md` note starts with this frontmatter block. **`type` is the only required
50
+ field**; everything else is recommended. `DOC-MAP.md` is the index, not a note — it stays
51
+ frontmatter-free:
51
52
 
52
53
  ```yaml
53
54
  ---
@@ -56,5 +57,18 @@ title: <human title>
56
57
  description: <one line — keep it identical to the note's DOC-MAP row description>
57
58
  tags: [topic, topic]
58
59
  timestamp: 2026-01-01 # ISO date of last substantive update
60
+ # --- OKF v0.2 trust signals (all optional; omit rather than guess) ---
61
+ status: stable # draft | stable | deprecated (absent reads as stable)
62
+ stale_after: 2026-12-31 # re-verify by this date; nothing auto-acts on it
63
+ verified: # who CONFIRMED it (not who wrote it); append, never rewrite
64
+ - { by: human:handle, at: 2026-07-28T10:00:00Z }
65
+ generated: { by: caddis/<model-id>, at: 2026-07-28T09:00:00Z }
59
66
  ---
60
67
  ```
68
+
69
+ The full schema, the caddis↔OKF `status` mapping, and what caddis deliberately skips from OKF v0.2
70
+ (`sources:`, `Attested Computation`) live in
71
+ [`.github/instructions/document-frontmatter.instructions.md`](../../.github/instructions/document-frontmatter.instructions.md).
72
+
73
+ **Backward compatible:** an existing note with no trust fields is still correct. Do not bulk-migrate
74
+ old notes — add the fields as notes are next touched.
@@ -35,7 +35,7 @@ alias claude-glm="<path-to>/claude-harness/scripts/claude-oss.sh"
35
35
  ```
36
36
  Resolve `<path-to>` per the same plugin-vs-source rule as the generator itself (`${CLAUDE_PLUGIN_ROOT}`
37
37
  for a plugin install, the harness checkout path for caddis). Also set `CADDIS_KEYS_FILE`
38
- (default `~/.claudster/keys.env`) with the provider keys — see `docs/guide/providers-and-keys.md`.
38
+ (default `~/.caddis/keys.env`) with the provider keys — see `docs/guide/providers-and-keys.md`.
39
39
 
40
40
  ## After the deterministic step — deploy private harness skills (optional)
41
41
 
@@ -45,9 +45,7 @@ such a source on disk; it is a no-op for everyone else. Point `CADDIS_HARNESS_SR
45
45
  (the folder containing your private `skills/private/`) and run:
46
46
 
47
47
  ```powershell
48
- # CADDIS_HARNESS_SRC is current; CLAUDSTER_HARNESS_SRC is read as a one-version fallback.
49
- $harnessSrc = if ($env:CADDIS_HARNESS_SRC) { $env:CADDIS_HARNESS_SRC } else { $env:CLAUDSTER_HARNESS_SRC }
50
- $src = if ($harnessSrc) { Join-Path $harnessSrc "skills\private" } else { $null }
48
+ $src = if ($env:CADDIS_HARNESS_SRC) { Join-Path $env:CADDIS_HARNESS_SRC "skills\private" } else { $null }
51
49
  $dest = ".github\skills\private"
52
50
  if ($src -and (Test-Path $src)) {
53
51
  New-Item -ItemType Directory -Force $dest | Out-Null
@@ -39,7 +39,7 @@ paired with `OSS_BASE_URL`/`OSS_MODEL`).
39
39
  ## Key resolution (never hardcoded)
40
40
  Precedence, highest wins:
41
41
  1. the provider's env var (`GLM_API_KEY` / `DEEPSEEK_API_KEY` / `OPENROUTER_API_KEY`) or generic `OSS_API_KEY`;
42
- 2. a keys file at `$CADDIS_KEYS_FILE` (default `~/.claudster/keys.env`, `KEY=VALUE` lines, `#` comments);
42
+ 2. a keys file at `$CADDIS_KEYS_FILE` (default `~/.caddis/keys.env`, `KEY=VALUE` lines, `#` comments);
43
43
  3. missing → the launcher exits non-zero with an actionable message naming the exact env var to set.
44
44
 
45
45
  The resolver is `claude-harness/scripts/oss_model.py` (`resolve(provider, env)`) — the one place a
@@ -25,7 +25,7 @@ import os
25
25
  import subprocess
26
26
  import sys
27
27
 
28
- _ARTIFACT_DIRS = (".caddis", ".claudster")
28
+ _ARTIFACT_DIRS = (".caddis",)
29
29
 
30
30
  INJECT_MAX_LINES = 120 # same budget as the Claude Code hook
31
31
  INJECT_MAX_CHARS = 24000 # hard backstop: an ephemeralMessage should never be a context bomb
@@ -59,8 +59,8 @@ def resolve_relay(root: str) -> str:
59
59
  """First existing relay doc for `root`, else "".
60
60
 
61
61
  Preference order mirrors inject_relay.py:
62
- 1. <artifact-dir>/relay/<branch>.md (per-branch team mode — .caddis, then .claudster)
63
- 2. <artifact-dir>/relay.md (solo/default — .caddis, then .claudster)
62
+ 1. .caddis/relay/<branch>.md (per-branch team mode)
63
+ 2. .caddis/relay.md (solo/default)
64
64
  3. .claude/relay/<branch>.md (legacy per-branch)
65
65
  4. relay.md (legacy repo root)
66
66
  """
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "caddis-extras",
3
- "version": "1.3.13",
3
+ "version": "1.3.14",
4
4
  "description": "caddis-extras — the long-tail skills for the Antigravity (agy) caddis plugin; install alongside caddis for the full set."
5
5
  }
@@ -136,7 +136,7 @@
136
136
  | Skill | Path | When to Use |
137
137
  |-------|------|-------------|
138
138
  | Agent Md Refactor | `agent-md-refactor/` | Refactor bloated agent instruction files (AGENTS.md, .cursorrules, .github/ files, etc.) to follow progressive disclosure principles. Splits monolithic files into organized, linked documentation. |
139
- | Agent Orchestration | `agent-orchestration/` | End-to-end blueprint for orchestrating the full agent pipeline — from spec intake through planning, implementation, testing, and debugging |
139
+ | Agent Orchestration | `agent-orchestration/` | End-to-end blueprint for orchestrating the full agent pipeline — from spec intake through planning, implementation, testing, and debugging — plus the multi-model fan-out rules (when a second model is worth it, the intent→model map, and the cost guardrails) |
140
140
  | Ask Questions If Underspecified | `asking-questions/` | Clarify requirements before implementing. Do not use automatically, only when invoked explicitly. |
141
141
  | Data Contract Pipeline | `data-contract-pipeline/` | **WORKFLOW SKILL** - Build, audit, and validate data-to-UI contracts for apps. Use whenever the user mentions data mapping, UI lineage, DB-to-UI, DisplayDTOs, source-to-screen mapping, data contracts, schema drift, typed API responses, frontend type alignment, mockup grounding, requirements-to-UI mapping, or asks whether a UI is backed by real DB/file data. Works for DBs, JSON, Markdown, CSV, XLSX, YAML, APIs, and UI mockups. |
142
142
  | Developer Growth Analysis | `developer-growth-analysis/` | Analyzes your recent Claude Code chat history to identify coding patterns, development gaps, and areas for improvement, curates relevant learning resources from HackerNews, and automatically sends a personalized growth report to your Slack DMs. |
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: agent-orchestration
3
- description: "End-to-end blueprint for orchestrating the full agent pipeline — from spec intake through planning, implementation, testing, and debugging"
3
+ description: "End-to-end blueprint for orchestrating the full agent pipeline — from spec intake through planning, implementation, testing, and debugging — plus the multi-model fan-out rules (when a second model is worth it, the intent→model map, and the cost guardrails)"
4
4
  ---
5
5
 
6
6
  # Agent Orchestration Blueprint
@@ -52,6 +52,11 @@ The operator (human) acts as **orchestrator**. Agents act as an **advisory board
52
52
 
53
53
  Every stage produces a **persistent artefact** (markdown file, commit, test run) that the next stage can consume without relying on conversation memory. This is what makes multi-session execution reliable.
54
54
 
55
+ > The pipeline below is the **sequential** axis — which agent, in what order. There is a second,
56
+ > independent axis: **how many models** work a given stage. That is deliberately rationed — see
57
+ > [Multi-model fan-out](#multi-model-fan-out-the-second-axis-how-many-models) before reaching for a
58
+ > second model.
59
+
55
60
  | Stage | Artefact | Location |
56
61
  |-------|----------|----------|
57
62
  | Requirements | Spec / feature file | Supplied by operator (e.g. `nextprompt.md`) |
@@ -392,10 +397,138 @@ The plan document should contain **copy-paste prompts** for each phase. This rem
392
397
 
393
398
  ---
394
399
 
400
+ ## Multi-model fan-out (the second axis: how many models)
401
+
402
+ > ### ⚠️ If you are not Claude Code, treat this section as ADVISORY and execute solo.
403
+ > The `Agent` tool, its per-agent `model:` override, the `Workflow` tool, and the `/glm`,
404
+ > `/deepseek`, `/caddis:cross-review` commands described below are **Claude-Code-only**. On Codex,
405
+ > Copilot, Antigravity/agy, or any other host: take the *judgement* from this section — default solo,
406
+ > cheapest deterministic check first, don't trust a single model on a security invariant — and
407
+ > **ignore the mechanics**. Do not attempt to emulate fan-out by hand, do not tell the user to run
408
+ > tools your host does not have, and do not treat the model map below as instructions you can execute.
409
+ > Solo execution is a correct, complete outcome here.
410
+
411
+ Everything above is *sequential*: one model, one stage at a time, operator in the loop. **Fan-out** —
412
+ running two or more models on the same work and reconciling their output — is a separate axis, and it
413
+ is **expensive in three currencies at once**: provider quota, the orchestrator's own context, and the
414
+ human's attention. It earns its cost rarely. The rules below are ordered; apply them in order.
415
+
416
+ ### Rule 0 — default SOLO
417
+
418
+ **One model does the work. That is the default and it is right most of the time.** Fan out only when
419
+ the work is genuinely high-risk *or* high-uncertainty:
420
+
421
+ | Fan out | Stay solo |
422
+ |---|---|
423
+ | Security-sensitive code — authn/authz, crypto, secret handling, input trust boundaries | Boilerplate, CRUD, scaffolding |
424
+ | Correctness-critical algorithms where a subtle wrong answer looks right (concurrency, money, dates/timezones, migrations, dedup/merge logic) | Mechanical refactors with a green suite either side |
425
+ | Ambiguous specs — where the risk is that *everyone* misreads the requirement the same way | Anything a test, type-checker, or linter can decide |
426
+ | Verifying a frontier model's **own** risky output — a model is the worst reviewer of its own reasoning | Work already covered by an existing review gate |
427
+ | Irreversible / wide blast radius — a drop, a flag day, a fleet-wide sweep | Work you can trivially revert |
428
+
429
+ Two failure modes, both real: **fanning out on size** (a big mechanical task is still solo — split it
430
+ across *sessions*, not models) and **fanning out for reassurance** (a second opinion you have already
431
+ decided to ignore is pure cost).
432
+
433
+ ### Rule 1 — cheapest check first
434
+
435
+ **Never spend a second model on something a deterministic check can decide.** Climb this ladder and
436
+ stop at the first rung that answers the question:
437
+
438
+ 1. **Tests / types / linters / the build.** If a failing test, `mypy`/`tsc`, or a lint rule confirms
439
+ the concern, you are done — that is a *fact*, not an opinion, and it costs nothing.
440
+ 2. **Read the code.** A targeted grep or a five-line read beats any model's guess about what the code
441
+ does.
442
+ 3. **A subagent on the same model** (`code-reviewer`, `security-analyst`, `anchor`, `preflight`) — a
443
+ fresh context, not a fresh vendor. Catches most "did we miss something" cases.
444
+ 4. **A different tier** — escalate one model tier for the hard part only.
445
+ 5. **Cross-vendor.** The last rung, and the rationed one (see the guardrails).
446
+
447
+ If a deterministic check *can* be written but doesn't exist yet, **write the check** — it is cheaper
448
+ than the model call and it keeps paying.
449
+
450
+ ### Rule 2 — name the INTENT, not the model
451
+
452
+ Talk about lanes by what they are *for*, so plans, prompts, and reviews survive model releases and the
453
+ LiteLLM cutover. **This table is the single place the intent→model mapping lives** — everything else
454
+ (plans, commands, skills) refers to the intent name and points here.
455
+
456
+ | Intent | What it's for | Current model | Claude Code mechanics | Cost |
457
+ |---|---|---|---|---|
458
+ | **deepest** | Subtle correctness, security invariants, novel architecture, judgment-heavy seams | `opus` | `/model opus`; `Agent(model: "opus")` | **High** — Anthropic plan quota |
459
+ | **broad** | Wide parallel coverage of a large but not-subtle surface; the workhorse | `sonnet` | `/model sonnet`; `Agent(model: "sonnet")` | Medium — the default; budget for several |
460
+ | **mechanical** | Fully-specced, repeat-of-a-known-pattern, no judgment required | `haiku` | `/model haiku`; `Agent(model: "haiku")` | Low |
461
+ | **cross-vendor-reviewer** | A *different vendor's* blind spots on a diff — **code review only** | `deepseek` (default), `glm` | `/caddis:cross-review`, `/glm`, `/deepseek` | **Scarce** — separate starter-tier subscription, NOT Anthropic quota. Ration it. |
462
+ | **synthesis / long-horizon** | Orchestrating many lanes, or work that can't self-verify across a large codebase | `fable` | `/model fable` | **Very high** — ~2× opus's rate-limit burn. RARE. |
463
+
464
+ **Update this table, not the callers**, when a model is added, retired, or re-tiered. A plan that says
465
+ "cross-vendor-reviewer" keeps working; a plan that says "deepseek-chat" rots.
466
+
467
+ ### Hard guardrails
468
+
469
+ These are constraints, not preferences. Each exists because breaking it produced a real cost.
470
+
471
+ 1. **DeepSeek and GLM are the CODE-REVIEW lane, and nothing else.** Map them to cross-vendor review of
472
+ a diff or a concrete file set. **Never** general audit, research, planning, architecture, or
473
+ open-ended subagent work — they are unreliable outside that lane, and an unreliable lane's output
474
+ still costs a full synthesis pass to disprove.
475
+ 2. **Ration cross-vendor to ~one consolidated pass per task.** One review of the whole change, not one
476
+ agent per area. Alternate vendors *between* tasks (DeepSeek this diff, GLM the next) — different
477
+ families have different blind spots and alternation maximises what the pair catches over time.
478
+ 3. **Degrade to solo when a lane's quota is exhausted.** A 402/429/quota error on GLM or DeepSeek is a
479
+ **downgrade, not a blocker**: log that the cross-vendor pass was skipped, continue with the
480
+ same-vendor reviewer, and say so in the report. Never stall the task waiting on a rationed lane,
481
+ and never silently drop the pass — an unrun check that reads as "reviewed" is worse than no check.
482
+ 4. **Name the synthesis cost before you add a lane.** N lanes do not cost N model calls — they cost N
483
+ calls **plus** reconciling N reports, which burns the orchestrator's frontier context (the scarcest
484
+ thing in the session) **and** the human's attention on the write-up. So:
485
+ - **Default cap: 3 lanes.** Above that, write the synthesis budget down first — who reconciles, on
486
+ what model, and what the human is expected to read.
487
+ - **Hard ceiling ~8**, and only for a one-off audit of a genuinely partitioned surface. The 8-lane
488
+ migration audit that motivated these rules produced a 272-line report that still needed a human
489
+ read and a main-thread re-verification of every HIGH finding. That tail is the real cost.
490
+ - If you cannot say what you would *do differently* based on lane N's output, lane N is not worth
491
+ running.
492
+ 5. **Lanes advise; they do not write.** Fan-out agents are read-only — they return findings, the main
493
+ thread applies them. This is the same rule as "agents never chain autonomously without review", and
494
+ it is what keeps parallel lanes from clobbering each other.
495
+ 6. **Verify high-severity findings in the main thread before acting.** A finding from a lane is a
496
+ *claim*. Re-read the cited file/line yourself. Subagent reports are confidently wrong often enough
497
+ that acting on an unverified HIGH is how fan-out turns into net-negative work.
498
+
499
+ ### Running it — existing mechanisms only
500
+
501
+ Invent no new machinery. Everything needed already ships:
502
+
503
+ | Need | Use |
504
+ |---|---|
505
+ | Second opinion, same vendor, fresh context | `Agent` tool → `code-reviewer` / `security-analyst` / `anchor` / `preflight` |
506
+ | A different tier for one lane only | The `Agent` tool's `model:` override (per-agent; does not change the session model) |
507
+ | 2–4 lanes in parallel | Several `Agent` calls **in one message** — they run concurrently. This is enough; you do not need anything heavier. |
508
+ | Deterministic multi-stage orchestration (fan out over a discovered list, loop until dry, adversarial verify stages) | The `Workflow` tool — **only when the human explicitly asks for it**; it can spawn dozens of agents |
509
+ | Cross-vendor review of a diff | `/caddis:cross-review` (or `python .github/tools/oss_review.py --provider deepseek\|glm --range <range>`) |
510
+ | Cross-vendor opinion that needs to read the repo | `/glm <prompt>` or `/deepseek <prompt>` |
511
+ | Cross-vendor one-shot, no repo context | `/ask-glm` / `/ask-deepseek` |
512
+ | Per-phase model + lane assignment in a plan | `/caddis:feature-plan` — every phase already carries **Model**, **Lane**, and a cross-review provider |
513
+
514
+ **Reviewer rule (standing):** the reviewer is always a different vendor than whoever wrote the code.
515
+ Claude or GLM implemented → DeepSeek reviews (or swap). Never same-vendor.
516
+
517
+ Full command/billing decision table: `docs/guide/multi-model-workflow.md`.
518
+
519
+ ---
520
+
395
521
  ## Anti-Patterns to Avoid
396
522
 
397
523
  | ❌ Anti-Pattern | ✅ Instead |
398
524
  |----------------|-----------|
525
+ | Fanning out because the task is *big* | Fan out for **risk**, not size — split a big mechanical task across sessions, not models |
526
+ | Spending a cross-vendor pass before the tests have run | Cheapest check first — deterministic gates decide it for free |
527
+ | One cross-vendor agent per area | One consolidated cross-vendor pass per task — the lane is rationed |
528
+ | Using DeepSeek/GLM for audit, research, or planning | Code-review lane only — they are unreliable outside it |
529
+ | Adding an Nth lane without budgeting the synthesis | Cap the lanes; reconciling N reports lands on you *and* the human |
530
+ | Acting on a subagent's HIGH finding as reported | Re-verify it in the main thread against the cited file/line first |
531
+ | Blocking the task when a rationed lane is out of quota | Degrade to solo, log the skipped pass, continue |
399
532
  | Jumping straight to code without a plan | Triage → ADR (if needed) → Plan → Implement |
400
533
  | Implementing all phases in one session | One phase per session — clean context, focused work |
401
534
  | Letting agents edit the plan document | Only the Planner agent (or operator) edits plans |
@@ -493,6 +626,7 @@ A well-orchestrated session should produce:
493
626
  | Session continuation context | `.github/skills/workflow/relay/SKILL.md` |
494
627
  | Verifying code before committing | `.github/skills/workflow/verification-loop/SKILL.md` |
495
628
  | Writing implementation plans | `.github/skills/docs/writing-plans/SKILL.md` |
629
+ | Running the cross-vendor review lane | `.github/skills/coding/cross-review/SKILL.md` |
496
630
  | Creating new reusable skills | `.github/skills/workflow/skill-creator/SKILL.md` |
497
631
  | Best practices reference | `.github/skills/workflow/best-practices/SKILL.md` |
498
632
 
@@ -1,7 +1,7 @@
1
1
  {
2
- "poolVersion": "1.3.39",
2
+ "poolVersion": "1.3.41",
3
3
  "bundles": {
4
- "antigravity-plugin": "1.3.39",
5
- "antigravity-plugin-extras": "1.3.13"
4
+ "antigravity-plugin": "1.3.41",
5
+ "antigravity-plugin-extras": "1.3.14"
6
6
  }
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@caddis/cli",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Install, update and diagnose the caddis dev harness across every coding agent you use (Claude Code, agy/Antigravity, and more).",
5
5
  "keywords": [
6
6
  "caddis",