Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
b8d2293
fix(bin): require a non-draft pull request before a PR-based done rep…
mremond Sep 21, 2026
d3c5e48
fix: support quota-axi schema 6 snapshots (#4904)
pedromuller-del Sep 21, 2026
a701e34
test: fix Claude session-start drain live E2E (#5165)
kunchenguid Sep 21, 2026
8015727
ci: pin the no-mistakes required check to v1.80.1 (#5195)
kunchenguid Sep 21, 2026
1fa9e9f
fix(bin): retain Pi watcher predecessor to stop false down alarms (#5…
sdivanl Sep 22, 2026
afc7b0e
fix(bin): allow cleanup of windowless legacy task records (#5236)
kunchenguid Sep 22, 2026
0551f95
ci: exempt kunchenguid from the no-mistakes required check (#5256)
kunchenguid Sep 22, 2026
0f99287
fix(bin): surface launches parked on an interactive prompt as not-sta…
sdivanl Sep 22, 2026
f412c61
fix: record away posture immediately on /afk (#5260)
kunchenguid Sep 22, 2026
12acf58
fix(bin): recognize passed-with-override as a passing outcome (#5294)
mremond Sep 22, 2026
53b7972
fix: clean up workers after their pull requests land (#5317)
kunchenguid Sep 22, 2026
4b9d8bf
fix: surface green no-mistakes PRs awaiting merge (#5327)
kunchenguid Sep 22, 2026
9fc20de
fix: derive Lavish polling route from board session (#5334)
kunchenguid Sep 22, 2026
1ffbb27
fix(bin): stop secondmate relaunch failing when watcher scratch files…
tiago-peixoto Sep 22, 2026
9e44ef6
fix(bin): stop each keyed answer from re-waking this home (#4907)
tiago-peixoto Sep 22, 2026
e1b277e
fix: deliver failed public follow-ups with updated AXI floors (#5350)
kunchenguid Sep 23, 2026
fdf55ae
fix(bin): refuse ship done: when the named head exists only in the wo…
tiago-peixoto Sep 23, 2026
fc03c1d
fix(bin): ring a proven-idle secondmate before raising a wake-loop st…
tiago-peixoto Sep 23, 2026
cfc198b
test(watch-arm): size re-arm waits off the real loaded recovery cost …
tiago-peixoto Sep 23, 2026
484dec4
fix: stop watchers reliably during blocked polls (#5362)
kunchenguid Sep 23, 2026
687ab2e
fix: submit stuck inbox doorbells instead of skipping them (#5374)
kunchenguid Sep 23, 2026
beaabe5
no-mistakes(test): Wake bash 3.2 watcher so one TERM stops it
danielkuykendall23-boop Sep 23, 2026
917e76f
no-mistakes(document): Note bash 3.2 SIGCHLD ticker in watcher signal…
danielkuykendall23-boop Sep 23, 2026
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
37 changes: 19 additions & 18 deletions .agents/skills/afk/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name: afk
description: >-
Enter the away posture when the captain invokes /afk, says they are going afk, `state/.afk-contract` or `state/.afk` exists, an incoming message starts with `FM_INJECT_MARK`, or any `state/.subsuper-*` marker is involved.
It records the captain's away words verbatim as the whole mandate, reads them back in plain sentences, writes the durable away-posture record after their go, announces hold-for-return only at entry, keeps the one supervision session running in the away posture (on Pi the supervision branch acts on the words by its own judgment and takes every safe actionable wake with main parked; the daemon still delivers batched digests on the other harnesses for now), and on the first unmarked message renders the return brief from durable records before ordinary work resumes.
It writes the durable away-posture record with the captain's away words verbatim as the whole mandate in the same turn as /afk, before any other work and without waiting for a further go, reads the words back in plain sentences after entry, announces hold-for-return only at entry, keeps the one supervision session running in the away posture (on Pi the supervision branch acts on the words by its own judgment and takes every safe actionable wake with main parked; the daemon still delivers batched digests on the other harnesses for now), and on the first unmarked message renders the return brief from durable records before ordinary work resumes.
user-invocable: true
metadata:
internal: true
Expand All @@ -13,26 +13,21 @@ metadata:
Away mode is a POSTURE of the one supervision session, not a second architecture.
Being away changes exactly two things: how the captain is informed, and what happens at a captain-owned decision point (hold for return, or the answer the captain's away words already gave).
It never changes the authority set.
The posture is a file, `state/.afk-contract`, written only by `bin/fm-afk-contract.sh` after the captain confirms a read-back; nothing infers the posture from chat.
The posture is a file, `state/.afk-contract`, written only by `bin/fm-afk-contract.sh` in the same turn as `/afk`; nothing infers the posture from chat.
Typing `/afk` is itself the go: the captain may not look at the screen again, so entry never waits for a further human response, and no read-back gates it or asks for a go.
Hold-for-return is the default and the only reach profile this release records: there is no phone channel, and the entry announcement says so aloud every time.

## Entering: `/afk [words]`

1. **Record the captain's words, verbatim.**
1. **Write the record first, in this same turn.**
Before any other work, run `bin/fm-afk-launch.sh enter --words-file <path> [--expected-return <UTC ISO 8601>] [--spend <n>]` (or `--words <text>`).
It writes `state/.afk-contract` at once, with no separate confirmation step, then prints the entry announcement and the record's read-back.
The words are the whole mandate: `bin/fm-afk-contract.sh` records them exactly as given, with no clause fields, verbs, ids, or merge-grant list, and by the captain's mandate no parser, tokenizer, classifier, or grammar reads them anywhere.
Read `bin/fm-afk-contract.sh --help` for the flags rather than memorizing them.
Plain `/afk` with no words is a valid entry with no mandate.
2. **Propose and read back.**
Run `bin/fm-afk-launch.sh propose --words-file <path> [--expected-return <UTC ISO 8601>] [--spend <n>]` (or `--words <text>`); it writes the proposal and prints the record's read-back.
Then relay your own plain-sentence restatement of the words to the captain in `AGENTS.md` section 9 language - what you read them as asking for, sentence by sentence, never a numbered field list - beside the expected return, the spend cap, and the one-sentence reach announcement, so the captain can catch a misreading before saying go.
Say plainly which sentence, if any, you could not act on while away (a red merge, a discard, anything on the never-set, local-only landing), so the captain can restate it or accept that it waits for their return.
3. **Confirm on the captain's go.**
Run `bin/fm-afk-launch.sh confirm`; it promotes the proposal into the record and prints the entry announcement.
Relay that announcement verbatim in spirit: hold-for-return only, no phone channel, your instructions are recorded and the away session will carry them out where it can, anything it is unsure of, or that needs you, waits for your return, and destructive, irreversible, and security-sensitive actions are never pre-authorizable whatever the words say.
With no words, run `propose` and `confirm` back to back; the announcement says no instructions were recorded.
Re-invoking `/afk` while already away with no new words is a refresh and leaves the standing record untouched; new words replace the mandate after the same read-back, preserve the original session entry, and archive the superseded words for the return brief.
4. **Per harness, after the record exists:**
- **Pi and pi-signed**: stop here.
Plain `/afk` with no words is a valid entry with no mandate; the announcement says no instructions were recorded.
Re-invoking `/afk` while already away with no new words is a refresh and leaves the standing record untouched; new words replace the mandate at once, preserve the original session entry, and archive the superseded words for the return brief.
2. **Per harness, after the record exists:**
- **Pi and pi-signed**: nothing to launch; go on to the announcement.
The away daemon is no longer launched on Pi; the ordinary supervision session (`docs/pi-supervision-branch.md`) keeps running with the record present, and `bin/fm-afk-launch.sh start` refuses on these harnesses.
With the record present main is parked: the supervision branch takes every safe actionable wake, captain outcomes accumulate for the return brief, and main's standing authority relocates to the branch through the guarded scripts (`docs/pi-supervision-branch.md` "Postures"); only a wake the branch declines (including a broken branch or unsafe scan) or a watcher failure wakes main.
`/quiet` needs nothing extra on Pi: the attended branch already keeps routine wakes out of this conversation, so quiet-while-present is the attended posture's own shape there.
Expand All @@ -42,9 +37,14 @@ Hold-for-return is the default and the only reach profile this release records:
Do not wrap it in `nohup ... &` (Codex/herdr can reap fire-and-forget shell children after a tool call returns).
- **Every other harness** (codex, opencode, omp, kimi, cursor): run `bin/fm-afk-launch.sh start`.
It is the single owner of the daemon terminal: it creates a NON-VISIBLE tracked terminal for the current backend and passes the captain pane in as `FM_SUPERVISOR_TARGET` so the daemon injects into the captain, not its own new pane (docs/herdr-backend.md "Away-mode supervisor support").
Both daemon paths require the already-confirmed record and share `bin/fm-afk-start.sh` as the daemon entry.
Both daemon paths require the record `enter` wrote and share `bin/fm-afk-start.sh` as the daemon entry.
The daemon is **presence-gated**: it injects escalations only while `state/.afk` exists, and stays quiet otherwise.
5. **Do not separately arm `fm-watch.sh` where the daemon runs.** The daemon manages the watcher as its child; the singleton lock no-ops a stray arm harmlessly.
3. **Announce, then read back after entry.**
Relay the announcement in spirit: hold-for-return only, no phone channel, your instructions are recorded and the away session will carry them out where it can, anything it is unsure of, or that needs you, waits for your return, and destructive, irreversible, and security-sensitive actions are never pre-authorizable whatever the words say.
Then give your own plain-sentence restatement of the words in `AGENTS.md` section 9 language - what you read them as asking for, sentence by sentence, never a numbered field list - beside the expected return, the spend cap, and the one-sentence reach announcement.
Say plainly which sentence, if any, you could not act on while away (a red merge, a discard, anything on the never-set, local-only landing); it waits for their return.
This read-back is informational: the record already stands, so never ask for a go or wait for a reply; a captain who wants a different reading sends `/afk` again with new words.
4. **Do not separately arm `fm-watch.sh` where the daemon runs.** The daemon manages the watcher as its child; the singleton lock no-ops a stray arm harmlessly.
On Pi nothing changes about arming: the supervision session's own cycle continues.

## While away
Expand All @@ -65,12 +65,13 @@ No `/back` is needed. The first genuine message is the return signal:
- A message **without** the current operational prefix or a legacy bare marker, and **not** starting with `/afk` -> the captain is back.
Run `bin/fm-afk-return.sh` before acting on the message that brought the captain back.
That script owns the correct-ordered daemon shutdown where a daemon ran, the archive of the posture record, durable wake presentation and post-handling acknowledgement, escalation and wedge evidence, the return brief, and the return-catch-up gate.
Relay the return brief in section 9 language and in its own order: supervisor health across the away window first (any gap leads), then the captain's instructions verbatim with the away session's account of every action it took under them, then what is waiting on the captain, then what was tried and failed or could not be fixed, then what was handled, then cost.
Relay every section of the return brief in its emitted order and in section 9 language; `bin/fm-afk-return.sh` owns that order.
The gate keeps every open `blocked:` event until that blocker's own resolution is proven: remediate each immediately through the normal lifecycle, or explicitly reclassify it with a durable reason and close its decision key with `resolved [key=...]`, then run `bin/fm-afk-return.sh check`.
Captain-verdict outcomes are listed under "waiting on you", but do not exempt open blockers: per-blocker provenance is deferred with no owner, and the gate fails safe by keeping every open blocker.
Once the record is archived, resume full per-wake responsiveness through the emitted primary-harness supervision protocol while blocker handling proceeds, so the gate never creates a blind wait.
A Bearings request may be answered while the gate is open, and the digest surfaces the catch-up state as a Charted Next `(return-catchup)` warning row naming what still holds it.
Acting on the fleet - dispatching, steering, merging, or any other ordinary captain work - still waits until the check exits successfully.
Once it does, close every task the brief lists under "Landed, cleanup due" through ordinary teardown (`bin/fm-teardown.sh <task>`, never forced; a refusal is a stop-and-investigate result) and tell the captain those workers are closed in outcome language.
- A message **with** the current operational prefix (`FM_OPERATIONAL_PREFIX`, U+2063 INVISIBLE SEPARATOR followed by `FIRSTMATE_OP: `), or a legacy bare `FM_INJECT_MARK` daemon escalation -> stay away and process it.
- Re-invoking `/afk` while already away -> stay away (refresh); this does **not** trigger an exit.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ A `--secondmate` launch omits the statement because a secondmate operates under

## Primary integration

Primary behavior was verified 2026-07-04 on 2.1.201, preserved 2026-07-08 on 2.1.204, and Stop auto-arm revalidated 2026-07-24 on 2.1.219.
[`../../../../../docs/verification/supervision.md`](../../../../../docs/verification/supervision.md#turn-end-guard) records the current primary and Stop auto-arm live evidence.
This differs from the worker hook, which only touches a task marker through `.claude/settings.local.json`.

Primary `.claude/settings.json` registers `../../../bin/fm-turnend-guard.sh --claude` and `../../../bin/fm-claude-stop-autoarm.sh` with `asyncRewake: true` and `timeout: 28800`.
Expand Down
1 change: 1 addition & 0 deletions .agents/skills/process-event-sources/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Firstmate registers a source, keeps working, and is woken when that process comp
## Arming a source

Use the adapter, not the generic runner, for a real source.
Before either Lavish arm form below, open the artifact with `lavish-axi` so its saved session can route the listener; the [operating contract](../../../docs/configuration.md#process-to-event-sources-stateprocevent) owns the prerequisite and refusal boundary.
For a Lavish review artifact firstmate owns:

```sh
Expand Down
15 changes: 8 additions & 7 deletions .agents/skills/quota-array-dispatch/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ This skill is the single owner of the completion-aware profile-array selection p
`harness-adapters` owns harness verification, model/provider discovery, and effort fallback.
`quota-axi` remains data-only: it publishes `spendPriority` as a comparable scalar and never recommends, selects, ranks, or infers a route.
Do not add a daemon, opaque composite score, routing wrapper, hard-coded model-specific policy, or producer-side route recommendation.
Deterministic shell owns only schema, configuration, and version validation plus concrete spawn safeguards; every model-to-provider, provider-to-credential, and quota-applicability relation is yours to establish transparently and to show your evidence for.
The [worker helper](../../../bin/fm-quota-choose.sh) and [typed resolver](../../../docs/configuration.md#typed-dispatch-resolution-env-typesafe_api_key) own their deterministic mapping boundaries.

## Worker-side quota helper

The canonical shell helper for a worker that has already performed its model-selection reasoning and now needs to pick the first viable candidate is `bin/fm-quota-choose.sh`.
Pass it the intake's already-captured default TOON or permitted JSON fallback through stdin or `--snapshot`; it never takes another quota snapshot, so it selects from the same quota state as the intake.
Pass each candidate as `harness:model`, with earlier candidates preferred.
The helper maps each harness to its primary provider family and applies the provider-wide scopes plus the exact model or product scopes for the model.
The helper's header owns its provider mapping and quota selection mechanics.
An `exhausted_now` runway vetoes the candidate.
The helper selects a candidate only when its applicable quota has a known `effectivePercentRemaining` greater than zero.
This is an optional narrow helper with a known limitation: it maps each harness to one primary provider family only, so a candidate whose established provider differs from that primary family is checked against the wrong quota row.
Expand All @@ -33,7 +33,8 @@ Authoritative multi-provider routing - including provider discovery from the har
Use it only when the brief already fixed the candidate order and every candidate's provider is the harness's primary family.
It does not replace the reasoning-class, runway-feasibility, or authentication gates above.
Firstmate can optionally arm `bin/fm-procevent-quota.sh` for a recurring mid-task check that wakes when the tracked provider drops below its configured threshold or its runway becomes `exhausted_now`.
The opt-in `bin/fm-dispatch-resolve.sh` (`docs/configuration.md` "Typed dispatch resolution") applies the same eligibility gates and `spendPriority` argmax in code after a typed rule match; it never removes this skill's authority, and its `ambiguous`, `escalate`, and `error` outcomes return here.
The opt-in [typed resolver](../../../docs/configuration.md#typed-dispatch-resolution-env-typesafe_api_key) has its own documented gates.
It never removes this skill's authority, and its `ambiguous`, `escalate`, and `error` outcomes return here.

## Read the default TOON

Expand Down Expand Up @@ -62,15 +63,15 @@ It cannot override a hard-gate failure, and it is never hidden inside a new comp

### 1. Eligibility

Deterministic shell must never map a model to a provider, a provider to a credential store, or a name prefix to a family.
You establish those relations yourself, in the open, from the candidate's own authoritative catalog (`harness-adapters` owns the per-harness discovery surface) plus the one intake snapshot.
Outside those documented mappings, deterministic shell must not infer a provider family or credential store from a harness, model, or source name.
You establish the remaining relations yourself, in the open, from the candidate's own authoritative catalog (`harness-adapters` owns the per-harness discovery surface) plus the one intake snapshot.

Confirm the catalog lists the candidate's model and record the provider family it reports.
A model the catalog does not list is concrete contradictory evidence: block that candidate and quote the catalog result.
Apply quota at the granularity the vendor actually supplies.
A provider-level or `all_models`/`all_products` scope bounds every model you established in that family, including one with no window of its own.
A provider-level or `all_models`/`all_products` scope bounds every model you established in that family within the candidate's matched account, including one with no window of its own.
A named-model or named-product scope is an additional bound for that model alone.
Match the candidate to its `quota[]` row by that established provider and scope; a stale, auth-required, or unmeasurable scope is named in `attention[]` instead of a fabricated number.
Match the candidate to its `quota[]` row by that established provider, its `accountKey` when the snapshot is schema 6 (a Pi lane's auth provider id such as `openai-codex-work`, or `codex-home` for native Codex including Pi's `codex-native/` adapter, then the `default` row, else unmeasured; never a row picked by position, never rows summed across accounts), and scope; a stale, auth-required, or unmeasurable scope is named in `attention[]` instead of a fabricated number.

A candidate authenticates through its own tuple's surface; another harness's CLI can never gate it, and `harness=pi` with `model=xai/grok-*` is Pi using xAI rather than the standalone Grok CLI.
`quota-axi auth --json` lists each provider's credential sources independently, so read the one source the candidate actually uses rather than collapsing a provider to a single status.
Expand Down
1 change: 1 addition & 0 deletions .agents/skills/stuck-crewmate-recovery/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ metadata:
# stuck-crewmate-recovery

Use this playbook when the session-start digest reports an ordinary direct report's endpoint dead or its metadata has no window, or when a direct report is stale, looping, repeatedly confused, asking a question its brief already answers, unresponsive, or when a steer failed to land.
A stale or dead-endpoint report for a worker whose pull request has already landed is not a recovery case: the work is finished, so close the task through ordinary teardown (`AGENTS.md` section 7 for firstmate, the landed-work rule in `bin/fm-branch-prompt.sh` for the supervision branch) instead of this playbook, never with `--force`.

Follow the crew-hosted Lavish board contract in [`docs/configuration.md`](../../../docs/configuration.md#crew-hosted-lavish-review-boards) when recovering a worker that hosts a board.

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ jobs:
[ "$parse_fail" -eq 0 ] || { echo "::error::stock macOS Bash 3.2 parse sweep failed"; exit 1; }

command -v npm >/dev/null || { echo "::error::npm is required to install tasks-axi"; exit 1; }
npm install -g tasks-axi@0.2.5 >/dev/null
npm install -g tasks-axi@0.2.6 >/dev/null
PATH="$(npm prefix -g)/bin:$PATH"
export PATH
command -v tasks-axi >/dev/null || { echo "::error::tasks-axi is required for the stock Bash regressions"; exit 1; }
Expand Down
Loading