Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .agents/skills/harness-adapters/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Use this reference before any harness-specific firstmate operation: spawn, recov

Crewmates default to the same harness firstmate is running on unless `config/crew-harness` records an adapter name.
Optional dispatch profiles in `config/crew-dispatch.json` can override that static default for one crewmate or scout dispatch by selecting concrete harness, model, and effort axes at intake.
When a matched rule or default is a profile array, load `quota-array-dispatch` for the pace-aware candidate choice after this skill establishes harness and model/provider facts.
The captain may override that file at session start or later; a per-task instruction such as "run this one on codex" overrides it for that dispatch only.
`default` means mirror firstmate's own harness.

Expand Down
170 changes: 170 additions & 0 deletions .agents/skills/quota-array-dispatch/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
---
name: quota-array-dispatch
description: >-
Agent-only decision procedure for resolving a matched crew-dispatch profile
array from current quota-axi output, including quota-window pace signals.
Load when a dispatch rule or default resolves to more than one profile candidate.
user-invocable: false
metadata:
internal: true
---

# quota-array-dispatch

This skill is the single owner of the pace-aware profile-array selection procedure.
The concise always-loaded intake boundary remains in `AGENTS.md` section 4.
`docs/configuration.md` owns the `config/crew-dispatch.json` schema only.
`quota-axi` remains data-only and never recommends a route.
Firstmate owns the judgment.
Do not add a daemon, opaque composite score, routing wrapper, hard-coded model-specific policy, or producer-side route recommendation.

## When to load

Load this skill whenever a matched dispatch rule or the configured default resolves to a profile array (more than one candidate), before choosing the concrete `--harness`, `--model`, and `--effort` passed to `fm-spawn`.
Keep using `harness-adapters` for harness verification, model/provider discovery, and effort fallback.

## Intake boundary this skill does not relax

1. Explicit per-task captain overrides still win over configured profiles.
2. Configured profile matching precedence is unchanged: best-fit rule, then configured default, then static crewmate harness.
3. Malformed `config/crew-dispatch.json` remains an actionable error; never select around it.
4. Every configured candidate in the matched array must be accounted for.
5. If any harness/model/provider relationship, applicable quota data, or interpretation cannot be established, stop and report that candidate instead of omitting it, guessing, falling back, or calling the result quota-informed.
6. When every candidate is tight, preserve the captain's strongest-reasoning class rather than silently downgrading it solely to conserve quota; stop and report the tight choice if that class cannot proceed.
7. Genuine ties must remain free of array-order or harness bias.

## Collect inspectable facts for every candidate

For each candidate profile:

1. Establish the harness/model/provider relationship from current authoritative discovery owned by `harness-adapters`.
Fail loudly on an unresolved relationship.
2. Run `quota-axi --json` once per intake and reuse that snapshot for every candidate.
3. Require a current provider report with known quota semantics and a known applicable effective-availability record for that candidate's provider and model scope.
Stale raw windows remain diagnostic evidence only and are never current headroom.
4. Read every bounding window relevant to that candidate, including windows named by `boundedBy`, `limitingWindowIds`, `aheadWindowIds`, `behindWindowIds`, `onPaceWindowIds`, and `unknownWindowIds` on the effective record.
5. Record these inspectable facts, never a hidden score:
- task/profile fit
- reasoning class required by the captain request or task ambiguity
- raw applicable headroom (`effectivePercentRemaining` or the tightest applicable remaining percentage)
- effective pace status when present
- signed reserve for each applicable window and the effective worst reserve when present
- whether any applicable window or effective summary is ahead of reset
- whether any applicable pace is `unknown`
- schema compatibility note when pace fields are absent

## Pace signals

quota-axi `schemaVersion` 3 window pace uses:

- `reservePercentPoints = percentRemaining - timeRemainingPercent`
- Negative reserve means usage is ahead of reset pace and creates conservation pressure.
- Positive reserve means usage is behind reset pace.
- `on_pace` is neutral.

Effective-availability pace summaries may report `ahead`, `behind`, `on_pace`, `mixed`, or `unknown`.

Treat conservation pressure as present when:

- effective pace status is `ahead`, or
- effective pace status is `mixed` and any `aheadWindowIds` remain, or
- any applicable bounding window itself has pace status `ahead`.

An effective `mixed` result is never healthy merely because one window is behind.
Any remaining `aheadWindowIds` keep conservation pressure.

Signed reserve comparison uses the worst applicable reserve, preferring the producer field `worstReservePercentPoints` when present and otherwise the minimum signed reserve across applicable bounding windows.

## Selection procedure

Apply these steps only among candidates that already satisfy required task/profile fit and the strongest reasoning class the request genuinely needs.
Never use pace or raw headroom to silently replace that reasoning class with a weaker one.

1. **Unresolved relationship or quota data**
Stop and report the blocked candidate.
2. **Strongest-reasoning / all-tight**
If every remaining candidate is tight, keep the strongest-reasoning class and either dispatch inside that class or stop and report that the tight choice cannot proceed.
Do not conserve quota through an unapproved downgrade.
3. **Conservation pressure vs sustainable pace**
When fit and reasoning class are comparable, prefer a candidate without ahead-of-reset conservation pressure over one with conservation pressure, even when the pressured candidate has somewhat higher raw remaining percentage.
4. **Among pressured candidates**
Prefer the least-negative worst applicable reserve.
Example: worst reserve `-4` is safer than `-18` when other inspectable facts are comparable.
5. **Among sustainable candidates**
Use known behind/on-pace evidence plus raw headroom transparently.
Do not collapse those facts into an opaque composite score.
Prefer known sustainable evidence over `unknown` pace when otherwise comparable.
Between known sustainable candidates, prefer the clearly better inspectable pair of pace reserve and raw headroom; state both facts in the choice rationale.
6. **Unknown pace**
`unknown` is valid explicit uncertainty from quota-axi, not a parser failure and not permission to assume the window is healthy or exhausted.
Inspect `unknownWindowIds` and each window's pace `reason` so the rationale preserves the producer's stated uncertainty.
Prefer known sustainable evidence when otherwise comparable.
If the dispatch choice materially hinges on unresolved pace, report the uncertainty rather than inventing a conclusion.
7. **Absent pace / older schema**
`schemaVersion` 2 payloads or missing pace fields must degrade explicitly and safely.
Do not crash, fabricate pace, or silently reinterpret absence as healthy/`on_pace`.
Compare raw applicable headroom only, using known effective availability rather than stale or isolated window percentages, state that pace is unavailable, and keep every other safety rule above.
8. **Genuine ties**
If every inspectable selection fact is equal, stop and report every tied candidate for captain choice.
Do not select by array order, harness name, or another arbitrary identity ordering.
Report duplicate concrete profiles as a configuration error.

The intake rationale must name the inspectable facts used for every candidate.
Never conclude with an unexplained "best quota" label.

## Acceptance scenarios

These scenarios are normative examples of the procedure above.

### Higher raw quota but materially ahead vs lower raw quota on/behind pace

Candidate A has higher `effectivePercentRemaining` but conservation pressure from an ahead bounding window.
Candidate B has lower raw headroom, no conservation pressure, and known behind or on-pace evidence.
Choose B when fit and reasoning class are comparable.

### Mixed effective pace with an ahead bound

Effective pace status is `mixed` and `aheadWindowIds` is non-empty.
Treat the candidate as conservation-pressured even if another window is behind or on pace.

### Both candidates ahead with different worst reserves

Both candidates have conservation pressure.
Choose the least-negative worst applicable reserve when fit and reasoning class are comparable.

### Known sustainable versus unknown

Candidate A has known behind or on-pace evidence.
Candidate B has comparable fit, reasoning class, and raw headroom but `unknown` pace.
Prefer A.
If the only way to prefer one side depends on unresolved pace and no known sustainable candidate remains, report the uncertainty.

### Every candidate tight while strongest-reasoning applies

All candidates are tight on real headroom.
Keep the strongest reasoning class required by the request.
Do not pick a weaker class only to save quota.
Dispatch inside that class or stop and report that the tight strongest-class choice cannot proceed.

### Genuine tie without array-order or harness bias

Two candidates match on fit, reasoning class, conservation pressure, worst reserve, pace class, raw headroom, and unknown flags.
Choosing either array order or a standing harness preference is forbidden.
Stop and report both tied candidates for captain choice.

### schemaVersion 2 or absent-pace compatibility

Older quota-axi output or missing pace fields still allow array resolution.
Compare raw headroom only, state that pace is unavailable, and do not invent ahead/behind/on_pace.

## Sanitized producer shape

Validate consumers against a sanitized `schemaVersion` 3 shape derived from quota-axi 0.1.15:

- top level: `schemaVersion`, `generatedAt`, `providers[]`
- each provider: `provider`, `state`, `windows[]`, and optional `quotaSemantics` with `status` and `effectiveAvailability[]`
- each window: `id`, `label`, `kind`, and optional `percentRemaining` and `pace`; pace has `status` plus optional `reason`, `timeRemainingPercent`, and `reservePercentPoints`
- each effective-availability entry: `scope`, `status`, `boundedBy`, optional `effectivePercentRemaining`, optional `limitingWindowIds`, and optional pace summary
- each effective pace summary: `status` plus optional `aheadWindowIds`, `behindWindowIds`, `onPaceWindowIds`, `unknownWindowIds`, `worstReservePercentPoints`, and `worstReserveWindowId`

Never persist live provider balances, reset timestamps, account identifiers, or other private account details in tracked fixtures.
6 changes: 4 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,12 +164,13 @@ If static `config/crew-harness` or `config/secondmate-harness` names an unverifi
`docs/configuration.md` owns dispatch-profile and runtime-backend schemas, `bin/fm-harness.sh` owns static resolution, and `bin/fm-spawn.sh` owns launch flags and fail-closed validation.
When dispatch profiles exist, consult them at every crewmate or scout intake and pass the resolved concrete profile required by `fm-spawn`.
Routing precedence is an explicit per-task captain override, then the best-fit configured rule, then the configured default, then the static crewmate harness.
Firstmate alone resolves a matched profile array: run `quota-axi --json` at that intake, evaluate every configured candidate against that current output, and choose the candidate with the most real headroom.
Firstmate alone resolves a matched profile array: run `quota-axi --json` at that intake, evaluate every configured candidate against that current output, and choose with inspectable real headroom including quota-window pace.
Account for every candidate; if any harness/model/provider relationship, applicable quota data, or interpretation cannot be established, stop and report that candidate instead of omitting it, guessing, falling back, or calling the result quota-informed.
Preserve malformed profile configuration as an actionable error rather than selecting around it.
When every candidate is tight, preserve the captain's strongest-reasoning class rather than silently downgrading it solely to conserve quota; stop and report the tight choice if that class cannot proceed.
Break genuine headroom ties without array-order or harness bias.
`quota-axi` owns how model or product windows relate to bounding account windows.
`quota-axi` owns how model or product windows relate to bounding account windows and remains data-only.
Load `quota-array-dispatch` before choosing among a matched profile array; that skill is the single owner of the pace-aware selection procedure.
The generic effort fallback and its precedence are owned by `harness-adapters`: explicit captain and standing configured effort win; otherwise use low for well-understood explicit work, xhigh for ambiguous investigation or design, intermediate levels proportionally, and never max without explicit captain preference.
Do not add model-specific versions of that policy.

Expand Down Expand Up @@ -472,6 +473,7 @@ These skills are not captain-invocable; load them only at their precise triggers
- `bootstrap-diagnostics` - load whenever the session-start digest's bootstrap section prints an actionable diagnostic line (`MISSING:`, `MISSING_MANUAL:`, `BACKEND_INVALID:`, `NEEDS_GH_AUTH`, `TANGLE:`, `CREW_DISPATCH: invalid`, `FLEET_SYNC:`, `PR_CHECK_MIGRATION:`, `SECONDMATE_SYNC:`, `SECONDMATE_LIVENESS:`, `NUDGE_SECONDMATES:`, or `FMX:`); silence and `BOOTSTRAP_INFO:` need no load.
- `diagnostic-reasoning` - load before scoping a reported bug and before acting on a diagnostic report.
- `ask-user-authority` - load before deciding any ask-user finding, regardless of the project's `yolo` posture.
- `quota-array-dispatch` - load before choosing among a matched crew-dispatch profile array from current quota-axi output.
- `harness-adapters` - load before spawning or recovering a crewmate or secondmate, handling a trust dialog, sending a harness-specific skill invocation, interrupting or exiting an agent, resuming an exited agent, or verifying a new harness adapter.
- `firstmate-orca` - load before switching to Orca, spawning or supervising Orca-backed work, smoke-testing Orca backend behavior, debugging Orca task state, or reconciling Orca-backed task metadata.
- `project-management` - load before adding, creating, removing, or initializing a project.
Expand Down
3 changes: 2 additions & 1 deletion bin/fm-bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@
# with update --archive-body and mv [<id>...]); an installed but
# incompatible build reports MISSING like no-mistakes. A compatible
# tasks-axi default backend is silent. quota-axi is required for the
# agent-owned dispatch-profile array procedure in AGENTS.md section 4.
# agent-owned dispatch-profile array procedure in AGENTS.md section 4
# and .agents/skills/quota-array-dispatch/SKILL.md.
# X mode is OPTIONAL and inert unless FM_HOME/.env has a non-empty
# FMX_PAIRING_TOKEN. When opted in, bootstrap requires curl+jq, writes
# the relay poll shim and 30s cadence config, and prints an FMX line.
Expand Down
2 changes: 1 addition & 1 deletion docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ The intake and authority contract in `AGENTS.md` owns when separate scout resear
## Dispatch profiles

Crewmate and scout dispatch can stay on the static crewmate harness resolved by `config/crew-harness`, or it can use local dispatch profiles in `config/crew-dispatch.json`.
The dispatch file is intentionally judgment-based: firstmate reads the natural-language rules at intake, chooses the best matching rule, resolves profile arrays itself from current quota output under `AGENTS.md` section 4, and passes only concrete `--harness`, `--model`, and `--effort` axes to `fm-spawn.sh`.
The dispatch file is intentionally judgment-based: firstmate reads the natural-language rules at intake, chooses the best matching rule, resolves profile arrays itself from current quota output under the `AGENTS.md` section 4 intake boundary and the `quota-array-dispatch` selection procedure, and passes only concrete `--harness`, `--model`, and `--effort` axes to `fm-spawn.sh`.
The shell scripts validate the JSON shape and verified harness/effort combinations, but they do not parse task intent, match natural-language rules, or own array selection.
The session-start bootstrap step keeps valid dispatch configuration silent unless verbose facts are enabled and surfaces a concise invalid-config line when validation fails.
When the file exists, `fm-spawn.sh` refuses crewmate and scout launches without an explicit harness, so `config/crew-harness` is only automatic when no dispatch profile file is active.
Expand Down
7 changes: 4 additions & 3 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,11 +207,12 @@ For Pi and pi-signed secondmate launches, `fm-spawn.sh` starts the selected exec
## Crew dispatch profiles (config/crew-dispatch.json)

`config/crew-dispatch.json` is an optional local, gitignored file containing natural-language rules that firstmate reads before dispatching a crewmate or scout.
The shell scripts do not match those rules; firstmate chooses the best matching rule with judgment, resolves its profile object or array under the operating contract in `AGENTS.md` section 4, and passes only concrete `--harness`, `--model`, and `--effort` flags to `fm-spawn.sh`.
The shell scripts do not match those rules; firstmate chooses the best matching rule with judgment, resolves its profile object or array under the operating contract in `AGENTS.md` section 4 and `quota-array-dispatch`, and passes only concrete `--harness`, `--model`, and `--effort` flags to `fm-spawn.sh`.
When the file exists, `fm-spawn.sh` enforces that contract by refusing crewmate and scout spawns that lack an explicit harness (`--harness`, a positional adapter, or a raw launch command).
Batch spawns satisfy the same requirement with a shared `--harness`.
Secondmate spawns are exempt and still resolve through `config/secondmate-harness` and its optional model and effort tokens.
This section is the single owner of the canonical schema and its per-field semantics; `AGENTS.md` section 4 owns the dispatch and array-selection procedure.
This section is the single owner of the canonical schema and its per-field semantics.
`AGENTS.md` section 4 owns the always-loaded dispatch intake boundary, and `quota-array-dispatch` owns the pace-aware profile-array selection procedure.

```json
{
Expand All @@ -235,7 +236,7 @@ Both `use` and the optional top-level `default` accept either one profile object
The single-object form stays fully backward-compatible, and every profile needs `harness`.
Profile `model` and `effort` fields and rule `why` are optional.
An omitted model or effort means the selected harness uses its own default for that axis.
Every profile array is an implicit quota-aware choice.
Every profile array is an implicit quota-aware choice resolved through `quota-array-dispatch`.
If no dispatch rule fits, firstmate resolves `default` through the same object-or-array path before falling back to `config/crew-harness`.
If a selected profile carries an effort value the chosen harness does not accept, `fm-spawn.sh` records the requested `effort=` in task meta for traceability but omits the launch flag, and bootstrap reports the invalid harness/effort pair as a `CREW_DISPATCH` diagnostic when it is visible in the file.
See [`docs/examples/crew-dispatch.json`](examples/crew-dispatch.json) for a starting point to copy into local `config/crew-dispatch.json`.
Expand Down
4 changes: 4 additions & 0 deletions docs/documentation-audiences.json
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,10 @@
"path": ".agents/skills/project-management/SKILL.md",
"audience": "agent-runtime"
},
{
"path": ".agents/skills/quota-array-dispatch/SKILL.md",
"audience": "agent-runtime"
},
{
"path": ".agents/skills/secondmate-provisioning/SKILL.md",
"audience": "agent-runtime"
Expand Down
Loading
Loading