⚓ firstmate field guide
Using firstmate

Relay, voice & extras

Opt-in surfaces — answering X and Discord mentions (Relay), the spoken voice relay, the fleet ledger and the community RGB lamp, calm mode, mail, the captain's inbox, and self-evolution.

Everything on this page is off by default. VISION.md: "new capability ships as an option to enable, never as behavior that assumes consent."

Relay — talk to your fleet from X and Discord#

Relay connects your firstmate to public mentions. Kun's own instance is @myfirstmate.

  • Enable: put FMX_PAIRING_TOKEN in the .env at the repo root. Kun confirmed it is the root, not config/.env. Relay ships inert without it. Relay needs curl and jq. Kun also noted tmux works best for the bot integration.
  • Who it listens to: direct mentions from the firstmate's own captain (owner-only routing).
  • What it does: normal, reversible requests go through the same lifecycle as chat. Destructive, irreversible or security-sensitive asks are always flagged to you first.
  • Replies are public-safe. No task ids, internal vocabulary, secrets or private plans.
  • Follow-ups: spawned work gets an immediate acknowledgement, plus up to 3 follow-ups within 7 days for milestones and the final outcome (FMX_FOLLOWUP_MAX_COUNT, FMX_FOLLOWUP_MAX_AGE_SECS).
  • Durable promises: a final reply promised in a thread is stored under state/public-followup/ and reconciled from disk. A restart or compaction can't lose it.
  • Dry run: FMX_DRY_RUN records would-be replies and dismissals in state/x-outbox/ without posting.

The skill is fmx-respond; the scripts are bin/fm-x-*.sh and bin/fm-public-followup.sh.

The demo that made this famous:

one-shot prompt from X -> firstmate worked for 3 hours straight -> modified and deployed itself -> replied with an image that was not supported at the time of my prompt. all that while i was watching house of the dragon. — @kunchenguid, 2026-06-30

Grok Bot variant

GROK_BOT.md is a copy-paste system prompt that recreates the first-mate pattern inside Grok's own bot platform. There, the "crewmates" are other bots and code goes to Cursor cloud agents. Kun published it as a one-click template (2026-09-07). It is a sibling of the CLI distro, not the same system.

Voice relay#

docs/voice-relay.md calls this "step one of three": a working spoken round trip.

laptop mic → fm-voice-client.py → SSH → fm-voice-relay.py (firstmate box) → AWS Bedrock Nova Sonic 2 → back
  • It reads records: counts, or full titles and PR links with config/voice-read-scope=full. It queues work through bin/fm-inbox.sh note. "It has no tool that changes a project."
  • Push-to-talk only. Open-mic refuses to start, because there is no end-of-speech detection yet. It handles one turn per session.
  • Measured: ~1.15–1.3s to first audio, ~$0.003 per exchange.
  • Config: FM_VOICE_REGION, FM_VOICE_MODEL, FM_VOICE_PROFILE, FM_VOICE_ID, FM_VOICE_RELAY.

The captain's inbox#

bin/fm-inbox.sh lets you add to the queue without interrupting a busy first mate:

bin/fm-inbox.sh note "look into the flaky e2e on xyz tomorrow"   # durable, one wake
bin/fm-inbox.sh status                                          # what's queued (no network)
bin/fm-inbox.sh ask "what's our default merge method?"          # side question, touches nothing
bin/fm-inbox.sh say memo.wav                                    # transcribe (Bedrock), then note

Fleet ledger (and the RGB lamp)#

Community member @jayparkcanada wired a Govee floor lamp to his fleet:

  • 🟡 an agent is working,
  • 🔴 a question or a failure,
  • 🟢 a PR is ready.

It used no polling. macOS kqueue wakes on new status-log lines, Herdr's push events supply the "working" state, and colour goes to the lamp over the Govee LAN UDP API. (X Article, 2026-09-22.)

Kun's response was to ask @myfirstmate whether firstmate should expose a general ledger file for tools like this. It now does:

  • Enable: touch config/fleet-ledger. It is per home and not inherited.
  • Output: state/fleet-ledger.jsonl, one JSON record per line, at-least-once delivery.
  • Records: task.dispatched (kind, project, harness, model), task.status (state, key, text ≤2000 chars), task.pr_ready, task.merged (via pr or local), task.cleaned_up.
  • Deliberately excluded: live busy/idle transitions (subscribe to Herdr's pane.agent_status_changed for those), sequence numbers, rotation, backfill.

Example records, from docs/fleet-ledger.md:

{"v":1,"ts":1790132857,"event":"task.dispatched","task":"fix-login","kind":"ship","project":"webapp","harness":"claude","model":null}
{"v":1,"ts":1790133400,"event":"task.status","task":"fix-login","state":"done","key":null,"text":" PR https://github.com/acme/webapp/pull/7 checks green"}
{"v":1,"ts":1790133410,"event":"task.pr_ready","task":"fix-login","pr":"https://github.com/acme/webapp/pull/7"}
{"v":1,"ts":1790133900,"event":"task.merged","task":"fix-login","via":"pr","pr":"https://github.com/acme/webapp/pull/7"}
{"v":1,"ts":1790133960,"event":"task.cleaned_up","task":"fix-login"}

A lamp-style consumer is one line:

tail -F state/fleet-ledger.jsonl | jq -c 'select(.event=="task.pr_ready")'

Calm mode#

/calm hides firstmate's own operational rows (session-start digests, watcher wakes, guard nudges, launch briefs). It replaces the working spinner with a small animated sailboat.

  • It is presentation only. Hidden content stays in model context, in storage, and in /export.
  • It works on Pi. On Claude Code it needs CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1, which you set yourself; firstmate never sets it.
  • Supervision notes on Claude Code. With that flag set, the Claude Code mod also shows gray, display-only supervision notes, whether Calm is on or off: ⛵ for a routine outcome, ⚓ [seq N] for a captain outcome, and a note when the supervision host's latch trips. The model never sees them, and a resumed session shows each one only once. They come from the supervision outcome store, so you see them on homes that run the supervision host.
  • One preference file, config/calm (on/off), applies to both.

Mail#

bin/fm-mail.sh read|send|poll|status is an IMAP/SMTP plane. poll turns unseen mail into check wakes, keyed by IMAP UID, and never marks mail read early. bin/fm-mail-check.sh arm runs it on the watcher's cadence. Credentials go in .env. Each surfaced email is a notification the first mate applies judgment to. It carries no authority.

Process-event sources and custom checks#

  • Custom check: drop a script at state/<id>.check.sh, then run bin/fm-check-register.sh <id>. That pins the script's SHA-256. The watcher runs it every cycle and surfaces its output as a check: wake.
  • Process events (process-event-sources skill): long-polling sources such as a Lavish board, quota thresholds, when condition→action watches, and remote replies. They wake the first mate later instead of blocking a turn. Results are input, never authority. Each is acknowledged with bin/fm-procevent.sh handled <source> <seq>. docs/examples/process-event-extension/ shows a complete minimal external extension.

Self-evolution#

The first mate can read and edit its own distro. That is why Kun says he got "500+ PRs coming from everyone using their firstmate to self evolve" (2026-08-10).

The rules:

  • It changes shared tracked files (AGENTS.md, bin/, skills) directly only when the fleet is empty. Otherwise it delegates to a crewmate.
  • The change ships through this repo's own no-mistakes pipeline and PR path.
  • It loads firstmate-coding-guidelines first: one sentence per line, no agent co-authors, shellcheck-clean, colocated <subject>.test.sh tests.
  • AGENTS.md stays under 9,000 words. Anything situational moves behind a skill trigger.

If you want your improvement upstream, just ask your first mate. CONTRIBUTING.md requires PRs to main to go through no-mistakes. CI checks a no-mistakes-pipeline-attestation bound to the exact PR head.

Unofficial guide built 2026-09-26 from kunchenguid/firstmate, the AXI repos, and Kun Chen's public posts. The repo moves daily; when this guide and the repo disagree, the repo wins.