Relay: Wire up model passthrough in spawn()
The SpawnPayload protocol type already defines model?: string but it's vestigial — never reaches the spawned CLI process. Three small changes close the gap.
Current State
SpawnPayload.model? ✅ Defined in protocol/src/types.ts:405
SDK client.spawn() ❌ Not in options interface
spawn-manager.ts ❌ Doesn't forward payload.model to AgentSpawner
spawner.ts ✅ Already reads model from agent config files
buildClaudeArgs() ✅ Already passes --model to CLI
mapModelToCli() ✅ Already maps friendly names → CLI variants
The entire downstream pipeline works (model → --model flag → CLI). The signal just doesn't flow from spawn() call through to the spawner.
Changes Required
1. SDK client — expose model in spawn options
File: packages/sdk/src/client.ts ~line 795
Add model to the options interface:
async spawn(
options: {
name: string;
cli: string;
task?: string;
cwd?: string;
team?: string;
model?: string; // ← ADD THIS
interactive?: boolean;
// ... rest unchanged
},
timeoutMs = 30000
): Promise<SpawnResult>
And include it in the payload (~line 854):
payload: {
name: options.name,
cli: options.cli,
task: taskWithContext,
team: options.team,
cwd: options.cwd,
model: options.model, // ← ADD THIS
spawnerName: options.spawnerName,
// ... rest unchanged
}
2. Spawn manager — forward model to AgentSpawner
File: packages/daemon/src/spawn-manager.ts ~line 98
const result = await this.spawner.spawn({
name: payload.name,
cli: payload.cli,
task: payload.task,
team: payload.team,
cwd: payload.cwd,
model: payload.model, // ← ADD THIS
spawnerName: payload.spawnerName ?? spawnerName,
// ... rest unchanged
});
3. Spawner — use model param with precedence over agent config
File: packages/bridge/src/spawner.ts ~line 946
The spawner currently resolves model only from agent config files. The spawn payload's model should take precedence:
if (isClaudeCli) {
const agentConfig = findAgentConfig(name, this.projectRoot);
const modelFromProfile = agentConfig?.model?.trim();
const modelFromPayload = payload.model?.trim(); // ← ADD THIS
// Payload model takes precedence over profile
const effectiveModel = modelFromPayload || modelFromProfile; // ← CHANGE THIS
const cliVariant = effectiveModel
? mapModelToCli(effectiveModel)
: mapModelToCli(); // defaults to claude:sonnet
const configuredArgs = buildClaudeArgs(name, args, this.projectRoot);
// If payload specified model, ensure it overrides whatever buildClaudeArgs set
if (modelFromPayload) { // ← ADD THIS BLOCK
const modelIdx = configuredArgs.indexOf('--model');
if (modelIdx !== -1) {
configuredArgs[modelIdx + 1] = modelFromPayload;
} else {
configuredArgs.push('--model', modelFromPayload);
}
}
args.length = 0;
args.push(...configuredArgs);
}
Also need to add model to the spawner's internal SpawnOptions interface (likely in the same file or an imported type).
Model Mapping Reference
mapModelToCli() in packages/utils/src/model-mapping.ts already handles these:
| Input |
Output |
opus |
claude:opus |
sonnet |
claude:sonnet |
haiku |
claude:haiku |
claude-opus-4 |
claude:opus |
claude-sonnet-4 |
claude:sonnet |
Use Case
We need to set agent model at spawn time from our server, and switch models mid-session by releasing and re-spawning:
// Spawn with specific model
await client.spawn({ name: 'Facilitator-abc123', cli: 'claude', model: 'opus', task: '...' });
// Later: switch to cheaper model
await client.release('Facilitator-abc123');
await client.spawn({ name: 'Facilitator-abc123', cli: 'claude', model: 'haiku', task: '...' });
The agent hydrates session state from storage on startup, so no conversation context is lost across re-spawns.
Testing
- Spawn agent with
model: 'opus' → verify --model opus appears in CLI args
- Spawn agent with
model: 'haiku' → verify --model haiku
- Spawn agent with no model + agent config file → verify config file model still works (backward compat)
- Spawn agent with model + conflicting agent config → verify spawn payload wins
Relay: Wire up
modelpassthrough in spawn()The
SpawnPayloadprotocol type already definesmodel?: stringbut it's vestigial — never reaches the spawned CLI process. Three small changes close the gap.Current State
The entire downstream pipeline works (model →
--modelflag → CLI). The signal just doesn't flow fromspawn()call through to the spawner.Changes Required
1. SDK client — expose
modelin spawn optionsFile:
packages/sdk/src/client.ts~line 795Add
modelto the options interface:And include it in the payload (~line 854):
2. Spawn manager — forward model to AgentSpawner
File:
packages/daemon/src/spawn-manager.ts~line 983. Spawner — use model param with precedence over agent config
File:
packages/bridge/src/spawner.ts~line 946The spawner currently resolves model only from agent config files. The spawn payload's
modelshould take precedence:Also need to add
modelto the spawner's internalSpawnOptionsinterface (likely in the same file or an imported type).Model Mapping Reference
mapModelToCli()inpackages/utils/src/model-mapping.tsalready handles these:opusclaude:opussonnetclaude:sonnethaikuclaude:haikuclaude-opus-4claude:opusclaude-sonnet-4claude:sonnetUse Case
We need to set agent model at spawn time from our server, and switch models mid-session by releasing and re-spawning:
The agent hydrates session state from storage on startup, so no conversation context is lost across re-spawns.
Testing
model: 'opus'→ verify--model opusappears in CLI argsmodel: 'haiku'→ verify--model haiku