Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
f5735dc
fix: record away posture immediately on /afk (#5260)
kunchenguid Sep 22, 2026
c5131a3
fix(bin): recognize passed-with-override as a passing outcome (#5294)
mremond Sep 22, 2026
ada21f5
fix: clean up workers after their pull requests land (#5317)
kunchenguid Sep 22, 2026
d92cea0
fix: surface green no-mistakes PRs awaiting merge (#5327)
kunchenguid Sep 22, 2026
884d76b
fix: derive Lavish polling route from board session (#5334)
kunchenguid Sep 22, 2026
dd9f2b4
fix(bin): stop secondmate relaunch failing when watcher scratch files…
tiago-peixoto Sep 22, 2026
39f4c2a
fix(bin): stop each keyed answer from re-waking this home (#4907)
tiago-peixoto Sep 22, 2026
706254d
fix: deliver failed public follow-ups with updated AXI floors (#5350)
kunchenguid Sep 23, 2026
a8a2959
fix(bin): refuse ship done: when the named head exists only in the wo…
tiago-peixoto Sep 23, 2026
82dec2e
fix(bin): ring a proven-idle secondmate before raising a wake-loop st…
tiago-peixoto Sep 23, 2026
a5d78f8
test(watch-arm): size re-arm waits off the real loaded recovery cost …
tiago-peixoto Sep 23, 2026
52fca51
fix: stop watchers reliably during blocked polls (#5362)
kunchenguid Sep 23, 2026
c576c2b
fix: submit stuck inbox doorbells instead of skipping them (#5374)
kunchenguid Sep 23, 2026
f2ab14a
feat: add opt-in fleet activity ledger (#5375)
kunchenguid Sep 23, 2026
e7cb23e
fix: validate public follow-up deliverables and wake on rejection (#5…
kunchenguid Sep 23, 2026
697d94d
feat: add Devin CLI crewmate and scout adapter (#5380)
kunchenguid Sep 23, 2026
7c8f9ee
fix(bin): recognize passed-with-skips as a passing outcome (#5322)
mremond Sep 23, 2026
2efa581
fix(bin): refuse unavailable backend adapters before sourcing (#5382)
Lakescape Sep 23, 2026
77e5af9
test: repair base-red liveness, export-DOM, and wake-queue self-tests…
blackxwhite88 Sep 23, 2026
fef37b9
fix: keep watcher status classification bounded to new log spans (#5383)
kunchenguid Sep 23, 2026
f0da72c
test: close pr-check watcher test gaps (original flake already fixed …
kunchenguid Sep 23, 2026
c00d5e1
feat: record fleet status immediately and emit PR-ready events (#5385)
kunchenguid Sep 23, 2026
1e0e773
test: synchronize foreign queue stall checks with watcher progress (#…
kunchenguid Sep 23, 2026
8c47279
test: isolate the bearings render fixture from the shared Lavish stor…
kunchenguid Sep 23, 2026
7e0e60a
fix(bin): prune a torn-down task's wake rows at teardown (#5390)
blackxwhite88 Sep 23, 2026
9296f9b
test: align portable test expectations with resolved host paths and f…
sandeepsalwan1 Sep 23, 2026
5df1294
test: make sibling secondmate stall tests wait for watcher observatio…
kunchenguid Sep 23, 2026
1d3ac67
fix(bin): refuse a Herdr Claude submit that would send only a message…
tiago-peixoto Sep 23, 2026
fdd3687
feat(bin): publish and watch Gerrit changes on forge-bound projects (…
slnkjthien Sep 23, 2026
0afc6b4
feat(bin): opt-in per-home Claude and Pi worker account pin (#5358)
tiago-peixoto Sep 23, 2026
5bbb978
fix(bin): keep Herdr lab session selection before passthrough argumen…
yasuhito Sep 23, 2026
ac2ed3b
fix: enforce supervision guards across harnesses (#5471)
kunchenguid Sep 23, 2026
67130f1
feat(bin): make the ship-branch prefix configurable per project (#2648)
wesleymatosdev Sep 24, 2026
795e4b5
feat(bin): send dispatch router only the brief's task sections and ad…
zachlandes Sep 24, 2026
9284978
feat: add opt-in Claude away supervision host (#5488)
kunchenguid Sep 24, 2026
d4f3b78
docs: correct the Grok harness reference on folder trust, training op…
Courtneyezra Sep 24, 2026
1293295
feat(spawn): support config/claude-launcher and mirasim process class…
Arobotmaster Sep 24, 2026
17069e8
fix(tests): quote variable assignments to satisfy ShellCheck SC2100
Arobotmaster Sep 24, 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
46 changes: 26 additions & 20 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,38 +13,41 @@ 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.
- **Harness WITH a native in-pane tracked-background tool** (claude's background bash, grok's background tool): run `bin/fm-afk-launch.sh start-native`, then run `FM_AFK_STATE_PREPARED=1 bin/fm-afk-start.sh` through that native tool.
- **Claude with `config/supervision-host`**: nothing to launch for `/afk`; go on to the announcement.
The supervision host (`docs/supervision-host.md`) is the away session there: it runs the branch's contract on a headless engine under the record while main is parked, and `bin/fm-afk-launch.sh start-native` refuses the away daemon on that home.
`/quiet` is unchanged there and still launches the daemon below.
- **Harness WITH a native in-pane tracked-background tool** (claude's background bash without the supervision host, grok's background tool): run `bin/fm-afk-launch.sh start-native`, then run `FM_AFK_STATE_PREPARED=1 bin/fm-afk-start.sh` through that native tool.
This is a deliberate no-separate-terminal exception because the harness-hosted job creates no terminal or layout mutation, and a shell launcher cannot invoke a harness-native background tool.
If the native launch fails, run `bin/fm-afk-launch.sh stop` to roll back the prepared lifecycle.
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 @@ -56,6 +59,7 @@ Hold-for-return is the default and the only reach profile this release records:
Destructive, irreversible, and security-sensitive actions are never pre-authorizable whatever the words say, and ask-user findings keep the `ask-user-authority` policy unless the words pre-answer the exact decision; anything else that needs the captain holds for their return.
- On Pi, main is parked and the supervision branch handles every safe actionable wake under main's standing authority, through the same guarded scripts main would use: any pull request green at its live head may merge (which one the words meant is the branch's reading), queued work whose blockers cleared - already queued, or filed by the branch because the words explicitly call for it - dispatches within the spend cap, and a decision is answered with the captain's own pre-stated answer or under `ask-user-authority`.
Anything else holds for the return, a red merge never proceeds while away, local-only landing always waits for the captain, and only a wake the branch declines (including a broken branch or unsafe scan) or a watcher failure wakes main (`docs/pi-supervision-branch.md` "Postures").
- On a Claude home with `config/supervision-host`, the host's engine is that branch under the same rules, and a wake it hands back reaches main as `Stop hook feedback` with a `supervision-host:` line: that is automatic supervision, never the captain's return, so handle it under the away posture ([supervision protocol](../../../docs/supervision-protocols/supervision-host.md)).
- The session-start digest reports the posture under its AFK subsection, so a restart re-enters the posture from the record, not from memory.

## How to exit: the return
Expand All @@ -65,13 +69,15 @@ 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.
- A `Stop hook feedback` wake from the Stop hook or the supervision host -> stay away and process it; it is automatic supervision, not a message from the captain.
- Re-invoking `/afk` while already away -> stay away (refresh); this does **not** trigger an exit.

Bias ambiguous cases toward exit: a present captain beats token savings, and a false exit is self-correcting (the captain re-runs `/afk`).
Expand All @@ -92,7 +98,7 @@ Destructive, irreversible, and security-sensitive actions are never pre-authoriz

## The daemon, where it still runs

On the harnesses that still launch the daemon (every verified harness except Pi and pi-signed), the mechanics below are unchanged.
On the harnesses that still launch the daemon (every verified harness except Pi and pi-signed, and except away mode on a Claude home with `config/supervision-host`), the mechanics below are unchanged.

### Operational prefix contract

Expand Down
1 change: 1 addition & 0 deletions .agents/skills/bootstrap-diagnostics/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ When any diagnostic needs captain attention, report the plain consequence and re
- `CREW_DISPATCH: invalid config/crew-dispatch.json - <reason>` - the optional dispatch profile file exists but failed low-cost bootstrap validation; stop profile-based dispatch, report the actionable error, and require correction of the malformed schema, unverified harness name, or invalid harness/effort pair rather than falling back around it or selecting a bad profile.
- `FLEET_SYNC: <repo>: skipped: <reason>` - a benign one-off skip (offline, no origin, local-only); bootstrap continued, investigate only if it blocks work.
A skip can also report the bounded fleet-refresh timeout (`FM_FLEET_SYNC_BOOTSTRAP_TIMEOUT`, or a fleet-size-aware default with a 20 second floor); a timeout never blocks startup.
`skipped: registry entry does not resolve to a delivery posture` is the one skip that is not one-off: the clone is left alone on every bootstrap until `data/projects.md` is corrected, so run the printed `bin/fm-project-mode.sh <repo>` to read the refusal and fix the entry.
- `FLEET_SYNC: <repo>: recovered: <detail>` - the clone had drifted onto a clean detached HEAD holding no unique commits and the sync self-healed it (re-attached the default branch and fast-forwarded); no action needed, it is reported only so the self-heal is visible.
- `FLEET_SYNC: <repo>: STUCK: on <state>, N commits behind <base> - needs attention` - the clone is dirty, on a non-default branch, detached with unique commits, or diverged, so the sync left it untouched (never forcing or discarding); it will keep falling behind until you look.
A loud STUCK, especially a growing N across bootstraps, means that clone needs hands-on attention; dispatch a crewmate or resolve it before it strands work.
Expand Down
5 changes: 4 additions & 1 deletion .agents/skills/fmx-respond/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ So treat second-mate-routed Relay work as a promised final by construction: the
2. Register it with `bin/fm-public-followup.sh register <obligation-id> --relation <relation-id> --work-home <main|secondmate:<id>> --work-id <task-id> --generation <n>`.
This is what makes the commitment reconcilable without you.
3. Put `bin/fm-public-followup.sh brief <obligation-id>` output straight into the worker's brief.
It prints the exact reporting command for that binding, including the obligation's actual required deliverable keys.
It prints the exact reporting command for that binding, pre-fills any deliverable value the binding determines, and gives the accepted format for every remaining placeholder.
When the work is routed to a second mate rather than spawned here, the routed item's own note MUST carry that same `brief` output so it survives the routing and reaches whoever ends up doing the work.
A header-only routed item loses the emit command.
Never ask a worker to find the thread or post the reply: only this home holds the relay consent and the thread binding.
Expand All @@ -273,6 +273,9 @@ So treat second-mate-routed Relay work as a promised final by construction: the
1. Run `bin/fm-public-followup.sh consume`.
It reconciles every typed terminal result from disk and prints `ready <obligation-id> <request-id> <platform>` for each commitment that became deliverable.
A refusal prints `rejected <event-id>: <reason>` and quarantines that event; read the reason rather than re-emitting blindly.
The same refusal later arrives as a `public-followup rejected <event-id> ...` wake, so the promise is not left owed silently: have the bound work re-emit with the value the reason names, using the corrected `brief` command.
That wake is at-least-once: a failed cleanup can raise the same refusal again, carrying the same event id and reason.
When the event id is one you already took up, acknowledge the wake and do not re-brief the work; re-acting is safe but redundant, because the corrected result resolves to the event id that was already accepted.
2. For each ready commitment, run `bin/fm-public-followup.sh deliver <obligation-id>`.
With no `--text-file` it reuses the accepted terminal outcome exactly, which is the preferred path for a landed result.
Only pass `--text-file` when the outcome genuinely needs composing, and hold it to the same public-safety bar as every other reply here.
Expand Down
Loading
Loading