Research brief
Landscape topic for this run: agent_mesh roadmap & comparable OSS agent
frameworks (OpenHands, SWE-agent, Aider, MetaGPT/ChatDev, Renovate,
claude-code-action). Inspired by Claude Code's own native fallback-model
chain (--fallback-model sonnet,haiku / fallbackModel settings array;
existed headless-only, extended to interactive sessions in v2.1.166, shipped
June 6 2026).
Gap
Every delegated worker in the mesh runs a single pinned model (per-peer
static selection landed in #457; per-peer extended-thinking effort in #530,
wired via --effort in src/delegate-invocation.js:109). If that peer's
model returns a non-retryable server error (529 overload / transient
unavailability) mid-spawn, the whole delegation surfaces as status:error
to the caller — even though Claude Code itself already ships a resilience
feature for exactly this: an ordered fallback chain the CLI switches into
within the same request, for non-retryable server errors only (auth,
billing, rate-limit and request-size errors are explicitly excluded from
triggering a switch, so this cannot mask a real caller-facing failure class).
Proposed direction
Thread a new optional per-peer registry.json field, fallback_model
(string or short array, e.g. "sonnet,haiku"), through the exact same path
already used for thinking_effort (#530's precedent):
src/a2a/registry.js normalizePeer passes it through (validated:
1–3 aliases after dedup, matching the CLI's own documented cap).
src/a2a/peer-bridge.js sets agentmesh/fallback_model metadata on
cross-peer SendMessage calls; src/a2a/stdio-server.js reads it back
and threads it into runAgent/delegateTask.
src/delegate-invocation.js buildClaudeInvocation appends
--fallback-model <chain> iff present — identical append-iff-present
shape as the existing --effort line.
This is intentionally thin plumbing (a registry-configured CLI flag), not
new retry logic invented by the mesh.
Why this does NOT touch the "never auto-retry" invariant
CLAUDE.md's invariant ("Failure is data, not an exception... The mesh never
auto-retries or auto-fails-over") governs delegation-level retries — the
mesh does not re-invoke delegateTask after a done/timeout/refused/
error result. This proposal operates strictly inside one claude -p
spawn: the model switch happens before that spawn produces any result at
all, entirely inside the claude binary's own request handling. If every
model in the configured chain is exhausted, the spawn still fails and the
mesh still returns a structured error exactly as today — the invariant is
unchanged, only the window for a transient 529 to become a full delegation
failure narrows.
Open questions flagged for human scoping (not yet resolved by this brief)
- Need a version-gated smoke test of
--fallback-model combined with
-p --output-format json (headless mode) specifically — sources describe
the flag mainly via interactive/general docs.
- Whether
parseResultEnvelope's usage/cost fields correctly attribute to
whichever model actually serviced the request after a fallback switch, or
silently misreport against the primary model — affects run-record cost
accuracy (src/delegate.js cost-capture, spec
2026-06-13-delegate-cost-capture-design.md).
Full draft spec
Written to
docs/superpowers/specs/2026-07-23-idea-per-peer-fallback-model-chain-for-do-mode-and-ask-mode-design.md
during this run, but could not be committed/pushed — this session's
GitHub token is the same App-installation credential #771 already tracks as
403'ing on Contents writes (git push / Contents API), confirmed again this
run (gh api user also 403s: "Resource not accessible by integration").
Pasting the spec content below so it isn't lost to the ephemeral checkout:
Full draft spec (click to expand)
# Per-peer fallback-model chain for delegated `claude -p` spawns
Status: **draft** — proposal only, subject to human approval gate (§5.3).
Inspired by: Claude Code's native `--fallback-model` chain (shipped as CLI
flag + `fallbackModel` settings array; extended to interactive sessions in
v2.1.166, June 2026) and the general "resilient model chain" pattern used
by agent frameworks under overload conditions.
## Goal
When a peer's primary model returns a non-retryable server error (529
overload, transient unavailability), let that single delegated `claude -p`
spawn degrade to a configured fallback model **within the same invocation**,
instead of the whole delegation surfacing as `status:error` to the caller.
## Non-goals
- Not a change to mesh-level retry policy. The mesh still never re-invokes
`delegateTask` after a `done`/`timeout`/`refused`/`error` result — that
invariant (CLAUDE.md "Failure is data, not an exception") is unchanged.
This proposal is scoped **strictly inside one spawn**: it is the `claude`
CLI's own request-level resilience (model switch on 529/unavailable),
which already exists as a first-party CLI feature — the mesh would only
be *threading a registry-configured value* into the spawn args, the same
shape as issue #530's `--effort` wiring, not inventing new retry logic.
- Not a change to which errors are eligible: per Claude Code's own docs,
auth/billing/rate-limit/request-size/transport errors never trigger a
model switch — only non-retryable server-side overload does. The mesh
does not need to (and should not) reimplement that classification; it is
entirely inside the `claude` binary.
- Not a substitute for #568 (daemon jobs skipping gracefully on
org-wide quota exhaustion) — that is a different layer (daemon builtin
tick vs. a single delegate spawn) and orthogonal.
## Design
1. **Registry field**: extend `registry.json` peer entries with an optional
`fallback_model` field, string or array (e.g. `"fallback_model":
"sonnet,haiku"` or `["sonnet","haiku"]`), mirroring the precedent set by
`thinking_effort` (#530). `src/a2a/registry.js` `normalizePeer` gains a
pass-through: `if (peer.fallback_model !== undefined) normalized.fallback_model = ...`
(validated: 1-3 model aliases after dedup, per the CLI's own documented
cap — extra entries are ignored upstream anyway, but validating early
gives a clear `bad_input` instead of a silent no-op).
2. **Cross-peer threading**: same shape as `thinking_effort` — the peer
bridge (`src/a2a/peer-bridge.js`) reads `managed.registry.peers[peer]?.fallback_model`
and sets `message.metadata['agentmesh/fallback_model']`; `stdio-server.js`
reads it back off `validation.value.metadata` and passes it through to
`runAgent`/`delegateTask`.
3. **Spawn args**: `buildClaudeInvocation` (`src/delegate-invocation.js`)
gains a `fallbackModel` param; iff present, appends
`--fallback-model <comma-joined-chain>` — identical append-iff-present
shape as the existing `--effort` line (delegate-invocation.js:109).
4. **Observability**: `parseResultEnvelope`'s existing `usage` block capture
already reports the model that actually serviced the request in the
terminal JSON envelope (needs verification during implementation — if
the envelope's `model` field doesn't reflect a mid-run switch, that is a
pre-existing Claude Code CLI limitation to note, not something to work
around). No new metrics field is proposed here; this is intentionally
thin plumbing, not a new cost-attribution feature.
## Invariants upheld
- Anti-spoof: the model-facing `delegate_task` tool surface is unchanged —
`fallback_model` is a **registry-set, operator-owned** value threaded the
same way `thinking_effort` already is, never a caller-suppliable tool arg.
- Failure is data: if all models in the chain are unavailable, the spawn
still fails as today and the mesh still returns a structured `error`
result — this proposal only narrows the window in which a transient
529 turns into a full delegation failure.
- No change to path-guard, recursion guard, or write-tool allowlists.
## Risks / open questions (for human scoping before this becomes buildable)
- Need to confirm current `claude` CLI version behavior for `--fallback-model`
combined with `-p --output-format json` (headless mode) specifically —
the July 2026 search sources describe the flag primarily via interactive
and general CLI docs; headless-mode envelope interaction needs a quick
version-gated smoke test before implementation.
- Whether cost/usage in the JSON envelope correctly attributes to whichever
model actually serviced the request, or reports the primary model
regardless — affects whether `total_cost_usd` in the run record stays
accurate under a fallback event.
## Sources
- Claude Code fallback model chain — https://www.digitalapplied.com/blog/claude-code-safe-mode-fallback-models-production-resilience-guide
- Claude Code fallbackModel overload fix — https://www.aiforanything.io/blog/claude-code-fallback-model-overload-fix-2026
- Claude Code model configuration docs — https://code.claude.com/docs/en/model-config
Dedup confirmation
Checked gh issue list --state open --limit 100 (and a scan of recent
generated:analyst closed issues) before writing this. No existing open or
closed issue mentions fallback, fallback_model, fallback-model, or a
resilience chain for delegate spawns. Closest neighbors, confirmed distinct:
Also checked the other five comparables named in this run's brief
(OpenHands, SWE-agent, Aider, MetaGPT/ChatDev, Renovate) against the current
backlog — every other angle surfaced during research maps onto an already-open
or already-closed issue:
Only the fallback-model chain is genuinely new today; filing just this one
per "quality over volume."
Sources
Research brief
Landscape topic for this run: agent_mesh roadmap & comparable OSS agent
frameworks (OpenHands, SWE-agent, Aider, MetaGPT/ChatDev, Renovate,
claude-code-action). Inspired by Claude Code's own native fallback-model
chain (
--fallback-model sonnet,haiku/fallbackModelsettings array;existed headless-only, extended to interactive sessions in v2.1.166, shipped
June 6 2026).
Gap
Every delegated worker in the mesh runs a single pinned model (per-peer
static selection landed in #457; per-peer extended-thinking effort in #530,
wired via
--effortinsrc/delegate-invocation.js:109). If that peer'smodel returns a non-retryable server error (529 overload / transient
unavailability) mid-spawn, the whole delegation surfaces as
status:errorto the caller — even though Claude Code itself already ships a resilience
feature for exactly this: an ordered fallback chain the CLI switches into
within the same request, for non-retryable server errors only (auth,
billing, rate-limit and request-size errors are explicitly excluded from
triggering a switch, so this cannot mask a real caller-facing failure class).
Proposed direction
Thread a new optional per-peer
registry.jsonfield,fallback_model(string or short array, e.g.
"sonnet,haiku"), through the exact same pathalready used for
thinking_effort(#530's precedent):src/a2a/registry.jsnormalizePeerpasses it through (validated:1–3 aliases after dedup, matching the CLI's own documented cap).
src/a2a/peer-bridge.jssetsagentmesh/fallback_modelmetadata oncross-peer
SendMessagecalls;src/a2a/stdio-server.jsreads it backand threads it into
runAgent/delegateTask.src/delegate-invocation.jsbuildClaudeInvocationappends--fallback-model <chain>iff present — identical append-iff-presentshape as the existing
--effortline.This is intentionally thin plumbing (a registry-configured CLI flag), not
new retry logic invented by the mesh.
Why this does NOT touch the "never auto-retry" invariant
CLAUDE.md's invariant ("Failure is data, not an exception... The mesh never
auto-retries or auto-fails-over") governs delegation-level retries — the
mesh does not re-invoke
delegateTaskafter adone/timeout/refused/errorresult. This proposal operates strictly inside oneclaude -pspawn: the model switch happens before that spawn produces any result at
all, entirely inside the
claudebinary's own request handling. If everymodel in the configured chain is exhausted, the spawn still fails and the
mesh still returns a structured
errorexactly as today — the invariant isunchanged, only the window for a transient 529 to become a full delegation
failure narrows.
Open questions flagged for human scoping (not yet resolved by this brief)
--fallback-modelcombined with-p --output-format json(headless mode) specifically — sources describethe flag mainly via interactive/general docs.
parseResultEnvelope'susage/cost fields correctly attribute towhichever model actually serviced the request after a fallback switch, or
silently misreport against the primary model — affects run-record cost
accuracy (src/delegate.js cost-capture, spec
2026-06-13-delegate-cost-capture-design.md).
Full draft spec
Written to
docs/superpowers/specs/2026-07-23-idea-per-peer-fallback-model-chain-for-do-mode-and-ask-mode-design.mdduring this run, but could not be committed/pushed — this session's
GitHub token is the same App-installation credential #771 already tracks as
403'ing on Contents writes (
git push/ Contents API), confirmed again thisrun (
gh api useralso 403s: "Resource not accessible by integration").Pasting the spec content below so it isn't lost to the ephemeral checkout:
Full draft spec (click to expand)
Dedup confirmation
Checked
gh issue list --state open --limit 100(and a scan of recentgenerated:analystclosed issues) before writing this. No existing open orclosed issue mentions
fallback,fallback_model,fallback-model, or aresilience chain for delegate spawns. Closest neighbors, confirmed distinct:
peer), not a resilience chain for overload.
reuses its exact wiring pattern but is a different field/flag.
exhaustion; a different layer (scheduled tick vs. single delegate
spawn) and a different error class (quota vs. transient overload).
Also checked the other five comparables named in this run's brief
(OpenHands, SWE-agent, Aider, MetaGPT/ChatDev, Renovate) against the current
backlog — every other angle surfaced during research maps onto an already-open
or already-closed issue:
triggering → idea: trigger-keyword skill surfacing — framework hints relevant skills to workers instead of relying on the caller to name them #820.
idea: post-do validation gate — declarative validators in agent.json run after do-mode tasks #509/idea: semantic dual-agent verification pass for do-mode delegations — complements #509's mechanical validators with an intent-fidelity check #825.
architect/editor model split → idea: per-peer model-tier selection — run Haiku workers, Opus orchestrator #457 (done); auto-test-and-iterate loop
→ explicitly incompatible with the never-auto-retry invariant, not
filed.
ChatDev MacNet large-topology fan-out → subsumed by idea: MIR-driven topology recommendations for orchestrator fan-out — inspired by MetaGPT's AFlow #826's scope.
dependency-dashboard consolidation → idea: Mesh Ops Dashboard issue — consolidate recurring automated issues (heartbeat/perf-regression) into one rolling issue #819; webhook/event-driven trigger →
idea: GitHub webhook bridge for reactive mesh delegation — push-triggered vs. cron-only #655; per-hour rate limiting → idea: shared per-hour rate limit for dev-mesh daemon builtins' issue/PR creation #689; merge-confidence-style scoring →
idea: inline peer-confidence on delegation results — attach historical success-rate to A2A Task metrics so calling agents can reason about reliability at the call site #671 (done, inline peer-confidence) / idea: concierge dispatch audit log — tap-gated actions have no persistent record #397.
.claude-pr/config snapshot → idea: snapshot PR-modified .claude/ config before automated review — inspired by claude-code-action's .claude-pr/ pattern #842; agent-approvalspoof-resistant gate → idea: spoof-resistant human-approval gate for agent-authored PR commits — inspired by claude-code-action's agent-approval-check #841; inline PR review comments → idea: inline, line-anchored PR review comments for the Reviewer — inspired by claude-code-action's GitHub review-API wrapper #838; WIF/OIDC →
idea: adopt Workload Identity Federation (WIF) for integration pipeline's real-claude CI auth — inspired by claude-code-action's OIDC support #836; subprocess env scrub → idea: adopt CLAUDE_CODE_SUBPROCESS_ENV_SCRUB for worker MCP-stdio/hook children — inspired by claude-code-action's subprocess credential scrub #831.
Only the fallback-model chain is genuinely new today; filing just this one
per "quality over volume."
Sources