← kanipi

Envoy

inbox assistant · triage + draft + sign-off

A product built on Kanipi. Monitors IMAP, triages incoming email, drafts replies. Routes every outbound draft through the same sign-off dashboard as Evangelist. Requires Kanipi V2 (email channel not yet built).
TL;DR
Envoy handles your inbox. It reads IMAP, labels and prioritizes messages, and drafts replies. Nothing sends without you seeing it first. Draft routing uses the same tap human-review mechanism as Evangelist — the sign-off dashboard shows both pending posts and pending emails. One queue. Two agents. One approval flow.

Triage

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.

Triage Pass
1
Classify the message
Read sender, subject, body. Classify into: user support inquiry, contributor question, partnership/business, automated notification, or noise. Classification determines whether to draft a reply, escalate, or ignore.
2
Priority scoring
Known senders (contributors, frequent contacts) get higher priority. Direct questions get higher priority than FYIs. Automated notifications go to the bottom. Priority score written to state file — dashboard sorts by it.
3
Draft or escalate
For auto-draftable: user questions, contributor inquiries — draft a reply. For escalate: anything requiring a decision, commitment, or access to information not in the agent's context — flag in the queue without a draft. For ignore: automated notifications, bounces, known spam patterns — mark read, skip queue.
The triage rules live in CLAUDE.md

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.

Drafting

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.

What it drafts well
  • User support questions (using project context from CLAUDE.md)
  • Contributor questions about architecture, process, roadmap
  • Status updates for ongoing requests ("we're looking into it")
  • Thank-you replies for contributions, feedback, reports
  • Initial responses to partnership or collaboration inquiries
What it doesn't draft
  • Commitments (pricing, timelines, contracts)
  • Anything requiring access to private information
  • Sensitive interpersonal situations
  • Replies where the right answer isn't clear from context
  • These go to the escalate queue with a summary, no draft

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.

Sign-off — Shared Dashboard

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.

Outbound Flow
1
Agent calls tools/email/send
The agent writes a reply and calls tools/email/send with the draft content. From the agent's perspective, this is a standard tool call.
2
Tap intercepts → pending queue
The human-review tap action writes the draft to /srv/data/kanipi/email/pending/{uuid}.json, alongside the original inbound message for context. Returns pending status to the agent.
3
Dashboard shows both email and post queues
The sign-off dashboard merges both pending directories into one queue, sorted by priority and age. Email drafts show the original inbound message inline. Posts show the context that triggered the draft.
4
Approved → SMTP send
Tap completes the tools/email/send call, injecting the SMTP credentials at call time. The agent never held the mail server password.
Why a shared dashboard makes sense

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.

Configuration

Status: V2 (not yet built). Requires the email channel adapter (IMAP polling + SMTP send), both planned for Kanipi V2.

Tap middleware

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"

config.yaml — agent personality

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

Channel config

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}

What Kanipi provides

PrimitiveUsed for
Email channel (IMAP)Poll inbox, deliver new messages as events to the agent
Tap: human-reviewIntercept every outbound send — write draft to pending queue
Tap: inject-credentialSMTP password injected only after approval; IMAP for reads
Tap: inject-credential (GitHub)Enrich support replies with live issue/PR status
Tap: rejectBlock Twitter/Telegram access — credential isolation
Per-agent CLAUDE.mdTriage rules, voice, escalation thresholds
Sign-off dashboardShared queue with Evangelist — email drafts + post drafts in one place
Container isolationEmail credentials never touch Evangelist or Support containers

Links

Related