inbox assistant · triage + draft + sign-off
Envoy polls IMAP on a configurable interval (default: 5 minutes). For each new message it runs a triage pass: classify, prioritize, and decide whether to draft a reply or flag for direct human attention.
Classification and escalation logic is part of the agent's personality, not hardcoded. What counts as "auto-draftable" versus "escalate" varies by project. A solo developer might want everything drafted. A team might only want drafts for user support emails and direct human handling for partnership inquiries. The agent reads its CLAUDE.md to know which is which.
For messages that clear triage, the agent drafts a reply. The draft is written to match the voice and style defined in the personality file — the agent is answering on your behalf, so it writes as you, not as an assistant.
The agent can also use its project context (via GitHub tap) to enrich replies. "Is issue X fixed?" → check GitHub, include the PR link and the version it shipped in.
Envoy shares the sign-off mechanism with Evangelist. Both agents route outbound actions
through the same tap human-review pattern, and both land in the same dashboard queue.
The dashboard distinguishes them by type (email-draft vs post-draft)
but uses a single approval flow.
tools/email/send with the draft content.
From the agent's perspective, this is a standard tool call.
/srv/data/kanipi/email/pending/{uuid}.json, alongside the original
inbound message for context. Returns pending status to the agent.
tools/email/send call, injecting the SMTP credentials
at call time. The agent never held the mail server password.
The sign-off workflow is the same regardless of whether the draft is a tweet or an email.
Read the draft. Edit if needed. Approve or reject.
Keeping one dashboard means one place to check, one muscle to build.
The underlying routing mechanism is identical — only the tap route pattern
(tools/email/send vs tools/twitter/post) differs.
tap:
routes:
# Outbound email always goes to human-review queue
- pattern: "tools/email/send"
action: human-review
queue: /srv/data/kanipi/email/pending/
timeout: 72h # longer window than posts
# SMTP credentials injected only after approval
- pattern: "tools/email/send"
action: inject-credential
credential: SMTP_PASSWORD
as: env
name: SMTP_PASSWORD
# IMAP read is allowed without approval (read-only)
- pattern: "tools/email/read"
action: inject-credential
credential: IMAP_PASSWORD
as: env
name: IMAP_PASSWORD
# GitHub access for enriching support replies
- pattern: "tools/github/*"
action: inject-credential
credential: GITHUB_TOKEN
as: header
name: Authorization
prefix: "token "
# Hard blocks
- pattern: "tools/twitter/*"
action: reject
reason: "Envoy agent does not have Twitter access"
- pattern: "tools/telegram/*"
action: reject
reason: "Envoy agent does not run in Telegram"
agents:
email:
personality: |
You manage incoming email for [project-name].
You read, triage, and draft replies. Nothing sends without human approval.
## Triage Rules
Auto-draft:
- User support and how-to questions
- Contributor questions about architecture, process, or roadmap
- Feature requests (acknowledge + log to GitHub issues if appropriate)
- Thank-you replies for contributions
Escalate (no draft):
- Pricing, licensing, legal, contract discussions
- Media or press inquiries
- Anything requiring a decision you can't make from context
Ignore (mark read, skip queue):
- CI/CD notifications, automated reports
- Bounce messages
- Known mailing lists not relevant to the project
## Voice
Write as [owner-name], not as an assistant.
- Direct and brief
- Warm but not sycophantic
- Include specific technical detail when helpful
- Never use: "Hope this helps!", "Feel free to", "Don't hesitate"
## Context sources
GitHub issues and PRs available via tools/github/*
Use them to answer status questions with specifics.
## State
/srv/data/kanipi/email/state.md:
- Triage log (sender, classification, draft or escalate)
- Pending queue size
- Rejected draft patterns (learn from what gets edited/rejected)
image: kanipi/agent:latest
network: true
channels:
email:
enabled: true
imap:
host: ${IMAP_HOST}
port: 993
user: ${EMAIL_USER}
poll_interval: 5m
smtp:
host: ${SMTP_HOST}
port: 587
user: ${EMAIL_USER}
| Primitive | Used for |
|---|---|
| Email channel (IMAP) | Poll inbox, deliver new messages as events to the agent |
| Tap: human-review | Intercept every outbound send — write draft to pending queue |
| Tap: inject-credential | SMTP password injected only after approval; IMAP for reads |
| Tap: inject-credential (GitHub) | Enrich support replies with live issue/PR status |
| Tap: reject | Block Twitter/Telegram access — credential isolation |
| Per-agent CLAUDE.md | Triage rules, voice, escalation thresholds |
| Sign-off dashboard | Shared queue with Evangelist — email drafts + post drafts in one place |
| Container isolation | Email credentials never touch Evangelist or Support containers |