Skip to main content

One-pass agentic inbox triage: classify, summarize, extract tasks, draft replies (never sends), flag calendar.

Project description

inbox-to-action

PyPI version Python 3.11+ License: MIT GitHub stars

Published on PyPI. MCP-registry manifests (server.json for the Official MCP Registry, smithery.yaml for Smithery, glama.json for Glama) ship in the repo — registry listings are pending submission.

One command. Your inbox triaged, summarized, drafted, and turned into tasks — in a single agentic pass.

Install

pip install inbox-to-action          # or: pipx install inbox-to-action
uvx inbox-to-action run --mock       # zero-install trial (uv)
pip install 'inbox-to-action[mcp]'   # + MCP server for Claude Code
docker run --rm ghcr.io/tarunlnmiit/inbox-to-action   # MCP server (stdio)

Try it with zero setup: inbox-to-action run --mock (bundled sample inbox).

📖 Full documentation → docs/install · providers · Gmail OAuth · multi-account · integrations · MCP & Skill · config · troubleshooting · testing checklist. Quick version: SETUP.md.

inbox-to-action — one command triages the inbox into a report, drafts, and tasks


Why this exists

Most people process their inbox with four separate tools: an email client to read, a task manager to capture to-dos, a calendar to block time, and (increasingly) an AI summarizer to make sense of long threads. Every message gets handled four times.

inbox-to-action collapses all four into one agentic pass. Run one command and get a unified triage report, drafted replies saved to Gmail, and extracted tasks — without ever leaving the terminal, and without ever sending an email automatically.

🔒 Drafts only — never sends

This tool cannot send email. It requests only the Gmail readonly + compose scopes; there is no send scope and no send API call anywhere in the codebase (enforced by a test). Replies are saved as Gmail drafts for you to review and send.

What it does

  1. Fetches unread email from Gmail (last 24h by default).
  2. Classifies each into action_needed · fyi · newsletter · noise.
  3. Summarizes long threads (>500 words) into two lines.
  4. Extracts tasks with deadlines → local tasks.md (optional Todoist via --todoist).
  5. Drafts replies for action_needed mail → saved as Gmail drafts.
  6. Flags emails that need a calendar block.

Final output: a single triage-report.md with a section per category, drafted-reply previews, a tasks summary, and a calendar list.

Architecture — the agent loop

The model's own classification of each email drives which tools fire next — the pipeline is not hardcoded. The same tool functions back the CLI agent and the MCP server.

flowchart TD
  CLI[main.py · typer] --> AGENT[agent.py · agentic loop]
  AGENT -->|model picks tools per email| T1[classify_email]
  AGENT --> T2[summarize_thread]
  AGENT --> T3[extract_tasks]
  AGENT --> T4[draft_reply → Gmail draft]
  AGENT --> T5[flag_for_calendar]
  T1 & T2 & T3 & T4 & T5 --> LLM[llm_client.py · pluggable providers]
  LLM --> P1[OpenRouter / Ollama / NIM / OpenAI<br/>OpenAI-compatible HTTP]
  LLM --> P2[Anthropic · official SDK · keyless via ant auth login]
  AGENT --> REPORT[report.py → triage-report.md]
fetch → for each email:  classify ─┬─ action_needed → extract_tasks + draft_reply + flag_calendar
                                   ├─ fyi / newsletter / noise → record only
                                   └─ (long thread) → summarize
                          → render triage-report.md

Quick start (2 minutes)

git clone https://github.com/tarunlnmiit/inbox-to-action.git && cd inbox-to-action
python3 -m venv .venv && source .venv/bin/activate
pip install -e '.[mcp]'        # installs the `inbox-to-action` command
cp .env.example .env

This installs an inbox-to-action console command (and the python -m inbox_to_action.mcp_server entry point used by Claude Code / Glama).

Free-first: run end-to-end on zero spend

Pick whichever keyless/free path you like — all run the full pipeline at no cost:

Option A — claude CLI (keyless, fastest; uses your Claude Code login):

PROVIDER=claude inbox-to-action run --mock     # no API key; needs `claude` on PATH

Option B — Ollama (truly keyless, fully local):

ollama serve            # in another terminal
ollama pull llama3.1
PROVIDER=ollama inbox-to-action run --mock     # uses bundled sample inbox

Option C — OpenRouter free model (free signup key):

# put OPENROUTER_API_KEY in .env (free models, $0 spend)
inbox-to-action run --mock                      # default PROVIDER=openrouter

Option D — inside Claude Code (keyless, Claude Code is the LLM): see below.

--mock uses the bundled sample inbox so you can see a full report with zero Gmail setup. Drop --mock once you've authorized Gmail. Free OpenRouter models are often rate-limited; the client auto-rotates a fallback list and retries with backoff.

Real inbox

# 1. Create OAuth credentials in Google Cloud Console (Desktop app),
#    download client_secret.json into the project, then:
inbox-to-action auth                 # one-time consent (read + compose only)
inbox-to-action run --since 24h --no-drafts   # safe first pass: report only, no writes
inbox-to-action run --since 24h      # triage the last day (creates Gmail drafts)
inbox-to-action run --since 3d --max 40 --todoist
  • --no-drafts — classify, summarize, extract tasks, write the report, but create no Gmail drafts. Recommended for a first run.
  • --max N — cap emails per account (default 25) to bound cost/volume.
  • Automated no-reply senders (security alerts, notifications) never get a drafted reply — the report notes them instead.

Telegram summary (--telegram)

Push a concise summary to your phone after each run — counts, action-needed subjects (with draft-ready status), extracted tasks, and a link to your Gmail Drafts.

# 1. In Telegram, message @BotFather → /newbot → copy the bot token.
# 2. Message your new bot once (say "hi"), then open:
#    https://api.telegram.org/bot<token>/getUpdates  → copy "chat":{"id": ...}.
# 3. Put both in .env:
#    TELEGRAM_BOT_TOKEN=...   TELEGRAM_CHAT_ID=...
inbox-to-action run --since 24h --telegram

Off by default (opt-in flag). A send failure never breaks the run. Privacy: this sends email subjects + extracted tasks to Telegram's servers (into your own chat). It's notification only — it never sends email.

Multiple accounts (Gmail + Google Workspace)

Declare accounts in config.json — one merged report, each email tagged with its account. Personal Gmail and Workspace both use the Gmail path (Workspace may need your admin to allow the OAuth app).

{
  "accounts": [
    { "id": "personal", "kind": "gmail", "label": "Personal Gmail" },
    { "id": "work",     "kind": "gmail", "label": "Workspace" }
  ]
}
inbox-to-action auth --account personal   # authorize each account once
inbox-to-action auth --account work
inbox-to-action run --since 24h           # fetches + triages across all accounts

Multiple personal Gmail accounts can reuse one client_secret.json — each gets its own cached token (~/.config/inbox-to-action/tokens/<id>.json). With no accounts block, the tool uses a single default Gmail account (backwards compatible).

Use inside Claude Code (keyless)

When run inside Claude Code, Claude Code is the LLM — no provider key needed. Two integration paths ship in this repo:

MCP server

Exposes IO-only tools (fetch_emails, save_gmail_draft, append_tasks, write_report). Claude Code does the classify/summarize/extract/draft reasoning itself and calls these.

# after `pip install -e '.[mcp]'`
claude mcp add inbox-to-action -- python -m inbox_to_action.mcp_server

This is the same stdio server that MCP registries (e.g. Glama) build from the bundled Dockerfile (CMD python -m inbox_to_action.mcp_server).

Skill

Copy skills/inbox-to-action/ into your Claude Code skills directory, then type /inbox-to-action. The skill instructs Claude Code to fetch, reason, draft, and write the report — keyless.

Anthropic (keyless via ant auth login)

The Anthropic provider uses the official SDK with a zero-arg client, so it picks up your ant auth login OAuth profile — no ANTHROPIC_API_KEY required:

ant auth login
PROVIDER=anthropic inbox-to-action run --mock   # default model: claude-opus-4-8

Configuration

All keys live in .env (.env.example is committed). Switch providers with PROVIDER: openrouter (default) · ollama · nim · openai · anthropic · claude · host.

Configure triage (make it yours)

The default buckets are generic — newsletters and job alerts are treated as no-action. Override that with config.json (copy config.example.json). Two layers:

  • rules — deterministic field → category overrides applied before the LLM (fast, free, exact). First match wins. fieldsender | subject | body | any.
  • triage_instructions — freeform guidance injected into the classifier prompt for nuance the model interprets.
{
  "triage_instructions": "I'm job hunting in ML/AI — treat relevant job alerts as action_needed.",
  "rules": [
    { "field": "sender",  "contains": "hirist.tech", "category": "action_needed" },
    { "field": "subject", "contains": "invoice",     "category": "noise" }
  ]
}
cp config.example.json config.json   # edit to taste (config.json is gitignored)
inbox-to-action run --since 24h                 # auto-loads ./config.json
inbox-to-action run --config /path/to/other.json

Quick override without a file: TRIAGE_INSTRUCTIONS="treat job alerts as action_needed".

Tests

pytest --cov=.        # 100+ tests, 90%+ coverage, incl. the never-send security test

Docs

  • docs/ — full guides with screenshots: install, every LLM provider, Gmail OAuth, multi-account, integrations, MCP & Skill, config, troubleshooting, testing checklist.
  • SETUP.md — 5-minute quickstart.
  • CONTRIBUTING.md — dev setup + the never-send rule.
  • CLAUDE.md — project map for Claude Code.

Built with

This project demonstrates the contract skills:

  • Agentic orchestration — model-driven, per-email tool selection (no hardcoded pipeline).
  • Function calling — typed tool schemas (agent.TOOL_SCHEMAS) shared by the CLI agent and MCP server.
  • Multi-API integration — Gmail + LLM + Todoist in one flow.
  • Pluggable LLM providers — one llm_client swaps OpenRouter / Ollama / NIM / OpenAI / Anthropic.
  • Claude Code integration — first-class MCP server and Skill, both keyless.

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

inbox_to_action-0.2.4.tar.gz (1.2 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

inbox_to_action-0.2.4-py3-none-any.whl (38.8 kB view details)

Uploaded Python 3

File details

Details for the file inbox_to_action-0.2.4.tar.gz.

File metadata

  • Download URL: inbox_to_action-0.2.4.tar.gz
  • Upload date:
  • Size: 1.2 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for inbox_to_action-0.2.4.tar.gz
Algorithm Hash digest
SHA256 6a78e8a3a85f54bfc92eb67fd2e8ad245e11b9b5132ebff1fe47572511506c12
MD5 d72e7b493200fdc33e335186fe27f360
BLAKE2b-256 e964a0c8a0c366b6f549fd7cba5b710b443923c37f94a3c1068ff629e71734b2

See more details on using hashes here.

File details

Details for the file inbox_to_action-0.2.4-py3-none-any.whl.

File metadata

File hashes

Hashes for inbox_to_action-0.2.4-py3-none-any.whl
Algorithm Hash digest
SHA256 840dfb2b331c854f4458b1e68e5f47077eca40f42c170755f2a0bf5b90649b26
MD5 400f4d724fee0af5674f5a59d0a012fb
BLAKE2b-256 6986745ed650e374244ea627669587069c3b6c3a4fd91d5b68f45c3659ccc682

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page