Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
a995ba0
docs(skills): add the standing upstream-sync skill and two-tier valid…
withally Aug 27, 2026
5241c03
docs(skills): fetch the sync base from the firstmate code root
withally Aug 27, 2026
4bcbcaa
no-mistakes(review): use fm-test-run --changed for weekly sync valida…
withally Aug 27, 2026
71167ea
no-mistakes(review): bind sync brief values and define upstream remote
withally Aug 27, 2026
a219022
no-mistakes(review): run Herdr family on lab-enabled weekly sync briefs
withally Aug 27, 2026
bc5a025
no-mistakes(review): map skill reference paths and verify upstream URL
withally Aug 27, 2026
6324792
no-mistakes(review): guard Herdr trigger check and enforce base drift…
withally Aug 27, 2026
a819463
no-mistakes(review): enforce snapshot window and fatal monthly Herdr …
withally Aug 27, 2026
750623a
no-mistakes(review): scope base drift to reachability, anchor upstrea…
withally Aug 27, 2026
f2141f0
no-mistakes(review): assert Herdr tool preconditions and tighten upst…
withally Aug 27, 2026
f9b4cd8
no-mistakes(review): verify snapshot marker on first-parent, drop tmu…
withally Aug 27, 2026
9511124
no-mistakes(review): compare snapshot marker to SNAPSHOT, gate lab he…
withally Aug 27, 2026
b8fa707
no-mistakes(review): rebind SNAPSHOT, widen upstream URLs, honor catc…
withally Aug 27, 2026
01821f1
no-mistakes(review): accept log-promoted SNAPSHOT in worker window guard
withally Aug 27, 2026
6108ce3
no-mistakes(review): use earliest reconciled commit as audit window s…
withally Aug 27, 2026
79a4b19
no-mistakes(review): exclude snapshot squashes and carry SETTLED in b…
withally Aug 27, 2026
465227a
no-mistakes(review): restore sync spine from origin/main, column SETTLED
withally Aug 27, 2026
1f95fdb
no-mistakes(review): scope spine restore to fork-local paths, commit …
withally Aug 27, 2026
94a0fdc
no-mistakes(review): name spine's upstream-owned companion edits in s…
withally Aug 27, 2026
d817d6a
no-mistakes(review): carry cumulative keep-list, commit targeted spin…
withally Aug 27, 2026
f7eae46
no-mistakes(review): define window end commit positionally, not by ad…
withally Aug 27, 2026
c2360bf
no-mistakes(review): pin window end, widen spine exemption, skip rebase
withally Aug 27, 2026
4af3e7c
no-mistakes(review): append catch-up row before shipping, verify wind…
withally Aug 27, 2026
8c37f3e
no-mistakes(review): require --intent, commit catch-up row before shi…
withally Aug 27, 2026
2cb8483
no-mistakes(review): stage before commit, tier in intent, cover skill…
withally Aug 27, 2026
62d4de7
no-mistakes(review): reconcile spine exemption, read catch-up log fro…
withally Aug 27, 2026
a16139d
no-mistakes(review): restore spine-only exemption, verify sync merge …
withally Aug 27, 2026
b146f85
no-mistakes(review): anchor marker search on subject, fix gh merge-co…
withally Aug 27, 2026
b61a750
no-mistakes(review): record landed m2 cutover, name five brief values
withally Aug 27, 2026
c6344b4
no-mistakes(document): fix upstream-sync step 13 continuation indent
withally Aug 27, 2026
4f90bb8
no-mistakes(document): correct Herdr lab helper suite count
withally Aug 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
296 changes: 296 additions & 0 deletions .agents/skills/upstream-sync/SKILL.md

Large diffs are not rendered by default.

78 changes: 78 additions & 0 deletions .agents/skills/upstream-sync/references/herdr-lab.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Herdr lab setup for upstream sync

This is the one place the sync worker learns how the isolated Herdr lab works, so nobody re-discovers it mid-sync.
`bin/fm-herdr-lab.sh` and its `--help` own the exact commands and refusals; `docs/herdr-backend.md` "Destructive lab safety" owns the safety rationale.

## When the lab is required

- Every `monthly` tier, because `bin/fm-test-run.sh --all --fail-on-gate-skip 'herdr not found'` includes the `real-herdr-gated` family and refuses to skip it.
- A `weekly` tier whose kept diff selects the `real-herdr-gated` family, which `bin/fm-test-run.sh`'s changed-file-to-test map decides, not a hand-written path list.
The skill's step 10 owns that check and the status guards it needs; a bare `comm` over two process substitutions reports a clean verdict when either listing fails, so do not re-derive it here.
- Never otherwise; a weekly sync that does not touch Herdr runs `--exclude-family real-herdr-gated` and needs no lab.

## What the brief must carry

The brief must be scaffolded with `bin/fm-brief.sh ... --herdr-lab` whenever the lab is required.
That flag emits the hard isolation contract naming `HERDR_LAB_HELPER` and the session name; a brief without it carries a loud `NOT ENABLED` declaration, and a worker must never add lab commands to such a brief by hand.
If the need appears only after dispatch, the worker stops with a `blocked:` line and Firstmate regenerates the brief; on the regenerated brief the worker runs the family from the skill's step 10 rather than blocking again.

## Preconditions

- `herdr`, `jq`, `treehouse`, and `python3` on `PATH`, because each one guards a whole suite at its head with `exit 0` and a missing binary is a skip, not a failure.
`tmux` is not on this list: its only checks are per-case `return 0` skips inside `tests/fm-afk-launch.test.sh`, so its absence never turns a suite green by skipping it.
- `$HERDR_LAB_HELPER` executable, defaulting to `bin/fm-herdr-lab.sh`, because `tests/fm-backend-herdr-presentation-e2e.test.sh` and `tests/fm-herdr-session-cleanup-e2e.test.sh` in the family head-gate on `[ -x "$HERDR_LAB_HELPER" ]` and skip the whole suite otherwise.
A monthly `--all` run adds a third such suite, `tests/fm-backend-herdr-focus-flash-e2e.test.sh`, which the family listing does not carry because it is unclassified.
A stale exported value pointing at a deleted tree, or a checkout copied without the executable bit, is the way this bites.
`--fail-on-gate-skip` accepts one token only, so assert these with `command -v` before the run rather than relying on it.
- Exactly one running `default` Herdr session, because the helper snapshots it as the fleet-state tripwire before provisioning and requires it byte-identical after teardown.
Check with `herdr session list --json | jq '.sessions[] | select(.default == true)'`.
- The worker is not inheriting a pane identity from a Herdr-hosted terminal that should place work elsewhere; `tests/herdr-test-safety.sh`'s `herdr_forget_inherited_pane` shows which variables the suites drop.

## The helper

`HERDR_LAB_HELPER` is the absolute path to `bin/fm-herdr-lab.sh`; the `--herdr-lab` brief section sets it.
Session names must begin with `fm-lab-` and can never be `default`; the helper refuses anything else.

| Action | Command | What it does |
| --- | --- | --- |
| name | `S=$("$HERDR_LAB_HELPER" name <label>)` | Sanitizes the label, caps it at 16 characters, and appends process and random suffixes so socket paths stay short. |
| prepare | `"$HERDR_LAB_HELPER" prepare "$S"` | Records the running default session as the tripwire without starting a server; provision calls it for you. |
| provision | `"$HERDR_LAB_HELPER" provision "$S"` | Records the tripwire, starts a named server, and waits up to 60 seconds for it to report running. |
| run | `"$HERDR_LAB_HELPER" run "$S" <herdr args...>` | Runs one task-level Herdr command with a trailing `--session "$S"`; refuses caller-supplied `--session`, leading options, and every server or session lifecycle subcommand. |
| stop | `"$HERDR_LAB_HELPER" stop "$S"` | Guarded mid-run session stop; re-checks refuse-default immediately before stopping. |
| teardown | `"$HERDR_LAB_HELPER" teardown "$S"` | Guarded stop and delete, then verifies the default session is byte-identical to the tripwire and removes the record. |

Install `trap '"$HERDR_LAB_HELPER" teardown "$S"' EXIT` before provisioning so an aborted run still cleans up.

## The tripwire

Provision writes `${FM_HERDR_LAB_STATE_DIR:-${TMPDIR:-/tmp}/fm-herdr-lab-<uid>}/<session>.fleet-state.json` holding `{name, default, running, socket_path}` of the one running default session.
Teardown and re-provision compare a fresh snapshot against it and refuse on any difference, printing `FLEET-STATE TRIPWIRE FAILED`.
A missing, stopped, or changed default session is a hard failure, never a warning to ignore: stop and report it.

## Running the Herdr test family

The `real-herdr-gated` suites provision their own `fm-lab-*` sessions through the helper; the worker does not provision one for them.

```sh
bin/fm-test-run.sh --family real-herdr-gated --fail-on-gate-skip 'herdr not found'
```

`--fail-on-gate-skip` turns a missing `herdr` binary into a failure instead of a silent skip, matching the required CI lane.

## Manual proof and teardown

Use this when a kept commit needs a hand check against a live Herdr, or to confirm the lab works before a monthly run.

```sh
HERDR_LAB_HELPER=$PWD/bin/fm-herdr-lab.sh
S=$("$HERDR_LAB_HELPER" name <task-id>)
trap '"$HERDR_LAB_HELPER" teardown "$S"' EXIT
"$HERDR_LAB_HELPER" provision "$S"
"$HERDR_LAB_HELPER" run "$S" status --json | jq '.server.running' # true
"$HERDR_LAB_HELPER" teardown "$S"; trap - EXIT
herdr session list --json | jq -r '[.sessions[].name] | join(",")' # the lab name is gone
```

Forbidden at all times: direct `herdr server stop`, `herdr session stop`, `herdr session delete`, any server-global operation, and any Herdr call scoped only by ambient or inline `HERDR_SESSION`.
Other `fm-lab-*` sessions in the list belong to other live workers or suites; never stop or delete one you did not create.
44 changes: 44 additions & 0 deletions .agents/skills/upstream-sync/references/worker-brief.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Worker brief template

Firstmate scaffolds with `bin/fm-brief.sh <task-id> firstmate --mode no-mistakes`, adding `--herdr-lab` when the tier is `monthly` or the sync is already known to touch Herdr backend or lab code, and replaces `{TASK}` with the block below.
Fill exactly five values; every other line is fixed text.

| Placeholder | Value |
| --- | --- |
| `UPSTREAM_BASE` | `git rev-parse --short=12 upstream/main` at intake |
| `SNAPSHOT` | short hash of the latest `chore: snapshot upstream main` first-parent commit on `origin/main`, or the window end commit when a catch-up log row names an older one; take it from the skill's intake command block, not by hand |
| `SETTLED` | window end commit from the newest catch-up log row, empty when no row names one; the worker cannot re-derive it after branching at `upstream/main` |
| `TIER` | `weekly` or `monthly`, from the skill's tier rule |
| `DATE` | the sync date, `YYYY-MM-DD` |

```markdown
## Task: {TIER} upstream sync of withally/firstmate onto kunchenguid/firstmate

This is SHARED TRACKED firstmate material: load `firstmate-coding-guidelines` before editing anything.
Then load `upstream-sync` and follow its "Worker checklist" step by step; it owns every command.
`docs/upstream-sync.md` owns the rules those commands implement.

Recorded values:

- UPSTREAM_BASE: `{UPSTREAM_BASE}`
- SNAPSHOT: `{SNAPSHOT}`
- SETTLED: `{SETTLED}`
- TIER: `{TIER}`
- DATE: `{DATE}`

Fixed rules:

- Bind UPSTREAM_BASE, SNAPSHOT, and SETTLED as shell variables from the recorded values above before running any checklist command, and stop if UPSTREAM_BASE or SNAPSHOT is empty.
- Branch at UPSTREAM_BASE; never merge origin/main into it.
- Audit only the first-parent commits in SNAPSHOT..WINDOW_END, where the skill's step 4 pins WINDOW_END from `origin/main` at listing time; never re-read `origin/main` for it later.
- Decide every keep by the doc's keep rule yourself; no mid-flight approval.
- Cherry-pick kept PRs with `-x`; upstream wins every conflict.
- Run only the TIER's validation from the skill; CI's portable shards and its required Herdr lane on the PR are the weekly full gate.
- Append the catch-up log row before shipping, recording that pinned WINDOW_END as the row's `Window end commit`, and commit it with `git add docs/upstream-sync.md && git commit -m 'docs: record the {DATE} catch-up'`, advancing the `Next monthly full run` line on a monthly tier; a row that is uncommitted or added after the PR is open is never validated and never reaches `origin/main`.
- Ship the PR with `no-mistakes axi run --skip rebase --intent "{TIER} upstream sync of withally/firstmate onto kunchenguid/firstmate at {UPSTREAM_BASE}"`; `--intent` is required to start a run, and a cutover branch is cut from `upstream/main`, so rebasing it onto the fork's `origin/main` would replay the divergent fork history back onto the new base and undo the adoption.
- Unrelated breakage is a `Follow-ups` entry in the PR, never a fix on this branch.
- If the kept diff selects the `real-herdr-gated` family per the skill's `comm -12` check against `bin/fm-test-run.sh --list`, and this brief was not scaffolded with `--herdr-lab`, stop with `blocked: sync touches Herdr, brief needs --herdr-lab` and wait.
- If that check selects the family and this brief does carry the lab contract, run the family locally per the skill's step 10; do not block a second time.
- PR title: `chore: snapshot upstream main for {DATE}`; PR body carries the verdict table, `Tier: {TIER}`, the validation commands run, and `Follow-ups`.
- Never push to `upstream`; never merge.
```
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,7 @@ These skills are not captain-invocable; load them only at their precise triggers
- `fmx-respond` - load on an `x-mention <request_id>` `check:` wake to handle the mention, on an `x-mode-error ...` `check:` wake to report the Relay configuration blocker, on a `public-followup ...` `check:` wake or a startup-surfaced public commitment, and on any milestone or terminal wake for a Relay-linked task before posting its completion follow-up; relevant only when Relay is on.
- `firstmate-codexapp` - load before coordinating a visible Codex Desktop thread, evaluating a Codex App backend request, or reconciling Codex Desktop host-tool smoke evidence for Firstmate work.
- `firstmate-coding-guidelines` - load before changing firstmate's shared, tracked material, as defined by section 1's list, whether editing directly or briefing a crewmate for a firstmate-repo task.
- `upstream-sync` - load when the captain asks to sync, catch up, or snapshot onto upstream, or when the weekly upstream sync is due; it owns the tier decision, the fixed worker brief, and the Herdr lab setup, over the procedure in `docs/upstream-sync.md`.

## 14. Relay

Expand Down
4 changes: 4 additions & 0 deletions bin/fm-test-run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1044,6 +1044,10 @@ families_for_changed_path() {
.agents/skills/*/SKILL.md)
printf '%s\n' pure-contract-unit
;;
.agents/skills/*)
families_for_test_reference "$path" \
|| printf '%s\n' pure-contract-unit
;;
.github/workflows/ci.yml|.no-mistakes.yaml)
printf '%s\n' pure-contract-unit
printf '%s\n' real-herdr-gated
Expand Down
12 changes: 12 additions & 0 deletions docs/documentation-audiences.json
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,18 @@
"path": ".agents/skills/stuck-crewmate-recovery/SKILL.md",
"audience": "agent-runtime"
},
{
"path": ".agents/skills/upstream-sync/SKILL.md",
"audience": "agent-runtime"
},
{
"path": ".agents/skills/upstream-sync/references/herdr-lab.md",
"audience": "agent-runtime"
},
{
"path": ".agents/skills/upstream-sync/references/worker-brief.md",
"audience": "agent-runtime"
},
{
"path": ".agents/skills/updatefirstmate/SKILL.md",
"audience": "agent-runtime"
Expand Down
Loading
Loading