Metadata-Version: 2.4
Name: inbox-to-action
Version: 0.2.5
Summary: One-pass agentic inbox triage: classify, summarize, extract tasks, draft replies (never sends), flag calendar.
Project-URL: Homepage, https://github.com/tarunlnmiit/inbox-to-action
Project-URL: Repository, https://github.com/tarunlnmiit/inbox-to-action
Project-URL: Issues, https://github.com/tarunlnmiit/inbox-to-action/issues
Author: Tarun Gupta
License: MIT
License-File: LICENSE
Keywords: agent,ai,anthropic,claude-code,email,gmail,llm,mcp,multi-account,nim,ollama,openrouter,telegram,todoist,triage
Classifier: Development Status :: 4 - Beta
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Communications :: Email
Requires-Python: >=3.11
Requires-Dist: google-api-python-client>=2.0
Requires-Dist: google-auth-oauthlib>=1.0
Requires-Dist: google-auth>=2.0
Requires-Dist: httpx>=0.27
Requires-Dist: python-dotenv>=1.0
Requires-Dist: typer>=0.12
Provides-Extra: all
Requires-Dist: anthropic>=0.40; extra == 'all'
Requires-Dist: mcp>=1.0; extra == 'all'
Provides-Extra: anthropic
Requires-Dist: anthropic>=0.40; extra == 'anthropic'
Provides-Extra: dev
Requires-Dist: build>=1.0; extra == 'dev'
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
Requires-Dist: pytest-mock>=3.0; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Requires-Dist: ruff>=0.4; extra == 'dev'
Requires-Dist: twine>=5.0; extra == 'dev'
Provides-Extra: mcp
Requires-Dist: mcp>=1.0; extra == 'mcp'
Description-Content-Type: text/markdown

# inbox-to-action

[![PyPI version](https://img.shields.io/pypi/v/inbox-to-action)](https://pypi.org/project/inbox-to-action/)
[![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue)](https://www.python.org/)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
[![GitHub stars](https://img.shields.io/github/stars/tarunlnmiit/inbox-to-action?style=social)](https://github.com/tarunlnmiit/inbox-to-action)

Published on [PyPI](https://pypi.org/project/inbox-to-action/). MCP-registry manifests
(`server.json` for the [Official MCP Registry](https://registry.modelcontextprotocol.io),
`smithery.yaml` for [Smithery](https://smithery.ai), `glama.json` for [Glama](https://glama.ai))
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

```bash
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/](docs/README.md)** — [install](docs/01-install.md) · [providers](docs/02-providers.md) · [Gmail OAuth](docs/03-gmail-oauth.md) · [multi-account](docs/04-multi-account.md) · [integrations](docs/05-integrations.md) · [MCP & Skill](docs/06-mcp-and-skill.md) · [config](docs/07-config-and-triage.md) · [troubleshooting](docs/08-troubleshooting.md) · [testing checklist](docs/09-testing-checklist.md). Quick version: [SETUP.md](SETUP.md).

<p align="center">
  <img src="docs/demo.gif" alt="inbox-to-action — one command triages the inbox into a report, drafts, and tasks" width="820">
</p>

---

## 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.

```mermaid
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)

```bash
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):**
```bash
PROVIDER=claude inbox-to-action run --mock     # no API key; needs `claude` on PATH
```

**Option B — Ollama (truly keyless, fully local):**
```bash
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):**
```bash
# 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

```bash
# 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.

```bash
# 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).

```json
{
  "accounts": [
    { "id": "personal", "kind": "gmail", "label": "Personal Gmail" },
    { "id": "work",     "kind": "gmail", "label": "Workspace" }
  ]
}
```

```bash
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.

```bash
# 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](https://glama.ai)) 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**:

```bash
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. `field` ∈ `sender | subject | body | any`.
- **`triage_instructions`** — freeform guidance injected into the classifier prompt for
  nuance the model interprets.

```json
{
  "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" }
  ]
}
```

```bash
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

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

## Docs

- **[docs/](docs/README.md)** — full guides with screenshots: install, every LLM provider, Gmail OAuth, multi-account, integrations, MCP & Skill, config, troubleshooting, testing checklist.
- [SETUP.md](SETUP.md) — 5-minute quickstart.
- [CONTRIBUTING.md](CONTRIBUTING.md) — dev setup + the never-send rule.
- [CLAUDE.md](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](LICENSE).
