Spec citation — SURFACE.md §2 rule 6 (lines 72–96)
- agent: Review this diff for security issues. # 1. anonymous
agents:
reviewer: { cli: claude, model: claude-sonnet-4-6 } # 2. named — explicit and reusable
The declarative named-agent schema in this slice is exactly { cli, model }...
Explicit step values win independently: step cli/model → named
declaration → the existing flow/project CLI default. Model has no
flow/project default.
— docs/SURFACE.md:74-92
Current state (2026-09-11, main @ 3c10e99b2accfd51e94dd6d4f90ca16187e4e724)
The declarative (YAML/JSON) side of this rule is fully shipped: AgentStepSpec
has real cli?/model? fields (packages/sdk/src/spec.ts:184,191), and
preflight.ts resolves them in the documented order — step → named agent →
flow → project (packages/sdk/src/preflight.ts:277-280).
The TypeScript authoring surface has none of this:
Ctx.agent's options type is { task: string; workspace?: string }
(packages/surface/src/context.ts:10-13) — no cli, no model.
FlowHeader has no agents map and no flow-level cli either
(packages/surface/src/flow.ts:4-9; the allowlist enforced by
assertFlowHeader at flow.ts:148-181 is exactly identity, memory,
budget, tools, workspace).
authored-flow-executor.ts's lowerAgent builds the compiled step with
no cli/model field at all (authored-flow-executor.ts:196-209) and
says so explicitly in its own comment: "CLI selection goes through the
project's flows.json default... an authored flow has no way to declare
one today" (authored-flow-executor.ts:169-176).
Net effect: every f.agent call in a TypeScript flow shares one project-wide
CLI (flows.json's cli) with no way to override it per call, and has no
way to pin a model at all — not even the flow/step defaults YAML already has.
Confirmed by writing the Relayflows product docs against real source and
real captured CLI output (agentrelay.com PR #66): the TypeScript example
for "a whole flow" cannot express what the equivalent YAML example expresses
inline on the step (cli: claude, model: claude-sonnet-4-6) — the docs had
to fall back to explaining flows.json's single project default instead.
(Note: #300's "What's shipped" section claims FlowHeader.agents TS types
are already in place — that's not accurate against current source; see my
correction there. This issue is the narrower, prerequisite gap: a single
call's cli/model, with no named-agent map or use: composition
required.)
Scope
Ctx.agent options. Add optional cli?: string and model?: string
to AgentOptions in packages/surface/src/context.ts, mirroring
AgentStepSpec's fields exactly.
- Lowering.
authored-flow-executor.ts's lowerAgent passes
options.cli/options.model through onto the compiled step spec when
present, the same way options.workspace is passed through today.
- Resolution order. No change needed to
preflight.ts — an authored
step with an explicit cli/model already takes the source: 'step'
branch (preflight.ts:277); this issue only adds the field an author can
set to reach it.
- Docs/tests. Surface + SDK test coverage mirroring the existing
AgentStepSpec.cli/.model cases; once shipped, the Relayflows docs'
TypeScript examples can show the CLI/model inline on the call instead of
pointing at a project-wide flows.json default.
Non-goal: named-agent maps or use:-based flow composition in TypeScript
(that's #300's scope). This issue is just parity for the single-call
cli/model override YAML already has.
Spec citation — SURFACE.md §2 rule 6 (lines 72–96)
Current state (2026-09-11, main @ 3c10e99b2accfd51e94dd6d4f90ca16187e4e724)
The declarative (YAML/JSON) side of this rule is fully shipped:
AgentStepSpechas real
cli?/model?fields (packages/sdk/src/spec.ts:184,191), andpreflight.tsresolves them in the documented order — step → named agent →flow → project (
packages/sdk/src/preflight.ts:277-280).The TypeScript authoring surface has none of this:
Ctx.agent's options type is{ task: string; workspace?: string }(
packages/surface/src/context.ts:10-13) — nocli, nomodel.FlowHeaderhas noagentsmap and no flow-levelclieither(
packages/surface/src/flow.ts:4-9; the allowlist enforced byassertFlowHeaderatflow.ts:148-181is exactlyidentity,memory,budget,tools,workspace).authored-flow-executor.ts'slowerAgentbuilds the compiled step withno
cli/modelfield at all (authored-flow-executor.ts:196-209) andsays so explicitly in its own comment: "CLI selection goes through the
project's flows.json default... an authored flow has no way to declare
one today" (
authored-flow-executor.ts:169-176).Net effect: every
f.agentcall in a TypeScript flow shares one project-wideCLI (
flows.json'scli) with no way to override it per call, and has noway to pin a model at all — not even the flow/step defaults YAML already has.
Confirmed by writing the Relayflows product docs against real source and
real captured CLI output (
agentrelay.comPR #66): the TypeScript examplefor "a whole flow" cannot express what the equivalent YAML example expresses
inline on the step (
cli: claude,model: claude-sonnet-4-6) — the docs hadto fall back to explaining
flows.json's single project default instead.(Note: #300's "What's shipped" section claims
FlowHeader.agentsTS typesare already in place — that's not accurate against current source; see my
correction there. This issue is the narrower, prerequisite gap: a single
call's
cli/model, with no named-agent map oruse:compositionrequired.)
Scope
Ctx.agentoptions. Add optionalcli?: stringandmodel?: stringto
AgentOptionsinpackages/surface/src/context.ts, mirroringAgentStepSpec's fields exactly.authored-flow-executor.ts'slowerAgentpassesoptions.cli/options.modelthrough onto the compiled step spec whenpresent, the same way
options.workspaceis passed through today.preflight.ts— an authoredstep with an explicit
cli/modelalready takes thesource: 'step'branch (
preflight.ts:277); this issue only adds the field an author canset to reach it.
AgentStepSpec.cli/.modelcases; once shipped, the Relayflows docs'TypeScript examples can show the CLI/model inline on the call instead of
pointing at a project-wide
flows.jsondefault.Non-goal: named-agent maps or
use:-based flow composition in TypeScript(that's #300's scope). This issue is just parity for the single-call
cli/modeloverride YAML already has.