Goal of this doc: make every message the Agent-School sends read like it came from one careful operator — plain English, a clear “what happened”, a clear “what to do”, and a consistent vocabulary. This is the contract the notify layer (
school_mail.py+agentmail_client.py) follows. If a new card is added, it must pass the checklist at the bottom.
The system has accumulated three names for the same object. Stop that. New messages must use the canonical terms below; old references may be migrated over time, but never introduce a new alias.
| Canonical | Meaning | Former aliases (avoid) |
|---|---|---|
| issue | A GitHub issue flowing through the school | “task”, “bead #…” (in human-facing text) |
| bead | The internal tracker id for a piece of work (used in commands + bookbag) | — (keep for /fix <bead>, bookbag) |
| review | The two-judge check (CTO/COO) a student’s work passes | “verdict”, “rubber-stamp” |
| accepted / rejected | The human’s final decision | “APPROVED / REJECTED” (subject still uses ✅/❌ marks) |
| retry / school-failed | A transient failure (will retry) vs. exhausted budget (needs human) | “error”, “blown”, “needs review” |
| pre-merge check | The entire review pass |
“Entire pre-merge”, “entire output” |
| the school | The agent system, as a collective actor | “Agent-School”, “principal”, “bridge” (human-facing) |
Rules:
/fix <bead> command needs it.job_id, thread_id,
repo, commit_sha in subjects — fine in the body as context).[school] <short thing> — <STATE>.Every notification is built from the same skeleton:
[line 1] Who + what + state e.g. [Agent-School] Issue #45 — ❌ SCHOOL-FAILED
[beat 1] Context Repo, title, the two verdicts — facts, no spin
[beat 2] What happened ONE plain sentence (the ELI5 line)
[beat 3] What to do Next step, or the reply commands
[footer] Reply path / link
The single most important sentence. Written for a smart non-expert.
What happened: a temporary failure — the school will try again automatically. No action needed.What happened: A2A connection refused; bridge escalated to retry budget state machine.Rules:
What happened:.Every actionable card ends with a footer that tells the human exactly how to respond. Commands on their own lines, in the form the poller parses:
Reply with one of:
/approve — accept this work and merge it
/reject — mark it rejected
/fix <note> — send it back with your note
Next step: open the issue (link below)…).IMPORTANT: never let a footer line begin with a parseable command token unless it IS a real command option. The poller skips the known footer lines (
_FOOTER_LINES), but the invariant is: footer = instructions, never votes.
Failures get their own tone: no blame, no jargon, always a next step.
| Situation | What happened (ELI5) | What to do |
|---|---|---|
| Retry (transient) | “a temporary failure … will be retried automatically” | “No action needed” |
| School-failed (budget out) | “the school could not finish this issue after N attempts” | “Open the issue and decide” (link) |
| CI red on main | “the automated checks failed on the main branch” | “Open the failing run” (link) |
| CI + integration job red | add: “this is usually infrastructure (the gateway/Orca on the Mac), not code” | same as CI |
configure_logging() in
agentmail_client.py). A 2-minute cron without timestamps is
indistinguishable from a dead one.logging, not print/sys.stderr.write — levels, timestamps, module
names. The notify layer migrated; keep it that way.delivered, skipped (no inbox), send failed) not
just the attempt.Next step:) is present.agentmail_client) — no new copy of _req/inbox logic.logging with timestamps.tests/test_school_mail.py).| Var | Purpose |
|---|---|
AGENTMAIL_API_KEY |
Required. User-scoped key (am_us_…); falls back to ~/.hermes/config.yaml. |
AGENTMAIL_SCHOOL_INBOX |
The Agent-School control-plane inbox (where verdict cards + human replies live). Current: vault-synthesis@agentmail.to. |
AGENTMAIL_INBOX |
Legacy/override destination inbox (falls back after SCHOOL). |
Resolution order: AGENTMAIL_SCHOOL_INBOX → AGENTMAIL_INBOX → first inbox
on the key. Set it at every entry point (hermes .env, crontab, CI workflow).