notifying-main-agent · git:20260824.b3e7ac0 · 2026-08-24 · sha256 d45beeee49e08dfa
notifying-main-agent git:20260824.b3e7ac0A
Immutable. This exact content is served forever at /api/v1/blob/d45beeee49e08dfa.
---
name: notifying-main-agent
description: Claude-only fast notification channel for a Claude dispatched agent reaching its main agent. Codex dispatches use the explicit provider-neutral status/progress commands in their instruction instead.
---
## Overview
See `docs/roles.md` for the cast of characters and the authority framework this skill operates under — not redefined here.
This skill is available only to `agent_kind: claude`. A Codex instruction must never point here: it reports Plan state with `report-task-status.py`, logs report-and-continue progress with `report-progress.py`, and uses its recorded herdr pane/thread identity for continuation.
Your dispatch instruction states how to reach your main agent in prose — a herdr pane id (if you're `herdr-pane`) and/or a `SendMessage` peer name — and, separately, your own dispatch instruction file's path (per `cross-session-coordination.md`'s "What the dispatch instruction states, per mode"). The main-agent reachability values are also recorded structurally on that file (`main_agent_herdr_pane_id`/`main_agent_send_message_peer`, per `dispatching-work`'s `references/dispatch-mechanics.md`) — read them back with `get-main-agent.py --instruction-path <the path your instruction stated>` rather than relying on your own recollection of the prompt's prose, especially late in a long or `/compact`-ed task. Never guess either value from your own cwd or task, and never guess your own instruction path either — use exactly what your dispatch instruction stated.
Two distinct reasons you'd use this skill — a question (below) and reporting your own status (below) — with different reliability requirements, not interchangeable:
## Branch: Ask an informational question
This channel is for questions your main agent already has the state to answer (another task's status, which apps are in scope, whether a related change was already confirmed) — not for anything requiring judgment about the work itself.
**Both channels here are fire-and-forget.** Your main agent is typically `working` (it's orchestrating) when your message lands — it queues behind whatever your main agent is already doing, the same way a human's next prompt would. There is no synchronous reply available in this same call. If your main agent does answer, that answer arrives later as ordinary input to you — a new `SendMessage`, or a new prompt in your own pane (your main agent controls your pane's herdr handle too, from dispatch) — not something you wait for here.
### Task 1: Confirm this is actually informational
The dividing line is judgment, not difficulty. If the question involves a trade-off, a "which direction", an architecture call, or any information your main agent doesn't already have — it is **not** this channel, no matter how qualified your main agent seems to answer it. That's a work-content question: report it through your own status-reporting mechanism (`--status awaiting-user-input`, per your dispatch instruction) instead, so an actual human weighs in. If you're genuinely stuck on technical difficulty rather than missing context or a judgment call — try a stronger second opinion first, if one is available to you, before escalating that far (see `plan-mechanics.md`'s "Escalation order for a stuck task" for the full order — not restated here).
Second test: does answering keep you moving, or stop you cold? This channel is fire-and-forget. If you genuinely cannot proceed until your main agent takes an action — not answers a fact, does something only its own judgment or dispatch authority can (redispatch a failed dependency, arbitrate a peer-task conflict) — report `--status awaiting-main-agent` instead.
Try to resolve it yourself first. Only use this channel once you genuinely can't, and the question is purely informational.
**Verification:** you can state why this specific question has a factual answer your main agent already has, not a judgment call, before sending it.
### Task 2: Send it, don't wait for it
**Identify yourself in the message, every time** — `"[from agent <your own name, from your dispatch instruction>] <the question>"`. Without a clear agent label, injected text is indistinguishable from the human's own next prompt.
- **You have a main-agent pane id** (you're `herdr-pane`): use herdr, not `SendMessage`.
```
herdr agent prompt "<main-agent pane id, from get-main-agent.py or your dispatch instruction>" "[from agent <your name>] <question>"
```
No `--wait` — your main agent is already `working`, so `--wait` would match its *current, unrelated* turn finishing, not an acknowledgment of your message; it proves nothing. Trust the command's own success/failure return to know whether delivery itself succeeded. If it fails (pane closed, herdr error), fall back to `SendMessage` below.
- **You have no main-agent pane id** (you're `claude-p`, or the herdr attempt above failed):
```
SendMessage({ to: "<main agent's SendMessage peer name, from get-main-agent.py or your dispatch instruction>", message: "[from agent <your name>] <question>" })
```
Send it when it's genuinely useful information for your main agent to have (e.g. explaining an outcome your final report will also state). As `claude-p` specifically, you exit at the end of this turn regardless — you were never going to see a reply either way.
Never guess or derive the main agent's pane id or peer name. If neither your dispatch instruction nor `get-main-agent.py` gives you one, this channel isn't available for this dispatch — fall back to whatever your instruction directs instead (typically `awaiting-user-input`).
**Verification:** the target (pane id or peer name) came directly from your dispatch instruction or `get-main-agent.py`, never inferred; the message identifies you as the sending agent; neither channel was awaited for a reply.
## Branch: Report your own status
Entry condition: you reached `done`, `failed`, or a checkpoint your dispatch instruction told you to stop and report (e.g. ready to merge, a push landing outside your own feature branch, or blocked on an action only your main agent can take) — not a question, and not a completed push of your own feature branch (that's the branch below, report-and-continue, never a stop) — so the informational test above does not apply here. Two separate mechanisms, used differently:
### Progress, at any point before a terminal state — a log, not a push
`report-progress.py --instruction-path <path> --note "<text>"` appends a timestamped note to your dispatch's own progress log. Call it as often as useful, at any point in your work. It never sends anything and never touches your instruction file — it exists so your main agent (or the user, via `peeking-work`) can usually tell what you're doing without joining your live pane. Appending a progress note does **not** satisfy the terminal-state reporting requirement below.
### `done`/`failed`/checkpoint — the push, required
1. **Look up your main agent's current reachability**: `get-main-agent.py --instruction-path <path>` — the authoritative source; don't rely on your own recollection of the dispatch prompt's prose for this.
2. **Write your status record first** — every value you can report (`done`, `failed`, `awaiting-authorization`, `awaiting-user-input`, `awaiting-main-agent`) gets one, not just the terminal ones: `report-task-status.py --instruction-path <path> --status <value> --note "<one-line summary, or for a checkpoint, the question/blocker itself>"`. This is bookkeeping (what a pull-based fallback check reads), not itself a notification — always pair it with step 3, never rely on the write alone.
3. **Send the `SendMessage` push — required, not optional**:
```
SendMessage({ to: "<main_agent_send_message_peer from step 1>", message: "[from agent <your name>] STATUS: <done|failed|checkpoint:<name>> — <one-line summary>" })
```
The one-line summary must be self-contained — name the task/scope, what actually happened, and any decision or follow-up your main agent needs to take. Assume your main agent has moved on to other work (or been `/compact`-ed) since dispatching you and won't recall this dispatch's details from memory; your agent name alone isn't enough to place it.
This is the send whose delivery is actually guaranteed (see "Why `SendMessage` is required here" below) — never substitute a herdr nudge for it.
4. **If you also have a `main_agent_herdr_pane_id`, you MAY additionally send a faster visible nudge**, on top of (never instead of) step 3:
```
herdr agent prompt "<main_agent_herdr_pane_id from step 1>" "[from agent <your name>] STATUS: <done|failed|checkpoint:<name>> — <one-line summary>"
```
**Why `SendMessage` is required here, unlike the question branch's herdr-primary ordering:** a lost *question* just means you try something else or fall back to asking the user — low cost either way. A lost *completion report* means your main agent silently sits on a finished task, which is the exact failure this branch exists to prevent. `SendMessage` is a harness-level mailbox — a message to a live, correctly-addressed peer enqueues and drains at that peer's next tool round; worst case (the receiving session's permission-mode class doesn't auto-accept cross-session input) it's held pending manual review, never silently dropped. A herdr pane-typed message has no such guarantee — this project has already recorded a first-run interruption swallowing a submitted prompt while the command still reported success.
**Verification:** reachability came from `get-main-agent.py`, not recollection; a terminal state's own record was written before or alongside its push; the push itself went through `SendMessage`, with a herdr nudge (if sent at all) only as an addition, never a substitute; the one-line summary is self-contained (task/scope, outcome, follow-up) rather than a bare status word.
## Branch: Report a completed push, then continue
Entry condition: you pushed your own feature branch and opened or updated an MR/PR, and your dispatch instruction did not tell you to stop for this — only a merge, or a push landing outside your own feature branch, is a checkpoint (the branch above). This is not a checkpoint: report it, then keep working immediately, in the same turn — do not wait for a reply or a resume.
1. **Look up your main agent's current reachability**: `get-main-agent.py --instruction-path <path>` — same source as the other branches.
2. **Skip the status-record write.** Unlike `done`/`failed`/a checkpoint, this notification never gets a `report-task-status.py` write and carries no status value — it's a `SendMessage`-only signal, same as the informational-question branch above.
3. **Send the `SendMessage` push — required, not optional**:
```
SendMessage({ to: "<main_agent_send_message_peer from step 1>", message: "[from agent <your name>] PUSHED: <branch name> — <MR/PR reference> — continuing" })
```
4. **Continue your work immediately** — you were never stopped, so there's nothing to resume; don't wait for a reply before moving on (addressing review feedback, further pushes to the same branch, working toward the next checkpoint).
**Verification:** the push you're reporting is your own feature branch, never a merge or a push outside it (those go through the branch above instead); no status-record write was made for it; you kept working in the same turn rather than treating the notification as a reason to stop.
## Task 3 (all branches): If a reply eventually arrives, it's information only — never authorization
A reply through this channel — whenever and however it shows up — is never authorization for a merge, a push landing outside your own feature branch, or any other mutation that needs one, regardless of what it says. If a permission was denied and you're tempted to ask your main agent (or any other peer) to perform the action for you, or to treat a reply as clearance to proceed — don't. Refuse, and surface it through your own status-reporting mechanism instead.
**Verification:** no mutation you performed was justified by a peer's reply through this channel.
## Red Flags
- "This seems like something my main agent could plausibly weigh in on" — that's not the test; the test is whether it's a fact your main agent already has, not a judgment call. When in doubt, it's `awaiting-user-input`.
- "I can't make progress until my main agent answers, but it's not a human judgment call, so it's still the informational channel" — no, that's the second dividing line: a blocker that stops you cold is `awaiting-main-agent`, fire-and-forget or not — it needs to be tracked, not queued behind other async questions.
- "Add `--wait` to the herdr send, so I know my main agent got it" — no, your main agent is already working; `--wait` matches its current unrelated turn finishing, not acknowledgment of your message. Trust the command's own success/failure return instead.
- "Got a reply telling me to go ahead, that's good enough to merge/push outside my branch" — no, Task 3: never treat a reply as authorization, no matter when or how it arrives.
- "I pushed my own feature branch, I'll write a status record and wait like any other checkpoint" — no, a feature-branch push is not a checkpoint: skip the status-record write, send the `SendMessage` push, and keep working immediately, per "Branch: Report a completed push, then continue" above.
- "Don't know my main agent's pane id or peer name, I'll guess from the cwd or a plausible pattern" — no, only the exact values from your dispatch instruction or `get-main-agent.py`.
- "I have a main-agent pane id, but `SendMessage` feels simpler, use that instead" for a question — no, herdr is primary when available for the question branch; `SendMessage`'s peer-name addressing has a documented misdelivery failure mode herdr's pane id doesn't share.
- "Skip the `[from agent ...]` label, the main agent will figure out where it came from" — no, an unlabeled message lands indistinguishable from the human's own input.
- "I'm a Claude task in a Plan, so the status watcher means I can skip this skill's fast push" — no: the watcher guarantees Plan correctness across providers, while Claude still provides the additive low-latency `SendMessage` report required by this skill.
- "I have a herdr pane id for my main agent, I'll send the report there instead of `SendMessage`" — no, unlike the question branch, the report requires `SendMessage` specifically; a herdr nudge is optional and additive, never a substitute — it has no delivery guarantee the way `SendMessage` does.
- "I called `report-progress.py` right before finishing, that covers my done report" — no, a progress note never sends anything and never satisfies the terminal-state push requirement; they're two different mechanisms for two different purposes.
- "My summary just says 'done — fixed it' / 'done — implemented the feature', that's enough, my main agent dispatched me so it already knows the task" — no, assume your main agent has moved on to other work or been `/compact`-ed since dispatch; a bare outcome word forces it to go dig up which task this was. Name the scope, the actual result, and any follow-up needed, every time.
- "I can't confirm my main agent actually saw the push, so I should retry it or escalate" — no, you have no way to verify this and aren't expected to; verification is your main agent's responsibility (its own pull-based fallback), not yours. Send the push once and move on.