← All Skills

snappy-gmail

v1.0.0
30 files, 221.9 KB ~1,933 words · 8 min read Updated 2026-09-09

snappy-gmail skill

49 of 55 checks pass
covers 7 of 79 operations of Google, checked 2026-09-09
What it can do
list limit? query?read
get message-id format?read
thread thread-id source?read
draft to subject text thread-id?draft
reply thread-id textsend
send to subject textsend
archive idswrite
What does not pass yet
$ npx snappy-skills install snappy-gmail
zip ↓
File Tree
├── AGENTS.md ├── SKILL.md ├── api.ts ├── face.test.ts ├── faces/ │ ├── components/ │ │ ├── gmail-bulk.css │ │ ├── gmail-bulk.tsx │ │ ├── gmail-decision.css │ │ ├── gmail-decision.tsx │ │ ├── gmail-face.css │ │ ├── gmail-face.tsx │ │ ├── gmail-inbox-list.css │ │ ├── gmail-inbox-list.tsx │ │ ├── gmail-message.css │ │ ├── gmail-message.tsx │ │ ├── gmail-reply.css │ │ ├── gmail-reply.tsx │ │ ├── gmail-thread.css │ │ └── gmail-thread.tsx │ ├── family.tsx │ └── fixtures/ │ ├── gmail-bulk-change.json │ ├── gmail-decision.json │ ├── gmail-draft.json │ ├── gmail-list.json │ ├── gmail-message.json │ ├── gmail-reply.json │ └── gmail-thread.json ├── html-text.test.ts ├── package-lock.json ├── package.json └── refusals.test.ts
Documents
AGENTS.md

snappy-gmail -- Agent Loader#

typescriptimport { listMessages, gmailMessage, gmailThread, gmailDraft } from "../snappy-gmail/api.ts";

Rules:

  1. Reads and drafts go straight to Gmail over fetch, with a Bearer token minted at call time from GMAIL_PERSONAL_REFRESH_TOKEN + GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRET. Do not route them through a Snappy connector door, and do not look for a press binary or a local mirror: both are gone (2026-09-08).
  2. Never send with sendNow or the raw API. Run the send verb WITHOUT --now; it stages through /hands/stage, a person decides, and the receipt is the proof. --now is the daemon's word after that decision.
  3. "Newest" means listMessages order (Gmail's own, newest first). Quote the coverage sentence the skill returns verbatim; never say "of N" from your own count.
  4. Every answer carries account, account_source and token_road -- name the mailbox you read AND whose credential read it. A null account means no Google credential on this Mac minted a token; hand that to the owner once, with account_gap verbatim, and do not retry in a loop.
  5. token_road: "service-account" means the personal grant did not mint and the hand fell to delegation -- a working read and a fact the owner is owed. Quote token_road_note when you report it; never present it as the personal mailbox.
  6. --json ON A READ IS THE FACE'S OBJECT, not the hand's envelope. list --json prints gmail-list, get --json prints gmail-message (and asks Gmail for format=full, because that face requires the letter's body), thread --json prints gmail-thread. Each carries kind, and its other keys ARE the face's props. Draw one with npx tsx ~/.claude/skills/snappy-faces/api.ts draw <kind> --data-file <file>. WITHOUT --json you get the hand's own answer, which is where id, threadId, coverage and the account words live -- use that when you need handles to go on with.

Show produced work with snappy-faces: call draw for image channels or lang for MCP Apps.

<!-- SKILL-INDEX-START -->

[snappy-gmail Index]|root: ~/.claude/skills/snappy-gmail|IMPORTANT: Prefer these files over pre-training assumptions for this domain. Read the relevant file when the AGENTS.md summary is insufficient.|root:{SKILL.md}

<!-- SKILL-INDEX-END -->

Used by#

Nothing in the collection names this skill.

<!-- SNAPPY-CONTRACT-VERBS-START -->

Contract verbs#

Generated from api.ts HAND_CONTRACT. Do not hand-edit this block.

Verb Contract arguments Effect First call
list limit?, query? read npx tsx ~/.claude/skills/snappy-gmail/api.ts list
get message-id, format? read npx tsx ~/.claude/skills/snappy-gmail/api.ts get <message-id>
thread thread-id, source? read npx tsx ~/.claude/skills/snappy-gmail/api.ts thread <thread-id>
draft to, subject, text, thread-id? draft npx tsx ~/.claude/skills/snappy-gmail/api.ts draft <to> "<subject>" "<text>"
reply thread-id, text send npx tsx ~/.claude/skills/snappy-gmail/api.ts reply <thread-id> "<text>"
send to, subject, text send npx tsx ~/.claude/skills/snappy-gmail/api.ts send <to> "<subject>" "<text>"
archive ids write npx tsx ~/.claude/skills/snappy-gmail/api.ts archive '["<ids>"]'

Show the result#

When an answer carries face_hint, show it with one snappy_present(<answer>) call.

See /snappy-faces for face selection. Human-facing images must crop to the

element, render at 2x on Retina, and fill the destination channel instead of

placing a small card in a full-page screenshot.

<!-- SNAPPY-CONTRACT-VERBS-END -->

---
name: snappy-gmail
role: Gmail hands for an agent on this machine -- read and draft straight from Gmail's REST API with a token minted from this machine's refresh token; send only through the Snappy stage door.
loaded-by: the Skill tool / a room's skills folder
---

# snappy-gmail -- Agent Loader

```typescript
import { listMessages, gmailMessage, gmailThread, gmailDraft } from "../snappy-gmail/api.ts";
```

Rules:
1. Reads and drafts go straight to Gmail over `fetch`, with a Bearer token minted at call time from `GMAIL_PERSONAL_REFRESH_TOKEN` + `GOOGLE_CLIENT_ID`/`GOOGLE_CLIENT_SECRET`. Do not route them through a Snappy connector door, and do not look for a press binary or a local mirror: both are gone (2026-09-08).
2. Never send with `sendNow` or the raw API. Run the `send` verb WITHOUT `--now`; it stages through `/hands/stage`, a person decides, and the receipt is the proof. `--now` is the daemon's word after that decision.
3. "Newest" means `listMessages` order (Gmail's own, newest first). Quote the `coverage` sentence the skill returns verbatim; never say "of N" from your own count.
4. Every answer carries `account`, `account_source` and `token_road` -- name the mailbox you read AND whose credential read it. A null `account` means no Google credential on this Mac minted a token; hand that to the owner once, with `account_gap` verbatim, and do not retry in a loop.
5. `token_road: "service-account"` means the personal grant did not mint and the hand fell to delegation -- a working read and a fact the owner is owed. Quote `token_road_note` when you report it; never present it as the personal mailbox.
6. `--json` ON A READ IS THE FACE'S OBJECT, not the hand's envelope. `list --json` prints `gmail-list`, `get --json` prints `gmail-message` (and asks Gmail for `format=full`, because that face requires the letter's body), `thread --json` prints `gmail-thread`. Each carries `kind`, and its other keys ARE the face's props. Draw one with `npx tsx ~/.claude/skills/snappy-faces/api.ts draw <kind> --data-file <file>`. WITHOUT `--json` you get the hand's own answer, which is where `id`, `threadId`, `coverage` and the account words live -- use that when you need handles to go on with.

Show produced work with `snappy-faces`: call `draw` for image channels or `lang` for MCP Apps.

<!-- SKILL-INDEX-START -->
[snappy-gmail Index]|root: ~/.claude/skills/snappy-gmail|IMPORTANT: Prefer these files over pre-training assumptions for this domain. Read the relevant file when the AGENTS.md summary is insufficient.|root:{SKILL.md}
<!-- SKILL-INDEX-END -->

## Used by

Nothing in the collection names this skill.

<!-- SNAPPY-CONTRACT-VERBS-START -->
## Contract verbs

Generated from `api.ts` `HAND_CONTRACT`. Do not hand-edit this block.

| Verb | Contract arguments | Effect | First call |
|---|---|---|---|
| `list` | `limit?`, `query?` | `read` | `npx tsx ~/.claude/skills/snappy-gmail/api.ts list` |
| `get` | `message-id`, `format?` | `read` | `npx tsx ~/.claude/skills/snappy-gmail/api.ts get <message-id>` |
| `thread` | `thread-id`, `source?` | `read` | `npx tsx ~/.claude/skills/snappy-gmail/api.ts thread <thread-id>` |
| `draft` | `to`, `subject`, `text`, `thread-id?` | `draft` | `npx tsx ~/.claude/skills/snappy-gmail/api.ts draft <to> "<subject>" "<text>"` |
| `reply` | `thread-id`, `text` | `send` | `npx tsx ~/.claude/skills/snappy-gmail/api.ts reply <thread-id> "<text>"` |
| `send` | `to`, `subject`, `text` | `send` | `npx tsx ~/.claude/skills/snappy-gmail/api.ts send <to> "<subject>" "<text>"` |
| `archive` | `ids` | `write` | `npx tsx ~/.claude/skills/snappy-gmail/api.ts archive '["<ids>"]'` |

## Show the result

When an answer carries `face_hint`, show it with one `snappy_present(<answer>)` call.
See `/snappy-faces` for face selection. Human-facing images must crop to the
element, render at 2x on Retina, and fill the destination channel instead of
placing a small card in a full-page screenshot.
<!-- SNAPPY-CONTRACT-VERBS-END -->

Keyboard Shortcuts

Search in document⌘K
Focus search/
Previous file tab
Next file tab
Close overlayEsc
Show shortcuts?