Documentation

Letterknife docs

Everything you need to install, understand, and run Letterknife — the local-first communications agent that lives on your machine and runs on your own Claude subscription. It's all on this one page: use the sidebar (or the menu above on mobile) to jump between sections.

What Letterknife is

Letterknife is an AI assistant that runs on your own computer and works your communications: it triages your Gmail, drafts replies in your voice, turns threads into tasks, chases follow-ups, and hands you a plan every morning. Email is one channel — Slack conversations (optional) and your Google Calendar feed the same tasks and the same plan, and WhatsApp is planned. It learns your preferences from one-line corrections — no filters to write, no setup interview.

Two architectural choices set it apart:

  • Your mail never leaves your machine. Letterknife talks to Gmail directly from your computer. There are no Letterknife servers holding your email — nothing of yours exists anywhere else to leak, mine, or train on.
  • The AI is your own Claude subscription. Letterknife orchestrates the Claude Code CLI you already have installed and logged in. No API keys to buy, no token markup, no third-party inference servers. The memory core — the part that distills your corrections into durable rules — runs on Opus, Anthropic's smartest model.

Start with Getting started to install, or read How it works first if you want the architecture in plain words. The trust model — scoped knowledge, consent gates, what an impersonator gets — is in Security. Privacy, cost, and troubleshooting live in the FAQ — still stuck after that, email hello@letterknife.com.

Getting started

From download to a working agent in about 10 minutes. Letterknife runs entirely on your machine — the setup is: install, tell it who you are, connect Gmail, hand the tools to Claude, start.

Prerequisites

  1. A Claude subscription (Pro or Max). Letterknife's AI runs through your own Claude Code — get a subscription at claude.com/pricing if you don't have one.
  2. Claude Code CLI, installed and logged in:
    npm install -g @anthropic-ai/claude-code
    claude   # opens browser login — sign in with your Claude account, then exit with Ctrl+C
  3. Node.js 20+ — check with node -v, install from nodejs.org if missing.
  4. A Gmail account (Gmail and Google Workspace are supported today).

1. Install

On a Mac, download the app and drag it to Applications. It carries everything it needs — no Node install, no repo, no npm install. The first launch asks who you are and you're done; skip to step 3.

Running from source instead (any platform, or if you want to hack on it) — you'll need Node 20+:

cd letterknife
npm install

2. Tell it who you are

The app asks this on first launch. From source, do it by hand:

cp owner.json.template owner.json

Edit owner.json: your full name, first name, and every email address that is you. This matters — the assistant must never treat your own messages as someone else's ask, so list all your aliases and secondary addresses.

Your owner.json values (addresses, team domains) are generated live into every prompt — no need to restate them anywhere. To tell the agent who you are and what you work on, add a couple of lines via Settings → Foundation once it's running: that's the hand-edit surface for the agent's knowledge base. (On first boot, a config.md and any memory/*.md files you have seed the knowledge base automatically.) Everything else it learns by itself.

3. Connect Gmail

Letterknife authenticates with Google using an OAuth Desktop client and stores the resulting token locally in tokens.json — access stays between your machine and Google. The client credentials live in credentials.json next to package.json:

  • If your download includes a credentials.json (or you received one with it), you're set — skip to running the auth script.
  • Otherwise, create your own (a few minutes, free): go to console.cloud.google.com → APIs & Services → Credentials → Create OAuth client ID → Desktop app, download the JSON, and save it as credentials.json next to package.json. Also enable the Gmail API and Calendar API for that project.

Then run the auth flow:

node scripts/auth.js

Open the printed URL in your browser and approve. Letterknife asks for Gmail (read/modify), Calendar events, and — optionally — read-only Contacts (saved people are never auto-flagged as spam; the app works fully without it).

If you created your own OAuth client, Google may show a "Google hasn't verified this app" warning — that's your own personal client it hasn't reviewed, not someone else's app. Click Advanced → Continue to proceed. You can revoke access at any time at myaccount.google.com/permissions.

4. Give Claude the Letterknife tools

One-time step — registers the email tools with your Claude Code. Run it from inside the Letterknife folder (the same place you ran npm install):

claude mcp add --scope user letterknife -- node "$PWD/mcp-server.js"

5. Start it

node task-ui.js

Open http://localhost:3007 in your browser. Keep the terminal running — Ctrl+C stops the agent.

6. First run: Learning mode

Click the Learn button in the topbar. Letterknife shows you one real email at a time and asks how you'd handle that sender — Important, Learn from, or Not important. Correct it freely in plain words; every correction becomes a durable rule, exceptions included. After a few dozen slides it starts getting them right, and the agent works from those rules from then on.

Nothing sends without you. The assistant only creates drafts; sending needs your explicit OK. See Settings for the per-action toggles.

How it works

The whole system runs on your computer. Understanding the three moving parts makes everything else in these docs obvious.

The three parts

  • A local Node app + your browser. node task-ui.js starts a small server bound to 127.0.0.1:3007 — the cockpit you open in your browser. Tasks, the daily plan, learning mode, settings: it's all served locally, to you only.
  • Your own Claude Code CLI. When the agent needs intelligence — triaging a sender, drafting a reply, building the plan — Letterknife spawns the Claude Code CLI you already have installed and logged in. Your subscription, your machine. No API keys, no third-party inference servers, no token markup.
  • An MCP server that exposes the inbox as tools.mcp-server.js gives Claude a toolbox — read email, manage tasks, touch the calendar, draft and (with consent) send replies. Claude never talks to Gmail directly; every action goes through a named tool with defined behavior and its own safety gate. The full list is in the tool reference.

Where your data lives

Your mail stays in Gmail — Letterknife reads it over Google's API from your machine and never uploads it anywhere. Everything the agent produces locally — tasks, its knowledge base of learned rules and sender memory, settings — lives in a SQLite database inside the Letterknife folder, and the knowledge base is mirrored write-through to plain-text files in memory/ as a readable, git-friendly backup. You can read, edit, or delete any of it in the app; there is no black box and no cloud copy.

The only thing that leaves your machine is what any Claude Code session sends: the prompts and tool results exchanged with Anthropic through your own logged-in Claude Code CLI — the same trust relationship you already have when you use Claude Code in a terminal.

Triage, tasks, and the plan

On each scan the agent sweeps new mail — and Slack, if connected — applies the rules it has learned, and files every real conversation as a task with a status, the current ask, and a next step. Follow-ups are reconciled automatically: it notices when someone replied, when they didn't, and when you already answered directly in Gmail, so nothing is handled twice. Each morning it merges open tasks with your calendar into one prioritized plan with a visible time budget.

Learning mode: corrections become rules

There is no settings interview. The agent makes a call on a real email, you correct it in one plain-English line ("keep newsletters from this one", "always archive these"), and the correction is distilled into a durable rule in the agent's knowledge base — exceptions included, readable and editable in Settings. This distillation is the memory core, and it runs on Opus, Anthropic's smartest model, because getting a rule subtly wrong compounds forever. If Opus is momentarily unavailable on your plan, the run falls back to your selected model and tells you.

Nothing sends without you

The default posture is drafts only. The agent writes replies in your voice and leaves them as Gmail drafts or task recommendations; actually sending requires your explicit OK. Reversible triage actions (archive, label) run autonomously — that's the point of an agent — but each action category has its own toggle in Settings, so you decide exactly how long the leash is.

Usage-aware orchestration

Because the AI is your subscription, Letterknife budgets it like it budgets your time: the cockpit shows your live Claude session usage, big sweeps pause automatically before hitting the session limit, and work resumes when the limit resets. You'll never find your Claude plan silently drained by a background job.

Tool reference

The MCP server (mcp-server.js) exposes 36 tools to your Claude. This is the complete list — every capability the agent has, and the safety gate on each one.

Four kinds of gates apply across the toolbox:

  • Scope-gated — knowledge about an organization or a person is disclosed only when a verified sender from that org, or that person, is in the conversation. Enforced in code, off verified addresses — see Security.
  • Consent-gated — sending-class actions (send, forward, unsubscribe, calendar deletes) only run after your explicit OK, or when you've switched training mode off for autonomous operation.
  • Settings-toggled — each Gmail action category (draft, send, forward, trash, archive, label, unsubscribe) has an on/off switch in Settings that only ever restricts. See Settings.
  • Reversible by design — archive keeps mail searchable, trash is recoverable for 30 days, and spam verdicts have an explicit undo.

📥Email

Reading, triaging, and (with consent) replying — the core of the toolbox.

scan_inbox

Lists inbox messages — sender, subject, snippet, date, labels — scoped by a Gmail search query (e.g. "is:unread", "from:acme.com", "has:attachment").

read_email

Full headers, plaintext body, and attachment list for one message by id.

get_thread

Loads every message in a conversation, oldest to newest — the way the agent sees full context before drafting a reply or deciding anything.

read_attachment

Fetches one attachment so the agent can actually look at it. Images come back inline-readable; PDFs and other types open in Gmail web instead.

draft_reply

Creates a draft reply in the thread, written in your voice and register. Deduplicates: if a draft already exists on the thread it is reused, not duplicated.

Never sends — this is the safe default. You review the draft in Gmail or the cockpit before anything goes out.

send_reply

Sends a reply in the thread immediately, replying to all by default.

Requires your explicit OK — the agent is instructed to prefer draft_reply whenever it is unsure, and typed conversation never counts as permission.

forward_email

Forwards an email to new recipients with original attachments preserved, plus an optional short intro note — for looping someone in without summarizing.

Sends immediately; gated by the forward settings toggle and the same consent rules as sending.

compose_email

Starts a brand-new outbound email (fresh thread) written in your voice, and files a follow-up task on the new thread so the reply folds back in.

Defaults to a Gmail draft for your review; sending immediately requires your explicit OK, exactly like send_reply.

archive_emails

Archives messages — removes them from the inbox but keeps them searchable in Gmail.

Reversible. Gated by the archive settings toggle.

label_emails

Applies a label to messages, creating the label if it does not exist yet.

Gated by the label settings toggle.

trash_emails

Moves messages to Trash. Not a permanent delete — Gmail keeps trashed mail recoverable for 30 days.

Gated by the trash settings toggle.

flag_spam

Records a durable spam verdict for a sender address (or, for wholly-junk domains, a whole domain) so future mail from it is auto-handled without re-judging.

Domain scope is reserved for entirely junk domains, never shared ones. Senders in your saved Google Contacts are guarded from being flagged.

unflag_spam

The undo for flag_spam — removes a spam verdict and puts the sender back on the normal judged path.

unsubscribe

Deterministically unsubscribes from a bulk sender using the message's List-Unsubscribe header — RFC 8058 one-click, mailto, or a web link handed to you. Code parses the link; no LLM guessing.

Consent-gated like sending, and separately gated by the unsubscribe settings toggle.

purge_sender

Bulk-archives every inbox message from one sender — clears thousands in one call, with an exclude list to keep specific mail (e.g. your own communities on a shared notification address).

Archive only — reversible and searchable, never a delete. Gated by the archive settings toggle.

reconcile_replies

Detects open tasks where you already replied directly in Gmail and folds your reply into the task — so the agent never re-handles something you answered yourself.

sender_digest

Deep-samples a high-volume sender — the last ~100 messages in both directions plus reply history and unsubscribe signals — so the agent can genuinely understand a sender before bucketing them.

🗓Calendar

Read and manage events on your Google Calendar via the same Google grant.

list_calendar_events

Lists events in a time window (default: the next 7 days) with attendees and organizer — what the daily plan builds on.

create_calendar_event

Creates an event — all-day or timed, with optional attendees and location.

Attendees are not emailed unless the agent explicitly sets notify.

update_calendar_event

Edits an existing event — partial update, only the fields passed change.

Attendees are not emailed unless notify is set.

delete_calendar_event

Deletes an event by id — the general-purpose delete.

Consent-gated. Attendees are not notified unless notify is set.

remove_calendar_event

The calendar-spam variant: removes a fake "order / membership / invoice" invite injected via a scam email, and trashes the notification email with it.

Consent-gated; only used after the email is judged spam — never on legitimate invites.

Tasks

Every real conversation becomes a task with a status (open, waiting, closed), the current ask, and a next step. Tasks group into your projects — name, optional working folder, keyword auto-match.

add_task

Adds a task derived from an email or Slack thread. Idempotent per thread — a follow-up in the same conversation updates the existing task (and reopens it if needed) instead of duplicating.

list_tasks

Lists tracked tasks, filterable by status, contact, participant, or person name — how the agent finds an existing task before creating a new one.

update_task

Updates a task: mark done, park it as waiting (ball on the other side — it reopens by itself on their reply), change priority, assign a project, refresh the ask, append notes, or record your explicit send consent.

Send consent is only recorded from an explicit approval in your latest message — a question or new information never counts.

schedule_routine

Schedules a timed follow-up on a task ("chase in a week"): the task parks as waiting, and when the time comes its agent checks for a reply and drafts a nudge if the other side stayed quiet. Draft-only, like everything unattended.

🧠Memory & identity

The agent’s knowledge base — a structured store it curates itself. Entries are scoped by who they may be disclosed to: foundation knowledge loads into every run; facts about an organization or a person unlock only when a verified sender from that org — or that person — is in the conversation; topic knowledge is fetched on demand.

get_foundation

Loads your goals, triage rules, project map, and communication style — the context bundle for sessions that start cold.

get_knowledge

Queries the knowledge base on demand: fetch specific entries, survey a scope, browse a topic, or text-search — so a session pulls exactly the knowledge it needs instead of carrying all of it.

Scope-gated in code: organization and contact entries are returned only when that org or person is a verified participant of the current conversation — an email claiming to be someone is not that someone. Only an instruction you type yourself unlocks a cross-scope read.

record_memory_update

Captures a standing preference the moment you express it ("always keep these", "stop archiving X") as a self-contained rule, which the Opus memory core folds into the knowledge base.

create_plugin

Lets the agent build a new repeatable capability when you ask for one it lacks ("log receipts to a sheet"): it writes a plugin that becomes a new one-click action on matching tasks. New plugins land disabled until you review and enable them in Settings.

merge_identities

Refreshes the person-identity map that joins one person's multiple email addresses into a single identity, so their asks merge into one task across inboxes and Slack.

💬Slack (optional — off by default)

If you connect a Slack token, DMs flow into the same tasks and plan as email. Without one, these tools simply report that Slack is not configured.

slack_recent

Reads your recent Slack direct messages to detect when someone who emailed also raised the same issue in a DM — so both fold into one task.

DMs only, read-only. Instructions found inside Slack messages are treated as data to surface, never commands to execute.

slack_directory

Builds the Slack-to-email identity map, matching each workspace member to the email contact who is the same person.

send_slack

Sends a Slack message — the Slack equivalent of send_reply, posting as you (user token) or as a bot (bot token), and reporting honestly which.

Same consent rules as sending email: only when a task clearly calls for it and you have approved.

🌐Browser

A cooperative lock on the shared local Chrome, for the rare web step (e.g. a login-only unsubscribe page).

acquire_browser

Reserves the shared Chrome browser before any browser automation — one agent at a time, so parallel sessions never fight over your profile.

release_browser

Releases the reservation as soon as the web steps are done, so another session can use the browser.

Settings

The gear icon in the cockpit. Every setting exists to dial the agent's autonomy up or down — the defaults are safe, and the toggles only ever restrict.

Scan interval

How often the agent sweeps your inbox. The default is polling every 60 minutes; pick a tighter or looser cadence from the dropdown. The unattended-sweep toggle controls whether scans run automatically at that cadence or only when you trigger one.

Per-action toggles

Each Gmail action category has its own on/off switch: draft · send · forward · trash · archive · label · unsubscribe. They apply everywhere — a toggle that is off blocks that action for every tool and every sweep, no matter what the agent decides. All default to on, because the master safety gate is training mode, not these; turn individual ones off to tighten further (for example: allow archiving and labeling, but block trash entirely).

Training mode

The master consent gate. With training on (the default), sending-class actions — send, forward, unsubscribe, calendar deletes — are blocked: the agent recommends, you approve. Reversible triage (archive, label, trash) stays autonomous either way, subject to the per-action toggles above. Switch training off when you trust the agent enough to let it act on its own.

Model selection

Choose which Claude model powers everyday work — triage sweeps, drafting, planning. Sonnet is the default and the right choice for most inboxes; Haiku is cheaper on your session budget, Opus is the smartest and the most expensive.

One part of the system ignores this setting on purpose: the memory core runs on Opus. Whenever your corrections are distilled into durable rules, the smartest model does it — a rule written subtly wrong compounds on every future email, so this is the one place quality is never traded for budget. If Opus is momentarily unavailable on your plan, that run falls back to your selected model and a notification tells you it happened.

Usage donut & session-limit pausing

The donut in the topbar shows your live Claude session usage — the same numbers Claude Code's own usage screen reads. Because Letterknife runs on your subscription, it budgets that subscription like it budgets your time:

  • Before a big sweep, the cockpit estimates what fits in your remaining session budget and offers sized options.
  • Long-running sweeps pause automatically as they approach the session limit, and resume on their own when the limit resets — no lost work, and no surprise "you've hit your limit" in the middle of your own Claude session.
  • If usage is momentarily unreadable, the donut renders gray and the agent assumes conservatively.

The knowledge base

Settings also gives you direct access to the agent's memory. What it knows lives in a structured knowledge base (part of the local SQLite database) that the agent curates itself: when you correct it, the Opus memory core folds the correction in as an edit to the affected entries — deduplicated, contradictions resolved, stale rules retired.

Entries are scoped by who a fact may be disclosed to: foundation knowledge is general and safe for any conversation, so it is always available; facts about a known organization (your bank, your insurer — family counts as a group too) unlock only when a verified sender from that organization is in the conversation; facts about a known person unlock only when that person is verifiably present; and topic knowledge is fetched on demand. These gates are enforced in code, keyed off verified sender addresses — never off what an email claims. See Security for why this matters.

Settings → Foundation opens the editor: browse everything it has learned — rules, style, sender memory — and change or delete any entry; the next run uses whatever you saved. Every change is also mirrored write-through to plain-text files in the memory/ folder, a readable, git-friendly backup of the whole knowledge base.

Security

An assistant that knows your life is a target: the classic attack is an email that pretends to be someone you trust and asks the AI to act on what it knows. Letterknife's defenses are structural — enforced in code, not in instructions an email could argue with.

Scoped knowledge: it knows who it's talking to

The knowledge base is split into scopes by who a fact may be disclosed to:

  • Foundation — general knowledge safe for any conversation. Always available.
  • Organization — facts about a known organization: account details at your bank, procedures with your insurer. Unlocked only when a verified sender from that organization is in the conversation. Family counts as a group too.
  • Contact — facts about a known person. Unlocked only when that person is verifiably present in the conversation.

Concretely: an email pretending to be "your broker", sent from some random Gmail address, meets an assistant with no account numbers anywhere in its context — and no tool that will hand them over. The best it can do is draft "I'll check and get back to you." Mail from your real broker — or anyone at the real insurer's domain — gets the full picture automatically, with zero extra friction.

What makes this a guarantee rather than a guideline is where the gate lives. Which facts unlock is decided by code from the conversation's verified sender addresses — never from names, signatures, or claims in the email text. Gated facts are simply never injected into the AI's context, and the knowledge lookup tool refuses cross-scope reads, so the model can't be sweet-talked into fetching them: the unlock is set by the app when it starts the agent process, and the agent cannot change it. The only bypass is an instruction you type yourself.

Access follows the address, not the person's claim

Organization access is double-authed: the organization vouches for specific addresses, and only mail actually sent from one of them unlocks its facts. A person's linked personal address surfaces their own record — never an organization's. That asymmetry solves the departed-employee problem by itself: when a company terminates someone's work address, their access to that company's information ends with it. No revocation list to remember, nothing to clean up.

And organizations are never invented from mail. "I'm from your bank" — from any address — creates nothing. A new organization relationship requires real engagement from you (you actually replied to them) and a person who checks out at the claimed company. A different mail domain alone proves nothing either way — plenty of real companies send from one you wouldn't guess — but an "employee" who doesn't exist at the org is the classic impersonation tell, and it's checked before anything is created.

The learning side is fenced the same way: the agent can harvest a useful insight from any email into its reference knowledge, but that write path is restricted in code to adding inert, public-tier notes — a malicious email can never use it to touch your foundation, an organization's record, or a person's record.

The rest of the posture

The same principle — structural, not promissory — runs through everything else:

  • Local-first. Your mail never leaves your machine. There are no Letterknife servers holding your email, so there is nothing of yours anywhere else to breach.
  • Drafts by default. The agent writes replies and leaves them as drafts; actually sending is a separate, gated act.
  • Consent gates. Nothing sends without your explicit OK — and typed conversation never counts as permission, so an agent can't talk itself (or be talked) into a send.
  • Training mode. The master gate: while it's on, every sending-class action is blocked outright — the agent recommends, you approve.
  • Letterknife-only mode. An optional security mode that strips the agent down to Letterknife's own tools — no filesystem, no shell, no web — so even a malicious email that influenced a draft can never reach your files, your repos, or the wider internet.
  • No API keys in agent processes. Any Anthropic API key in your environment is stripped before an agent process starts: agents run only through your logged-in Claude subscription, and a key that isn't there can't be leaked or spent.

The per-action toggles that back this up are described in Settings; the gate on each individual tool is listed in the tool reference.

FAQ & troubleshooting

Privacy, cost, and the handful of things that most commonly need a second look during setup.

Privacy

Where does my data live?

On your machine, full stop. Your mail stays in Gmail; Letterknife reads it over Google's API from your computer. Everything the agent creates — tasks, its knowledge base of learned rules and sender memory, settings, the Google token — lives in a local SQLite database and plain-text backup files inside the Letterknife folder. There are no Letterknife servers holding any of it.

What leaves my machine?

Only what any Claude Code session sends: prompts and tool results exchanged with Anthropic through your own logged-in Claude Code CLI. That is the same data path you use when you run Claude Code in a terminal yourself — no third parties in between, and nothing flows through Letterknife's infrastructure.

How do I revoke Gmail access?

Go to myaccount.google.com/permissions and remove Letterknife (or your own OAuth client, if you created one). Locally, delete tokens.json from the Letterknife folder. Access is cut immediately.

Cost

What does the AI cost me?

Nothing beyond the Claude subscription you already have. Letterknife orchestrates your own Claude Code — there are no AI credits to buy from us and no token markup. The usage donut shows exactly how much of your session budget the agent is using, and big sweeps pause before they hit your limit.

Troubleshooting

Port 3007 is already in use

Another Letterknife (or something else) is on the port. Either stop it, or start on a different port:

# find what holds the port
lsof -i :3007

# or run Letterknife on another port
LETTERKNIFE_PORT=3008 node task-ui.js

Claude isn't logged in

If sweeps fail immediately or the usage donut stays gray, your Claude Code CLI session has likely expired. Run claude in a terminal, complete the browser login, then exit with Ctrl+C and retry.

The Letterknife tools are missing in Claude

If the agent reports it has no email tools, the MCP registration is missing or points at a moved folder. Re-run it from inside the Letterknife directory:

claude mcp add --scope user letterknife -- node "$PWD/mcp-server.js"

You can check what's registered with claude mcp list. If you moved or renamed the Letterknife folder, remove and re-add: claude mcp remove letterknife, then the add command above.

The Google sign-in fails or loops

Make sure credentials.json exists next to package.json and is a Desktop app OAuth client (not a Web client), and that the Gmail and Calendar APIs are enabled for its Google Cloud project. Then re-run node scripts/auth.js. See Getting started for the full flow.

How do I update Letterknife?

Download the latest release, replace the app files in your Letterknife folder (keep your data: owner.json, credentials.json, tokens.json, the SQLite database, and the memory/ folder), then run npm install and restart node task-ui.js. Your rules, tasks, and connections carry over.

Still stuck?

Email hello@letterknife.com with a screenshot and a short note — during the beta, everything you hit is signal we want.