Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ Four artifacts, one architecture. The three Node workspaces below are private an

| Artifact | What | Where |
|---|---|---|
| `thunderbird-cli` | `tb` CLI (47 commands) | `cli/` → bin `tb` in `@odience-network/thunderbird-cli-enhanced` |
| `thunderbird-cli` | `tb` CLI (74 commands: mail, contacts, calendar, tasks, notes, skills, Fast Actions) | `cli/` → bin `tb` in `@odience-network/thunderbird-cli-enhanced` |
| `thunderbird-cli-bridge` | Stateless HTTP↔WS proxy daemon | `bridge/` → bin `tb-bridge` in `@odience-network/thunderbird-cli-enhanced` |
| `thunderbird-cli-mcp` | MCP server (16 tools for Claude Desktop) | `mcp/` → bin `tb-mcp` in `@odience-network/thunderbird-cli-enhanced` |
| `thunderbird-cli-mcp` | MCP server (42 tools for Claude Desktop) | `mcp/` → bin `tb-mcp` in `@odience-network/thunderbird-cli-enhanced` |
| Thunderbird WebExtension | WS client inside Thunderbird | `extension/` → Mozilla-signed (unlisted) XPI in `dist/releases/` |

```
Expand All @@ -27,8 +27,8 @@ Everything localhost-only. Thunderbird holds credentials; no creds pass through

```bash
npm install # installs workspace deps for cli/, bridge/, mcp/
npm test # 46 CLI/bridge integration tests
npm run test:mcp # 34 MCP server tests
npm test # CLI/bridge integration tests
npm run test:mcp # MCP server tests
npm run bridge # start bridge (needed for live tests; not for unit tests)
```

Expand All @@ -42,7 +42,7 @@ Node 20+ required. All three packages are ES modules (`"type": "module"`).
- **CLI framework:** `commander.js`. Command definitions in `cli/src/cli.js`; HTTP client + formatters in `cli/src/client.js`.
- **Bridge:** vanilla Node `http` + `ws`. Zero business logic — it's a UUID-correlated proxy. Don't add state.
- **MCP server:** `@modelcontextprotocol/sdk`. Stdio transport. Reuses `cli/src/client.js` — don't re-implement the HTTP client in `mcp/`.
- **Extension:** pure WebExtension (`manifest_version: 2`). No Experiment APIs. Compatible with Thunderbird 128+.
- **Extension:** WebExtension (`manifest_version: 2`) on `messenger.*`, plus three vendored Experiment APIs (`calendar_calendars`, `calendar_items`, `calendar_tasks`) for calendar and tasks only — don't add more without discussing, each one forces ATN manual review. Compatible with Thunderbird 128.0 – 156.* (`strict_max_version` is required with Experiment APIs).

### Output format

Expand All @@ -53,7 +53,7 @@ By default every command outputs atomic JSON (`--output-version 2` / `TB_OUTPUT_
{ "ok": false, "error": "message", "code": "ERROR_CODE" }
```

Error codes: `BRIDGE_UNREACHABLE`, `EXTENSION_DISCONNECTED`, `AUTH_REQUIRED`, `FORBIDDEN`, `TIMEOUT`, `NOT_FOUND`, `INVALID_ARGS`, `THUNDERBIRD_ERROR`, `EVENT_TIMEOUT`, `RECONNECT_TIMEOUT`. Don't invent new ones — pick an existing one or extend the union intentionally.
Error codes: `BRIDGE_UNREACHABLE`, `EXTENSION_DISCONNECTED`, `AUTH_REQUIRED`, `FORBIDDEN`, `TIMEOUT`, `NOT_FOUND`, `INVALID_ARGS`, `THUNDERBIRD_ERROR`, `EVENT_TIMEOUT`, `RECONNECT_TIMEOUT`, plus `NO_ENGINE` / `ENGINE_FAILED` for `tb notes transcribe`. Don't invent new ones — pick an existing one or extend the union intentionally.

### Safety defaults (NEVER weaken)

Expand Down Expand Up @@ -128,7 +128,7 @@ Tagging `vX.Y.Z` fires `.github/workflows/release.yml`:
3. Finds the signed XPI in `dist/releases/` (must be checked in)
4. Creates the GitHub Release with both XPIs attached

The signed XPI itself comes from `.github/workflows/sign-xpi.yml`: bumping `version` in `extension/manifest.json` on `main` runs `npm run verify`, signs through the addons.thunderbird.net API (`npm run sign:xpi`, secrets `MOZILLA_HUB_JWT_ISSUER` / `MOZILLA_HUB_JWT_SECRET`) and commits `dist/releases/<name>-<version>-tb.xpi`. Tag after that commit lands.
The signed XPI itself comes from `.github/workflows/sign-xpi.yml`: bumping `version` in `extension/manifest.json` on `main` runs `npm run verify`, signs through the addons.thunderbird.net API (`npm run sign:xpi`, secrets `MOZILLA_HUB_JWT_ISSUER` / `MOZILLA_HUB_JWT_SECRET`) and commits `dist/releases/<name>-<version>-tb.xpi`. Tag after that commit lands. `release.yml` attaches whichever signed XPI is newest in `dist/releases/`, so while ATN's manual review is pending (as for 2.4.0 at v1.3.0) a release ships the older signed build next to the unsigned current one — say so in the release notes.

npm publish is manual (`cd cli && npm publish`) — intentionally, so a release tag without publish is a no-op you can recover from.

Expand All @@ -139,7 +139,7 @@ npm publish is manual (`cd cli && npm publish`) — intentionally, so a release
| `SPEC.md` | Full technical specification — source of truth for tool surface |
| `SECURITY.md` | Threat model, CLI defenses, agent patterns |
| `docs/SETUP.md` | User install guide |
| `docs/COMMANDS.md` | All 43 CLI commands reference |
| `docs/COMMANDS.md` | All 74 CLI commands reference |
| `docs/CLAUDE.md` | Claude Code–focused CLI quick-ref (end-user oriented) |
| `docs/distribution-log.md` | Launch venue submission tracker |
| `skills/thunderbird-cli/SKILL.md` | End-user Claude skill (separate from this file) |
Expand All @@ -152,7 +152,7 @@ Don't propose these without discussing first:
- **Server-side filtering logic.** Thunderbird is source of truth; we don't reimplement IMAP filter semantics.
- **Cloud deployment.** Bridge is localhost-only by design. No remote auth, no TLS, no tunnels.
- **New credential flow.** We never touch user email credentials. If a feature needs OAuth, it doesn't belong here.
- **Breaking the CLI ↔ MCP symmetry.** CLI is the superset (38 cmds); MCP is the curated 12-tool subset. When adding a bulk op, CLI-only is the correct choice — don't expose it as an MCP tool unless it's individually-scoped.
- **Breaking the CLI ↔ MCP symmetry.** CLI is the superset (74 cmds); MCP is the curated 42-tool subset. When adding a bulk op, CLI-only is the correct choice — don't expose it as an MCP tool unless it's individually-scoped.

## Questions / weirdness

Expand Down
6 changes: 3 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ Needs add-on 2.4.0 for the calendar, task and Fast Actions commands. Until ATN f

### Added
- Calendars and events: `tb calendar list|events|create|update|delete|clashes` and MCP `calendar_list`/`calendar_events`/`calendar_event_create`/`calendar_event_update`/`calendar_event_delete`/`calendar_clashes`, backed by vendored `calendar_calendars` and events-only `calendar_items` Experiment APIs (see [docs/decisions/calendar-backend.md](docs/decisions/calendar-backend.md)). Clash detection across calendars is a pure function (`extension/src/calendar-clash.js`). Writes are gated by `calendarWrite`. (ODIAA-2328)
- Tasks: `tb tasks list|create|update` and MCP `task_list`/`task_create`/`task_update` through a vendored `calendar_tasks` Experiment API, with writes gated by `tasksWrite`. `tb action-items <messageId>` turns an email body into a Markdown checklist with a deterministic (no LLM) extractor. (ODIAA-2329)
- Tasks: `tb tasks list|create|update` and MCP `task_list`/`task_create`/`task_update` through a vendored `calendar_tasks` Experiment API, with writes gated by `tasksWrite`. `tb action-items <messageId>` (MCP `email_action_items`) turns an email body into a Markdown checklist with a deterministic (no LLM) extractor. (ODIAA-2329)
- Deterministic skills: `tb today`/`week`/`clashes`/`from` and MCP `skill_today`/`skill_week`/`skill_clashes`/`skill_from` render compact Markdown from existing read-only endpoints; CLI and MCP output are byte-identical. (ODIAA-2332)
- Fast Actions: one-click Email → Note / Task / Event / Contact (`tb email-to-note`/`email-to-task`/`email-to-event`/`email-to-contact`, matching MCP tools, and context-menu items in Thunderbird's message list/display). `email-to-event` uses a new deterministic (no LLM) date/time/location parser (`extension/src/email-event-parse.js`) and falls back to a tentative draft event when it can't detect one. `email-to-contact` dedupes by sender email. Two new ungated routes (`GET /addressbooks`, `POST /messages/:id/event-draft`); no new access switch — writes are gated by the existing `tasksWrite`/`calendarWrite`/`contactsWrite` switches. (ODIAA-2333)
- Fast Actions: one-click Email → Note / Task / Event / Contact (`tb email-to-note`/`email-to-task`/`email-to-event`/`email-to-contact`, matching MCP tools, and context-menu items in Thunderbird's message list/display). "Save to Notes" hands the message to a waiting `tb notes listen` / MCP `notes_listen_once`, and `tb address-books` / MCP `address_book_list` lists the address books `email-to-contact` can write to. `email-to-event` uses a new deterministic (no LLM) date/time/location parser (`extension/src/email-event-parse.js`) and falls back to a tentative draft event when it can't detect one. `email-to-contact` dedupes by sender email. Two new ungated routes (`GET /addressbooks`, `POST /messages/:id/event-draft`); no new access switch — writes are gated by the existing `tasksWrite`/`calendarWrite`/`contactsWrite` switches. (ODIAA-2333)
- **`tb notes transcribe <audioFile>`** / MCP `note_transcribe` — voice memo transcription into
Notes. Local-first: at runtime it detects a locally-installed speech-to-text engine —
[whisper.cpp](https://github.com/ggml-org/whisper.cpp) (`whisper-cli` on PATH, or
Expand All @@ -33,7 +33,7 @@ Needs add-on 2.4.0 for the calendar, task and Fast Actions commands. Until ATN f
stubbed engine (`test/fixtures/stub-*.mjs`). (ODIAA-2331)

### Changed
- Extension 2.4.0 declares `strict_max_version: "155.*"`. ATN requires a max version for any add-on with Experiment APIs, so each new Thunderbird major needs a manifest bump and re-signing. Signing also waits for ATN's manual review.
- Extension 2.4.0 declares `strict_max_version: "156.*"`. ATN requires a max version for any add-on with Experiment APIs, so each new Thunderbird major needs a manifest bump and re-signing. Signing also waits for ATN's manual review.
- Release and sign-xpi workflows build on Node 22 (was Node 20, past end of life). The package still declares `engines.node >= 18`.

## [1.2.1] — 2026-09-27
Expand Down
12 changes: 7 additions & 5 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ thunderbird-cli-enhanced/

The four runtime components are intentionally separated:

- **extension** — runs inside Thunderbird, calls `messenger.*` APIs, talks to bridge over WebSocket
- **extension** — runs inside Thunderbird, calls `messenger.*` APIs (plus vendored calendar/task Experiment APIs), talks to bridge over WebSocket
- **bridge** — stateless HTTP↔WS proxy, no business logic
- **cli** — thin HTTP client, parses args, formats JSON output
- **mcp** — MCP server, exposes 16 curated tools to Claude Desktop and other MCP clients
- **cli** — thin HTTP client, parses args, formats JSON output (74 commands; the notes workspace and local transcription run in `cli/` itself)
- **mcp** — MCP server, exposes 42 curated tools to Claude Desktop and other MCP clients

## Local development

Expand Down Expand Up @@ -52,11 +52,13 @@ node cli/src/cli.js stats
npm test # CLI/bridge integration (mock bridge)
npm run test:bridge-auth # bridge TB_AUTH_TOKEN enforcement (real bridge process)
npm run test:bridge-security # bridge browser-origin defenses (real bridge process)
npm run test:extension # background script, thread utils, access policy (mocked messenger API)
npm run test:extension # background script, thread utils, access policy, action items, calendar clashes (mocked messenger API)
npm run test:sign # XPI signing script (mock ATN API)
npm run test:docs # docs/COMMANDS.md and README match `tb --help`; diagrams are complete
npm run test:notes # notes workspace and transcription (stubbed STT engine)
npm run test:skills # deterministic skills (today/week/clashes/from)
npm run test:mcp # MCP server integration (spawns server)
npm run test:all # all of the above + MCP concurrency
npm run test:all # all of the above + MCP concurrency + npm pack check
npm run verify # everything CI runs: build XPI, lint, all test suites
```

Expand Down
Loading
Loading