Skip to content
This repository was archived by the owner on Aug 25, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
1719160
feat: guard against missed secondmate reports
JTInventory Jul 26, 2026
cf57719
no-mistakes(review): Harden secondmate pending-reply lifecycle
JTInventory Jul 26, 2026
f633dbe
no-mistakes(review): Preserve pending replies through forced teardown
JTInventory Jul 26, 2026
31685fb
no-mistakes(review): Make forced retirement failure-safe
JTInventory Jul 26, 2026
24138b5
no-mistakes(review): Bind retirement handoffs to source state
JTInventory Jul 26, 2026
b09e6e9
no-mistakes(review): Promote resolved history before receipt cleanup
JTInventory Jul 26, 2026
76436f7
no-mistakes(review): Serialize pending-reply handoff transactions
JTInventory Jul 26, 2026
749b661
no-mistakes(review): Harden pending-reply transaction recovery
JTInventory Jul 26, 2026
b295f15
no-mistakes(review): Harden pending-reply takeover and finalization
JTInventory Jul 26, 2026
94f6b1f
no-mistakes(review): Harden pending-reply ownership and handoff retries
JTInventory Jul 26, 2026
453dde7
no-mistakes(review): Drain legacy locks and require explicit correlat…
JTInventory Jul 26, 2026
ac57d7b
no-mistakes(review): Enforce watcher restart barrier for legacy locks
JTInventory Jul 26, 2026
bce5fe7
no-mistakes(review): Enforce verified watcher protocol migration
JTInventory Jul 27, 2026
adfe8ae
no-mistakes(review): Harden watcher migration and pending-reply proto…
JTInventory Jul 27, 2026
384ed2b
no-mistakes(review): Harden watcher migration and replay update oblig…
JTInventory Jul 27, 2026
3894711
no-mistakes(review): Make update obligations durable and explicitly a…
JTInventory Jul 27, 2026
891d32b
no-mistakes(review): Make update obligations generation-safe across p…
JTInventory Jul 27, 2026
3f3ba10
no-mistakes(review): Make update obligation claims atomic and replayable
JTInventory Jul 27, 2026
21e59e2
no-mistakes(review): Make update obligations immutable and crash-safe
JTInventory Jul 27, 2026
04b6720
no-mistakes(review): Keep ancestor update acknowledgements replayable
JTInventory Jul 27, 2026
0c909ef
no-mistakes(review): Preserve future legacy update obligations
JTInventory Jul 27, 2026
ebf77fb
no-mistakes(review): Recover future-only obligations on first retry
JTInventory Jul 27, 2026
35a2de1
no-mistakes(test): Fix pending-reply teardown test fixtures
JTInventory Jul 27, 2026
dc9f81c
no-mistakes(document): Document Phase 2 secondmate resilience
JTInventory Jul 27, 2026
bcf1200
no-mistakes(lint): Fix ShellCheck warnings in secondmate resilience s…
JTInventory Jul 27, 2026
9741923
no-mistakes: apply CI fixes
JTInventory Jul 27, 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
29 changes: 21 additions & 8 deletions .agents/skills/updatefirstmate/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: updatefirstmate
description: Self-update a running firstmate and its secondmates to the latest from origin. Use when the captain invokes /updatefirstmate (e.g. "/updatefirstmate", "update firstmate", "pull the latest firstmate"). Fast-forwards this firstmate repo's default branch and every secondmate home from origin (fast-forward only, never forced, never disruptive), then re-reads AGENTS.md and nudges each updated secondmate to do the same, so the whole tree runs the latest bin/ and instructions.
description: Self-update a running firstmate and its secondmates to the latest from origin. Use when the captain invokes /updatefirstmate (e.g. "/updatefirstmate", "update firstmate", "pull the latest firstmate"). Fast-forwards this firstmate repo's default branch and every secondmate home from origin, verifies pending-reply-aware watcher handoff, and durably tracks instruction re-reads and secondmate nudges without disturbing agent panes or project work.
user-invocable: true
---

Expand All @@ -22,24 +22,38 @@ This touches only the firstmate repo and its own worktrees, never anything under
bin/fm-update.sh
```
It fast-forwards this firstmate repo's default branch from origin, then fast-forwards every registered secondmate home (each a treehouse worktree of this same repo, leased at a detached HEAD on the default branch) the same way.
It prints one status line per target (`updated <old>..<new>` / `already current` / `skipped: <reason>`), followed by two action lines that tell you exactly what to do next:
It prints one status line per target (`updated <old>..<new>` / `already current` / `skipped: <reason>`), followed by action lines that tell you exactly what to do next:
- `reread-firstmate: yes|no`
- `reread-firstmate-generation: <commit>|none`
- `restart-firstmate-watcher: yes|no`
- `restart-secondmate-watchers: <window-targets...>|none`
- `nudge-secondmates: <window-targets...>|none`
- one `nudge-secondmate-generation: <window-target>|<commit>` line per nudge

2. **Re-read AGENTS.md if your own instructions changed.**
When the updater printed `reread-firstmate: yes`, the tracked instruction surface (AGENTS.md, bin/, or skills) just advanced under you.
**Read `AGENTS.md` now** (CLAUDE.md is a symlink to it) to refresh your operating instructions before doing anything else, so you are acting on the new instructions rather than the stale ones you were started with.
After the read succeeds, acknowledge it:
```sh
bin/fm-update.sh --ack-reread-firstmate <commit-from-reread-firstmate-generation>
```
When the first run updated firstmate, run `bin/fm-update.sh` once more from the installed checkout before acknowledging. This second invocation is required so an updater that began on the previous protocol cannot validate a watcher with its old in-memory rules.
When it printed `reread-firstmate: no`, nothing changed for you - skip the re-read.

3. **Nudge each updated live secondmate.**
3. **Restart this home's watcher when required.**
The updater verifies the home-scoped watcher and its harness-tracked follower before it prints its summary. If it finds a legacy watcher, it stops that home-scoped cycle and exits non-zero with durable protocol and reread obligations. Let the existing follower wake the harness, re-arm the watcher through the harness's tracked background mechanism, then run `bin/fm-update.sh` again. The retry replays the required AGENTS.md reread and any secondmate nudges even when every checkout is already current. `restart-firstmate-watcher: yes` is printed only after that tracked replacement is verified.

4. **Nudge each updated live secondmate.**
For every target listed on the `nudge-secondmates:` line (do nothing when it says `none`), send a one-line re-read nudge so that secondmate picks up its new instructions too:
```sh
bin/fm-send.sh <window-target> 'firstmate was updated to the latest - please re-read your AGENTS.md to pick up the new instructions.'
bin/fm-update.sh --ack-secondmate-nudge <window-target> <commit-from-the-matching-generation-line>
```
This is a gentle steer, not an interruption: the secondmate already got a safe tracked-files fast-forward, and the nudge never forces, tears down, or discards its work.
Run the acknowledgement only after `fm-send.sh` confirms delivery. A failed or interrupted send leaves the durable nudge obligation for the next updater retry.
The updater has already verified each watcher and follower listed on `restart-secondmate-watchers:`. If it stopped a legacy secondmate watcher, that secondmate must complete its normal harness-tracked re-arm before the updater retry can succeed. Updated homes without a running watcher need no restart because no legacy process remains; their next watcher starts from the updated code. The restart does not stop a secondmate's agent pane or project work.
A secondmate that was skipped, already current, or has no live metadata is not on the list and needs no nudge.

4. **Report to the captain in plain outcomes.**
5. **Report to the captain in plain outcomes.**
Summarize what landed without firstmate's internal vocabulary: which parts of the fleet are now on the latest, and which were left as-is and why.
For example: "Captain, firstmate and both domain supervisors are now on the latest."
Surface any skipped target whose reason needs the captain's attention - for instance a home with its own un-landed changes (diverged) or local edits (dirty), which were left untouched on purpose.
Expand All @@ -51,6 +65,5 @@ This touches only the firstmate repo and its own worktrees, never anything under
Nothing with unlanded work is ever discarded - this is prime directive #3.
- **Only the firstmate repo and its worktrees** are touched, never `projects/`.
It is the same sanctioned self-write as the fleet sync.
- **Secondmates are never disrupted.**
A secondmate gets a tracked-files fast-forward (safe while it is mid-task, since its work lives in gitignored operational dirs and separate project worktrees) plus a gentle re-read nudge.
It is never torn down, interrupted, or forced.
- **Secondmate work is never disrupted.**
A secondmate gets a tracked-files fast-forward plus a home-scoped watcher restart and re-read nudge. Its agent pane, operational state, and project work remain intact.
9 changes: 7 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ backups/ root-local preservation files; not a canonical tracked surf
<id>.pr-poll private validated data sidecar for the byte-static PR merge poll
<id>.pr-poll-registration private transactional provenance record binding the task, canonical metadata identity, sidecar, and static poll publication
<id>.pr-poll-retirement private identity-bound crash-recovery receipt for one exact validated merged result; removed after its poll artifacts retire
pending-replies/ parent-owned unresolved marked-secondmate requests; never delete or treat delivery as acknowledgement
pending-reply-history/ resolved or explicitly retired marked-secondmate request history, including crash-safe teardown handoffs
.pr-check-quarantine/ private non-runnable storage for checks neutralized by the non-executing migration
.pr-check-migration.log private per-task outcomes distinguishing rebuilt or canonically registered replacement polls, quarantined unarmed polls, and incomplete migrations
.pr-check-migration-scan-v1 private marker proving the non-executing scan disabled every unsafe legacy check; .pr-check-migration-v1 separately records completed private repairs
Expand All @@ -121,6 +123,7 @@ backups/ root-local preservation files; not a canonical tracked surf
.wake-queue durable queued wakes: epoch<TAB>seq<TAB>kind<TAB>key<TAB>payload
.afk durable away-mode flag; present = sub-supervisor may inject escalations (set by /afk, cleared on user return)
.watch.lock .watch-arm.lock .wake-queue.lock watcher singleton, one-arm follower, and queue serialization locks
.watch-protocol-required .watch-protocol-reread-required durable watcher-generation and instruction-reread obligations; clear only through the verified update/acknowledgement path
.hash-* .count-* .stale-* .stale-since-* .paused-* .paused-rechecked-* .paused-resurfaced-* .seen-* .hb-surfaced-* .last-* .heartbeat-streak watcher internals; never touch
.watch-triage.log watcher's absorbed-wake debug log (size-capped); never relied on, safe to delete
.last-watcher-beat watcher liveness beacon, touched every poll (including while absorbing benign wakes); fm-guard.sh reads it
Expand Down Expand Up @@ -158,6 +161,7 @@ For a mid-session inheritable-config change that should reach live secondmates w
It is inheritance-only: it uses the same live secondmate discovery, per-home inheritance lock, `propagate_secondmate_inheritance` helper, and `CONFIG_REREAD` delivery path as bootstrap, prints a per-home/per-item summary, and does not fast-forward tracked files.
The propagation helper itself keeps stdout silent for existing callers, but warns on stderr when an item is skipped because the destination does not allow it or when a copy/remove error occurs.
The sweep reports the `NUDGE_SECONDMATES:` line below only when a running secondmate actually advanced with an instruction change, so firstmate knows which ones to live-converge.
It also verifies every live secondmate home's pending-reply-aware watcher generation. A legacy cycle is replaced only through its home-scoped watcher/follower handoff, and any required instruction re-read remains durable until the matching nudge succeeds.
Silence means all good: say nothing and move on.
Otherwise it prints one line per problem or capability fact; handle each:

Expand Down Expand Up @@ -455,6 +459,7 @@ A secondmate is itself a firstmate, so a request reaches it in its own chat, whi
So `fm-send` to a bare `fm-<id>` whose meta is `kind=secondmate` automatically prepends the terminal-safe U+2063 from-firstmate marker (`bin/fm-marker-lib.sh`) without stripping trailing newlines; the secondmate recognizes it and returns its answer via its status file, or via a doc under its home plus a status pointer for a detailed response, never only in chat.
For codex secondmates, that marked ordinary-text path also uses the longer pre-Enter settle so the already-typed request is not left unsubmitted by input timing.
Expect and read that response on the status/doc path the same way you read any other status signal; do not peek the secondmate's chat for the answer.
The parent owns a durable correlation record for every marked request. It requests one bounded repost after a completed turn without a correlated report, then escalates once if the repost is also missed; `bin/fm-pending-reply-lib.sh` owns that recovery contract.
A captain typing directly into the secondmate's window is unmarked and stays a conversational captain intervention, so do not relay captain-destined chat through this path; the marker is applied only by `fm-send` to a `kind=secondmate` target.
Do not spawn a direct crewmate for work that belongs to a secondmate scope unless the secondmate is blocked or the captain explicitly redirects it.
If no secondmate scope fits, proceed in the main firstmate or create a new secondmate with the captain when that domain should become persistent.
Expand Down Expand Up @@ -595,7 +600,7 @@ A secondmate is persistent by default.
An empty queue is healthy and does not trigger teardown.
Run `bin/fm-teardown.sh <id>` for `kind=secondmate` only when the captain or main firstmate explicitly decides to retire that persistent supervisor.
Load `secondmate-provisioning` before retiring it.
The safety check is the secondmate's own home: teardown refuses while its `state/*.meta` contains in-flight work. A successful secondmate teardown does not mark or remind against the main backlog; its queue was already transferred to the secondmate home.
The safety checks cover both homes: teardown refuses while the secondmate's own `state/*.meta` contains in-flight work or the parent has an unresolved correlated reply. Captain-approved `--force` may retire a reply only after its bounded recovery reached escalation or another terminal recovery state; the crash-safe handoff preserves that history before parent route removal. A successful secondmate teardown does not mark or remind against the main backlog; its queue was already transferred to the secondmate home.
For a leased home, the same bounded retry applies only to a transient Git `index.lock`/`File exists` error while releasing the lease; any remaining return failure leaves the home and route intact.
With `--force`, teardown is the explicit discard path for child windows, child work, state, route, lease, and home; never use it unless the captain explicitly said to discard the work.

Expand Down Expand Up @@ -845,7 +850,7 @@ Adjust the other sections only when the task genuinely deviates from the standar

firstmate is its own repo behind the no-mistakes gate, so improvements to `AGENTS.md`, `bin/`, and skills reach `main` and then wait for each running firstmate to pull them.
When the captain invokes `/updatefirstmate` or asks to update firstmate, load the `/updatefirstmate` skill.
It performs only fast-forward self-updates of firstmate and registered secondmate homes, re-reads `AGENTS.md` when needed, nudges updated live secondmates, and never touches anything under `projects/`.
It performs only fast-forward repository updates, verifies or migrates each affected home's watcher protocol, durably requires and acknowledges instruction re-reads and secondmate nudges, and never touches anything under `projects/`.

### Session stow

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ For matching JT Control Room PR-mode ship work in `.openclaw` or `jt-control-roo
For allowlisted ship and scout work, spawn can also add optional codebase-memory-mcp (CBM) orientation and pass its environment into the worker. CBM is non-blocking context for multi-file navigation only: it never replaces runtime sources or source-file proof, and secondmate charters stay unchanged. The logged CLI records best-effort task-tagged usage in local `data/cbm/usage.jsonl`, which `bin/fm-cbm-usage.sh` can summarize or tail; an optional host MCP wrapper counts process starts only. The captain owns host MCP registration and any indexing through `bin/fm-cbm-index.sh`; Firstmate does not install or configure it automatically.
Secondmate launch can use a separate local `config/secondmate-harness`, plus a primary-local `config/secondmate-profile.json` for durable model and effort defaults.
Secondmate homes inherit the primary's declared local config, including `config/crew-dispatch.json`, `config/crew-harness`, and `config/backlog-backend`, at launch, bootstrap, or an explicit `bin/fm-config-push.sh` run, so their own crewmates, dispatch profiles, and backlog backend use the primary settings.
When a routed request goes to a secondmate, firstmate marks it so the answer returns through status or a document pointer; direct typing into that secondmate window stays conversational.
When a routed request goes to a secondmate, firstmate marks and correlates it so the answer returns through status or a document pointer; if that report is missed, the parent requests one repost and then escalates once without reading the secondmate's conversation. Direct typing into that secondmate window stays conversational.
A presence-gated sub-supervisor (`/afk`) can self-handle routine events and batch only what matters while you step away.
An opt-in X mode can also use the watcher check path to answer your public `@myfirstmate` mentions and act on normal reversible mention requests from the current fleet state, with `FMX_DRY_RUN` available to test the poll -> compose -> would-post loop without publishing.
The relay routes only the owner's own mentions to that owner's firstmate home; parent-thread context may still include other public accounts.
Expand All @@ -150,7 +150,7 @@ Claude and grok use the slash form shown here; codex uses the same names with `$
| Skill | What it does |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `/afk` | Enter away-mode supervision: the sub-supervisor self-handles routine wakes in bash, re-surfaces declared external waits for review on a bounded cadence, and escalates captain-relevant events as one batched digest |
| `/updatefirstmate` | Self-update the running firstmate and its secondmates to the latest from origin with fast-forward-only pulls, then re-read instructions and nudge secondmates |
| `/updatefirstmate` | Self-update the running firstmate and its secondmates with fast-forward-only pulls, verified watcher migration, acknowledged instruction re-reads, and durable secondmate nudges |
| `/stow` | Sweep the session for uncaptured durable knowledge, route each finding to its disk home per AGENTS.md, file undone next steps to the backlog, and report what is now safe to reset |

Agent-only reference skills live under `.agents/skills/` and are loaded by firstmate at the trigger points named in [`AGENTS.md`](AGENTS.md).
Expand Down
Loading
Loading