Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
4a28dcf
Keep parked and aged undated captain holds off live Captain's Call.
kunchenguid Sep 2, 2026
bd207b8
no-mistakes(review): Bound parked marker matching to lexical tokens
kunchenguid Sep 2, 2026
ec46588
no-mistakes(review): Age undated holds from durable hold-set dates
kunchenguid Sep 2, 2026
d3f23ab
no-mistakes(review): Reset re-held timestamps and scan full bodies
kunchenguid Sep 2, 2026
d81f05d
no-mistakes(review): Preserve timestamp precision and prioritize park…
kunchenguid Sep 2, 2026
815b063
no-mistakes(document): Document undated captain-hold aging
kunchenguid Sep 2, 2026
cbc3588
no-mistakes(ci): Fixed stock Bash CI test-count expectations (16 snap…
kunchenguid Sep 2, 2026
1a929d5
no-mistakes(ci): account for rebased snapshot regression
kunchenguid Sep 2, 2026
2d3e3bc
no-mistakes(review): Restore legacy hold aging and mandate wrapper
kunchenguid Sep 2, 2026
0ee6c0b
no-mistakes(review): Restrict hold stamps to canonical leading lines
kunchenguid Sep 2, 2026
2bd2c0d
no-mistakes(review): Exclude historical answers and deduplicate revea…
kunchenguid Sep 2, 2026
3b94980
no-mistakes(document): Correct captain-hold projection documentation
kunchenguid Sep 2, 2026
5262c2b
no-mistakes(ci): Rebased onto 8988af2 and resolved Bearings conflicts…
kunchenguid Sep 2, 2026
bbae2b9
no-mistakes(review): Bound current prose before historical resolutions
kunchenguid Sep 2, 2026
f73ad79
no-mistakes(review): Preserve hold age across interrupted answers
kunchenguid Sep 2, 2026
87a92e3
no-mistakes(review): Preserve leading hold stamps until answer closure
kunchenguid Sep 2, 2026
5d7fe66
no-mistakes(review): Normalize answer bodies on matching retries
kunchenguid Sep 2, 2026
f9404c6
no-mistakes(review): Document concurrent re-hold age-basis limitation
kunchenguid Sep 2, 2026
5c3578b
no-mistakes(document): Refresh captain hold lifecycle documentation
kunchenguid Sep 2, 2026
db8d5c3
no-mistakes(ci): Fixed both CI failures. Updated the macOS Bash snaps…
kunchenguid Sep 2, 2026
05e710b
no-mistakes(ci): Fixed Greptile’s P1 finding by restricting parked-st…
kunchenguid Sep 2, 2026
8251ffb
no-mistakes(ci): Fixed parked-style undated captain holds disappearin…
kunchenguid Sep 2, 2026
ed1a693
no-mistakes(test): Stabilize concurrency budget and provision timeout…
kunchenguid Sep 3, 2026
d436930
no-mistakes(document): Correct captain hold documentation details
kunchenguid Sep 3, 2026
3255fc2
no-mistakes(ci): Fixed hold-reason parsing so commas in contextual re…
kunchenguid Sep 3, 2026
b10e330
Restore the Herdr lab timeout test to its main version.
kunchenguid Sep 3, 2026
493449c
no-mistakes(review): Preserve metadata-like prose in captain hold rea…
kunchenguid Sep 3, 2026
2d4368c
no-mistakes(review): Resurface due dated captain holds
kunchenguid Sep 4, 2026
621f18e
no-mistakes(review): Distinguish parked holds from explicit deferrals
kunchenguid Sep 4, 2026
a7801d7
no-mistakes(review): Invalidate legacy secondmate summary caches
kunchenguid Sep 4, 2026
e57c7ef
no-mistakes(review): Keep blocked deferred holds in Charted Next
kunchenguid Sep 4, 2026
3ada675
no-mistakes(review): Count blocked deferred holds in omission disclosure
kunchenguid Sep 4, 2026
d632d8c
no-mistakes(document): Correct captain-hold projection documentation
kunchenguid Sep 4, 2026
b4851ac
no-mistakes(ci): Fixed both CI failures. Updated the macOS Bearings t…
kunchenguid Sep 4, 2026
6a7d4c0
no-mistakes(ci): Fixed Greptile’s valid finding: `--all-decisions` no…
kunchenguid Sep 4, 2026
3175f89
no-mistakes(ci): Fixed the actionable-state bug in Bearings: an arriv…
kunchenguid Sep 4, 2026
0a9fcea
Show why a revealed captain hold is deferred.
kunchenguid Sep 4, 2026
d2ac77a
Classify captain holds from structured fields alone.
kunchenguid Sep 4, 2026
8408014
no-mistakes(review): Preserve working captain holds across bucket sur…
kunchenguid Sep 4, 2026
7de38ba
no-mistakes(review): Reject pre-classifier secondmate summary caches
kunchenguid Sep 4, 2026
7a38735
no-mistakes(review): Preserve complete live hold summaries
kunchenguid Sep 4, 2026
9768605
no-mistakes(review): Clarify working hold decision bucket semantics
kunchenguid Sep 5, 2026
6cdc078
no-mistakes(review): Reveal bounded remote holds and preserve blocker…
kunchenguid Sep 5, 2026
9733a7d
no-mistakes(review): Make blocker overflow explicit in hold summaries
kunchenguid Sep 5, 2026
8333797
no-mistakes(document): Correct captain-hold projection documentation
kunchenguid Sep 5, 2026
fee5bbe
no-mistakes(ci): Updated the stock macOS Bash CI snapshot expectation…
kunchenguid Sep 5, 2026
0be7f35
no-mistakes(ci): Updated the stock macOS Bash CI expectation from 51 …
kunchenguid Sep 5, 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
24 changes: 15 additions & 9 deletions .agents/skills/bearings/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,12 @@ Board answers are acted on later under the normal authority rules; this skill's
Only pass `--include-prs` when the captain asks for live GitHub PR enrichment.
For registered secondmates, use the snapshot's structured-home classification and provenance.
A parent event or bounded terminal contradiction is fallback evidence, never authority over readable structured home state.
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.
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.
A decision is simply a task held for the captain (`captain-hold-lifecycle`), whatever its kind.
The canonical snapshot assigns every captain hold exactly one bucket from structured fields only: `blocked` when any blocker is unresolved, else `dated` while `hold_until` is in the future, else `aged` when an undated hold has reached the configured age threshold, else `live`.
Never use hold-reason or body prose to classify or place a decision.
A `live` hold appears in Captain's Call; `blocked`, `dated`, and `aged` holds appear as disclosed Charted Next gates stating their structured reason.
Use `--all-decisions` to reveal every captain hold available within the bounded snapshot and remove each revealed gate from Charted Next so the buckets remain exclusive.
Aging is only a presentation safety net, and re-holding with `--until` remains the durable deferral.
Do not scrape reports, visual-review artifacts, raw status-event tails, or visible conversation history to supplement current state.
A queued item under `gates` only becomes "next work" when its blocker is gone and its time/date gate has arrived.
Until then it stays queued with the reason.
Expand Down Expand Up @@ -74,10 +78,10 @@ Board answers are acted on later under the normal authority rules; this skill's
This is the only file-mode write allowed by the skill.
The detailed report includes:
- **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.
- **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`.
- **Captain's Call** - every unsuppressed 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`.
- **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.
- **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).
- **Charted Next** - queued or gated work, including any main-inventory integrity warning, with each item's blocker, date, or integrity reason.
- **Charted Next** - queued or gated work, including deferred or aged captain-hold safety gates and any main-inventory integrity warning, with each item's blocker, date, age, or integrity reason.
After writing the file, return the concise four-section chat digest and include the report path or link without adding a fifth section.
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.

Expand Down Expand Up @@ -105,7 +109,7 @@ Never run `lavish-axi poll` for the board yourself: the armed source's supervise
### Handling a board wake

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.
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.
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 `bin/fm-captain-hold.sh hold <id> --reason "<reason>" --until <date>` instead of a closure.
Route the non-decision keys yourself:

- `merge.<task-id>` is the captain's explicit merge order; follow the merge ruling below.
Expand All @@ -124,22 +128,24 @@ Only the exact answer value `merge` authorizes a merge; an answer carrying a fre
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.
Every `/bearings` chat response renders EXACTLY these four sections, in THIS order, and nothing else structural (there is no At Anchor section):

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.
1. **Captain's Call** - ONLY unsuppressed 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.
Deferred or aged holds follow the presentation safety rule above instead.
Empty-state: "Nothing needs your action right now."
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.
Empty-state: "No recent completions are in the current baseline."
3. **Underway** - live work progressing on its own, one line of current state per direct report.
Empty-state: "Nothing is underway."
4. **Charted Next** - queued or gated work waiting on the fleet or a date, plus action-free fleet-integrity warnings, never on the captain.
4. **Charted Next** - queued or gated work waiting on the fleet or a date, deferred or aged captain-hold safety gates, plus action-free fleet-integrity warnings.
Empty-state: "Nothing is queued."

Rules that keep the contract unambiguous:

- Every section ALWAYS renders, even when empty, with its short empty-state sentence; never omit a section.
- Every chat digest and file-mode report is a complete current snapshot, never a delta against a prior report.
- Recently Landed always renders the bounded current baseline, even when the same completions appeared in an earlier report.
- The four buckets are mutually exclusive per item: 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.
- A secondmate home can contribute to more than one section at once. Each active child is an Underway row regardless of the home-level `bearings_state`, while that same home's due captain hold is Captain's Call and its queued or external holds stay Charted Next. Do not hide active children because the home also has an open captain hold.
- A captain hold appears in exactly one decision bucket: an unsuppressed live hold is in Captain's Call, while a blocked, dated, or aged hold is in Charted Next; `--all-decisions` moves the latter into Captain's Call and removes its gate.
- Underway independently reports active work, so an actively worked captain-held task may appear there plus its one decision bucket.
- A secondmate home can contribute to more than one section at once. Each active child is an Underway row regardless of the home-level `bearings_state`, while that same home's live captain hold is Captain's Call and its queued or external holds stay Charted Next. Do not hide active children because the home also has an open captain hold.
- 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.
- A secondmate's own home-level row is not an Underway unit: `externally_held` belongs in Charted Next, and `unknown` belongs there as an unavailable-state gate unless its reason requires the captain's action.
- 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.
Expand Down
4 changes: 2 additions & 2 deletions .agents/skills/captain-hold-lifecycle/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ metadata:
# Captain-hold lifecycle

A decision is not a separate thing: it is simply a task waiting on the captain.
The one primitive is an ordinary backlog task held for the captain (`tasks-axi hold <id> --kind captain`), its identity is the task id, and `bin/fm-captain-hold.sh` owns the deterministic mechanics this policy relies on.
The one primitive is an ordinary backlog task held for the captain through `bin/fm-captain-hold.sh hold`; its identity is the task id, and that wrapper owns the deterministic mechanics this policy relies on.
The agent performs the semantic inventory because scripts must not infer captain calls from report prose, visual-review artifacts, terminal output, or chat.

## Policy
Expand All @@ -28,7 +28,7 @@ Holding the work item the question gates is safe for exactly that reason: cleanu

Never close anything the captain owns without recording what he actually said: `bin/fm-captain-hold.sh answer` writes his exact words into the task and closes it in the same act, with `--release` when the answer frees a captain-gated work item to proceed instead of completing a question.
When the answer changes what a task must build, follow `AGENTS.md` section 7's Validate contract to preserve the captain's words in the brief and steer the worker.
When the captain says "later", that is an answer too: re-hold with `tasks-axi hold <id> ... --until <date>` so the item leaves the live Captain's Call and resurfaces on its date, instead of leaving a live-looking card or fabricating a closure.
When the captain says "later", that is an answer too: re-hold with `bin/fm-captain-hold.sh hold <id> --reason "<reason>" --until <date>` so the item leaves the live Captain's Call and resurfaces on its date, instead of leaving a live-looking card or fabricating a closure.
"A keyed answer closes its matching captain-held task" is one capability with one owner, `bin/fm-captain-hold.sh answers`, and every channel that carries a captain answer feeds it the same task id and answer; a channel never maps keys to tasks, records a decision, or closes anything itself.
Chat already feeds it through `bin/fm-send.sh --resolve-key`, and a captured-answer source feeds it once bound with `bin/fm-captain-hold.sh bind <source-id>`; bind before arming the source, and key each structured question by the held task's id.
An unbound source and a key that names no captain-held task both simply feed nothing: the answer is still captured and firstmate is still woken, and closing falls back to the direct command above.
Expand Down
2 changes: 1 addition & 1 deletion .agents/skills/stow/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ A local skill exists only in this home, so offloading an entry out of `data/capt
Autonomously relocate it only by adding it to an already-existing allowed JIT note, or by routing it through a project's established delivery path to its existing owning `AGENTS.md`, then confirming that destination holds the quoted entry before removing the memory entry.
A destination that needs creation, uncompleted project delivery, or any other future work is not live and cannot count as relief, so continue with the next archival or eviction rung instead of leaving an over-budget proposal pending.
2. Propose pinned relocation only.
For a pinned candidate, append a `proposed-offload` section with the same fields to the completion receipt and create or refresh one durable captain-held backlog item using `tasks-axi add`, `tasks-axi hold`, `tasks-axi show <id> --full`, and `tasks-axi update <id> --body-file <path>` as appropriate.
For a pinned candidate, append a `proposed-offload` section with the same fields to the completion receipt, create or refresh one durable backlog item with `tasks-axi add`, `tasks-axi show <id> --full`, and `tasks-axi update <id> --body-file <path>` as appropriate, then hold it through `bin/fm-captain-hold.sh hold`.
Preserve each candidate's approval state in that item, and require explicit plain-chat approval for that named item before any migration.
If the captain never answers, nothing migrates and the held item persists, but it is never treated as budget relief.
3. Migrate an approved pinned candidate outside this pass.
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -377,16 +377,16 @@ jobs:
snapshot_output=$(/bin/bash tests/fm-fleet-snapshot-view.test.sh)
printf '%s\n' "$snapshot_output"
snapshot_count=$(printf '%s\n' "$snapshot_output" | grep -c '^ok - ')
[ "$snapshot_count" -eq 16 ] || {
echo "::error::expected 16 snapshot/fleet-view tests, got $snapshot_count"
[ "$snapshot_count" -eq 18 ] || {
echo "::error::expected 18 snapshot/fleet-view tests, got $snapshot_count"
exit 1
}

bearings_output=$(/bin/bash tests/fm-bearings-snapshot.test.sh)
printf '%s\n' "$bearings_output"
bearings_count=$(printf '%s\n' "$bearings_output" | grep -c '^ok - ')
[ "$bearings_count" -eq 49 ] || {
echo "::error::expected 49 Bearings tests, got $bearings_count"
[ "$bearings_count" -eq 53 ] || {
echo "::error::expected 53 Bearings tests, got $bearings_count"
exit 1
}

Expand Down
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -503,8 +503,8 @@ Mention cost as a courtesy when unusually much work is running, but never block
`data/backlog.md` is the durable queue.
It tracks work items only, never agents; persistent secondmates never appear as backlog items.
Work routed to a secondmate is recorded in that secondmate home's own backlog, not the main backlog.
A decision is simply a task held for the captain: `tasks-axi hold <id> --reason "<reason>" --kind captain`, with `--until <date>` when the captain defers it.
When a main-side thread such as a pending captain decision or relay reminder is worth durable tracking, file it as its own work item and hold it the same way.
A decision is simply a task held for the captain: create the task with `tasks-axi add` when needed, then always hold it through `bin/fm-captain-hold.sh hold <id> --reason "<reason>"`, with `--until <date>` when the captain defers it.
When a main-side thread such as a pending captain decision or relay reminder is worth durable tracking, file it as its own work item and hold it through that wrapper.
Captain calls discovered by investigations or visual reviews follow `captain-hold-lifecycle`, which owns their completion gate and recorded-answer rules.
When the automatic transition gate applies, dispatch and completion move the item themselves - `bin/fm-spawn.sh` and `bin/fm-teardown.sh` own those transitions and refuse rather than report success without them - so what remains yours is filing the item before dispatch, recording decisions, and keeping notes current; `docs/configuration.md` owns gate applicability and the manual-backend exception.
Re-evaluate queued work after every teardown and heartbeat, dispatching items only when dependencies and time gates have cleared.
Expand Down
6 changes: 3 additions & 3 deletions bin/fm-backlog-transition-lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -319,9 +319,9 @@ fm_backlog_done() { # <data-dir> <id> [flag...]
# Keep a captain-held row open across the removal of the work record that
# discovered it: record the finished work's deliverable as one line at the end
# of the task body (a line already present is left alone) and return the row to
# Queued, which is the shape every other captain call has and what
# bin/fm-fleet-snapshot.sh's captain_actionable requires. The hold itself is
# untouched; only bin/fm-captain-hold.sh answer closes the call. The links are
# Queued, the conventional post-cleanup shape for an open captain call.
# bin/fm-fleet-snapshot.sh classifies that retained hold from its structured
# fields; only bin/fm-captain-hold.sh answer closes the call. The links are
# written into the body rather than through `tasks-axi update --report`,
# because that flag rewrites the title of a row that is not Done.
fm_backlog_retain() { # <data-dir> <id> [flag...]
Expand Down
Loading
Loading