@zerwiz/ymir 0.1.15 → 0.1.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.json +31 -0
- package/.codex/hooks.json +43 -0
- package/.cursor/hooks.json +33 -0
- package/.pi/extensions/README.md +39 -0
- package/.pi/extensions/gna-pi-watch.ts +15 -0
- package/.pi/extensions/lib/ro-assistant-layout.ts +96 -0
- package/.pi/extensions/lib/ro-operational-user-layout.ts +145 -0
- package/.pi/extensions/lib/ro-visibility.ts +99 -0
- package/.pi/extensions/lib/ro-working-ship.ts +243 -0
- package/.pi/extensions/lib/rodd-operational-input.ts +62 -0
- package/.pi/extensions/lib/skuld-branch-dispatch.ts +252 -0
- package/.pi/extensions/lib/skuld-branch-model-picker.ts +77 -0
- package/.pi/extensions/lib/vordr-sessionstart-supervisor.mjs +48 -0
- package/.pi/extensions/ro.ts +11 -0
- package/.pi/extensions/skuld-branch-supervision.ts +11 -0
- package/.pi/extensions/syn-turnend-guard.ts +11 -0
- package/.pi/mcp.json +16 -0
- package/.pi/mcp.json.example +11 -0
- package/.pi/npm/.gitignore +2 -0
- package/.pi/settings.json +8 -0
- package/.pi/shared/extensions/gna-pi-watch.ts +750 -0
- package/.pi/shared/extensions/herdr-agent-state.ts +257 -0
- package/.pi/shared/extensions/open-editor.ts +509 -0
- package/.pi/shared/extensions/ro.ts +504 -0
- package/.pi/shared/extensions/skuld-branch-supervision.ts +1535 -0
- package/.pi/shared/extensions/syn-turnend-guard.ts +683 -0
- package/.pi/shared/extensions/todo.ts +133 -0
- package/.pi/shared/extensions/ymir-subagents.ts +287 -0
- package/.pi/shared/extensions/ymir-well.ts +130 -0
- package/CHANGELOG.md +8 -0
- package/assets/Ymir.md +4654 -0
- package/assets/healer.html +717 -0
- package/assets/icon-family/family-sheet.png +0 -0
- package/assets/icon-family/hlidskjalf.svg +1 -0
- package/assets/icon-family/sessrumnir.svg +1 -0
- package/assets/icon-family/smidja.svg +1 -0
- package/assets/icon-family/ymir.svg +1 -0
- package/assets/mimirswell.html +880 -0
- package/assets/mock/README.md +16 -0
- package/assets/mock/feeds.ts +175 -0
- package/assets/mock/mock.ts +408 -0
- package/assets/reference/docs/agent-control.md +122 -0
- package/assets/reference/docs/apodex/Appdex_as_Orchestrator_Planner_Reviewer_Assessment.md +176 -0
- package/assets/reference/docs/apodex/Final Report(1).md +198 -0
- package/assets/reference/docs/apodex/Final Report(2).md +54 -0
- package/assets/reference/docs/apodex/Final Report(3).md +40 -0
- package/assets/reference/docs/apodex/Final Report(4).md +234 -0
- package/assets/reference/docs/apodex/Final Report(5).md +13 -0
- package/assets/reference/docs/apodex/Final Report.md +82 -0
- package/assets/reference/docs/architecture.md +392 -0
- package/assets/reference/docs/arm-pretool-check.md +247 -0
- package/assets/reference/docs/calm-mode-feasibility.md +541 -0
- package/assets/reference/docs/calm.md +59 -0
- package/assets/reference/docs/captain-hold-lifecycle.md +96 -0
- package/assets/reference/docs/cd-guard.md +165 -0
- package/assets/reference/docs/cmux-backend.md +133 -0
- package/assets/reference/docs/codex-app-backend.md +57 -0
- package/assets/reference/docs/configuration.md +924 -0
- package/assets/reference/docs/documentation-audiences.json +468 -0
- package/assets/reference/docs/documentation-audiences.md +28 -0
- package/assets/reference/docs/examples/crew-dispatch.json +26 -0
- package/assets/reference/docs/examples/process-event-extension/file-signal.mjs +96 -0
- package/assets/reference/docs/examples/process-event-extension/firstmate-extension.json +15 -0
- package/assets/reference/docs/examples/watched-tools.json +24 -0
- package/assets/reference/docs/examples/wedge-alarm +22 -0
- package/assets/reference/docs/extension-bindings.md +237 -0
- package/assets/reference/docs/fm-test-isolation-proof.json +37 -0
- package/assets/reference/docs/fm-test-isolation-proof.md +149 -0
- package/assets/reference/docs/fm-test-portable-shards.md +118 -0
- package/assets/reference/docs/gitlab-merge-watch.md +275 -0
- package/assets/reference/docs/herdr-backend.md +346 -0
- package/assets/reference/docs/orca-backend.md +84 -0
- package/assets/reference/docs/pi-supervision-branch-poster.svg +125 -0
- package/assets/reference/docs/pi-supervision-branch.md +96 -0
- package/assets/reference/docs/plans/agentic-engineering-workflow.md +395 -0
- package/assets/reference/docs/plans/agentic-factory-implementation-plan.md +615 -0
- package/assets/reference/docs/plans/command-factory-enhancement-plan.md +420 -0
- package/assets/reference/docs/plans/phase-1-layer3-program-design.md +134 -0
- package/assets/reference/docs/plans/phase-2-vertical-slices.md +100 -0
- package/assets/reference/docs/plans/phase-3-measurable-goals.md +106 -0
- package/assets/reference/docs/plans/phase-4-context-budget.md +106 -0
- package/assets/reference/docs/plans/phase-5-pre-mortem-confidence.md +100 -0
- package/assets/reference/docs/plans/phase-6-incident-to-agent.md +109 -0
- package/assets/reference/docs/remote-secondmates.md +268 -0
- package/assets/reference/docs/scripts.md +146 -0
- package/assets/reference/docs/sessionstart-nudge.md +115 -0
- package/assets/reference/docs/subagent-guard.md +383 -0
- package/assets/reference/docs/supervision-protocols/claude.md +27 -0
- package/assets/reference/docs/supervision-protocols/codex.md +16 -0
- package/assets/reference/docs/supervision-protocols/cursor.md +31 -0
- package/assets/reference/docs/supervision-protocols/grok.md +39 -0
- package/assets/reference/docs/supervision-protocols/opencode.md +17 -0
- package/assets/reference/docs/supervision-protocols/pi.md +33 -0
- package/assets/reference/docs/supervision-protocols/unknown.md +13 -0
- package/assets/reference/docs/tmux-backend.md +115 -0
- package/assets/reference/docs/trace-context.md +117 -0
- package/assets/reference/docs/turnend-guard.md +170 -0
- package/assets/reference/docs/verification/dispatch-auth.md +204 -0
- package/assets/reference/docs/verification/muse.md +221 -0
- package/assets/reference/docs/verification/process-event-sources.md +208 -0
- package/assets/reference/docs/verification/public-followup.md +119 -0
- package/assets/reference/docs/verification/runtime-backends.md +1022 -0
- package/assets/reference/docs/verification/stow-memory.md +53 -0
- package/assets/reference/docs/verification/supervision.md +534 -0
- package/assets/reference/docs/verification/trace-context.md +31 -0
- package/assets/reference/docs/voice-relay.md +295 -0
- package/assets/reference/docs/watcher-continuity.md +119 -0
- package/assets/reference/docs/wedge-alarm.md +39 -0
- package/assets/reference/docs/zellij-backend.md +114 -0
- package/assets/reference/index.html +1172 -0
- package/assets/reference/skills/afk/SKILL.md +241 -0
- package/assets/reference/skills/ahoy/SKILL.md +56 -0
- package/assets/reference/skills/ask-user-authority/SKILL.md +56 -0
- package/assets/reference/skills/bearings/SKILL.md +161 -0
- package/assets/reference/skills/bearings/assets/board-template.html +731 -0
- package/assets/reference/skills/bootstrap-diagnostics/SKILL.md +68 -0
- package/assets/reference/skills/captain-hold-lifecycle/SKILL.md +54 -0
- package/assets/reference/skills/decision-hold-lifecycle/SKILL.md +15 -0
- package/assets/reference/skills/diagnostic-reasoning/SKILL.md +53 -0
- package/assets/reference/skills/firstmate-codexapp/SKILL.md +110 -0
- package/assets/reference/skills/firstmate-codexapp/agents/openai.yaml +4 -0
- package/assets/reference/skills/firstmate-coding-guidelines/SKILL.md +127 -0
- package/assets/reference/skills/firstmate-orca/SKILL.md +92 -0
- package/assets/reference/skills/fmx-respond/SKILL.md +283 -0
- package/assets/reference/skills/harness-adapters/SKILL.md +95 -0
- package/assets/reference/skills/harness-adapters/references/common/control-and-recovery.md +37 -0
- package/assets/reference/skills/harness-adapters/references/common/dispatch.md +32 -0
- package/assets/reference/skills/harness-adapters/references/common/model-and-effort.md +42 -0
- package/assets/reference/skills/harness-adapters/references/common/primary-hooks.md +40 -0
- package/assets/reference/skills/harness-adapters/references/harness/claude.md +55 -0
- package/assets/reference/skills/harness-adapters/references/harness/codex.md +43 -0
- package/assets/reference/skills/harness-adapters/references/harness/cursor.md +75 -0
- package/assets/reference/skills/harness-adapters/references/harness/grok.md +69 -0
- package/assets/reference/skills/harness-adapters/references/harness/kimi.md +51 -0
- package/assets/reference/skills/harness-adapters/references/harness/muse.md +70 -0
- package/assets/reference/skills/harness-adapters/references/harness/opencode.md +42 -0
- package/assets/reference/skills/harness-adapters/references/harness/pi.md +56 -0
- package/assets/reference/skills/process-event-sources/SKILL.md +137 -0
- package/assets/reference/skills/project-management/SKILL.md +92 -0
- package/assets/reference/skills/quota-array-dispatch/SKILL.md +131 -0
- package/assets/reference/skills/secondmate-provisioning/SKILL.md +254 -0
- package/assets/reference/skills/stow/SKILL.md +309 -0
- package/assets/reference/skills/stuck-crewmate-recovery/SKILL.md +54 -0
- package/assets/reference/skills/updatefirstmate/SKILL.md +64 -0
- package/assets/skills/README.md +5 -0
- package/assets/yggdrasil.html +649 -0
- package/assets/ymir-banner-01.png +0 -0
- package/assets/ymir-banner-02.png +0 -0
- package/assets/ymir-banner-03.png +0 -0
- package/assets/ymir-banner-04.png +0 -0
- package/assets/ymir-banner-05.png +0 -0
- package/assets/ymir-banner-06.png +0 -0
- package/assets/ymir-emblem-darksteel.svg +63 -0
- package/assets/ymir-emblem-forged.svg +55 -0
- package/assets/ymir-emblem-slate.svg +55 -0
- package/assets/ymir-mark-algiz-anvil.svg +9 -0
- package/assets/ymir-stave.svg +53 -0
- package/assets/ymir.html +563 -0
- package/data/learnings.md +33 -0
- package/data/local-models.md +34 -0
- package/data/operator.md +15 -0
- package/data/projects.md +28 -0
- package/data/realm.md +1 -0
- package/deploy/Containerfile +27 -0
- package/deploy/README.md +104 -0
- package/deploy/compose/compose.yaml +45 -0
- package/deploy/env.example +30 -0
- package/deploy/quadlet/ymir.container +57 -0
- package/package.json +11 -3
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: afk
|
|
3
|
+
description: >-
|
|
4
|
+
Enter away-mode supervision when the captain invokes /afk, says they are going afk, `state/.afk` exists, an incoming message starts with `FM_INJECT_MARK`, or any `state/.subsuper-*` marker is involved.
|
|
5
|
+
It sets a durable away-mode flag so the sub-supervisor daemon can self-handle routine wakes and escalate captain-relevant events plus bounded declared-external-wait rechecks as batched digests during walk-away stretches, then exits automatically when any real unmarked message returns firstmate to full per-wake responsiveness.
|
|
6
|
+
user-invocable: true
|
|
7
|
+
metadata:
|
|
8
|
+
internal: true
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# afk
|
|
12
|
+
|
|
13
|
+
Away-mode supervision. When invoked, `/afk` makes the daemon's token-saving
|
|
14
|
+
tradeoff **consented** and **explicit**: the captain is stepping away, so the
|
|
15
|
+
sub-supervisor may triage routine wakes in bash instead of waking firstmate's
|
|
16
|
+
LLM for each one. Escalations still reach the captain, but as one pre-read,
|
|
17
|
+
batched digest rather than per-wake injections.
|
|
18
|
+
|
|
19
|
+
## What it does
|
|
20
|
+
|
|
21
|
+
1. **Enter the lifecycle through `bin/fm-afk-launch.sh`.**
|
|
22
|
+
This owns the durable state write, session-scoped stale-artifact clearing,
|
|
23
|
+
terminal record, and rollback.
|
|
24
|
+
The flag survives a firstmate restart, so recovery re-enters afk when it is present.
|
|
25
|
+
|
|
26
|
+
2. **Ensure the sub-supervisor daemon is running as a tracked background process.**
|
|
27
|
+
Its hosting differs by harness.
|
|
28
|
+
Pick the right path:
|
|
29
|
+
- **Harness WITH a native in-pane tracked-background tool** (e.g. claude's
|
|
30
|
+
background bash, grok's background tool): first run
|
|
31
|
+
`bin/fm-afk-launch.sh start-native`, then run
|
|
32
|
+
`FM_AFK_STATE_PREPARED=1 bin/fm-afk-start.sh` through that native tool.
|
|
33
|
+
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.
|
|
34
|
+
The launcher still owns lifecycle state and records the no-terminal mode, while the daemon inherits and auto-discovers the captain pane.
|
|
35
|
+
If the native launch fails, run `bin/fm-afk-launch.sh stop` to roll back the prepared lifecycle.
|
|
36
|
+
Do not wrap it in `nohup ... &` (Codex/herdr can reap fire-and-forget shell children after a tool call returns).
|
|
37
|
+
- **Harness WITHOUT one** (e.g. pi): run `bin/fm-afk-launch.sh start`. It is
|
|
38
|
+
the single owner of the daemon terminal: it creates a NON-VISIBLE tracked
|
|
39
|
+
terminal for the current backend (a herdr dedicated `--no-focus` workspace,
|
|
40
|
+
a detached tmux session), records its exact id, and passes the captain pane
|
|
41
|
+
in as `FM_SUPERVISOR_TARGET` so the daemon injects into the captain, not its
|
|
42
|
+
own new pane. **Never manufacture a terminal by splitting the captain's
|
|
43
|
+
active pane** (`herdr pane split`): a split co-tenants the tab and visibly
|
|
44
|
+
shrinks the captain's pane (.agents/skills/herdr-panes/assets/herdr-backend.md "Away-mode supervisor
|
|
45
|
+
support").
|
|
46
|
+
Both paths share `bin/fm-afk-start.sh` as the daemon entry.
|
|
47
|
+
The native path tells it that the launcher already prepared lifecycle state; the terminal-backed path lets the entry perform its existing state setup inside the new terminal.
|
|
48
|
+
It exits immediately if the identity-backed daemon lock already names a live process, otherwise it execs `bin/fm-supervise-daemon.sh` in the foreground.
|
|
49
|
+
The daemon is **presence-gated**: it injects escalations only while
|
|
50
|
+
`state/.afk` exists, and stays quiet otherwise.
|
|
51
|
+
|
|
52
|
+
3. **Do not separately arm `fm-watch.sh`.** The daemon manages the watcher as
|
|
53
|
+
its child; the singleton lock no-ops a stray arm harmlessly.
|
|
54
|
+
|
|
55
|
+
4. **Acknowledge** in `AGENTS.md` section 9 language: "Captain, away mode is active; I will batch routine updates and surface only decisions, failures, credentials, or review-ready work until you return."
|
|
56
|
+
|
|
57
|
+
## How to exit afk
|
|
58
|
+
|
|
59
|
+
No `/back` is needed. The first genuine message is the return signal:
|
|
60
|
+
|
|
61
|
+
- A message **without** the current operational prefix or a legacy bare marker, and **not** starting with `/afk` -> the captain is back.
|
|
62
|
+
Run `bin/fm-afk-return.sh` before acting on the message that brought the captain back.
|
|
63
|
+
That script owns correct-ordered daemon shutdown, durable wake presentation and post-handling acknowledgement, escalation and wedge evidence, and the return-catch-up gate.
|
|
64
|
+
If it reports a firstmate-actionable `blocked:` event, remediate it 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`.
|
|
65
|
+
Once the daemon stops, resume full per-wake responsiveness through the emitted primary-harness supervision protocol while blocker handling proceeds, so the gate never creates a blind wait.
|
|
66
|
+
Do not answer a Bearings request or perform any other ordinary captain work until the check exits successfully.
|
|
67
|
+
- 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 afk and process it.
|
|
68
|
+
- Re-invoking `/afk` while already away -> stay afk (refresh the flag); this
|
|
69
|
+
does **not** trigger an exit.
|
|
70
|
+
|
|
71
|
+
Bias ambiguous cases toward exit: a present captain beats token savings, and
|
|
72
|
+
a false exit is self-correcting (the captain re-runs `/afk`).
|
|
73
|
+
|
|
74
|
+
## Orthogonal to approval authority
|
|
75
|
+
|
|
76
|
+
afk changes how aggressively firstmate surfaces things, **not who approves what**.
|
|
77
|
+
"Away" never means "approves more" or "approves less."
|
|
78
|
+
A PR ready for merge keeps the merge authority from `AGENTS.md` section 7, and a needs-decision finding keeps the `ask-user-authority` policy; anything requiring the captain still waits for the captain's explicit word.
|
|
79
|
+
The daemon only batches the notification.
|
|
80
|
+
|
|
81
|
+
## Operational prefix contract
|
|
82
|
+
|
|
83
|
+
The daemon constructs every current injection as the `away-supervisor` kind owned by `bin/fm-operational-input.sh`, beginning with `FM_OPERATIONAL_PREFIX`: `FM_INJECT_MARK` (U+2063 INVISIBLE SEPARATOR) followed by the stable `FIRSTMATE_OP: ` label.
|
|
84
|
+
The bare `FM_INJECT_MARK` form remains accepted for legacy daemon escalations during rollout.
|
|
85
|
+
U+2063 has no normal keyboard keystroke and survives terminal transport as UTF-8 text.
|
|
86
|
+
This is how firstmate tells a daemon escalation apart from a real message in the same pane.
|
|
87
|
+
The operational prefix travels with the message text; it does not rely on harness-level typed-vs-injected detection, which is not portable across claude, codex, opencode, pi, pi-signed, grok, and kimi.
|
|
88
|
+
|
|
89
|
+
## Busy-guard and composer guard
|
|
90
|
+
|
|
91
|
+
The daemon never injects into an in-use pane. Two checks run before every
|
|
92
|
+
injection, dispatched through `bin/fm-backend.sh` for the supervisor's own
|
|
93
|
+
backend (tmux or herdr; see "Auto-discovered supervisor pane" below):
|
|
94
|
+
|
|
95
|
+
- **Primary-pane busy guard** - `pane_is_busy` trusts Herdr native `busy` when available, otherwise matches rendered output against only the detected primary harness's signature.
|
|
96
|
+
This narrow delivery guard never classifies a recorded worker task and never uses a global union of vendor patterns.
|
|
97
|
+
- **Composer-state guard** - `inject_msg` reads the full `empty`/`pending`/`pending-unproven`/`unknown` verdict from `fm_backend_composer_state` and injects only when it is affirmatively `empty`.
|
|
98
|
+
Every other or future verdict defers, including an unreadable pane, ambiguous geometry, a blank unidentified row, and a bare shell prompt left after the agent exits.
|
|
99
|
+
Each adapter contributes only capture and capability facts to the fleet-wide screen classifier in `bin/fm-composer-lib.sh`, which owns every shape and verdict.
|
|
100
|
+
It preserves proven idle composers as empty but requires a genuine container around shell glyphs; see `.agents/skills/herdr-panes/assets/herdr-backend.md` "Composer and injection safety" for the operator contract.
|
|
101
|
+
`pane_input_pending` is the tested fail-closed predicate for callers that need to know whether the composer is unsafe: it treats every result except exact `empty` as pending.
|
|
102
|
+
|
|
103
|
+
A busy primary pane, or any composer verdict other than `empty`, defers the injection; the buffered escalation survives in `state/.subsuper-escalations` and is retried on the next housekeeping tick.
|
|
104
|
+
In afk mode the composer guard is belt-and-suspenders (no human is typing), but it protects against the race window between the captain returning and their message landing, a dead shell, and the daemon's own previous injection sitting unsent.
|
|
105
|
+
|
|
106
|
+
**Max-defer escape (the daemon must never silently wedge).**
|
|
107
|
+
If anything stays buffered past `FM_MAX_DEFER_SECS` (default 300), the daemon
|
|
108
|
+
attempts one normal flush, which still requires an idle pane and an affirmatively empty composer.
|
|
109
|
+
The alarm is defense in depth rather than a substitute for keeping every genuinely idle supported composer injectable.
|
|
110
|
+
If that submit cannot be confirmed, it raises a loud, rate-limited wedge alarm:
|
|
111
|
+
an ERROR in the daemon log, a durable
|
|
112
|
+
`state/.subsuper-inject-wedged` marker (surface it on the "while you were out"
|
|
113
|
+
catch-up if present), a tmux status-line flash when applicable, and a configurable backend-independent active alert.
|
|
114
|
+
`docs/wedge-alarm.md` owns the alert channel setup, and `docs/verification/supervision.md` "Wedge-alarm channels" owns active evidence.
|
|
115
|
+
So a guard false-positive becomes a visible stall, never an unbounded silent no-op.
|
|
116
|
+
|
|
117
|
+
## Submit model
|
|
118
|
+
|
|
119
|
+
The digest is typed **once** (`send-keys -l` on tmux, `pane send-text` on
|
|
120
|
+
herdr - both literal, non-submitting sends), then submitted with Enter and
|
|
121
|
+
**verified** through the selected backend's submit primitive.
|
|
122
|
+
Enter is retried (Enter only, never a retype) until the backend confirms the
|
|
123
|
+
submit landed.
|
|
124
|
+
For tmux that confirmation is normally a proven cleared composer from the shared classifier; an idle baseline transitioning to busy across this submit's own Enter also confirms that the turn started when a working harness hides its composer.
|
|
125
|
+
Without that baseline, busy state never converts an `unknown` composer into confirmation.
|
|
126
|
+
For herdr, idle-baseline submits first seek native agent-state showing a real turn started, then use the shared classifier when native state remains idle: a cleared composer confirms delivery, while pending text retries Enter and reaches the shared busy-queue verdict only after the retry budget.
|
|
127
|
+
A bordered-empty or ghost-only composer is recognized as empty where that backend uses composer confirmation, rather than mistaken for a swallowed Enter.
|
|
128
|
+
`fm-send.sh` uses the same primitive only on its typed plane and exits non-zero when that plane's Enter is positively swallowed; ordinary local text steers use the durable inbox and do not treat doorbell submission as delivery proof.
|
|
129
|
+
|
|
130
|
+
**Busy-queued Enter exception (opencode 1.18.4).** OpenCode keeps queued text visible while it is mid-turn, so tmux and herdr delegate the final delivery decision to `fm_composer_queued_enter_verdict` in `bin/fm-composer-lib.sh` rather than treating visible text alone as a swallowed Enter.
|
|
131
|
+
The daemon still clears its buffer only on the backend's `empty` success verdict; [`.agents/skills/herdr-panes/assets/tmux-backend.md`](../../../.agents/skills/herdr-panes/assets/tmux-backend.md) and [`.agents/skills/herdr-panes/assets/herdr-backend.md`](../../../.agents/skills/herdr-panes/assets/herdr-backend.md) own the backend-specific confirmation signals.
|
|
132
|
+
|
|
133
|
+
## Classification policy
|
|
134
|
+
|
|
135
|
+
The daemon wraps `fm-watch.sh`, runs the watcher as a child, presents every durable wake after each actionable watcher close, classifies each presented record in bash, and acknowledges the presented generation only after routing completes.
|
|
136
|
+
It self-handles the routine majority without consuming a firstmate turn.
|
|
137
|
+
Captain-relevant events, plus a bounded recheck of a declared wait that is still declared, escalate to firstmate's context as one pre-read, single-line, batched digest.
|
|
138
|
+
The captain-relevant verb set, declared-wait vocabulary, status-span classifier, and presentation-marker contract live in shared `bin/fm-classify-lib.sh`, while each supervisor owns its routing and fleet scan as a consumer of that policy.
|
|
139
|
+
While `state/.afk` exists the daemon owns the watcher, so the watcher reverts to one-shot and lets the daemon do the triage - the two never run their triage at the same time.
|
|
140
|
+
|
|
141
|
+
Classify each wake this way:
|
|
142
|
+
|
|
143
|
+
- `signal` whose newly classified status span contains captain-relevant events -> escalate every event in source order.
|
|
144
|
+
A nonterminal progress verb remains nonterminal even when its prose contains a legacy free-text token such as `PR ready`, `checks green`, `ready in branch`, or `merged`; only a bare legacy line with such a token escalates.
|
|
145
|
+
Other signals with no captain-relevant event in the span -> self-handle.
|
|
146
|
+
- `signal` or `stale` whose latest status declares a wait, either a `paused:` external wait or a verified `captain-held` transfer, tracks the pause rather than a wedge whether its pane reads idle or busy.
|
|
147
|
+
An unreported captain-relevant event in the newly classified span still escalates immediately while the current declaration independently keeps the pause cadence.
|
|
148
|
+
With no unreported actionable event, the wake self-handles, and the current declaration outranks an enriched possible-wedge reason so it never escalates on the `FM_STALE_ESCALATE_SECS` cadence.
|
|
149
|
+
If it is still declared past `FM_PAUSE_RESURFACE_SECS` (default 3600s), housekeeping sends one recheck and resets the pause window.
|
|
150
|
+
The window ages against the crew's own latest status line, so only a status append that stops declaring the wait ends this routing and restores wedge detection.
|
|
151
|
+
That recheck names which human the wait is on: the external dependency for `paused:`, and the captain themself for a `captain-held` transfer, who can answer the held decision or release the hold.
|
|
152
|
+
- `check` -> always escalate. Check scripts print only when firstmate should wake.
|
|
153
|
+
- `stale` with a terminal status or bare legacy captain-relevant line -> escalate.
|
|
154
|
+
Nonterminal progress remains transient even when its prose contains a legacy free-text token or its seen-status marker already matches, so record a marker and self-handle.
|
|
155
|
+
If the pane is still idle past `FM_STALE_ESCALATE_SECS` (default 240s), housekeeping escalates it as a possible wedge.
|
|
156
|
+
This bounds wedge-detection latency to the threshold plus a tick: a delay, never a loss.
|
|
157
|
+
Healthy crewmates are autonomous and do not wait on firstmate mid-task.
|
|
158
|
+
- `heartbeat` -> self-handle.
|
|
159
|
+
The daemon runs its own cheap bash fleet scan every `FM_HEARTBEAT_SCAN_SECS` (default 300s) as the catch-all for captain-relevant events still unread by the per-wake classifier.
|
|
160
|
+
- An unknown wake reason escalates fail-safe, while status-read uncertainty follows the shared one-report-without-position-advance contract referenced under Dedupe below.
|
|
161
|
+
|
|
162
|
+
Escalations are buffered up to `FM_ESCALATE_BATCH_SECS` (default 90s; 0 =
|
|
163
|
+
immediate) and flushed as one single-line digest prefixed with the current
|
|
164
|
+
operational prefix, carrying pre-read status summaries and a recommended action.
|
|
165
|
+
The single-line format makes the submission unambiguous across harnesses, and
|
|
166
|
+
the operational prefix lets firstmate distinguish it from a real captain message.
|
|
167
|
+
|
|
168
|
+
## Injection hardening
|
|
169
|
+
|
|
170
|
+
- **Single-line digest** - embedded newlines are collapsed to a literal
|
|
171
|
+
separator before injection, so submission is unambiguous regardless of
|
|
172
|
+
harness.
|
|
173
|
+
- **Busy and composer guards on the supervisor pane** - before injecting, the daemon runs the detected-primary-harness rendered busy guard and reads `fm_backend_composer_state` directly.
|
|
174
|
+
Only `empty` permits injection; `pending` protects half-typed or swallowed input, and `unknown` protects unreadable panes and bare dead-shell prompts.
|
|
175
|
+
Every other result preserves the buffer for retry, so the daemon never merges its digest into the captain's half-typed line or types it into a shell.
|
|
176
|
+
- The active backend passes its capture plus declarative styled, cursor, identity, and row capabilities to the shared screen classifier; all structural recognition and verdict logic remains in `bin/fm-composer-lib.sh`.
|
|
177
|
+
Styled captures let that owner remove dim/faint and dark-TRUECOLOR ghost or placeholder text while shape detection uses the ANSI-stripped screen, so a dark border is not lost with ghost content.
|
|
178
|
+
A ghost-only or idle bordered composer such as claude's `│ > ... │` therefore reads empty without allowing an unbordered shell prompt to do the same.
|
|
179
|
+
`FM_COMPOSER_IDLE_RE` overrides the shared idle-placeholder regex, but a match alone never bypasses the classifier's shape-specific position and ANSI de-emphasis safety gates.
|
|
180
|
+
`FM_BUSY_REGEX` overrides the rendered delivery guards plus Grok's isolated task-state fallback.
|
|
181
|
+
A blank or otherwise unidentified input row carries no positive container proof and defers injection, so a modal dialog or a mid-redraw pane is never an injection target.
|
|
182
|
+
- **Max-defer escape** - the daemon must never silently wedge. If anything stays
|
|
183
|
+
buffered past `FM_MAX_DEFER_SECS` (default 300s), the daemon attempts one
|
|
184
|
+
normal flush, which still requires an idle pane and an affirmatively empty composer. If that
|
|
185
|
+
cannot confirm a submit, it raises a loud, rate-limited wedge alarm: ERROR log,
|
|
186
|
+
durable `state/.subsuper-inject-wedged` marker, a tmux status-line flash when
|
|
187
|
+
applicable, and a backend-independent active alert. A
|
|
188
|
+
composer false-positive surfaces as a visible stall, never an unbounded silent
|
|
189
|
+
no-op.
|
|
190
|
+
- **Verified type-once submit model** - the digest is typed once (`send-keys -l`
|
|
191
|
+
on tmux, `pane send-text` on herdr), then submitted with Enter and verified.
|
|
192
|
+
Enter is retried, Enter only and never a retype, until the backend submit
|
|
193
|
+
primitive reports `empty` as its caller-facing success verdict.
|
|
194
|
+
For tmux that verdict normally means the shared classifier proved the composer cleared; a baseline-gated idle-to-busy transition may instead prove this Enter started the turn.
|
|
195
|
+
For herdr's idle-baseline path it means native agent-state observed a turn start, the shared classifier proved the composer cleared, or the shared queued-Enter verdict proved delivery while busy.
|
|
196
|
+
This lets ghost-only or bordered-empty composers count as empty where a composer read is the active confirmation signal.
|
|
197
|
+
- **Marker strip** - `strip_injection_marker` removes the current operational
|
|
198
|
+
prefix or legacy bare marker before classification or relay, so the digest
|
|
199
|
+
text firstmate sees is clean.
|
|
200
|
+
- **Portable singleton lock** - the daemon uses the repo's portable lock helper
|
|
201
|
+
(`fm-wake-lib.sh`) instead of `flock`, which is absent on macOS.
|
|
202
|
+
- **Dedupe across signal/stale/scan** - all three paths use the shared status presentation markers defined by `bin/fm-classify-lib.sh`, so a successfully classified span is not re-escalated by another path in the same digest.
|
|
203
|
+
Never treat a reported unreadable state as classified; the shared library header owns that marker contract, and the marker does not clear or suppress possible-wedge aging for a nonterminal progress line.
|
|
204
|
+
- **Auto-discovered supervisor pane** - the daemon resolves its own BACKEND
|
|
205
|
+
(tmux vs herdr) and TARGET independently, mirroring
|
|
206
|
+
`bin/fm-backend.sh`'s own runtime auto-detection. Backend: `FM_SUPERVISOR_BACKEND`
|
|
207
|
+
override, then `$TMUX_PANE` set (tmux), then `$HERDR_ENV=1` with
|
|
208
|
+
`$HERDR_PANE_ID` present (herdr), then a tmux fallback. Target:
|
|
209
|
+
`FM_SUPERVISOR_TARGET` override (a tmux target or a herdr
|
|
210
|
+
`"<session>:<pane-id>"` target), then `$TMUX_PANE`, then
|
|
211
|
+
`"${HERDR_SESSION:-default}:${HERDR_PANE_ID}"` under herdr, then a
|
|
212
|
+
`firstmate:0` fallback with a warning. Both resolution sources are logged at
|
|
213
|
+
startup so a wrong-but-resolving fallback is detectable. Other runtime
|
|
214
|
+
backends, including zellij, orca, and cmux, are not yet supported as
|
|
215
|
+
supervisor backends; the daemon refuses loudly at startup instead of
|
|
216
|
+
misapplying tmux primitives to a pane that isn't one
|
|
217
|
+
(.agents/skills/herdr-panes/assets/herdr-backend.md "Away-mode supervisor support").
|
|
218
|
+
|
|
219
|
+
## Stale-artifact lifecycle
|
|
220
|
+
|
|
221
|
+
Treat `state/.subsuper-escalations`, its `.since` sidecar, and `state/.subsuper-inject-wedged` as session-scoped delivery artifacts, not as the durable work record.
|
|
222
|
+
Always enter through `bin/fm-afk-launch.sh`, which clears prior-session artifacts only for a fresh entry and preserves the current session's buffer on refresh.
|
|
223
|
+
Always exit through `bin/fm-afk-launch.sh stop`, which keeps `state/.afk` present through the daemon's shutdown flush and clears it last.
|
|
224
|
+
`.agents/skills/herdr-panes/assets/herdr-backend.md` "Away-mode supervisor support" owns the current mechanism, and `docs/verification/runtime-backends.md` "Away-mode transport" owns active evidence.
|
|
225
|
+
|
|
226
|
+
## Reliability properties
|
|
227
|
+
|
|
228
|
+
These properties must hold:
|
|
229
|
+
|
|
230
|
+
- Nothing is lost after queue publication.
|
|
231
|
+
The daemon leaves every presented wake durable until routing completes and post-handling acknowledgement succeeds, so interruption replays the same work to the daemon or its successor.
|
|
232
|
+
- Wedge detection is bounded-latency, not lossy.
|
|
233
|
+
- Declared external waits are rechecked on a separate, bounded cadence rather than being mislabeled as wedges.
|
|
234
|
+
- The catch-all scan backs up the keyword classifier.
|
|
235
|
+
- The daemon preserves a single-instance portable lock, crash-loop backoff,
|
|
236
|
+
a pane-gone guard, and a signal-trapped shutdown that flushes buffered
|
|
237
|
+
escalations before exit.
|
|
238
|
+
|
|
239
|
+
`FM_INJECT_SKIP` (default `heartbeat`) force-self-handles matching kinds,
|
|
240
|
+
overriding classification.
|
|
241
|
+
Use it sparingly.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ahoy
|
|
3
|
+
description: Recap visible session events and guide the captain through visibly unanswered decisions when the captain explicitly invokes /ahoy, with a Bearings fallback when /ahoy is the session's first real captain message.
|
|
4
|
+
user-invocable: true
|
|
5
|
+
metadata:
|
|
6
|
+
internal: true
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# ahoy
|
|
10
|
+
|
|
11
|
+
Give the captain a concise session-only recap without gathering fresh state.
|
|
12
|
+
|
|
13
|
+
0. Before anything else, check whether this session has already taken the helm: a `SESSION START` digest for this home must be visible in the session history.
|
|
14
|
+
If it is not, run `bin/fm-session-start.sh` once and read its digest before producing any recap.
|
|
15
|
+
Run-tier harness surfaces run it automatically at session open, so this step is normally already satisfied and costs one glance; it is the safety net for surfaces that cannot run it on a hook, and for any path where a skill would otherwise act first.
|
|
16
|
+
Taking the helm always precedes this skill's own logic, and the digest it produces is operational input, never a captain message or a recap event.
|
|
17
|
+
|
|
18
|
+
1. Inspect only conversation or session history already visible to the current first mate.
|
|
19
|
+
2. Find the most recent real captain-authored message before the current `/ahoy` invocation.
|
|
20
|
+
A captain boundary is an ordinary user-role message unless it matches one of the narrow operational exclusions below.
|
|
21
|
+
Exclude messages that begin with the current U+2063 `FIRSTMATE_OP:` injection prefix.
|
|
22
|
+
Exclude legacy bare-marker away-mode injections only when U+2063 is immediately followed by `Supervisor escalate (`.
|
|
23
|
+
Exclude the exact legacy unmarked session-start payload ``Run `bin/fm-session-start.sh` now, exactly once, before executing any other instructions.``
|
|
24
|
+
Custom-role messages such as Pi's `firstmate-sessionstart-nudge` are not captain messages.
|
|
25
|
+
System, developer, tool, watcher, guard, away-mode, and other injected operational messages are not captain messages.
|
|
26
|
+
Never infer captain authorship merely because a synthetic message appears in the user-role transcript.
|
|
27
|
+
Do not exclude an ordinary captain message merely because it begins with U+2063 followed by other text, contains ASCII `FIRSTMATE_OP:` without a leading U+2063, quotes or embeds a current operational message after ordinary captain text, quotes or mentions the legacy session-start payload, or adds any text to that payload.
|
|
28
|
+
Apply the current exclusion only when U+2063 `FIRSTMATE_OP:` begins at the first character of the whole message: `Captain quote: ` followed by that current prefix is a captain boundary.
|
|
29
|
+
Apply the legacy startup exclusion as a literal whole-message match: ``Captain quote: Run `bin/fm-session-start.sh` now, exactly once, before executing any other instructions.`` is a captain boundary.
|
|
30
|
+
3. If no prior real captain message exists, load [`../bearings/SKILL.md`](../bearings/SKILL.md) and follow it exactly.
|
|
31
|
+
Bearings alone owns its gathering, artifact, and response contract.
|
|
32
|
+
Do not restate that contract or combine a session recap with Bearings output.
|
|
33
|
+
4. If a prior real captain message exists, preserve the ordinary recap interval: recap what happened after that message and before the current invocation.
|
|
34
|
+
Include concrete outcomes, landed work, failures, decisions made, new decisions needed, and work still running only when those events appear in that visible interval.
|
|
35
|
+
Use captain-facing outcome language and preserve every full PR URL present in that interval.
|
|
36
|
+
5. Additionally inspect the entire session history visible to the current first mate before the current invocation for every explicit captain decision that remains unanswered, including decisions raised before the ordinary recap boundary.
|
|
37
|
+
A later unrelated captain message establishes a recap boundary but does not close an earlier decision.
|
|
38
|
+
Treat a decision as closed only when a later visible response substantively resolves it, chooses an option, declines it, grants or denies the requested approval, or otherwise directly addresses that decision.
|
|
39
|
+
Include every visibly supported open decision once, and deduplicate by the decision's substance when the ordinary interval recap already represents it or its wording differs.
|
|
40
|
+
6. The normal recap branch is session-history-only, apart from the step 0 helm check.
|
|
41
|
+
Do not call Bearings, shell commands, fleet snapshots, status readers, GitHub or browser APIs, tools, or file reads or writes.
|
|
42
|
+
Create no report, persist nothing, and do not guess current live state beyond the last visible event.
|
|
43
|
+
7. If no ordinary events occurred after the previous captain message but an older visibly open decision exists, report that decision instead of claiming nothing happened.
|
|
44
|
+
If neither ordinary events nor visibly open decisions exist, say directly in one sentence that nothing happened after the previous captain message.
|
|
45
|
+
|
|
46
|
+
8. After the normal recap, when the existing visibly open decision inventory contains decisions, begin a guided decision-clearing flow by presenting only the single open decision judged most impactful by the first mate.
|
|
47
|
+
Make clear that impact ordering is the first mate's judgment rather than a mechanical score.
|
|
48
|
+
Give enough escalation-quality context to decide easily: the decision, why it matters, the options, and a recommendation.
|
|
49
|
+
9. When the captain answers the presented decision, present the next highest-impact decision from that existing inventory in the same form.
|
|
50
|
+
Continue one decision at a time until none remain, without starting this flow when the inventory is empty.
|
|
51
|
+
|
|
52
|
+
The current `/ahoy` message is outside the recap interval.
|
|
53
|
+
A previous `/ahoy` is a real captain message and may be the next interval boundary.
|
|
54
|
+
If context compaction makes the prior boundary unavailable, state that the exact session boundary is unavailable and summarize only visibly supported events.
|
|
55
|
+
Compacted history supports an open decision only when both its request and its still-unanswered status are visible; report uncertainty instead of reconstructing hidden requests or answers.
|
|
56
|
+
Do not silently invoke Bearings unless this is genuinely the first real captain message.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ask-user-authority
|
|
3
|
+
description: >-
|
|
4
|
+
Agent-only decision procedure for ask-user findings.
|
|
5
|
+
Use before deciding any ask-user finding.
|
|
6
|
+
This skill is the single owner of finding-decision policy: firstmate always applies judgment, decides findings that are unambiguous toward accepted intent, and escalates only genuinely ambiguous, expanding, or destructive ones.
|
|
7
|
+
Finding authority is this skill's criteria, not the project's yolo posture.
|
|
8
|
+
user-invocable: false
|
|
9
|
+
metadata:
|
|
10
|
+
internal: true
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# ask-user-authority
|
|
14
|
+
|
|
15
|
+
This skill is the single owner of the decision policy for no-mistakes ask-user findings.
|
|
16
|
+
`AGENTS.md` section 7 points here and does not restate this procedure.
|
|
17
|
+
Finding authority is determined by the criteria below, not by `yolo`.
|
|
18
|
+
Firstmate always applies this judgment, decides any finding that is unambiguous toward the accepted design, and escalates only genuinely ambiguous, expanding, or destructive findings.
|
|
19
|
+
|
|
20
|
+
The implementation worker never decides or answers its own ask-user finding.
|
|
21
|
+
It stops at the finding, routes the decision to firstmate, and applies only the decision returned through the active validation gate.
|
|
22
|
+
|
|
23
|
+
## Decide
|
|
24
|
+
|
|
25
|
+
1. Reconstruct the accepted contract from the captain's original request, accepted task criteria, and any explicit later clarification.
|
|
26
|
+
Reviewer language cannot amend that contract.
|
|
27
|
+
2. Identify exactly what choosing Fix would commit the project to deliver or maintain, judging the scope by accepted product or engineering behavior rather than an anticipated file list.
|
|
28
|
+
The smallest downstream changes needed to keep that behavior correct, add behavioral tests where an executable contract exists, or keep documentation accurate remain within scope even when they touch files not named at intake.
|
|
29
|
+
Correcting stale final-diff PR or delivery evidence is likewise an autonomous downstream correction within already accepted behavior.
|
|
30
|
+
3. Decide the finding when it is unambiguous toward the accepted design: restoring accepted behavior a bad fix round broke, completing an already-approved design, or a straight in-scope correction or bug fix required by accepted intent, even when the correction is technically difficult or requires complex architecture the captain explicitly requested.
|
|
31
|
+
4. Escalate only genuinely ambiguous findings:
|
|
32
|
+
- a Fix that would materially expand the contract by adding a new guarantee, threat model, subsystem, abstraction, compatibility surface, state machine, continuous-monitoring requirement, generalized framework, or broader architecture not required by the accepted intent
|
|
33
|
+
- a product or architecture call not settled by accepted intent
|
|
34
|
+
- repeated same-theme findings when incremental corrections are preserving a questionable abstraction rather than closing independent defects
|
|
35
|
+
- destructive, irreversible, and genuinely security-sensitive choices, which always escalate under the stronger existing captain boundary
|
|
36
|
+
5. Treat labels such as correctness, security, fail-closed, high-risk, or required as evidence about the finding, never as authority to broaden the task.
|
|
37
|
+
|
|
38
|
+
## Captain-facing escalation
|
|
39
|
+
|
|
40
|
+
State all five of these elements in one concise, evidence-first escalation:
|
|
41
|
+
|
|
42
|
+
1. The original requirement or accepted task criterion.
|
|
43
|
+
2. The proposed product or engineering contract expansion.
|
|
44
|
+
3. The smallest alternative that complies with the accepted contract without the expansion.
|
|
45
|
+
4. The concrete consequences of accepting and declining the expansion.
|
|
46
|
+
5. A recommendation with the reason it best serves the accepted intent.
|
|
47
|
+
|
|
48
|
+
Do not relay reviewer labels or gate output as if they settled the decision.
|
|
49
|
+
|
|
50
|
+
## Classification examples
|
|
51
|
+
|
|
52
|
+
- Fixing a concrete defect that violates an original acceptance criterion is firstmate's to decide, regardless of implementation difficulty.
|
|
53
|
+
- Adding continuous frame-by-frame monitoring when the accepted criterion requested checkpoint proof expands the contract and requires the captain.
|
|
54
|
+
- A new finding in the same causal theme requires the captain before another fix round when prior fixes are accreting machinery around a questionable abstraction.
|
|
55
|
+
- A genuinely security-sensitive action requires the captain under the stronger existing boundary even if it is otherwise within scope.
|
|
56
|
+
- Complex architecture explicitly requested by the captain stays within scope and does not escalate merely because it is complex.
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bearings
|
|
3
|
+
description: >-
|
|
4
|
+
Generate a "pick up where I left off" fleet digest from firstmate's live fleet state.
|
|
5
|
+
Use when the captain invokes /bearings or asks for a bearings report, morning brief, status report, catch-up, "where did I leave off", or "what's in the works".
|
|
6
|
+
Plain /bearings is chat-only by default, /bearings file explicitly writes the dated data/status-report-<YYYY-MM-DD>.md artifact, and /bearings lavish additionally builds and arms the interactive fleet board; live PR enrichment remains opt-in and composes with the other modes.
|
|
7
|
+
Also load this skill's board-wake handling when a procevent lavish wake's source id matches the canonical source id of the stable bearings board path.
|
|
8
|
+
user-invocable: true
|
|
9
|
+
metadata:
|
|
10
|
+
internal: true
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# bearings
|
|
14
|
+
|
|
15
|
+
Generate a complete current snapshot from the fleet's current state, so the captain can resume in one read after a break, a night, or a context reset.
|
|
16
|
+
Plain `/bearings` returns only the concise four-section chat digest.
|
|
17
|
+
Only `/bearings file` writes the dated markdown report artifact and then returns the concise four-section chat digest linked to that report.
|
|
18
|
+
Only `/bearings lavish` builds the interactive fleet board beside that digest, through `bin/fm-bearings-board.sh` (its header owns every board mechanic and the fm-bearings-board.v1 payload contract).
|
|
19
|
+
A digest/build invocation is operationally read-only apart from the cooldown-limited reconcile instruction and its `state/<id>.reconcile-nudged` record, plus the explicit per-mode artifacts: the dated report in file mode, and in lavish mode the board file plus the answer binding and source registration that `bin/fm-bearings-board.sh build` records through their own owners.
|
|
20
|
+
During that invocation it never tears down a task, merges a PR, dispatches new work, steers a worker except through that reconcile hook, answers a decision, cleans up work, or mutates backlog or task state beyond the reconcile record.
|
|
21
|
+
Board answers are acted on later under the normal authority rules; this skill's board-wake section explicitly owns the guarded routing at that time.
|
|
22
|
+
|
|
23
|
+
## Invocation modes
|
|
24
|
+
|
|
25
|
+
- Plain `/bearings` gathers a fresh bounded snapshot and renders the four-section chat digest without creating, deleting, reading, or replacing `data/status-report-<YYYY-MM-DD>.md`.
|
|
26
|
+
- `/bearings file` gathers a fresh bounded snapshot, replaces today's `data/status-report-<YYYY-MM-DD>.md` from scratch, and renders the four-section chat digest with a link or path to that report.
|
|
27
|
+
- `/bearings lavish` gathers a fresh bounded snapshot, rebuilds and arms the interactive fleet board (the "Lavish board mode" section below), and renders the four-section chat digest with the board's URL inside it.
|
|
28
|
+
- Treat `file` and `lavish` only as explicit invocation options in the slash command.
|
|
29
|
+
- Do not treat natural-language requests such as "write a report", "save this", "persist it", "make a file", or "make a board" as file or lavish mode unless the invocation explicitly includes the standalone option.
|
|
30
|
+
- When the captain asks to include PRs, pass the snapshot command's live-PR opt-in.
|
|
31
|
+
- `/bearings include PRs` remains chat-only and makes the live-PR opt-in.
|
|
32
|
+
- `/bearings file include PRs` and `/bearings lavish include PRs` compose the same way.
|
|
33
|
+
|
|
34
|
+
## What it does
|
|
35
|
+
|
|
36
|
+
1. **Gather live fleet state with one deterministic command.**
|
|
37
|
+
Run `snapshot=$(bin/fm-bearings-snapshot.sh --json)` at invocation time and read that compact output.
|
|
38
|
+
It is the single bounded, deterministic fleet-state source for Bearings.
|
|
39
|
+
Do not create or consult a second fleet-state reader, parser contract, status-event-tail interpretation, visible-session recap, ad-hoc project probe, or ad-hoc `gh-axi`/`gh` query.
|
|
40
|
+
The command's header and `--help` output own its exact fields, bounds, opt-ins, and output contract.
|
|
41
|
+
Keep the default local-only read unless the captain asks to include PRs.
|
|
42
|
+
For registered secondmates, use the snapshot's structured-home classification and provenance.
|
|
43
|
+
A parent event or bounded terminal contradiction is fallback evidence, never authority over readable structured home state.
|
|
44
|
+
A decision is simply a task held for the captain (`captain-hold-lifecycle`); every due, unblocked captain-held task appears under `decisions_open`, whatever its kind.
|
|
45
|
+
A captain hold deferred by date sits under `gates` with its `until <date>:` reason until it is due, and a hold whose reason or body carries an explicit deferred/superseded marker is suppressed from the default view with an `omitted` disclosure.
|
|
46
|
+
Do not scrape reports, visual-review artifacts, raw status-event tails, or visible conversation history to supplement current state.
|
|
47
|
+
A queued item under `gates` only becomes "next work" when its blocker is gone and its time/date gate has arrived.
|
|
48
|
+
Until then it stays queued with the reason.
|
|
49
|
+
The `(main-inventory)` gate is an action-free integrity warning rather than queued work.
|
|
50
|
+
Render it under Charted Next with the related `omitted` disclosure, never invent an Underway row from backlog-only state, and never move it into Captain's Call.
|
|
51
|
+
The same holds for a secondmate home whose current state is unavailable, and for a readable home whose `invalidity` reports a backlog-vs-metadata mismatch: the mismatch is a repair notice about that home's own books, not a reason to drop its separately projected decisions, queued, landed, or live work.
|
|
52
|
+
|
|
53
|
+
2. **Ask any home whose own books disagree to reconcile them.**
|
|
54
|
+
When the snapshot reports a secondmate home whose `invalidity` is `orphan_in_flight`, `unowned_current`, or `terminal_in_flight`, that home's backlog and its own task metadata disagree and only that home may fix it.
|
|
55
|
+
Run `printf '%s\n' "$snapshot" | bin/fm-secondmate-reconcile.sh notify --snapshot -` inline immediately after gathering the snapshot, so the durable fire-and-forget enqueue finishes before digest composition without spawning any child or second snapshot.
|
|
56
|
+
The script header owns the cooldown window, non-blocking lock skips, stale-endpoint checks, retry, and fire-and-forget delivery contract; this hook arms no reply recovery or inbox escalation.
|
|
57
|
+
If the hook reports a skip or failure, continue composing the digest from the captured snapshot; a lock skip or known-undelivered send leaves the cooldown unset for a later recap.
|
|
58
|
+
A home is asked at most once per four-hour window, so running this on every recap costs nothing and cannot nag, while a mismatch still sitting there after the window earns one gentle re-nudge.
|
|
59
|
+
Never edit another home's backlog or metadata from here, and never expect or wait on a reply: the mate acts asynchronously from its durable inbox while the digest is composed from the snapshot already in hand.
|
|
60
|
+
|
|
61
|
+
3. **Compose the four-section chat digest from the fresh snapshot.**
|
|
62
|
+
The gather step is deterministic; your judgment is scoped to ranking the command's facts by what matters right now and writing scannable captain-facing prose.
|
|
63
|
+
The chat response uses the four complete sections in the chat-response contract below, in the same order, each always present.
|
|
64
|
+
Plain mode stops here and writes no report artifact.
|
|
65
|
+
|
|
66
|
+
4. **In explicit file mode only, compose and replace the detailed report file.**
|
|
67
|
+
The report uses the same four complete sections as the chat, in the same order, and adds the detail the chat omits.
|
|
68
|
+
Never read an earlier `data/status-report-*.md` to decide what to omit, include, describe as changed, or call current.
|
|
69
|
+
Write the full report to `data/status-report-<YYYY-MM-DD>.md` using today's date.
|
|
70
|
+
If today's file already exists, delete it first, then create a new file from scratch.
|
|
71
|
+
This is the only file-mode write allowed by the skill.
|
|
72
|
+
The detailed report includes:
|
|
73
|
+
- **Title** - `# Bearings - <day> <YYYY-MM-DD>` (use "Morning status" only when the captain specifically asks for a morning brief), followed by two or three sentences framing where things stand.
|
|
74
|
+
- **Captain's Call** - every open decision summarized with its options from the structured decision record, plus each PR ready to merge and each needed credential or login, every PR with the full `https://...` URL, never a bare `#number`.
|
|
75
|
+
- **Recently Landed** - the bounded current recent-completions baseline from structured state across the main fleet and every registered secondmate home, rendered in full on every run.
|
|
76
|
+
- **Underway** - each live direct report making progress, with its current state, and the plans or main pickup pointers worth reopening (`data/<id>/report.md` files, `.lavish/*.html` boards).
|
|
77
|
+
- **Charted Next** - queued or gated work, including any main-inventory integrity warning, with each item's blocker, date, or integrity reason.
|
|
78
|
+
After writing the file, return the concise four-section chat digest and include the report path or link without adding a fifth section.
|
|
79
|
+
For a richer review surface, offer `/bearings lavish` when the report has enough structure to deserve one, but only after the required digest is ready.
|
|
80
|
+
|
|
81
|
+
## Lavish board mode
|
|
82
|
+
|
|
83
|
+
`/bearings lavish` adds one deliverable beside the unchanged chat digest: the interactive fleet board, a myfirstmate-styled Lavish page where the captain answers Captain's Call items directly instead of replying in chat.
|
|
84
|
+
`bin/fm-bearings-board.sh` owns every board mechanic - the stable board path, fm-bearings-board.v1 payload validation, template injection, Lavish session establishment, the any-origin answer binding, and arm-if-absent registration - so the per-invocation work is composing the payload and running its `build`.
|
|
85
|
+
|
|
86
|
+
Compose the payload from the same snapshot with the same ranking judgment as the chat digest, plus these board rules:
|
|
87
|
+
|
|
88
|
+
- A Captain's Call decision key is the captain-held TASK ID from `decisions_open` (legacy `<origin>-decision-<key>` rows are already task ids); a merge card's key is `merge.<task-id>`; the Charted Next dispatch picker's key is `dispatch.charted`.
|
|
89
|
+
- Compose exactly one decision card per captain-held task id. When one task carries multiple questions, consolidate all of them and their options into that card; never emit duplicate cards with the same task-id key.
|
|
90
|
+
- Decision cards carry agent-authored copy: a short noun-phrase title, one-line `about` and `decide` context rows, and option labels with hints, with the recommended option marked.
|
|
91
|
+
- Card `type` (decision, merge, credential) is your composing judgment from the row's content; no backlog field types a card for you.
|
|
92
|
+
- When the card's task is a captain-gated WORK item (the answer should free it to proceed rather than complete it), set the card's `close: "release"` so the answer lifts the hold instead of closing the task; question-shaped items omit it.
|
|
93
|
+
- A Charted Next row's optional `kind` separates work from alarms: omit it (or set `"queued"`) for real queued work, and set `"warning"` on every action-free fleet-integrity notice - the `(main-inventory)` gate, an unavailable secondmate home, and an inventory-mismatch repair notice. The board badges a warning row `needs repair` instead of `waiting` and leaves it out of the Charted Next count, so those rows never read as dispatchable queued work.
|
|
94
|
+
- `charted_more` counts omitted queued rows only, while `charted_warning_more` counts omitted warning rows only; keep both counts separate whenever the board payload truncates Charted Next.
|
|
95
|
+
- Every Captain's Call item and every Underway, Recently Landed, and Charted Next row carries an explicit `repo` field. Fill it from the snapshot and task records wherever known; use null or an empty string only as the deliberate genuinely-no-repo marker, in which case the template may show the internal id. Ids otherwise stay in the payload only as the routing channel, and composed reasons name blockers in plain words.
|
|
96
|
+
|
|
97
|
+
Run `build` once after composing the payload.
|
|
98
|
+
Its serve-first sequence publishes the board, establishes or resumes its Lavish session with `lavish-axi`, and only then binds and arms the polling source; use the session URL it prints in the chat digest.
|
|
99
|
+
Never bind or arm the board before that session exists.
|
|
100
|
+
Never run `lavish-axi poll` for the board yourself: the armed source's supervised runner owns the blocking poll, and the watcher's ordinary reconcile restarts it, so no conversational turn ever blocks on the board.
|
|
101
|
+
|
|
102
|
+
### Handling a board wake
|
|
103
|
+
|
|
104
|
+
A board answer arrives as an ordinary `procevent lavish <source-id> <sequence>` check wake. Identify it by comparing the wake source id with `bin/fm-procevent-lavish.sh source-id "$(bin/fm-bearings-board.sh path)"`, regardless of which answer kinds the result contains; then load `process-event-sources` and follow its contract for the result read, adapter classification, and the handled acknowledgement.
|
|
105
|
+
Decision answers need no routing from you: the runner feeds the board's binding into `bin/fm-captain-hold.sh`'s one keyed-answer intake, which closes or releases each answered captain-held task at answer time; reconcile any `skipped:` key yourself with a direct `answer`, and when the captain's answer is "later", record it as a deferral with `tasks-axi hold <id> ... --until <date>` instead of a closure.
|
|
106
|
+
Route the non-decision keys yourself:
|
|
107
|
+
|
|
108
|
+
- `merge.<task-id>` is the captain's explicit merge order; follow the merge ruling below.
|
|
109
|
+
- `dispatch.charted` carries comma-separated task ids the captain picked to start now; verify each id against the current backlog - still queued, blocker and time gate actually clear - then dispatch through the normal lifecycle, and report any id that no longer qualifies instead of forcing it.
|
|
110
|
+
|
|
111
|
+
After handling, rebuild the board from a fresh snapshot so acted-on items leave Captain's Call, and echo every action taken in chat so the board and chat never diverge silently.
|
|
112
|
+
|
|
113
|
+
### The merge-click ruling (captain-decided)
|
|
114
|
+
|
|
115
|
+
A board "Merge now" answer IS the captain's explicit merge word for that one exact PR; ask no second confirmation.
|
|
116
|
+
The safeguards are mandatory, not optional: resolve the PR from the task's own `state/<task-id>.meta` `pr=` record, never from board bytes; re-verify at wake time that the PR is still open and CI-green; refuse and report a red or changed PR rather than merging it; merge only through `bin/fm-pr-merge.sh`; and echo every merge in chat with the full PR URL.
|
|
117
|
+
Only the exact answer value `merge` authorizes a merge; an answer carrying a freeform note is the captain's instruction text to read and act on with judgment, never an auto-merge.
|
|
118
|
+
|
|
119
|
+
## Chat-response contract
|
|
120
|
+
|
|
121
|
+
This skill is the one owner of the `/bearings` chat-response format; the snapshot and classifier own the data that feeds it, and no other file restates this contract.
|
|
122
|
+
Every `/bearings` chat response renders EXACTLY these four sections, in THIS order, and nothing else structural (there is no At Anchor section):
|
|
123
|
+
|
|
124
|
+
1. **Captain's Call** - ONLY items that need the captain's own action now: a decision to make, a PR to approve or merge, a credential or login to provide, or a blocker only the captain can clear.
|
|
125
|
+
Empty-state: "Nothing needs your action right now."
|
|
126
|
+
2. **Recently Landed** - the bounded current recent-completions baseline: merged PRs, completed scouts, and finished local-only merges across the main fleet and every registered secondmate home.
|
|
127
|
+
Empty-state: "No recent completions are in the current baseline."
|
|
128
|
+
3. **Underway** - live work progressing on its own, one line of current state per direct report.
|
|
129
|
+
Empty-state: "Nothing is underway."
|
|
130
|
+
4. **Charted Next** - queued or gated work waiting on the fleet or a date, plus action-free fleet-integrity warnings, never on the captain.
|
|
131
|
+
Empty-state: "Nothing is queued."
|
|
132
|
+
|
|
133
|
+
Rules that keep the contract unambiguous:
|
|
134
|
+
|
|
135
|
+
- Every section ALWAYS renders, even when empty, with its short empty-state sentence; never omit a section.
|
|
136
|
+
- Every chat digest and file-mode report is a complete current snapshot, never a delta against a prior report.
|
|
137
|
+
- Recently Landed always renders the bounded current baseline, even when the same completions appeared in an earlier report.
|
|
138
|
+
- The four buckets are mutually exclusive, so every item is forced into exactly one: needs-your-action is Captain's Call, done is Recently Landed, self-progressing is Underway, and not-yet-started work or an action-free fleet-integrity warning is Charted Next.
|
|
139
|
+
- The strict boundary keeps action-free items OUT of Captain's Call: a working or validating task, a queued item blocked on another task or a date, landed work, a completed scout's report pointer, a declared `paused:` external wait, and a bare recorded PR with no merge-ready signal each belong to one of the other three sections, never Captain's Call.
|
|
140
|
+
- A secondmate's own row appears Underway only for `active_child_work`; `externally_held` belongs in Charted Next, and `unknown` belongs there as an unavailable-state gate unless its reason requires the captain's action.
|
|
141
|
+
- Do not suppress separately projected decisions, landed records, or gates from a `partial-structured` home merely because that secondmate's own row is `unknown` or its `invalidity` reports an inventory mismatch.
|
|
142
|
+
- Include the required direct address to the captain inside one item or empty-state sentence.
|
|
143
|
+
- Every PR appears as the full `https://...` URL; a shorthand `#number` is fine only as a back-reference after the full URL has already appeared in the same digest.
|
|
144
|
+
- The chat follows `AGENTS.md` section 9 and carries one scannable line per item.
|
|
145
|
+
- Detailed decisions, plans, full gate reasons, and evidence stay out of chat; file mode puts them in the report, while lavish mode puts only its payload-backed interactive detail on the board.
|
|
146
|
+
- In file mode, include the report path or link inside the four-section digest without adding another heading.
|
|
147
|
+
- In lavish mode, include the board URL inside the four-section digest the same way.
|
|
148
|
+
|
|
149
|
+
## Tone and content rules
|
|
150
|
+
|
|
151
|
+
- The optional file-mode report is a private, captain-facing internal artifact that lives in gitignored `data/`, so unlike normal captain chat it MAY reference task ids, PR URLs, and repo names.
|
|
152
|
+
- The captain works with those directly and needs them to resume; keep the report organized and scannable, not a raw dump.
|
|
153
|
+
- Every PR reference is a full `https://...` URL, never a bare `#number`.
|
|
154
|
+
- Never include PHI or secret values; the report is an operational artifact, but it is still subject to the same security and compliance rules that govern everything else in this fleet.
|
|
155
|
+
|
|
156
|
+
## Supervision discipline
|
|
157
|
+
|
|
158
|
+
During a digest/build invocation, this skill changes no fleet state beyond its reconcile instruction and cooldown record, explicit report or board artifacts, binding, and source registration.
|
|
159
|
+
Do not tear down a task, merge a PR, dispatch queued work, steer a worker except through the reconcile hook, answer a queued decision, clean up work, or mutate any other `state/` or `data/` file during that invocation.
|
|
160
|
+
If the state gathered for the digest suggests an action, name it in its section and leave it to the normal lifecycle and configured authority.
|
|
161
|
+
On a later board wake, this read-only invocation rule yields to "Handling a board wake" and its guarded authority for captain-selected dispatches and merges.
|