telegram-draft-for-review
The HITL gate for outbound Telegram. No human-addressed message ships without π.
Why this exists
Today, swarm/telegram_alerts.py sends unreviewed alerts. That's fine for system alerts (severity tags, [AGENT OUTPUT] prefix). It is not fine for messages that look like Phill speaking β replies to people, board comments, draft summaries.
This skill is the gate. It posts a draft to a private review chat (or a dedicated thread), waits for a π/β reaction, and only then sends the real message.
Flow
1. Caller passes a draft payload:
{
"draft_text": "...",
"destination_chat_id": "...", // where the REAL message will go
"destination_thread_id": null,
"drafted_by_role": "Scribe" | "CoS" | "Margot",
"originating_intent_id": "..." // ties back to intent-parser output
}
2. Skill posts to REVIEW_CHAT_ID with format:
βοΈ DRAFT (Scribe) β for chat -100xxx
βββββββββββββββββββββββββββββββββ
<draft_text>
βββββββββββββββββββββββββββββββββ
React π to send Β· β to revise Β· β³ to delay 24h
3. Skill writes a pending entry to .harness/telegram_drafts.jsonl:
{
"draft_id": "...",
"review_message_id": "...",
"destination_chat_id": "...",
"draft_text": "...",
"status": "pending",
"drafted_at": "...",
"expires_at": "+24h"
}
4. The orchestrator's existing reaction listener (extended in Wave 2)
matches reactions on review_message_id:
- π β status=sent β call existing send_telegram() path β audit log
- β β status=revise β notify originating role, optionally Margot for re-research
- β³ β status=deferred, expires_at extended +24h
- <no reaction by expires_at> β status=expired β log, do NOT send
5. Final state ALWAYS persisted. No silent send, no silent drop.
Contract
Input: the JSON payload above.
Output: {"draft_id": "...", "review_message_id": "...", "status": "pending"} synchronously. Final-state callbacks are async (next orchestrator cycle).
Safety bindings
- Kill-switch: when
TAO_SWARM_ENABLED=0, drafts can still be posted to review chat (so the user sees what Pi-CEO would have done) butstatus=sentis not honoured β sends are halted at the send-call boundary. - Rate limit: drafts inherit the existing
<1 msg/s, <20/min/grouplimit on review chat. If breached, drafts are queued intelegram_drafts.jsonlwithstatus=queuedand posted on the next available slot. - PII redactor (Wave 2): binds in front of both the review post and the eventual send. Wave 1 logs a warning if
pii-redactoris missing but does not block the draft. - Audit log: every status transition (pending β sent / revise / deferred / expired) appended to
.harness/swarm.jsonlwith full draft text and reaction metadata.
Where the review chat lives
REVIEW_CHAT_ID is a new env var. Recommendation: a private 1:1 chat between Phill and Pi-CEO bot, separate from the existing swarm alert chat. Setting it up is a one-time config β flag if missing on first invocation.
When NOT to use this skill
- System alerts (severity-tagged
[AGENT OUTPUT]prefix) continue to ship viaswarm/telegram_alerts.pydirectly. They are not addressed to people. - Reaction-gate signals (π/β) on existing drafts β those route to the reaction handler, not this skill.
- Linear comments β Wave 2
linear-comment-draftextends this pattern to Linear; not yet built.
Verification (Wave 1)
In test mode (TAO_DRAFT_REVIEW_TEST=1), the skill:
- Accepts a draft payload.
- Writes to
.harness/telegram_drafts.jsonlwithout posting to Telegram. - Returns a synthetic
review_message_id. - Accepts a synthetic reaction via stdin (not a real Telegram reaction).
- Transitions state correctly: pending β sent on π, pending β revise on β, pending β deferred on β³, pending β expired after simulated 24h.
End-to-end live test happens in Wave 2 once the reaction listener is extended in swarm/orchestrator.py.
Out of scope
- Real reaction-listening β extends
swarm/orchestrator.py's existing /ack listener; that's a Wave 2 wiring task. - Multi-recipient gating (e.g. "send to A or B based on reaction") β Wave 3.
- Email or Slack draft-for-review β Wave 2 expansion.
References
- Topology:
~/Pi-CEO/Second-Brain-Agent-Topology-2026-05-01.md - Existing send path (do not modify in Wave 1):
Pi-Dev-Ops/swarm/telegram_alerts.py - 15 mandatory safety controls:
~/Pi-CEO/Hermes-Swarm-Recommendation-2026-04-14.mdΒ§5