Skip to content
9 changes: 7 additions & 2 deletions .agents/skills/bootstrap-diagnostics/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,14 @@ When any diagnostic needs captain attention, report the plain consequence and re
The original watcher remains the slow delivery backstop.
- `FREQUENCY_MONITOR_UNIT: systemd --user is unavailable ...` - fast Bridge delivery cannot run on this host through the tracked unit, but the original watcher still provides slow durable delivery.
Do not invent or auto-start an unapproved background-process fallback.
- `AXI_SUITE_UPDATED: <tool> <old> -> <new>` - the vessel completed a gated patch or minor self-update; report it only when it materially affects current work.
- `AXI_SUITE_REVIEW: <detail>` - a major release or newly required suite command was deliberately not installed; present the printed install command and purpose to the captain, then use `bin/fm-bootstrap.sh install <approved tool...>` only after consent.
- `AXI_SUITE_UPDATED: <detail>` - the vessel completed a self-repair of its own npm prefix and needs nothing from you; report it only when it materially affects current work.
`<tool> <old> -> <new>` is a gated patch or minor self-update, `<tool> <version> installed in vessel prefix` is the home's own copy being seeded from the version already on `PATH`, and `<tool> unreadable vessel copy removed from <prefix>` means a copy that could not report its version was dropped so the intact external copy stops being shadowed and a readable version can be reinstalled.
- `AXI_SUITE_REVIEW: <detail>` - a major release, a newly required suite command, or a locally-ahead build the registry cannot supply was deliberately not installed; present the printed install command and purpose to the captain, then use `bin/fm-bootstrap.sh install <approved tool...>` only after consent.
For the locally-ahead case the external copy keeps working, so the decision is whether to publish that build or let the vessel accept the registry version.
- `AXI_SUITE_STUCK: <detail>` - the vessel could not check or apply an eligible update and persisted the condition in `state/axi-suite-update.stuck`; investigate the local install path first, and if the vessel cannot repair itself, relay the status through the existing Bridge workflow by dispatching a crewmate rather than calling project automation directly.
The condition is retried on the next currency window rather than on every session, so a line that keeps reappearing means the underlying cause is still present.
A `vessel-prefix seeding ... was not attempted: the <N>s seeding budget is spent` detail is not a broken install: the vessel ran out of its one-time seeding budget, the external copy is still the working fallback, and the next window seeds the rest, so report it only if it survives a second window.
While seeding runs, the script names each installing tool and the remaining seeding budget on standard error; that progress output is not a diagnostic and needs no handling.
- `FIRSTMATE_UPDATE_AVAILABLE: <detail>` - the configured upstream firstmate has an upstream-only instruction-surface change; dispatch a crewmate to send an All-Ships update notice through the existing Bridge workflow, and never call Bridge project automation directly from firstmate or the check script.
- `FIRSTMATE_UPDATE_STUCK: <detail>` - the read-only upstream framework comparison failed and persisted the condition in `state/firstmate-update.stuck`; investigate the repository or network failure, and do not broadcast an update until the comparison succeeds.
A `config/firstmate-update-base is unusable` detail is not a network failure: the check refused a configured comparison base, so handle it as `CURRENCY_BASE` below.
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ state/
data/
.no-mistakes/
.lavish/
.local/axi/
.fm-secondmate-home
.DS_Store
__pycache__/
Expand Down
5 changes: 3 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ Never add an agent name as a commit co-author.
## 2. Layout and state

`docs/configuration.md` is the single owner of the top-level operational-home layout and configuration schemas; each producing script's header and help own exact child fields and mutation mechanics.
`FM_HOME` selects an instance's private `data/`, `state/`, `config/`, and `projects/`, while scripts continue to come from their tracked code root.
`FM_HOME` selects an instance's private `data/`, `state/`, `config/`, `projects/`, and `.local/axi/`, while scripts continue to come from their tracked code root.
Each secondmate has a persistent isolated `FM_HOME`, including its own state, backlog, projects, and session lock.
`bin/fm-send.sh` fails closed unless `FM_HOME` is explicit, so a steer cannot silently resolve against another home.

Expand Down Expand Up @@ -104,6 +104,7 @@ data/ personal fleet records; LOCAL, gitignored as a whole
<panel-id>/panel.meta model-panel record written by bin/fm-model-panel.sh: form, project, question pointer, stage, member task ids, and each role's resolved profile
<panel-id>/question.md the one question text every member of that panel was given, written by bin/fm-model-panel.sh; survives teardown like the reports
projects/ cloned repos; gitignored; READ-ONLY for you
.local/axi/ home-private npm prefix for this vessel's managed AXI CLI suite; gitignored
graphify-out/ local Graphify knowledge graph artifacts; gitignored, expected to drift after hook or incremental updates
state/ volatile runtime signals; gitignored
<id>.status appended by crewmates: "<state>: <note>" wake-event lines, not current-state truth
Expand Down Expand Up @@ -156,7 +157,7 @@ A lock-refused session must not spawn, steer, merge, drain the wake queue, repai
1. **Lock** - acquires the per-home session lock first, before anything mutates shared state.
2. **Bootstrap** - detect-only checks (tool/version problems, GitHub auth, the worktree-tangle check, harness override, dispatch-profile validation, backlog-backend status) always run, but routine confirmations stay silent by default.
When the lock could not be acquired, the worktree-tangle check uses read-only advisory wording without a checkout repair command.
The five MUTATING sweeps - non-executing legacy PR-check migration, fleet sync, the local secondmate fast-forward sweep, the secondmate liveness sweep, and X-mode artifact writes - run only when this session actually holds the lock from step 1.
The six MUTATING sweeps - non-executing legacy PR-check migration, the AXI-suite currency check that installs into this home's own npm prefix, fleet sync, the local secondmate fast-forward sweep, the secondmate liveness sweep, and X-mode artifact writes - run only when this session actually holds the lock from step 1.
The secondmate liveness sweep deterministically guarantees every registered secondmate is actually running: it probes each live secondmate's endpoint for a real agent process (not just pane presence), respawns only on a confident dead reading, and reports only skipped or failed guarantees as `SECONDMATE_LIVENESS:` lines (`bin/fm-bootstrap.sh`; `bin/fm-backend.sh`'s `fm_backend_agent_alive`).
3. **Wake queue** - when locked, drains the durable wake queue and prints the raw records prominently as this turn's first work queue; a bounded, clearly labeled historical status-event annotation may follow a valid `signal` record but never replaces it or current-state reconciliation, and a lapsed watcher chain still surfaces here via the same guard alarm.
When the lock could not be acquired, the queue is left untouched because another session owns it, and the guard's tangle/watcher-liveness alarms still print in read-only advisory mode without drain, supervision repair, or checkout repair commands.
Expand Down
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,21 +86,24 @@ Then launch one of the co-primary harnesses; AGENTS.md takes over from there:
**Claude Code**

```sh
claude
PATH="$PWD/.local/axi/bin:$PATH" claude
```

**Grok**

```sh
grok --trust
PATH="$PWD/.local/axi/bin:$PATH" grok --trust
```

**Pi**

```sh
pi
PATH="$PWD/.local/axi/bin:$PATH" pi
```

The prefix directory may be absent on first launch; keeping it first from process start makes the vessel-owned AXI copies take precedence as soon as bootstrap installs them.
When `FM_HOME` differs from the checkout root, prepend `$FM_HOME/.local/axi/bin` instead.
Codex and OpenCode use the same PATH assignment before their `codex` or `opencode` launch command.
For Grok, `--trust` is needed once per clone so project hooks and the turn-end guard load; `/hooks-trust` inside Grok works too.
For Pi, approve the project trust prompt once per clone on first launch so the tracked `.pi/extensions/*.ts` files auto-load.
Every Pi session starts with calm mode off; `/calm` is a session-local conversation-focused transcript toggle.
Expand Down
2 changes: 1 addition & 1 deletion bin/backends/cmux.sh
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,7 @@ fm_backend_cmux_send_key() { # <target> <key> [expected-label]
# no single-call atomic "run and submit" primitive (like herdr's `pane run`),
# so this composes send (literal) + send-key enter, exactly like zellij's
# equivalent - used for the fixed spawn-time commands (treehouse get, the
# GOTMPDIR export).
# GOTMPDIR export, the vessel AXI PATH export).
fm_backend_cmux_send_text_line() { # <target> <text> [expected-label]
fm_backend_cmux_send_literal "$1" "$2" "${3:-}" || return 1
fm_backend_cmux_send_key "$1" Enter "${3:-}"
Expand Down
4 changes: 2 additions & 2 deletions bin/backends/herdr.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1301,8 +1301,8 @@ fm_backend_herdr_current_path() { # <target>

# fm_backend_herdr_send_text_line: send one line of TEXT then submit,
# ATOMICALLY - mirrors tmux's `send-keys -t T text Enter`. Used for the fixed
# spawn-time commands (treehouse get, the GOTMPDIR export). `pane run` types
# the command and submits it in one call (verified).
# spawn-time commands (treehouse get, the GOTMPDIR export, the vessel AXI PATH
# export). `pane run` types the command and submits it in one call (verified).
fm_backend_herdr_send_text_line() { # <target> <text>
fm_backend_herdr_target_ready "$1" || return 1
fm_backend_herdr_cli "$FM_BACKEND_HERDR_SESSION" pane run "$FM_BACKEND_HERDR_PANE" "$2" >/dev/null 2>&1
Expand Down
5 changes: 3 additions & 2 deletions bin/backends/tmux.sh
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,9 @@ fm_backend_tmux_current_path() { # <target>

# fm_backend_tmux_send_text_line: send one line of TEXT then Enter, with no
# composer verification - used for the fixed spawn-time commands
# (`treehouse get`, the GOTMPDIR export) that already ran this exact sequence
# inline in fm-spawn.sh. Mirrors `tmux send-keys -t "$T" "<text>" Enter`.
# (`treehouse get`, the GOTMPDIR export, the vessel AXI PATH export) that
# already ran this exact sequence inline in fm-spawn.sh. Mirrors
# `tmux send-keys -t "$T" "<text>" Enter`.
fm_backend_tmux_send_text_line() { # <target> <text>
tmux send-keys -t "$1" "$2" Enter
}
Expand Down
9 changes: 5 additions & 4 deletions bin/backends/zellij.sh
Original file line number Diff line number Diff line change
Expand Up @@ -463,10 +463,11 @@ fm_backend_zellij_send_key() { # <target> <key> [expected-label]
# fm_backend_zellij_send_text_line: send one line of TEXT then submit,
# ATOMICALLY - mirrors tmux's `send-keys -t T text Enter` / herdr's `pane
# run`. Used for the fixed spawn-time commands (treehouse get, the GOTMPDIR
# export). Zellij has no single-call atomic "run and submit" action, so this
# composes paste (literal) + send-keys Enter, exactly like send_literal +
# send_key are composed elsewhere - the two-step form is the ONLY form for
# this adapter, unlike tmux/herdr which have a genuinely atomic primitive.
# export, the vessel AXI PATH export). Zellij has no single-call atomic "run
# and submit" action, so this composes paste (literal) + send-keys Enter,
# exactly like send_literal + send_key are composed elsewhere - the two-step
# form is the ONLY form for this adapter, unlike tmux/herdr which have a
# genuinely atomic primitive.
fm_backend_zellij_send_text_line() { # <target> <text> [expected-label]
fm_backend_zellij_send_literal "$1" "$2" "${3:-}" || return 1
fm_backend_zellij_send_key "$1" Enter "${3:-}"
Expand Down
33 changes: 33 additions & 0 deletions bin/fm-axi-path-lib.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env bash
# Resolve the npm prefix owned by one Firstmate operational home.
#
# Usage:
# . bin/fm-axi-path-lib.sh
# fm_axi_prefix [<home>] # prints <home>/.local/axi
# fm_axi_bin_dir [<home>] # prints <home>/.local/axi/bin
# fm_axi_prepend_path [<home>] # exports that bin directory first on PATH
#
# The location is derived only from FM_HOME, so a fresh vessel needs no local
# configuration before bootstrap can install its AXI suite.

fm_axi_prefix() {
local home=${1:-${FM_HOME:-}}
[ -n "$home" ] || return 1
printf '%s/.local/axi\n' "${home%/}"
}

fm_axi_bin_dir() {
local prefix
prefix=$(fm_axi_prefix "${1:-${FM_HOME:-}}") || return 1
printf '%s/bin\n' "$prefix"
}

fm_axi_prepend_path() {
local bin
bin=$(fm_axi_bin_dir "${1:-${FM_HOME:-}}") || return 1
case "${PATH:-}" in
"$bin"|"$bin":*) ;;
*) PATH="$bin${PATH:+:$PATH}" ;;
esac
export PATH
}
Loading
Loading