Repository navigation
Let a role say where it wants to run, so a cloud parent can delegate locally #43
Description
Proposal
Why
The most-wanted setup — a capable cloud model reasoning and planning with you, while
local agents do the tedious implementation — does not work today.
// Only reroute when the parent itself runs locally: a cloud parent has no
// queue problem, and silently downgrading it to a local model would be a
// quality surprise.
if (!input.target && (!parentInfo || !baseURLOf(parentInfo))) return nullA cloud parent gets no placement at all, so every subagent inherits the cloud model. Fan
out from a cloud session and the fleet sits idle while you pay for the coder too.
The guard's reasoning is correct and should not be deleted. Silently moving a cloud
parent's subagents onto local weights is a quality surprise — the user picked that model.
What is missing is a way to say "not a surprise, this is what I want", per role.
Supersedes role-model-chains
That change proposed an ordered models: fallback list per agent. It was aimed at the
wrong thing, on two counts:
Residency is already solved. placement.ts:169
scores an already-loaded model 100_000 against a maximum of ~4,000 from every other term —
an absolute tier, commented "same rule as skein". A warm model always wins over one needing
a multi-second swap-in. Nothing to add.
Per-role model pinning is not what is wanted. With one model family across the fleet,
pinning changes nothing; and which weights are loaded is managed directly. What is worth
expressing is which hosts a role may run on, which then decides the model implicitly.
That is also skein's shape. ChainEntry is { Provider, ModelRef } where the comment reads
"optional: direct provider/modelID ref; bypasses model assignment when set" — provider
first, model the exception.
What Changes
An agent may declare where it wants to run:
---
mode: subagent
description: Implements one named slice of an openspec change
placement: local # a local host, even when the parent is a cloud model
---| value | meaning |
|---|---|
absent / inherit |
today's behaviour exactly — placement only from a local parent |
local |
any eligible local host, even from a cloud parent |
[rocky, m3] |
those hosts in order, then any eligible local host |
Declaring it is the authorization the guard was missing. An agent that says nothing keeps
today's behaviour, so no existing setup changes and nothing is ever downgraded silently.
Resolution order becomes: pinned model: → explicit provider argument → role
placement → existing placement → inherit. It still cannot fail: an unreachable or busy
preferred host falls through to ordinary placement and then to the parent's model, exactly
as now.
coder, tester and reviewer ship with placement: local — the three gate roles that do
bulk work. researcher and persona-auditor keep inheriting, because they answer questions
for a human and the parent's model is the right one.
For reviewer this is a bonus rather than a compromise: a second opinion from the same
model that wrote the code is barely a second opinion, and a cloud parent with a local
reviewer gets genuine model diversity for free.
Cloud is not a special case that needs handling
Switching models on a cloud provider is instant and free, so none of the residency
machinery applies to it — and none of it runs, because placement only ever considers
providers with a local baseURL. A role that wants cloud simply says nothing and inherits.
Impact
- One optional agent field. Absent, nothing changes anywhere.
- Delivers "cloud plans, local implements" without touching the guard's default.
- Does not read skein's
chains:. Those are auto-synthesized identically across all twelve
roles today, so there is nothing role-specific to consume. If they ever diverge, this
field is where that config would land.
Disposition (2026-09-18)
Shipped — live checks moved. Shipped; live check 4.2 moved to fleet-live-verification.
Tasks
Supersedes role-model-chains (renamed 2026-08-07). See the proposal for why the ordered
models: list was aimed at the wrong thing.
Phase 1: Schema
- 1.1 Add optional
placementto the agent config schema andAgent.Info"inherit" | "local" | string[]; absent behaves asinherit- Validation:
bun run typecheck
- 1.2 Parse it from markdown frontmatter alongside
modelandpermission- Validation: a persona declaring
placement: localloads with it set
- Validation: a persona declaring
Phase 2: Resolution
- 2.1 Relax the non-local-parent guard in
LocalPlacement.pickfor a declared placement- Extracted as
shouldAttemptPlacement— a pure exported function, because the rule is
the whole change and burying it inside a function that does real HTTP probes would have
left it untestable. - The guard stays the default; a declared placement is the authorization it was missing
- Validation: unit test — cloud parent + declared local → placement runs; cloud parent +
no declaration → returns null, unchanged
- Extracted as
- 2.2 Honour an ordered host list, then fall through to any eligible local host
- Validation: unit tests for first-eligible, first-busy-second-wins, all-unusable
- 2.3 Keep the precedence:
model→ explicitproviderarg →placement→ placement → inherit- Validation: unit test for each rung
- 2.4 An unsatisfiable preference degrades, never fails
- Preferred hosts RANK candidates (
hostRankFor), they do not filter them: an unreachable
or busy named host scores 0 and every other candidate stays eligible. - Caught writing the tests:
placement: []authorized placement from a cloud parent,
because an empty array is neitherundefinednor"inherit". A typo would have
silently downgraded a cloud session. An empty list now authorizes nothing. - Unknown provider id, unreachable host, no free slot — all fall through
- Validation: unit test that the subagent still runs
- Preferred hosts RANK candidates (
Phase 3: The personas
- 3.1
coder,tester,reviewerdeclareplacement: local- The three gate roles that do bulk work. For
reviewerit also buys real model
diversity: a second opinion from the parent's own model is barely a second opinion.
- The three gate roles that do bulk work. For
- 3.2
researcherandpersona-auditorkeep inheriting- They answer questions for a human; the parent's model is the right one
- Validation: extend
test/agent/repo-personas.test.ts
Phase 4: Verification
- 4.1
bun test test/loop/ test/agent/ test/local/ test/tool/— 744 pass; typecheck clean - 4.2 Live check: a cloud-model session fans out and the subagent lands on a local host
- The whole point of the change; assert on the subagent's resolved provider, not a claim
Unchecked items above: see Disposition in proposal.md (2026-09-18).
Plan changes
9 done
Activity
androidand commentedon Sep 17, 2026
Archived 2026-09-18 — see the change's Disposition section.