2-setup-claim. Advisory claim at setup (relay-managed repos only, <root>/ROADMAP.md exists). For relay-managed repos, /meeting acquires ONE advisory repo claim at SETUP — early in setup, immediately after root resolution and metadata capture — so the relay pool (which already honors claims via claim.sh peek) skips the repo for the meeting's duration:
2b. Git hygiene check (run after metadata, before loading anything else):
-
Load format spec: read ~/.claude/skills/meeting/format.md. If <root>/docs/meeting-notes/meeting-style.md exists, append its contents to your working context under "## Project-specific overrides". Honour any natural-language overrides (e.g. "exclude Riku", "include Sage as standing", "meetings here are casual") — no structured parsing, just follow them.
-
Load persona registry: read ~/.claude/skills/meeting/personas.md. If the meeting calls for any persona by name, onboard them with their established lens from the registry — no re-introduction needed.
-
Surface relevant discoveries: if EMBED_ENDPOINT is set and a meeting subject was provided (i.e., /meeting <subject>), run:
~/.claude/skills/meeting/retrieve-top-k.py \
--file ~/.claude/skills/meeting/discoveries.md \
--query "<subject>" \
--chunk-sep "^- \[" \
--k 15
Use the stdout as the discoveries context. If the script exits non-zero, EMBED_ENDPOINT is unset, or this is a no-arg invocation, fall back to reading ~/.claude/skills/meeting/discoveries.md (full). At the start of the meeting, mention entries that intersect the meeting topic.
GitHub prior art (subject mode only): also run:
~/.claude/skills/meeting/gh-audit.sh search "<subject>"
If stdout is non-empty, surface any matching issues/PRs alongside the discoveries block labeled GitHub prior art — issues/PRs matching this topic. Exit 0 with no stdout means no GitHub remote or no matches — skip silently. Do not label as ADVISORY; GitHub search results are factual, not scan candidates.
-
Load user profile: run ~/.claude/skills/meeting/profile-active.sh --filter via Bash (filter mode — emits only pre-emption-eligible med/high-confidence entries + file header; flip gate cleared 2026-06-05: ratio consistently 0.26–0.34 ≪ 0.60, setup-ctx ~30% of meeting cache_read tokens; ratio still logged to ~/.claude/logs/meeting-profile-active.log each run for observability). Treat the script's stdout as the profile content for this session. Personas may apply pre-emption per the rule defined in format.md (eligible + med+ confidence + contradiction; Riku ≫ others).
-
Broker mode (recommended — launch via ~/src/meeting-rpg/meeting-rpg <topic> to activate): Probe echo "$MEETING_LIVE" (plain expansion — never ${MEETING_LIVE:-...}). If non-empty, or if a broker may be running (probe echo "$MEETING_BROKER_PORT"), read ~/.claude/skills/meeting/broker-mode.md and follow it for the rest of step 7, per-item discussion routing, and decision points. If $MEETING_LIVE is empty and no broker is probed live, skip broker-mode.md entirely — the meeting proceeds as canonical. Savings confirmed 2026-06-05: ≥5k tok/meeting across 3 pilots (discussion suppressed from chat → no context inflation; auto-detects renderer via $MEETING_BROKER_PORT).
7b. Inbox surface: grep the shared inbox — $RELAY_INBOX if set, else ~/.claude/projects/todo-inbox.md (the store lives in the git-tracked private ~/.claude/projects repo for free history/recovery, id:9fdb; the legacy ~/.claude/todo-inbox.md is migrated there automatically on first use) — for unchecked lines - [ ] tagged with [<basename of <root>>] (skip silently if the file does not exist). If any match, display them as visible text before the agenda:
📥 Inbox — items routed to this repo:
- [ ] [<repo>] <description> (from <source>, <note-relpath>) <!-- routed:XXXX -->
These are read-only; do not auto-write them into <root>/TODO.md. To adopt: add the item to <root>/TODO.md keeping its <!-- routed:XXXX --> breadcrumb (mint a fresh <!-- id:YYYY --> too if you want a local ledger id), then run ~/.claude/skills/meeting/append.sh inbox-done <routed-token>. As of id:9fdb, inbox-done REFUSES (exit 3) unless the target repo's TODO.md/ROADMAP.md already carries the routed:XXXX twin — so preserve that breadcrumb, or let relay/scripts/scan-routed.sh --apply do the write-then-resolve automatically.
Lint the inbox, not just grep it (id:de36 — a grep-only surface missed the acc7
defect, a well-formed-looking <!-- routed:$ID --> line where $ID was a literal,
unexpanded shell variable): also run relay/scripts/todo-conformance.sh --inbox <the same resolved inbox path> (the detector already used by scan-routed.sh — invoke
it, never reimplement its conforming-form regex). If it emits any findings, display them
as visible text, in a heading distinct from the routed-item list above:
⚠ Inbox — non-conforming entries (todo-conformance.sh --inbox)
<class>\t<lineno>\t<text> (one per finding, verbatim from the script's stdout)
Surface-only, matching this step's existing read-only contract: display and move on —
never edit the inbox, never halt or gate the rest of the meeting on a finding. If the
lint emits nothing (clean inbox, or the inbox file does not exist), skip this block
silently.
-
Warrantability self-check (see format spec). If the request looks like a bug fix, one-liner, or already-decided feature, respond "are you sure you want a meeting?" and briefly explain why it might be overkill — before running the agenda. If it clearly passes, note that and proceed.
-
Past-meetings audit: run ~/.claude/skills/meeting/orphan-scan.sh. Uses exact <!-- id:XXXX --> match; FP is ~0 by construction (un-IDed legacy lines skipped). Display any candidates as orphan candidates requiring resolution before opening the agenda. Also run ~/.claude/skills/meeting/orphan-scan.sh --reverse and display any results labeled ADVISORY — reverse-orphan candidates (done/inline items never mirrored to TODO; possible ledger gap). (Observation window closed 2026-06-11: 0 spurious FPs in 34 runs; forward scan is authoritative; reverse stays ADVISORY — expected to return in-session completions.) If <root>/ROADMAP.md exists (relay-managed repo), also run ~/.claude/skills/meeting/orphan-scan.sh --cross-ledger and display any results labeled ADVISORY — cross-ledger drift (id in both TODO and ROADMAP with disagreeing checkbox state; single-id-two-views D2). Skip silently in non-relay repos (no ROADMAP.md).
Also run ~/.claude/skills/meeting/gh-audit.sh open and display any output labeled ADVISORY — open GitHub issues/PRs (supplementary orphan context). Exit 0 with no stdout means no GitHub remote or no open items — skip silently.
-
Call EnterPlanMode. Accumulate the transcript in the plan file the system creates.
-
Run the interactive meeting: open with attendees line + topic. For each persona marked "(new)" in the attendees line, emit a one-sentence introduction naming their lens in the opening exchange before the agenda. Then follow the format spec (agenda → named discussion → decision points → decisions → action items) using the harness-class protocol from format.md §Interactive mode — AskUserQuestion on Sonnet/Opus/Haiku, inline-prose on Fable-class.
-
Present the transcript at every decision point per the harness-class protocol in format.md §Interactive mode. The plan file is not shown in the chat UI; the user must see the discussion before the options appear. On Sonnet/Opus/Haiku: output the complete, verbatim discussion text for the most recent agenda item as visible chat content, then immediately call AskUserQuestion in the same response — both in the same message, never end on bare prose. On Fable-class: emit the transcript as the turn's FINAL text with numbered options inline; no AskUserQuestion.
-
Proceed to end-of-meeting steps.
-
Read <root>/TODO.md. Run ~/.claude/skills/meeting/orphan-scan.sh: display any candidates before the classifier output as orphan scan candidates requiring resolution (authoritative; exact-ID match, un-IDed legacy skipped). Also run ~/.claude/skills/meeting/orphan-scan.sh --reverse and display any results labeled ADVISORY — reverse-orphan candidates (done/inline items never mirrored to TODO; possible ledger gap). If <root>/ROADMAP.md exists (relay-managed repo), also run ~/.claude/skills/meeting/orphan-scan.sh --cross-ledger and display any results labeled ADVISORY — cross-ledger drift (id in both TODO and ROADMAP with disagreeing checkbox state; single-id-two-views D2). Skip silently in non-relay repos (no ROADMAP.md).
Also run ~/.claude/skills/meeting/gh-audit.sh open and display any output labeled ADVISORY — open GitHub issues/PRs (supplementary orphan context). Exit 0 with no stdout means no GitHub remote or no open items — skip silently.
REVIEW_ME surface (D5 — relay-managed repos only): if <root>/REVIEW_ME.md exists, count its open boxes (grep -c '^- \[ \] ' <root>/REVIEW_ME.md). If ≥1, add a synthetic Class 3 candidate to the classifier buckets: discuss REVIEW_ME backlog of <root-basename> (N open judgment box(es)). These boxes are judgment calls by design (@manual BDD scenarios, "is this green test a frozen bug?" questions) — a persona-scrutinized session is the right venue for the chewy ones. Surface-only: never auto-dispatch; the user picks it like any other candidate. Skip silently when no REVIEW_ME.md or zero open boxes.
Scope discipline: <root>/TODO.md is the sole authority for this invocation. Do not read or write any other TODO.md — not the parent repo's, not a sibling worktree's, not one textually referenced from within this file (e.g. > Subset of ../../TODO.md). An empty ## Current section, or one where all items are checked, is a valid terminal state — report "no open work at <root>" and stop; do not look elsewhere for "real" work. If <root>/TODO.md does not exist, report missing and ask the user — do not auto-create.
Then run:
~/.claude/skills/meeting/find-todos.sh
If any paths are returned, print a warning before the classifier output: WARNING: subdirectory TODO.md files found — consider merging into <root>/TODO.md: <paths>. Classification proceeds against root TODO.md only; subdir items are not classified.
-
Pre-classify with classify.sh — run:
~/.claude/skills/meeting/classify.sh <root>
The script outputs TSV lines (CLASS, ID, SUMMARY, NOTE-LINK) for each unchecked item. Use this as the starting classification, then apply model judgment:
- Class 1 — impl-ready: C1 from classify.sh (link + Decisions section present). Confirm the design actually covers this item.
- Class 2 — planning-worthy: C2 from classify.sh (link without Decisions, or keyword hint). Also reclassify C1 items whose linked design is incomplete.
- Class 3 — meeting-worthy: C3 from classify.sh (no link, ambiguous scope). Use model judgement when neither rule fires cleanly.
- Skip: items that are purely date-triggered (activation date in text); items explicitly deferred/reopen-gated with unmet conditions;
RELAY lines (the ROADMAP.md mirror — executor work, never meeting-worthy); POOL lines ([HARD — pool] — relay-executor work; nudge /relay instead) and HANDS lines ([HARD — hands] — human-manual work). POOL/HANDS are NOT meeting candidates — surface them under a separate "not meeting-worthy" note, never in the C1/C2/C3 buckets (this is the fix for the /meeting over-claim where a settled, pool-executable [HARD — pool] item was recommended for a redundant design meeting, 2026-07-14).
-
Print the classified bucket summary as visible text (group by class, show each item one-liner). If an item has GATED in the 5th TSV field, append [GATED] to its one-liner so the gate condition is visually obvious; if it has HARD-NOLANE, append [HARD — needs a lane] (id:78ff — the item is [HARD] with no — pool|meeting|hands lane and must be lane-tagged before it can be routed). Print POOL/HANDS items under a separate "↪ not meeting-worthy (executor / human-manual)" note, NOT in the pick-eligible buckets. Pick head -1 of the highest-class non-empty meeting bucket (priority: 1 > 2 > 3); POOL/HANDS/RELAY are never picked. Show one-line rationale.
Relay-ready nudge (D4 — relay-managed repos only): if <root>/ROADMAP.md exists AND has at least one open (- [ ]) [ROUTINE] item (grep -qE '^- \[ \].*\[ROUTINE\]' <root>/ROADMAP.md), print ONE surface-only line above the bucket summary: ↪ <root> has N open [ROUTINE] item(s) — run \/relay review ` to verify executor work and re-dispatch.Name the repo explicitly (bare/relay reviewdefaults to--all). This is a **surface-only nudge** — never invoke /relayinline (on/opusplan the post-ExitPlanModetier is Sonnet, the executor tier, so strong-model relay work must run in its own strong session). Skip silently when no ROADMAP.md (non-relay repo) or no open[ROUTINE]items. *(Deferred under id:5ab4's friction gate: inline dispatch, Fable-vs-Sonnet auto-detection, window-check fold-in, strong-Agent-spawn.)* Note:classify.shroutes[HARD]items **by lane** —[HARD — meeting]→ C3 (design work, never C1/C2), while[HARD — pool]→POOLand[HARD — hands]→HANDSare skipped from the meeting buckets entirely (executor / human-manual). A bare[HARD]with no lane classifies C3 but is flaggedHARD-NOLANE` (id:78ff loud reject).
-
Ask via AskUserQuestion: [do this / pick something else] — no "not yet" option.
-
Dispatch by class:
- Class 1 → proceed to implementation in normal mode (no plan mode, no meeting). (D7 — relay-managed repos,
<root>/ROADMAP.md exists): the inline implementation follows the /relay executor contract — "C1s work as if picked by /relay executor". Concretely (contract rules 2–4): definition of done = the item's previously-failing tests pass + a refactor pass + the FULL suite (make test or equivalent) is green; never weaken, skip, delete, or rewrite a test to make it pass; append a one-paragraph self-report to <root>/RELAY_LOG.md and commit it. On /opusplan the post-ExitPlanMode tier IS Sonnet (the executor tier), so treat C1 work exactly as a /relay executor session would. (Unlike a relay child, a direct /meeting session still pushes + runs git-diary-workflow at end — the fable-ckpt-* tag remains the next /relay review's job, not this session's.) In non-relay repos (no ROADMAP.md), proceed in normal mode as before.
- Class 2 → call
EnterPlanMode; use Claude Code's native explore → design → present → ExitPlanMode workflow. No persona scaffolding. After ExitPlanMode and implementation: write a Class 2 planning record to <root>/docs/meeting-notes/YYYY-MM-DD-HHMM-<slug>.md using the Class 2 template defined in format.md (distinct from Class 3: **Mode:** field, no ## Discussion, uses ## Context / ## Plan / ## Implementation findings / ## Decisions / ## Action items). Content synthesises the plan file; plan file is left to Claude Code's auto-cleanup. No allowlist changes needed (Read+Write paths already covered).
- Class 3 → proceed as if
/meeting <candidate> was invoked (full meeting flow).
- REVIEW_ME backlog candidate (D5): if the chosen Class 3 candidate is the
discuss REVIEW_ME backlog of <repo> entry, the meeting is grounded in the boxes, not an open-ended topic. Read <root>/REVIEW_ME.md; take each open (- [ ]) box as one agenda item (the box text states the ambiguity and the interpretation the test currently encodes). Run the normal persona flow, but the decision at each box is narrow: confirm the encoded interpretation (tick the box) or correct it (edit the linked test / leave a note under the box, leave it unticked for the next /relay review to re-derive). Pull the linked test (roadmap:XXXX / test::name) into context so the discussion is concrete. Batch trivially-confirmable boxes; spend persona scrutiny on the chewy ones. The end-of-meeting step 2e write-back applies the tick/correction to REVIEW_ME.md and keeps any shared id: consistent across TODO.md/ROADMAP.md. If there are more open boxes than fit one focused session, resolve the highest-leverage subset and say so — the rest stay open for a follow-up.
On "pick something else": re-ask with the next candidate.