Merge pull request 'docs: PM-mode discipline + multi-agent relay coordination protocol' (#5) from docs/pm-discipline into main
Some checks failed
CI / fmt (push) Successful in 1m14s
CI / clippy (push) Successful in 1m55s
CI / test (1.85) (push) Successful in 4m24s
CI / deny (push) Has been cancelled
CI / test (stable) (push) Has been cancelled

Reviewed-on: #5
This commit was merged in pull request #5.
This commit is contained in:
2026-07-04 15:23:34 +00:00
3 changed files with 513 additions and 3 deletions

304
AGENTS.md
View File

@@ -219,10 +219,28 @@ and "why isn't X here?" questions. Consult it before adding anything.
- **Trunk-based development** (target, once branch protection is in place):
1. Branch from `main` for any change.
2. Open a PR targeting `main`.
3. CI gates: `cargo fmt --check`, `cargo clippy -- -D warnings`, `cargo test --all`,
2. Push the branch to origin (`git push -u origin <branch>`).
3. Open a PR targeting `main` via **`tea`** (Gitea CLI, not `gh`):
```bash
tea pulls create \
--head <branch> \
--base main \
--title "<imperative subject ≤72 chars>" \
--description "<body — what, why, merge instructions, reviews>"
```
The `tea` login is `alee` (default), against `https://git.adlee.work`. Verify with
`tea login list` if auth fails. `tea pulls list` shows open PRs; `tea pulls merge <index>`
merges from CLI (honors the merge strategy passed via `--style`).
4. CI gates: `cargo fmt --check`, `cargo clippy -- -D warnings`, `cargo test --all`,
`cargo deny check`. All must pass before merge.
4. Squash-merge to keep `main` linear.
5. **Merge strategy — default squash, carve-out for stacked branches:**
- **Default:** squash-merge to keep `main` linear. One commit per PR, clean history.
- **Rebase-merge carve-out:** when a PR's commit SHAs are carried by downstream branches
(the "stacked branches" topology — pivot/strategic-doc PRs that depend on each other),
use **rebase-merge** instead. This preserves the original commit SHAs so downstream
branches see the pivot as "already in main" with zero rebase pain. Squash would orphan
the originals and force conflict-prone rebases across every dependent branch. State
"merge via rebase-merge, not squash" explicitly in the PR description when this applies.
- **Never push directly to `main`.** Branch protection (planned) will enforce; until then,
self-discipline.
- **Commit messages:** imperative mood, subject ≤ 72 chars, body wraps at 72, blank line
@@ -232,6 +250,286 @@ and "why isn't X here?" questions. Consult it before adding anything.
each land as separate commits when practical. Don't bundle unrelated work.
- **Never commit secrets.** The `.gitignore` already covers `.env*`, `*.pem`, `*.key`. If
a new secret pattern appears, extend `.gitignore` in the same commit.
- **Developer Certificate of Origin (DCO) — REQUIRED on every commit.** Every commit
MUST be signed off (`git commit -s` or `git commit --signoff`) to attest the author
has the right to contribute the code under the project's license (GPL-3.0-or-later,
ADR-0004). This preserves the copyright-holder's option to dual-license later —
without a DCO/CLA instrument, every external contribution erodes that option. See
[`DCO.md`](DCO.md) for the full text. The signoff line (`Signed-off-by: Name <email>`)
is the canonical attestation; CI (planned) will reject unsigned commits. Agents
committing on behalf of a human MUST sign off with the human's name + email, not
their own identity.
- **PR description template** (for non-trivial PRs):
```
## What lands
- <bullet per logical change>
## Merge instructions (if non-default)
- <e.g. "rebase-merge, not squash — see AGENTS.md Git workflow">
## Reviews (if applicable)
- <companion review docs / ADRs / specs>
```
---
## Multi-agent coordination — the relay (cross-model)
When more than one agent session works this repo in parallel (the PM / senior-dev "lift"
paradigm), they coordinate through a small MCP message-bus — the **relay** at
[`~/Sources/relay`](file:///home/alee/Sources/relay). One server, many terminals: each
session posts and drains messages **by role** instead of the user copy-pasting blocks
between windows.
**The relay is model-agnostic.** Nothing about it is Claude-specific — it speaks plain
MCP / JSON-RPC over HTTP. A **GLM-backed agent and a Claude agent share the same bus** and
exchange messages transparently, as long as both point at the same running relay and use
the same role/kind vocabulary below.
- **Currently running on `localhost:7110`.** The port is set by `RELAY_PORT` (default
`7331` if unset). The server binds `127.0.0.1`, so **all agents must be on this host**
(a GLM agent in a separate container/VM can't reach it over localhost).
- **Roles are slots, not models.** The relay knows `pm, dev-a, dev-b, dev-c, dev-d,
dev-e, dev-f` — that's it. A GLM agent claims a free role (say `dev-c`) exactly like a
Claude agent claims `dev-a`; the relay neither knows nor cares which model drives a role.
- **Start the relay before opening sessions** if you want MCP auto-registration. The shell
shim (below) works at any time.
### Port assignments (per project)
Each project gets its own relay port so multiple coordinated lifts can run side by side
without colliding. Set `RELAY_PORT` to the project's port when launching the relay and in
every agent/shim that talks to it.
| Port | Project | Notes |
|---|---|---|
| `7110` | [`~/Sources/rutster`](file:///home/alee/Sources/rutster) | **this repo** |
| `7331` | [`~/Sources/relicario`](file:///home/alee/Sources/relicario) | also the relay's built-in default |
Adding a project? Pick an unused port, launch with
`~/Sources/relay/start.sh --repo <path> --port <n>`, and add the row here.
### Two ways for an agent to connect
**1. MCP-native** — for any harness that speaks MCP over SSE (this includes Claude Code
pointed at a GLM model). Register the relay as an SSE server, then call `post_message` /
`read_messages` / `list_pending` as native tools. Config shape:
```jsonc
// .mcp.json (or your harness's MCP config)
{ "mcpServers": { "relay": { "type": "sse", "url": "http://localhost:7110/sse" } } }
```
For Claude Code specifically: `claude mcp add --transport sse relay http://localhost:7110/sse`.
**2. Shell shim** — for any agent that can run a shell command (model- and harness-agnostic;
the fallback when MCP isn't registered). The shims read `RELAY_PORT`, so export it once:
```bash
export RELAY_PORT=7110 # match the running relay
python3 ~/Sources/relay/call.py list_pending '{"for":"dev-c"}'
python3 ~/Sources/relay/call.py read_messages '{"for":"dev-c"}' # drains the inbox
python3 ~/Sources/relay/call.py post_message \
'{"from":"dev-c","to":"pm","kind":"status","body":"Slice-1 media codec boundary DONE. Tests green."}'
# call.ts is the TypeScript equivalent: npx tsx ~/Sources/relay/call.ts <tool> '<json>'
```
### The three tools
| Tool | Args | Behavior |
|---|---|---|
| `post_message` | `from`, `to`, `kind`, `body` | Push to a role's inbox; returns `{"id": "<uuid>"}` |
| `read_messages` | `for` | **Drains** the inbox (consume-once), oldest first |
| `list_pending` | `for` | Count + kinds **without** consuming |
`kind` is one of `status` (a dev's STATUS UPDATE / PM rollup), `directive` (PM → dev:
PROCEED / HOLD / RESCOPE), `question` (dev → PM), or `free` (anything else). Keep `body`
single-line (periods between sentences, ` -- ` for stronger breaks) — some inbox monitors
use strict JSON parsers that choke on embedded newlines.
A GLM `dev-c` posting a `status` and a Claude `pm` reading it is the same roundtrip in both
directions — the bus is symmetric. See [`~/Sources/relay/README.md`](file:///home/alee/Sources/relay/README.md)
for roles, ports, and the `pm` convenience wrapper.
### Multi-dev parallelism — dispatching work without serial bottlenecks
When the PM dispatches a slice across N devs, the goal is **N devs actively
working, not N-1 blocked on one.** File-level non-overlap (no merge conflicts)
is necessary but NOT sufficient — task dependencies, not file ownership, are
what stall a dev. Apply this checklist to every multi-dev dispatch:
1. **Identify the critical-path foundation first.** Anything consumed by other
tasks (a new trait + impl others extend, an mpsc channel others wire into,
a mock others depend on) belongs to ONE dev's "foundation" sub-task that
lands FIRST. Don't parallelize across a dependency; parallelize the tail
AFTER the foundation lands.
2. **Pre-list "parallelizable-now" work explicitly, per slice, up front.**
Before dispatching, scan the spec's test section (often §7.4) and §8
done-criteria for: unit tests against already-existing types, golden JSON
fixtures, harness scaffolding, docs, `examples/`, LEARNING.md pointers,
README e2e plans, behavior-preserving refactors. These are the "filler" a
blocked dev picks up instead of stalling. List them in the dispatch so a
blocked dev knows the fallback without asking.
3. **Sequence so the blocking path is the shortest one.** If dev-a's
foundation takes 30 min and dev-b's dependent work takes 20 min, the
parallelizable tail needs to be >50 min of work or you'll have idle devs.
Either bundle more into the foundation (so less depends on it) or split
the dependent work across more devs.
4. **State dependencies explicitly in each directive.** Every directive
names: (a) files the dev owns, (b) files that are off-limits (seam-test
invariants), (c) blockers — which dev's status unblocks this dev, and
what to do in the meantime (the "filler" from rule 2).
5. **The seam test is sacred.** When a slice has a "these files stay
byte-identical to baseline" gate (e.g. slice-2/3's
`loop_driver.rs` + `rtc_session.rs`), tell EVERY dev not to touch them.
Don't rely on one dev's directive; broadcast the constraint.
**Anti-pattern (real, from slice-3):** split by file (no conflict) but one
dev's task consumed another's unwritten outputs (mpc channels + mock). File
non-overlap still produced a serial bottleneck because the task dependency
wasn't surfaced. Fix: rule 1 + 2 + 4 together.
### Background poller (`poller.py`) — for PM sessions that monitor the relay over time
A PM session that drains the inbox only when prompted will miss time-sensitive `question`s
from devs and let directives stall. **Launch the relay's `poller.py` as a background
process at the start of every PM session** (one per relay port — for rutster that's 7110):
```bash
setsid env RELAY_PORT=7110 python3 ~/Sources/relay/poller.py \
>> /tmp/relay-poller/7110/poller.log 2>&1 < /dev/null & disown
```
What it does (every 20s by default): lists/drains the PM inbox (logging full bodies to
`/tmp/relay-poller/7110/inbox.log`), lists pending for each dev role, and posts a
`question`-kind nudge if a directive has sat undrained >120s. State files persist across
PM sessions — read `inbox.log` to catch up on what the poller drained while you were away,
and `poller.log` to confirm the poller is actually cycling.
**Verification discipline (load-bearing — this was a real failure mode):** after launching,
wait ≥60s, then confirm the log shows **at least 3 "poll cycle N complete" lines** before
claiming the poller is running. A "poller start" line + a live process is NOT sufficient —
the SSE client can launch then silently fail on the first poll. The cycle entries are the
proof of life. If you only see the start line, kill + relaunch + re-verify.
**Do NOT use `call.py` in a loop.** Each `call.py` invocation opens a fresh SSE
connection + spawns a daemon thread that doesn't clean up. Over hundreds of polls
this piles up connections/threads and eventually wedges. `poller.py` opens ONE
persistent SSE connection and reuses it — that's the whole point of the distinction.
**For dev sessions:** dev agents don't need the poller. They should drain their own
inbox at the start of every turn (or poll every ~20-30s if the harness supports
background polling). The poller exists to keep PM-side state warm and catch devs who
go quiet — devs are the *consumers* of directives, not the pollers.
### Session handoff — what to read when resuming a PM session
When a PM session resumes (new terminal, cleared context, etc.), the relay's in-memory
queues may have been drained by the poller in the previous session. Reconstruct state
from, in order:
1. `/tmp/relay-poller/<port>/inbox.log` — every message the poller drained, full bodies,
in order. **Read this first.**
2. `/tmp/relay-poller/<port>/poller.log` — poll-cycle entries, nudges posted, errors.
Skim for any nudge you sent that the dev never responded to.
3. `~/Sources/relay/relay-log.jsonl` — the relay's own append-only archive, **the durable
full-body record** of every posted message (the in-memory queues are consume-once and
vanish on relay restart; this file is the source of truth across restarts). Use this if
the poller state dir was wiped.
4. `git log --oneline --all -20` — what actually landed; reconcile against the statuses
in inbox.log.
The PM session's first action on resume is reading these — not posting directives. You
cannot direct devs whose last status you don't know.
### PM session launch checklist — reproducible setup for new sessions
When you (the user) open a fresh set of kitty/tmux terminals for a new PM + N-dev lift,
run this checklist so polling "just works" without manual relay between you and the PM
agent:
**1. Start the relay before opening agent sessions.** The PM and dev agents auto-register
their MCP tools against the relay on startup — but only if the relay is already running.
For rutster:
```bash
~/Sources/relay/start.sh --repo ~/Sources/rutster --port 7110
```
(This terminal becomes the relay log. Leave it open, or background it.)
**2. Launch the poller in the background (PM-side inbox monitoring):**
```bash
setsid env RELAY_PORT=7110 python3 ~/Sources/relay/poller.py \
>> /tmp/relay-poller/7110/poller.log 2>&1 < /dev/null & disown
```
The poller drains the `pm` inbox every 20s and logs full bodies to
`/tmp/relay-poller/7110/inbox.log`. It also nudges any dev whose directive inbox stays
undrained >120s. State files persist across PM sessions, so closing the PM terminal
doesn't lose history.
**3. Open a side kitty window for live inbox + poller tail:**
```bash
# In a kitty tab alongside the PM chat:
RELAY_PORT=7110 ~/Sources/relay/watch.sh
```
This live-tails both `inbox.log` (dev → pm messages) and `poller.log` (poll cycle
markers + nudges), so you see dev activity in real time without depending on the PM
agent surfacing it. You see what the PM sees.
**4. Bring up the PM/dev sessions (manual / tmux / kitty):**
```bash
~/Sources/relay/start.sh --repo ~/Sources/rutster --port 7110 --kitty # or --tmux
```
`--kitty` / `--tmux` spawns 5 terminals (relay + pm + dev-a/b/c) with the MCP relay
pre-registered for each. The generated prompts bake in `RELAY_PORT=7110` so the shims
(`call.py`) self-configure even without the env. (For `--manual`, the relaying prompts
are printed for you to paste into separate terminals.)
### PM-mode discipline (load-bearing — this was a real failure mode)
The poller and watch.sh capture state, but **the PM agent is still turn-based** — a
background process cannot interrupt the PM mid-conversation. The user's prompt is the
only thing that spins the PM up. Therefore, **at the start of every turn**, before answering
the user's question or acting on it, the PM agent MUST:
1. Drain its own inbox via `python3 ~/Sources/relay/call.py read_messages '{"for":"pm"}'`
(or read `inbox.log` if the poller has been running).
2. Poll pending for each dev role: `python3 ~/Sources/relay/call.py list_pending '{"for":"<role>"}'`
— catches directives that haven't been picked up.
3. Check `git log --oneline --all -10` for commits that landed since last seen.
4. Surface anything actionable to the user BEFORE they have to ask "did you see X?":
"`<dev>` posted `<status>` at `<ts>`; next action I'm taking is `<action>`."
If a dev posted a `question` kind that needs a user decision (architectural forks,
build-vs-reuse calls, etc.), surface it explicitly with a proposed default and ask for
confirmation — don't go silent on it and don't proceed without the user's call.
**Anti-pattern (real, from slice-3):** the poller was running and draining state
correctly, but the PM only read it when the user asked "did you see X?" — wasting the
poller's value. The turn-start discipline above is what makes the poller actually useful.
### When the PM is blocked on a user decision
Devs posting `question`-kind messages often need a user-only decision (architecture
forks, build-vs-reuse, licensing posture, etc.). The PM should NOT bike-shed these in
relay messages — surface them to the user immediately and propose a default:
```
<dev-X> asked an architectural question: <one-line summary>.
My recommendation: <default>. Confirm or redirect?
```
Devs don't wait for the PM to bike-shed; they wait for the user. The PM's job is to
telescope the decision needed to one line, propose a sound default, and let the user
confirm. If the user is away, the PM can post a `status` to the dev saying "blocked on
user decision re: <X>, you'll get a directive when they confirm" so the dev can pick up
parallel work or stand down.
---

82
DCO.md Normal file
View File

@@ -0,0 +1,82 @@
# Developer Certificate of Origin (DCO)
Version 1.1
Copyright (C) 2004, 2006 The Linux Foundation. All rights reserved.
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
---
## How to sign off
Every commit MUST be signed off. Use `git commit -s` (or `git commit --signoff`)
to add the attestation line automatically:
```
$ git commit -s -m "feat: add barge-in reflex"
commit 0123456789abcdef...
Author: A.D. Lee <alee@example.com>
Date: Wed Jul 2 10:00:00 2026 +0000
feat: add barge-in reflex
Signed-off-by: A.D. Lee <alee@example.com>
```
The `Signed-off-by: Name <email>` line is the canonical DCO attestation. The
name and email MUST match the git author identity.
## Why DCO (not a CLA)
The DCO is a per-commit attestation (lightweight, no registration), not a
Contributor License Agreement (which would require a one-time grant + tracking).
The DCO preserves the copyright-holder's option to dual-license the project
later — every contributor retains their own copyright but attests they have the
right to contribute under GPL-3.0-or-later (the project's license, ADR-0004).
See [ADR-0004](docs/adr/0004-license.md) for the license decision and the
dual-license rationale.
## For agents committing on behalf of a human
An AI agent that commits code on behalf of a human operator MUST sign off with
the **human's** name + email, not the agent's own identity. The human is the
contributor of record; the agent is the instrument. The DCO attestation
certifies the human's right to contribute, not the agent's.
```
# Correct — the human (alee) is the contributor of record
Signed-off-by: A.D. Lee <alee@example.com>
# WRONG — the agent is not a legal entity that can hold copyright
Signed-off-by: opencode-agent <agent@example.com>
```
CI (planned) will reject commits missing a valid `Signed-off-by` line matching
the author identity.

View File

@@ -0,0 +1,130 @@
# PM kickoff prompt — slice 4 (barge-in / VAD-driven playout kill)
> Drop this prompt into a fresh PM agent session to bootstrap it with full
> context. Long because the agent has zero priors — the session discipline
> (turn-start polling, proactive surfacing, no standby mode) is load-bearing
> in the prompt itself.
>
> To reuse for future slices: copy this file, swap the slice number + topic
> + open-loose-ends, update the "current state" + "what's already in place"
> sections to match the new baseline.
---
```
You are the PM for the rutster project. Slice-3 just merged. Your job: plan
slice-4 (spearhead step 4 — barge-in / VAD-driven playout kill) and stand up
the multi-agent relay workflow to execute it.
## Current state (verify at turn-start, don't just trust this)
- `main` is clean through slice-3 + the strategic pivot (ADR-0007/0008,
rutster-trunk rename). All 4 PRs merged (slice-1, slice-2, pivot, slice-3).
Run `git log --oneline -15` to confirm.
- CI is green on main: fmt, clippy --all-targets -D warnings, test --all
(stable + 1.85), cargo deny check.
- Poller SHOULD be running in background (check: `pgrep -af poller.py`).
If not, relaunch per AGENTS.md "PM session launch checklist".
- Relay on localhost:7110. State at /tmp/relay-poller/7110/.
- Open loose ends (don't block slice-4, just note):
- slice-1-review-fixes branch still unmerged (real F1-F9 fixes, needs
rebase forward onto current main — see AGENTS.md parallelism rules)
- Server is memory-constrained (1.9 GB RAM) — CI matrix jobs sometimes
OOM-kill in parallel. Known infra issue, not a code defect.
- AGENTS.md PM-mode discipline edits + crates/rutster-tap/tests/ may
be uncommitted in the main checkout working tree — check `git status`
and land them if so.
## What slice-4 is
Spearhead step 4 of 6: **barge-in / VAD-driven playout kill.** The FOB reflex
loop acts on the advisory signals slice-3 pre-paved.
What's already in place (DO NOT rebuild):
- **S4 turn-ownership decision** (slice-3 spec §4.3 + §7.5 #7): OpenAI
Realtime's server-side VAD is DISABLED (`session.update` with
`turn_detection: null`). The FOB owns turn-taking. Locked by unit test.
- **`speech_started` / `speech_stopped` advisory events** (slice-3 spec §3.2):
the brain forwards these; slice-3 logs + counts them but does NOT act on
them in the hot media loop. Slice-4 wires them into the reflex loop.
- **Core-authoritative playout buffer** (slice-2 §4.1): structurally
prevents the brain from gating playout. Already in place. Slice-4 makes
the FOB use it: on barge-in, the FOB kills playout from the buffer, not
the brain.
What slice-4 adds:
- The FOB reflex: local VAD (or the brain's advisory signals, or both)
drives a playout-kill decision in the 20 ms media loop.
- The playout buffer gets a "kill now" path (drains the ring, stops
pushing to str0m encode) triggered by the reflex.
- The seam test continues: `loop_driver.rs` + `rtc_session.rs` stay
byte-identical except for the new reflex hook (or however the spec
lands it — that's the brainstorming work).
## What to read FIRST (in order)
1. **AGENTS.md** — the whole thing. Especially: "PM-mode discipline"
(turn-start polling rules), "PM session launch checklist," "Multi-dev
parallelism" (5 rules w/ anti-pattern), "Session handoff," Git workflow
(tea, rebase-merge carve-out for stacked branches).
2. **docs/superpowers/specs/2026-06-30-slice-3-realtime-brain-design.md**
§4.3 (S4 decision), §1.2 (what step 4 defers), §7.5 #7 (S4 done-criteria).
3. **docs/superpowers/specs/2026-06-28-slice-2-agent-tap-design.md** §4.1
(the core-authoritative playout buffer).
4. **docs/ARCHITECTURE.md** — "Biggest technical risk" section (the reflex
loop is the remaining long pole + the differentiator).
5. **docs/PORT_PLAN.md** §Phasing (step 4 = barge-in).
6. **docs/reviews/2026-06-29-strategic-reviews-post-pivot-rescore.md** —
S4 is now resolved by ADR-0008; refresh context on which strategic
findings remain open.
## How to run slice-4 planning
1. **Brainstorm first** — use the `brainstorming` skill before any design
doc. Explore: what triggers barge-in (local VAD vs brain advisory vs
both)? Where does the kill decision live (loop_driver? a new reflex
module?)? How does the playout buffer drain? What's the latency budget?
What does the seam test look like (which files stay byte-identical)?
Subject every assumption to "would this re-introduce a hop on the
per-call hot path?" (ADR-0002's load-bearing rule).
2. **Write the spec** — `docs/superpowers/specs/<date>-slice-4-barge-in-design.md`
using the `writing-plans` skill pattern. Include §1.2 out-of-scope
table (what step 5 / 6 defer), §7 done-criteria with the seam test, §8
open decisions.
3. **Write the implementation plan** — `docs/superpowers/plans/<date>-slice-4-barge-in.md`.
Structure it for parallelism (see AGENTS.md "Multi-dev parallelism"
checklist): identify the critical-path foundation first, pre-list
parallelizable-now work, sequence so the blocking path is shortest,
state dependencies explicitly per directive, broadcast the seam-test
invariant to EVERY dev.
4. **Use the `multi-agent-kickoff` skill** to generate the PM + dev
terminals. It bakes in the relay coordination protocol, branch/worktree
setup, and the launch checklist. Port 7110 for rutster.
5. **Launch the poller** per AGENTS.md before devs come online. Verify
≥3 "poll cycle N complete" lines in /tmp/relay-poller/7110/poller.log
before claiming it's running.
6. **Dispatch** using the 5-rule parallelism checklist. Don't repeat
slice-3's mistake (sent dev-a AND dev-b to write the same protocol
tests — file non-overlap ≠ task independence).
## PM-mode discipline (load-bearing)
You are turn-based. The poller keeps state warm but cannot interrupt you.
At the start of EVERY turn, before answering the user:
1. Drain pm inbox (or read /tmp/relay-poller/7110/inbox.log if poller ran).
2. `list_pending` for each dev role.
3. `git log --oneline --all -10`.
4. Surface anything actionable BEFORE the user asks "did you see X?"
Do NOT go on standby waiting for commands. When a task completes, move
to the next one (PR, next slice, next dispatch) unless the user redirects.
When a dev posts a `question` needing a user decision, surface it with a
proposed default — don't bike-shed it in relay messages.
## First action
Read AGENTS.md in full, then the slice-3 + slice-2 specs. Confirm poller
is alive. Report back to me: (a) current git state, (b) poller state,
(c) your proposed brainstorming approach for slice-4, (d) any open
questions before you start. Then begin.
```