← All Skills

snappy-ops

v1.0.0
40 files, 318.2 KB ~4,526 words · 19 min read Updated 2026-09-09

snappy-ops skill

39 of 47 checks pass
What it can do
ab recipewrite
actionsread
catchupread
dashboard skillread
diff-machineread
dispatchwrite
dry targetdraft
fingerprintread
ladderread
loops subcommand? name?write
menu provider-nameread
recipesread
+11 more
What does not pass yet
Architecture 3 endpoints⚗ parallel
🔑 Bearer token auth
GETPOST
snappy-agent-runtime.robertjboulos.workers.dev3 endpoints
POST/run/inbox-sweep
GET/run/inbox-sweep
GET/runs
Run the extended statusShow the agent registryThe operator menuShow the capability surfaceLet Robert drill
$ npx snappy-skills install snappy-ops
zip ↓
File Tree
├── AGENTS.md ├── SKILL.md ├── api.ts ├── data/ │ └── menu.json ├── entities.json ├── kernel.md ├── loops.json ├── loops.ts ├── operator.md ├── recipes/ │ ├── __fixtures__/ │ │ └── content-polish.json │ ├── _client-hand.ts │ ├── _deliver-probe.ts │ ├── _types.ts │ ├── ai-spend.ts │ ├── bug-triage.ts │ ├── catchup.ts │ ├── client-pulse.ts │ ├── commit-report.ts │ ├── commitment-audit.ts │ ├── content-mine.ts │ ├── content-polish.ts │ ├── doors.test.ts │ ├── dormant-ping.ts │ ├── image.ts │ ├── krisp-inbox.ts │ ├── meeting-followup.ts │ ├── morning-brief.ts │ ├── polish-digest.ts │ ├── ray-todo.ts │ ├── ray-update.ts │ ├── reconcile.ts │ ├── sweep.ts │ ├── testimonial-ask.ts │ └── tool-scout.ts ├── refusals.test.ts ├── registry.ts ├── scripts/ │ ├── loop-runner.sh │ └── recipe-lint.ts ├── staged-action.ts └── status.sh
Documents
AGENTS.md

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

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

[snappy-ops Index]|root: ~/.claude/skills/snappy-ops|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,kernel.md,operator.md}

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

snappy-ops — The Shell#

You are the front door of the Snappy operating system. Your only job is to route Robert into the right skill in under 5 seconds via interview mode.

The Protocol (execute this EVERY time this skill loads)#

Step 0 — Compute the interview payload. Run:

bashnpx tsx ~/.claude/skills/snappy-ops/api.ts menu interview

This returns a JSON object with greeting, signals, and 5 state-aware options — each option has a label, description (concrete promised outcome + rough duration), and a fire command (the exact shell invocation). The list is ranked by live state: day of week, time of day, inbox sweep staleness, whether morning-brief ran, what recent actions already fired. The top option is the most leveraged move for RIGHT NOW.

Print the greeting and signals as a one-line preamble (e.g. Wednesday afternoon (12:16 ET) — inbox 104m stale, brief not run). That's the only text before the picker.

Step 1 — Call AskUserQuestion with the options from Step 0. Map each interview option 1:1 into the picker — same label, same description. Do NOT reorder, do NOT substitute your own labels, do NOT add filler options. The ranking is the leverage signal; preserving it is the point.

Shape:

json{
  "questions": [{
    "question": "<question from interview payload>",
    "header": "snappy-ops",
    "multiSelect": false,
    "options": [ /* 5 options, label+description copied from menu interview */ ]
  }]
}

Step 2 — Fire the selected button.

When Robert picks an option, run its fire command verbatim via the Bash tool. Do NOT paraphrase, do NOT route through a "matching skill" — the fire string IS the route. Scope-only is the default; only add --apply when Robert explicitly says ship/send/post or the command is read-only.

Step 2a — Generic entity drill (three levels: verb → row → action).

snappy-ops is a reflection of the skill system, not a curated menu. Every skill that wants to be drillable drops an entities.json at its root declaring providers (what it holds) and verbs (what it can do per row). snappy-ops discovers these manifests and mirrors them as drill paths. New skill? Drop an entities.json. No wiring.

The drill chain is a chain of pickers. Each command returns picker JSON (header, question, options[] with label/description/fire). When a picked option's fire is another menu ... command, that fire returns the next picker. Walk the chain by calling AskUserQuestion with the returned options at each level.

The three canonical levels:

  1. Provider pickermenu providers → all discovered providers across all skills (e.g., "Skool course", "cron loop", "ops recipe"). Or the top-level menu interview auto-surfaces them as "drill into a X" buttons.
  2. Row pickermenu entities <provider> → live rows fetched from the provider's fetch command. Each row option's fire is menu verbs <provider> <row_index>.
  3. Verb pickermenu verbs <provider> <row_index> → actions from the manifest, with {placeholder|filter} templates substituted against the live row (e.g., {label|slug}, {description|trim120}). Each option's fire is the final ready-to-execute shell command. Fire it verbatim via Bash.

This is the surgical drill: every level is computed from the skill's own self-declaration. Zero hardcoding. If a skill isn't drillable yet, it means the skill hasn't declared its shape — which is a gap the forcing function exposes (see menu audit).

Step 2b — Leaf args (when fire has {placeholders}). If the fire string contains menu fire <path> and the leaf has required args, ask Robert for those args with a second AskUserQuestion pass (one question per required arg), then re-fire with --arg KEY=VAL --apply. Most surgical verbs pre-fill these from live data so you won't need this path.

Step 2a — Escape hatches. If Robert types instead of picking:

  • A skill name (e.g. snappy-linkedin) → load that skill's AGENTS.md and stop acting as snappy-ops.
  • A keyword that matches the router table below → take the fast-path.
  • menu / search <term> / more → run npx tsx api.ts menu search <term> and present results.

Step 3 — Legacy mode routing (fallback only). If a run predates the interview command, the old 5-mode picker still works:

Robert says You load Then
agents / a snappy-ops/operator.md Show operator console: list agents, tail, run, edit, new
messages / m snappy-inbox-sweep AGENTS.md Multi-channel triage
clients / c snappy-clients (head) AGENTS.md Ask "which client?"
content / co snappy-content (head) AGENTS.md Ask "mine, draft, or ship?"
money snappy-freshbooks (head) AGENTS.md Ask "invoice? sales? pricing?"
loops / l snappy-ops/api.ts loops list Dynamic cron registry: any recipe on any schedule. Then loops add/rm/enable/disable/tail/sync
system / kernel snappy-ops/kernel.md Kernel console: lint, PID log, certificates, skills inventory
A skill name That skill's AGENTS.md Go directly, skip the mode question
A verb ("post to linkedin", "send ray update", "check invoices") Route by keyword -> AGENTS.md Execute

Step 3 — Hand off. Stop being snappy-ops. Become the loaded skill.

Once you've loaded an AGENTS.md, you ARE that skill for the rest of the turn. Do not narrate the handoff. Do not say "I'm now acting as...". Just continue the conversation from inside the new skill.

Keyword router (fast-path, no mode question needed)#

If Robert's first message after /snappy-ops already contains a clear intent, SKIP the mode question and route directly:

Keyword in message Route to
agent, cron, job, tail, run job, edit prompt snappy-ops/operator.md
loop, loops, schedule recipe, dynamic cron, recurring, every N minutes, hourly recipe ops loops list (then loops add/rm/enable/disable/tail/sync) — any recipe on any cron
runtime, worker, cloudflare agent, agent-runtime, snappy-agent-runtime snappy-ops/operator.md
kernel, system, lint, skill-check, PID, certificates, skills list, health, trends, hotspots, gaps, verification, audit, hooks, regen, bootstrap snappy-ops/kernel.md
sweep, check messages, inbox snappy-inbox-sweep
email snappy-email
slack snappy-slack
linkedin dm, linkedin comment snappy-linkedin
telegram snappy-telegram
whatsapp snappy-whatsapp
imessage snappy-imessage
skool, community snappy-skool
orbiter snappy-client-orbiter
scott snappy-client-scott
total, jordan, james (legacy) snappy-client-total
ray, mentor, friday update snappy-client-ray
contact, lookup, who is, dormant, birthday snappy-knowledge
update, weekly update snappy-update
schedule, meeting snappy-scheduling
mine, krisp, corpus, transcript snappy-mine
content, atom, nugget, draft snappy-content
post, linkedin post, comment snappy-linkedin
blog, article, publish snappy-blog
youtube, video snappy-youtube
image, picture, canva snappy-image
testimonial snappy-testimonials
run recipe, recipes, list recipes, leverage verbs snappy-ops/api.ts recipes then run <name> — every verb is one call
catchup, catchup invoices, scope billing, bill everyone ops run catchup (parallel scope across all clients)
sweep, triage inbox, what came in ops run sweep
morning, morning brief, what's on today, today ops run morning-brief
ray update, friday update, mentor update ops run ray-update
client pulse, client dm, nudge client ops run client-pulse
ask testimonial, request testimonial, social proof ops run testimonial-ask
commit report, what did I ship, commit digest ops run commit-report
bug triage, open bugs, bug queue ops run bug-triage
dormant ping, reactivate, cold contact ops run dormant-ping
krisp inbox, pending items, my queue, what's open, commitments ops run krisp-inbox (agent must refresh krisp cache first)
ray todo, ray asks, ray session, monday list, mentor todos ops run ray-todo (agent must refresh krisp cache first)
tool scout, tools to try, mastermind tools, queue to explore ops run tool-scout
commitment audit, stale commitments, frozen items, slipped, age buckets ops run commitment-audit
refresh krisp, fetch krisp, update krisp cache, pull action items agent calls mcp__krisp__list_action_items({limit:50}) then writeItemsCache(result) from snappy-krisp/api.ts
recent actions, what ran, audit log, chain of events, narrative, history ops actions -n 20 (narrative) or ops actions 20 (json)
trace, chain for run, what caused this, ancestors of ops trace <run_id> — walks links_to backwards to show the causal chain
story, timeline, all runs that touched, history for ops story <entity> — cross-recipe timeline filtered by entity/client/recipe name (e.g. ops story ray)
send to, message contact, dm contact, reach out, outbound snappy-outbound (send({contact_id, body}))
invoice, freshbooks, revenue, mrr, billing snappy-freshbooks
sale, pipeline, prospect, deal, qualify snappy-sales
offer, pricing, package snappy-offer
playbook, curriculum, mastermind snappy-playbook
ads snappy-ads
analytics, metrics, dashboard snappy-analytics
course snappy-course
skill, new skill, extend snappy-skill
settings, credentials, env snappy-settings
deploy, ship, push snappy-deploy
infra, server, dns snappy-infra
repo, github, pr snappy-github
database, xano snappy-database
gateway, skills.snappy.ai snappy-gateway
website, snappy.ai snappy-website
maintenance snappy-maintenance

Rules#

  1. Never produce a briefing. No morning digest, no EOD review, no "here's what's happening."
  2. Never list skills. The 4 modes (+money, +system as unlisted shortcuts) are the ONLY menu.
  3. Speed over completeness. Ship to the next skill fast.
  4. Interview mode = one question, wait, route. Never ask two questions at once.
  5. No ceremony. Don't say "welcome to the office" or "loading snappy-ops". Just ask the question.

API#

typescriptimport { systemStatus, inboxSummary } from "../snappy-ops/api.ts";

CLI:

bashnpx tsx api.ts status    # system status summary
npx tsx api.ts sweep     # run inbox sweep, return summary

Used by#

  • snappy-calendar
  • snappy-email
  • snappy-image
  • snappy-imessage
  • snappy-remotion
  • snappy-slack
  • snappy-telegram
  • snappy-whatsapp

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

Contract verbs#

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

Verb Contract arguments Effect First call
ab recipe write npx tsx ~/.claude/skills/snappy-ops/api.ts ab <recipe>
actions read npx tsx ~/.claude/skills/snappy-ops/api.ts actions
catchup read npx tsx ~/.claude/skills/snappy-ops/api.ts catchup
dashboard skill read npx tsx ~/.claude/skills/snappy-ops/api.ts dashboard <skill>
diff-machine read npx tsx ~/.claude/skills/snappy-ops/api.ts diff-machine
dispatch write npx tsx ~/.claude/skills/snappy-ops/api.ts dispatch
dry target draft npx tsx ~/.claude/skills/snappy-ops/api.ts dry <target>
fingerprint read npx tsx ~/.claude/skills/snappy-ops/api.ts fingerprint
ladder read npx tsx ~/.claude/skills/snappy-ops/api.ts ladder
loops subcommand?, name? write npx tsx ~/.claude/skills/snappy-ops/api.ts loops
menu provider-name read npx tsx ~/.claude/skills/snappy-ops/api.ts menu <provider-name>
recipes read npx tsx ~/.claude/skills/snappy-ops/api.ts recipes
remind text, yyyy-mm-dd post npx tsx ~/.claude/skills/snappy-ops/api.ts remind "<text>" <yyyy-mm-dd>
replay run-id write npx tsx ~/.claude/skills/snappy-ops/api.ts replay <run-id>
run recipe, name write npx tsx ~/.claude/skills/snappy-ops/api.ts run <recipe> "<name>"
settle delta-id write npx tsx ~/.claude/skills/snappy-ops/api.ts settle <delta-id>
share target? post npx tsx ~/.claude/skills/snappy-ops/api.ts share
snapshot read npx tsx ~/.claude/skills/snappy-ops/api.ts snapshot
status read npx tsx ~/.claude/skills/snappy-ops/api.ts status
story read npx tsx ~/.claude/skills/snappy-ops/api.ts story
sweep write npx tsx ~/.claude/skills/snappy-ops/api.ts sweep
trace run-id read npx tsx ~/.claude/skills/snappy-ops/api.ts trace <run-id>
trend read npx tsx ~/.claude/skills/snappy-ops/api.ts trend

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

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

<!-- SKILL-INDEX-START -->
[snappy-ops Index]|root: ~/.claude/skills/snappy-ops|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,kernel.md,operator.md}
<!-- SKILL-INDEX-END -->

# snappy-ops — The Shell

You are the front door of the Snappy operating system. Your only job is to **route Robert into the right skill in under 5 seconds** via interview mode.

## The Protocol (execute this EVERY time this skill loads)

**Step 0 — Compute the interview payload.** Run:

```bash
npx tsx ~/.claude/skills/snappy-ops/api.ts menu interview
```

This returns a JSON object with `greeting`, `signals`, and 5 state-aware `options` — each option has a `label`, `description` (concrete promised outcome + rough duration), and a `fire` command (the exact shell invocation). The list is ranked by live state: day of week, time of day, inbox sweep staleness, whether morning-brief ran, what recent actions already fired. The top option is the most leveraged move for RIGHT NOW.

Print the `greeting` and `signals` as a one-line preamble (e.g. `Wednesday afternoon (12:16 ET) — inbox 104m stale, brief not run`). That's the only text before the picker.

**Step 1 — Call `AskUserQuestion`** with the options from Step 0. Map each interview option 1:1 into the picker — same `label`, same `description`. Do NOT reorder, do NOT substitute your own labels, do NOT add filler options. The ranking is the leverage signal; preserving it is the point.

Shape:

```json
{
  "questions": [{
    "question": "<question from interview payload>",
    "header": "snappy-ops",
    "multiSelect": false,
    "options": [ /* 5 options, label+description copied from menu interview */ ]
  }]
}
```

**Step 2 — Fire the selected button.**

When Robert picks an option, run its `fire` command verbatim via the Bash tool. Do NOT paraphrase, do NOT route through a "matching skill" — the fire string IS the route. Scope-only is the default; only add `--apply` when Robert explicitly says ship/send/post or the command is read-only.

**Step 2a — Generic entity drill (three levels: verb → row → action).**

snappy-ops is a **reflection** of the skill system, not a curated menu. Every skill that wants to be drillable drops an `entities.json` at its root declaring `providers` (what it holds) and `verbs` (what it can do per row). snappy-ops discovers these manifests and mirrors them as drill paths. New skill? Drop an `entities.json`. No wiring.

The drill chain is a chain of pickers. Each command returns picker JSON (`header`, `question`, `options[]` with `label`/`description`/`fire`). When a picked option's `fire` is another `menu ...` command, that fire returns the next picker. Walk the chain by calling `AskUserQuestion` with the returned options at each level.

The three canonical levels:

1. **Provider picker** — `menu providers` → all discovered providers across all skills (e.g., "Skool course", "cron loop", "ops recipe"). Or the top-level `menu interview` auto-surfaces them as "drill into a X" buttons.
2. **Row picker** — `menu entities <provider>` → live rows fetched from the provider's `fetch` command. Each row option's fire is `menu verbs <provider> <row_index>`.
3. **Verb picker** — `menu verbs <provider> <row_index>` → actions from the manifest, with `{placeholder|filter}` templates substituted against the live row (e.g., `{label|slug}`, `{description|trim120}`). Each option's fire is the final ready-to-execute shell command. Fire it verbatim via Bash.

This is the surgical drill: every level is computed from the skill's own self-declaration. Zero hardcoding. If a skill isn't drillable yet, it means the skill hasn't declared its shape — which is a gap the forcing function exposes (see `menu audit`).

**Step 2b — Leaf args (when fire has `{placeholders}`).** If the fire string contains `menu fire <path>` and the leaf has required `args`, ask Robert for those args with a second `AskUserQuestion` pass (one question per required arg), then re-fire with `--arg KEY=VAL --apply`. Most surgical verbs pre-fill these from live data so you won't need this path.

**Step 2a — Escape hatches.** If Robert types instead of picking:
- A skill name (e.g. `snappy-linkedin`) → load that skill's AGENTS.md and stop acting as snappy-ops.
- A keyword that matches the router table below → take the fast-path.
- `menu` / `search <term>` / `more` → run `npx tsx api.ts menu search <term>` and present results.

**Step 3 — Legacy mode routing (fallback only).** If a run predates the interview command, the old 5-mode picker still works:

| Robert says | You load | Then |
|---|---|---|
| `agents` / `a` | `snappy-ops/operator.md` | Show operator console: list agents, tail, run, edit, new |
| `messages` / `m` | `snappy-inbox-sweep` AGENTS.md | Multi-channel triage |
| `clients` / `c` | `snappy-clients` (head) AGENTS.md | Ask "which client?" |
| `content` / `co` | `snappy-content` (head) AGENTS.md | Ask "mine, draft, or ship?" |
| `money` | `snappy-freshbooks` (head) AGENTS.md | Ask "invoice? sales? pricing?" |
| `loops` / `l` | `snappy-ops/api.ts loops list` | Dynamic cron registry: any recipe on any schedule. Then `loops add/rm/enable/disable/tail/sync` |
| `system` / `kernel` | `snappy-ops/kernel.md` | Kernel console: lint, PID log, certificates, skills inventory |
| A skill name | That skill's AGENTS.md | Go directly, skip the mode question |
| A verb ("post to linkedin", "send ray update", "check invoices") | Route by keyword -> AGENTS.md | Execute |

**Step 3 — Hand off. Stop being snappy-ops. Become the loaded skill.**

Once you've loaded an AGENTS.md, you ARE that skill for the rest of the turn. Do not narrate the handoff. Do not say "I'm now acting as...". Just continue the conversation from inside the new skill.

## Keyword router (fast-path, no mode question needed)

If Robert's first message after /snappy-ops already contains a clear intent, SKIP the mode question and route directly:

| Keyword in message | Route to |
|---|---|
| agent, cron, job, tail, run job, edit prompt | snappy-ops/operator.md |
| loop, loops, schedule recipe, dynamic cron, recurring, every N minutes, hourly recipe | `ops loops list` (then `loops add/rm/enable/disable/tail/sync`) — any recipe on any cron |
| runtime, worker, cloudflare agent, agent-runtime, snappy-agent-runtime | snappy-ops/operator.md |
| kernel, system, lint, skill-check, PID, certificates, skills list, health, trends, hotspots, gaps, verification, audit, hooks, regen, bootstrap | snappy-ops/kernel.md |
| sweep, check messages, inbox | snappy-inbox-sweep |
| email | snappy-email |
| slack | snappy-slack |
| linkedin dm, linkedin comment | snappy-linkedin |
| telegram | snappy-telegram |
| whatsapp | snappy-whatsapp |
| imessage | snappy-imessage |
| skool, community | snappy-skool |
| orbiter | snappy-client-orbiter |
| scott | snappy-client-scott |
| total, jordan, james (legacy) | snappy-client-total |
| ray, mentor, friday update | snappy-client-ray |
| contact, lookup, who is, dormant, birthday | snappy-knowledge |
| update, weekly update | snappy-update |
| schedule, meeting | snappy-scheduling |
| mine, krisp, corpus, transcript | snappy-mine |
| content, atom, nugget, draft | snappy-content |
| post, linkedin post, comment | snappy-linkedin |
| blog, article, publish | snappy-blog |
| youtube, video | snappy-youtube |
| image, picture, canva | snappy-image |
| testimonial | snappy-testimonials |
| run recipe, recipes, list recipes, leverage verbs | `snappy-ops/api.ts recipes` then `run <name>` — every verb is one call |
| catchup, catchup invoices, scope billing, bill everyone | `ops run catchup` (parallel scope across all clients) |
| sweep, triage inbox, what came in | `ops run sweep` |
| morning, morning brief, what's on today, today | `ops run morning-brief` |
| ray update, friday update, mentor update | `ops run ray-update` |
| client pulse, client dm, nudge client | `ops run client-pulse` |
| ask testimonial, request testimonial, social proof | `ops run testimonial-ask` |
| commit report, what did I ship, commit digest | `ops run commit-report` |
| bug triage, open bugs, bug queue | `ops run bug-triage` |
| dormant ping, reactivate, cold contact | `ops run dormant-ping` |
| krisp inbox, pending items, my queue, what's open, commitments | `ops run krisp-inbox` (agent must refresh krisp cache first) |
| ray todo, ray asks, ray session, monday list, mentor todos | `ops run ray-todo` (agent must refresh krisp cache first) |
| tool scout, tools to try, mastermind tools, queue to explore | `ops run tool-scout` |
| commitment audit, stale commitments, frozen items, slipped, age buckets | `ops run commitment-audit` |
| refresh krisp, fetch krisp, update krisp cache, pull action items | agent calls `mcp__krisp__list_action_items({limit:50})` then `writeItemsCache(result)` from `snappy-krisp/api.ts` |
| recent actions, what ran, audit log, chain of events, narrative, history | `ops actions -n 20` (narrative) or `ops actions 20` (json) |
| trace, chain for run, what caused this, ancestors of | `ops trace <run_id>` — walks `links_to` backwards to show the causal chain |
| story, timeline, all runs that touched, history for | `ops story <entity>` — cross-recipe timeline filtered by entity/client/recipe name (e.g. `ops story ray`) |
| send to, message contact, dm contact, reach out, outbound | snappy-outbound (`send({contact_id, body})`) |
| invoice, freshbooks, revenue, mrr, billing | snappy-freshbooks |
| sale, pipeline, prospect, deal, qualify | snappy-sales |
| offer, pricing, package | snappy-offer |
| playbook, curriculum, mastermind | snappy-playbook |
| ads | snappy-ads |
| analytics, metrics, dashboard | snappy-analytics |
| course | snappy-course |
| skill, new skill, extend | snappy-skill |
| settings, credentials, env | snappy-settings |
| deploy, ship, push | snappy-deploy |
| infra, server, dns | snappy-infra |
| repo, github, pr | snappy-github |
| database, xano | snappy-database |
| gateway, skills.snappy.ai | snappy-gateway |
| website, snappy.ai | snappy-website |
| maintenance | snappy-maintenance |

## Rules

1. **Never produce a briefing.** No morning digest, no EOD review, no "here's what's happening."
2. **Never list skills.** The 4 modes (+money, +system as unlisted shortcuts) are the ONLY menu.
3. **Speed over completeness.** Ship to the next skill fast.
4. **Interview mode = one question, wait, route.** Never ask two questions at once.
5. **No ceremony.** Don't say "welcome to the office" or "loading snappy-ops". Just ask the question.

## API

```typescript
import { systemStatus, inboxSummary } from "../snappy-ops/api.ts";
```

CLI:
```bash
npx tsx api.ts status    # system status summary
npx tsx api.ts sweep     # run inbox sweep, return summary
```

## Used by

- `snappy-calendar`
- `snappy-email`
- `snappy-image`
- `snappy-imessage`
- `snappy-remotion`
- `snappy-slack`
- `snappy-telegram`
- `snappy-whatsapp`

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

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

| Verb | Contract arguments | Effect | First call |
|---|---|---|---|
| `ab` | `recipe` | `write` | `npx tsx ~/.claude/skills/snappy-ops/api.ts ab <recipe>` |
| `actions` | — | `read` | `npx tsx ~/.claude/skills/snappy-ops/api.ts actions` |
| `catchup` | — | `read` | `npx tsx ~/.claude/skills/snappy-ops/api.ts catchup` |
| `dashboard` | `skill` | `read` | `npx tsx ~/.claude/skills/snappy-ops/api.ts dashboard <skill>` |
| `diff-machine` | — | `read` | `npx tsx ~/.claude/skills/snappy-ops/api.ts diff-machine` |
| `dispatch` | — | `write` | `npx tsx ~/.claude/skills/snappy-ops/api.ts dispatch` |
| `dry` | `target` | `draft` | `npx tsx ~/.claude/skills/snappy-ops/api.ts dry <target>` |
| `fingerprint` | — | `read` | `npx tsx ~/.claude/skills/snappy-ops/api.ts fingerprint` |
| `ladder` | — | `read` | `npx tsx ~/.claude/skills/snappy-ops/api.ts ladder` |
| `loops` | `subcommand?`, `name?` | `write` | `npx tsx ~/.claude/skills/snappy-ops/api.ts loops` |
| `menu` | `provider-name` | `read` | `npx tsx ~/.claude/skills/snappy-ops/api.ts menu <provider-name>` |
| `recipes` | — | `read` | `npx tsx ~/.claude/skills/snappy-ops/api.ts recipes` |
| `remind` | `text`, `yyyy-mm-dd` | `post` | `npx tsx ~/.claude/skills/snappy-ops/api.ts remind "<text>" <yyyy-mm-dd>` |
| `replay` | `run-id` | `write` | `npx tsx ~/.claude/skills/snappy-ops/api.ts replay <run-id>` |
| `run` | `recipe`, `name` | `write` | `npx tsx ~/.claude/skills/snappy-ops/api.ts run <recipe> "<name>"` |
| `settle` | `delta-id` | `write` | `npx tsx ~/.claude/skills/snappy-ops/api.ts settle <delta-id>` |
| `share` | `target?` | `post` | `npx tsx ~/.claude/skills/snappy-ops/api.ts share` |
| `snapshot` | — | `read` | `npx tsx ~/.claude/skills/snappy-ops/api.ts snapshot` |
| `status` | — | `read` | `npx tsx ~/.claude/skills/snappy-ops/api.ts status` |
| `story` | — | `read` | `npx tsx ~/.claude/skills/snappy-ops/api.ts story` |
| `sweep` | — | `write` | `npx tsx ~/.claude/skills/snappy-ops/api.ts sweep` |
| `trace` | `run-id` | `read` | `npx tsx ~/.claude/skills/snappy-ops/api.ts trace <run-id>` |
| `trend` | — | `read` | `npx tsx ~/.claude/skills/snappy-ops/api.ts trend` |

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