Per-role model/effort defaults: wire cli-guard#192 overlay + populate director/engineer x claude/codex #620

Closed
opened 2026-07-06 17:54:37 +00:00 by coilysiren · 2 comments
Owner

What

Wire and populate per-role x per-agent model/effort defaults so a role's launch
config diverges from the flat per-agent default. The cli-guard side of this (the
role X { agent claude { model ... reasoning-effort ... } } overlay grammar) already
landed as cli-guard#192, shipped in cli-guard v0.73.0. ward pins v0.72.0
and reads only role.Guardfiles, so the overlay is parsed-but-unused today.

Target end state:

  • claude director - model claude-opus-4-8[1m] (Opus 4.8, 1M context), effort high
  • claude engineer - model claude-fable-5 (Fable), effort medium
  • codex director - model gpt-5.5, effort medium
  • codex engineer - model gpt-5.4-mini, effort medium

advisor is unspecified, leave it with no overlay (inherits the flat per-agent default).

Why

Directors run the attached heartbeat and want the strongest model at 1M context.
Engineers fan out many parallel containers, so a cheaper/faster model (Fable, gpt-5.4-mini)
at the same medium effort is the right cost/throughput trade. Today every role shares one
per-agent model, so there is no way to express "director gets Opus, engineer gets Fable".

Scope (all in ward)

  1. Bump the cli-guard dep from v0.72.0 to >= v0.73.0 (latest is v0.75.0) via
    ward tidy, so fleetconfig.RoleAgentOverride / Role.AgentConfig are reachable.

  2. Consume the overlay at launch. Where the role is known and the agent's launch
    env-defaults are computed (cmd/ward/container_bootstrap.go reads claude.Model /
    claude.ReasoningEffort, codex likewise), apply the resolved role's
    AgentConfig[<agent>] overlay. Slot it into the existing precedence
    (--config > WARD_* env > role overlay > flat per-agent fleet default) from
    docs/agent-config-overrides.md. The role is already resolved for the guardfile set
    in cmd/ward/agent_capability.go (capabilityForRole), reuse that resolution.

  3. Populate the values in .ward/ward-kdl/ward-kdl.fleet.kdl (the single hand-edited
    source), then make sync-fleet-assets to regenerate
    cmd/ward/fleetassets/fleet.generated.kdl. fleetassets_test.go fails the build on drift.

    roles {
        role engineer {
            agent claude { model "claude-fable-5" reasoning-effort "medium" }
            agent codex  { model "gpt-5.4-mini"   reasoning-effort "medium" }
        }
        role director {
            guardfiles ward-kdl.aws.guardfile.kdl ward-kdl.tailscale.guardfile.kdl
            agent claude { model "claude-opus-4-8[1m]" reasoning-effort "high" }
            agent codex  { model "gpt-5.5"            reasoning-effort "medium" }
        }
        role advisor {
            guardfiles ward-kdl.aws.guardfile.kdl ward-kdl.tailscale.guardfile.kdl
        }
    }
    
  4. Tests + echo. Add a launch-resolution test that a director claude run resolves
    --model claude-opus-4-8[1m] with effort high, and an engineer claude run resolves
    --model claude-fable-5 with effort medium. codex likewise on model +
    WARD_CODEX_REASONING_EFFORT. The startup
    ===== ward agent config ===== echo (echoAgentConfigGo) should reflect the
    role-resolved values.

Known open question for the implementer

The claude --model value is passed through verbatim (internal/agents/claude/claude.go
appends --model <v>; claude has no native effort flag, so effort is echo-only). Confirm
the CLI accepts the claude-opus-4-8[1m] bracket form as a --model token in-container.
If the 1M context needs a beta header / env rather than the model token alone, wire that
too so director actually gets 1M, not just base Opus 4.8. Same check for claude-fable-5
vs a short fable alias.

Doctrine notes

  • Config placement: fleet tuning (model/effort per role) is dialect-2 fleet config,
    authored in the ward-kdl fleet source and embedded, exactly where this lands. If a
    separate canonical ward-kdl repo mirrors this file, mirror the change there too.
  • Update docs/agent-config-overrides.md (and docs/FEATURES.md if the role-overlay is a
    user-visible capability) to document that per-role model/effort defaults now resolve.
  • pre-commit run --all-files green, land on main.
## What Wire and populate **per-role x per-agent** model/effort defaults so a role's launch config diverges from the flat per-agent default. The cli-guard side of this (the `role X { agent claude { model ... reasoning-effort ... } }` overlay grammar) already landed as **cli-guard#192**, shipped in **cli-guard v0.73.0**. ward pins **v0.72.0** and reads only `role.Guardfiles`, so the overlay is parsed-but-unused today. Target end state: - **claude director** - model `claude-opus-4-8[1m]` (Opus 4.8, 1M context), effort **high** - **claude engineer** - model `claude-fable-5` (Fable), effort medium - **codex director** - model `gpt-5.5`, effort medium - **codex engineer** - model `gpt-5.4-mini`, effort medium advisor is unspecified, leave it with no overlay (inherits the flat per-agent default). ## Why Directors run the attached heartbeat and want the strongest model at 1M context. Engineers fan out many parallel containers, so a cheaper/faster model (Fable, gpt-5.4-mini) at the same medium effort is the right cost/throughput trade. Today every role shares one per-agent model, so there is no way to express "director gets Opus, engineer gets Fable". ## Scope (all in `ward`) 1. **Bump the cli-guard dep** from `v0.72.0` to `>= v0.73.0` (latest is v0.75.0) via `ward tidy`, so `fleetconfig.RoleAgentOverride` / `Role.AgentConfig` are reachable. 2. **Consume the overlay at launch.** Where the role is known and the agent's launch env-defaults are computed (`cmd/ward/container_bootstrap.go` reads `claude.Model` / `claude.ReasoningEffort`, codex likewise), apply the resolved role's `AgentConfig[<agent>]` overlay. Slot it into the existing precedence (`--config` > `WARD_*` env > **role overlay** > flat per-agent fleet default) from `docs/agent-config-overrides.md`. The role is already resolved for the guardfile set in `cmd/ward/agent_capability.go` (`capabilityForRole`), reuse that resolution. 3. **Populate the values** in `.ward/ward-kdl/ward-kdl.fleet.kdl` (the single hand-edited source), then `make sync-fleet-assets` to regenerate `cmd/ward/fleetassets/fleet.generated.kdl`. `fleetassets_test.go` fails the build on drift. ``` roles { role engineer { agent claude { model "claude-fable-5" reasoning-effort "medium" } agent codex { model "gpt-5.4-mini" reasoning-effort "medium" } } role director { guardfiles ward-kdl.aws.guardfile.kdl ward-kdl.tailscale.guardfile.kdl agent claude { model "claude-opus-4-8[1m]" reasoning-effort "high" } agent codex { model "gpt-5.5" reasoning-effort "medium" } } role advisor { guardfiles ward-kdl.aws.guardfile.kdl ward-kdl.tailscale.guardfile.kdl } } ``` 4. **Tests + echo.** Add a launch-resolution test that a director claude run resolves `--model claude-opus-4-8[1m]` with effort `high`, and an engineer claude run resolves `--model claude-fable-5` with effort `medium`. codex likewise on model + `WARD_CODEX_REASONING_EFFORT`. The startup `===== ward agent config =====` echo (`echoAgentConfigGo`) should reflect the role-resolved values. ## Known open question for the implementer The claude `--model` value is passed through verbatim (`internal/agents/claude/claude.go` appends `--model <v>`; claude has no native effort flag, so effort is echo-only). Confirm the CLI accepts the `claude-opus-4-8[1m]` bracket form as a `--model` token in-container. If the 1M context needs a beta header / env rather than the model token alone, wire that too so director actually gets 1M, not just base Opus 4.8. Same check for `claude-fable-5` vs a short `fable` alias. ## Doctrine notes - Config placement: fleet tuning (model/effort per role) is dialect-2 fleet config, authored in the ward-kdl fleet source and embedded, exactly where this lands. If a separate canonical ward-kdl repo mirrors this file, mirror the change there too. - Update `docs/agent-config-overrides.md` (and `docs/FEATURES.md` if the role-overlay is a user-visible capability) to document that per-role model/effort defaults now resolve. - `pre-commit run --all-files` green, land on `main`.
Member

🔒 Reserved by ward agent --driver claude — container engineer-claude-ward-620 on host KAI-DESKTOP-TOWER is carrying this issue (reserved 2026-07-06T17:56:05Z). Concurrent ward agent runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); --force overrides.

Do not comment on or edit this issue to steer the run while it is reserved. The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a new issue, dispatched fresh — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494).

run seed context — what this run is carrying (ward#609)
  • Resolved: coilyco-flight-deck/ward#620 · branch issue-620 · driver claude · workflow direct-main
  • Run: engineer-claude-ward-620 · ward v0.414.0 · dispatched 2026-07-06T17:56:05Z
  • Comment thread: 0 included in the pre-flight read, 0 stripped (ward's own automated comments).

Issue body as seeded:

## What

Wire and populate **per-role x per-agent** model/effort defaults so a role's launch
config diverges from the flat per-agent default. The cli-guard side of this (the
`role X { agent claude { model ... reasoning-effort ... } }` overlay grammar) already
landed as **cli-guard#192**, shipped in **cli-guard v0.73.0**. ward pins **v0.72.0**
and reads only `role.Guardfiles`, so the overlay is parsed-but-unused today.

Target end state:

- **claude director** - model `claude-opus-4-8[1m]` (Opus 4.8, 1M context), effort **high**
- **claude engineer** - model `claude-fable-5` (Fable), effort medium
- **codex director** - model `gpt-5.5`, effort medium
- **codex engineer** - model `gpt-5.4-mini`, effort medium

advisor is unspecified, leave it with no overlay (inherits the flat per-agent default).

## Why

Directors run the attached heartbeat and want the strongest model at 1M context.
Engineers fan out many parallel containers, so a cheaper/faster model (Fable, gpt-5.4-mini)
at the same medium effort is the right cost/throughput trade. Today every role shares one
per-agent model, so there is no way to express "director gets Opus, engineer gets Fable".

## Scope (all in `ward`)

1. **Bump the cli-guard dep** from `v0.72.0` to `>= v0.73.0` (latest is v0.75.0) via
   `ward tidy`, so `fleetconfig.RoleAgentOverride` / `Role.AgentConfig` are reachable.

2. **Consume the overlay at launch.** Where the role is known and the agent's launch
   env-defaults are computed (`cmd/ward/container_bootstrap.go` reads `claude.Model` /
   `claude.ReasoningEffort`, codex likewise), apply the resolved role's
   `AgentConfig[<agent>]` overlay. Slot it into the existing precedence
   (`--config` > `WARD_*` env > **role overlay** > flat per-agent fleet default) from
   `docs/agent-config-overrides.md`. The role is already resolved for the guardfile set
   in `cmd/ward/agent_capability.go` (`capabilityForRole`), reuse that resolution.

3. **Populate the values** in `.ward/ward-kdl/ward-kdl.fle

… (truncated to 2000 chars; full body is on this issue)

Static container doctrine and seed boilerplate are identical every run and omitted here (they ride ward v0.414.0).

— Claude (she/her), via ward agent

<!-- ward-agent-reservation --> 🔒 Reserved by `ward agent --driver claude` — container `engineer-claude-ward-620` on host `KAI-DESKTOP-TOWER` is carrying this issue (reserved 2026-07-06T17:56:05Z). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); `--force` overrides. **Do not comment on or edit this issue to steer the run while it is reserved.** The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a **new issue, dispatched fresh** — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494). <details><summary>run seed context — what this run is carrying (ward#609)</summary> - **Resolved:** `coilyco-flight-deck/ward#620` · branch `issue-620` · driver `claude` · workflow `direct-main` - **Run:** `engineer-claude-ward-620` · ward `v0.414.0` · dispatched `2026-07-06T17:56:05Z` - **Comment thread:** 0 included in the pre-flight read, 0 stripped (ward's own automated comments). **Issue body as seeded:** ``` ## What Wire and populate **per-role x per-agent** model/effort defaults so a role's launch config diverges from the flat per-agent default. The cli-guard side of this (the `role X { agent claude { model ... reasoning-effort ... } }` overlay grammar) already landed as **cli-guard#192**, shipped in **cli-guard v0.73.0**. ward pins **v0.72.0** and reads only `role.Guardfiles`, so the overlay is parsed-but-unused today. Target end state: - **claude director** - model `claude-opus-4-8[1m]` (Opus 4.8, 1M context), effort **high** - **claude engineer** - model `claude-fable-5` (Fable), effort medium - **codex director** - model `gpt-5.5`, effort medium - **codex engineer** - model `gpt-5.4-mini`, effort medium advisor is unspecified, leave it with no overlay (inherits the flat per-agent default). ## Why Directors run the attached heartbeat and want the strongest model at 1M context. Engineers fan out many parallel containers, so a cheaper/faster model (Fable, gpt-5.4-mini) at the same medium effort is the right cost/throughput trade. Today every role shares one per-agent model, so there is no way to express "director gets Opus, engineer gets Fable". ## Scope (all in `ward`) 1. **Bump the cli-guard dep** from `v0.72.0` to `>= v0.73.0` (latest is v0.75.0) via `ward tidy`, so `fleetconfig.RoleAgentOverride` / `Role.AgentConfig` are reachable. 2. **Consume the overlay at launch.** Where the role is known and the agent's launch env-defaults are computed (`cmd/ward/container_bootstrap.go` reads `claude.Model` / `claude.ReasoningEffort`, codex likewise), apply the resolved role's `AgentConfig[<agent>]` overlay. Slot it into the existing precedence (`--config` > `WARD_*` env > **role overlay** > flat per-agent fleet default) from `docs/agent-config-overrides.md`. The role is already resolved for the guardfile set in `cmd/ward/agent_capability.go` (`capabilityForRole`), reuse that resolution. 3. **Populate the values** in `.ward/ward-kdl/ward-kdl.fle ``` … (truncated to 2000 chars; full body is on this issue) Static container doctrine and seed boilerplate are identical every run and omitted here (they ride ward v0.414.0). </details> <!-- ward-agent-signature --> — Claude (she/her), via `ward agent`
Author
Owner

WARD-OUTCOME: done - per-role model/effort overlay resolves at launch; director claude=claude-opus-4-8[1m]/high, engineer claude=claude-fable-5/medium (codex likewise), landed on main c8bf6bc.

Went smoothly, but two things fought back worth noting. First, the cli-guard bump: v0.75.0 (the latest) pulled in an unrelated broker.Executor change (a new LabelIssue method) that broke the build. The overlay itself landed in v0.73.0, so I pinned that instead - minimal surface, exactly what the issue asked (>= v0.73.0), and no half-related API churn dragged in. Second, the role plumbing had a subtle trap: the director surface builds its plan with roleDirector for capability resolution but then overwrites plan.Role to session for labels/naming. If I'd emitted WARD_ROLE from plan.Role the director surface would never have gotten Opus. I added a distinct upPlan.ConfigRole that carries the capability role through to the container, so the overlay resolves as director even though the container labels itself session. That felt like the real design decision of the ticket.

The "open question" resolved itself cleanly: my own runtime model id is claude-opus-4-8[1m], so the bracket form is confirmed a valid --model token for 1M-context Opus - no beta header needed, effort stays echo-only as before.

Confidence is high: precedence (env > overlay > flat default) is unit-tested end to end through buildAgentArgv, plus env-beats-overlay and the WARD_ROLE-carries-config-role cases. Pre-commit, build, test, vet all green.

Rough edges / follow-ups: (1) a fair bit of churn went into fitting the docs under the 4000-char/80-line caps in agent-config-overrides.md - it's tight now, and the next addition there will likely need a split. (2) /substrate/agentic-os/ward-specs/ward-kdl.fleet.kdl holds a reference copy of the fleet config; it's a neutral starter (not a live coilyco mirror) and read-only substrate, so I left it - but if that ever becomes an authored mirror, this overlay would need to propagate there too (tracked spirit of ward#503).

WARD-OUTCOME: done - per-role model/effort overlay resolves at launch; director claude=claude-opus-4-8[1m]/high, engineer claude=claude-fable-5/medium (codex likewise), landed on main c8bf6bc. Went smoothly, but two things fought back worth noting. First, the cli-guard bump: v0.75.0 (the latest) pulled in an unrelated broker.Executor change (a new LabelIssue method) that broke the build. The overlay itself landed in v0.73.0, so I pinned that instead - minimal surface, exactly what the issue asked (>= v0.73.0), and no half-related API churn dragged in. Second, the role plumbing had a subtle trap: the director surface builds its plan with roleDirector for capability resolution but then overwrites plan.Role to `session` for labels/naming. If I'd emitted WARD_ROLE from plan.Role the director surface would never have gotten Opus. I added a distinct upPlan.ConfigRole that carries the capability role through to the container, so the overlay resolves as `director` even though the container labels itself `session`. That felt like the real design decision of the ticket. The "open question" resolved itself cleanly: my own runtime model id is claude-opus-4-8[1m], so the bracket form is confirmed a valid --model token for 1M-context Opus - no beta header needed, effort stays echo-only as before. Confidence is high: precedence (env > overlay > flat default) is unit-tested end to end through buildAgentArgv, plus env-beats-overlay and the WARD_ROLE-carries-config-role cases. Pre-commit, build, test, vet all green. Rough edges / follow-ups: (1) a fair bit of churn went into fitting the docs under the 4000-char/80-line caps in agent-config-overrides.md - it's tight now, and the next addition there will likely need a split. (2) /substrate/agentic-os/ward-specs/ward-kdl.fleet.kdl holds a reference copy of the fleet config; it's a neutral starter (not a live coilyco mirror) and read-only substrate, so I left it - but if that ever becomes an authored mirror, this overlay would need to propagate there too (tracked spirit of ward#503).
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
coilyco-flight-deck/ward#620
No description provided.