← All Skills

snappy-corpus

v1.0.0
7 files, 33.4 KB ~1,771 words · 8 min read Updated 2026-09-09

snappy-corpus skill

41 of 47 checks pass
What it can do
list year? month?read
read path offset?read
search queryread
What does not pass yet
reached bysnappy-course
$ npx snappy-skills install snappy-corpus
zip ↓
File Tree
├── AGENTS.md ├── SKILL.md ├── api.test.ts ├── api.ts ├── contract.test.ts └── scripts/ ├── make-summaries.py └── persist-batch.py
Documents
AGENTS.md

snappy-corpus -- loader#

You are working inside Robert's content engine. Every published artifact (carousel, blog, DM, sales asset) must ultimately trace back to something Robert actually said in a Krisp transcript. This loader covers the rules. Read SKILL.md only if you need the full architecture rationale.

API module#

typescriptimport { listTranscripts, readTranscript, searchCorpus } from "../snappy-corpus/api.ts";
Function Purpose
listTranscripts(year?, month?) List transcript .md files, optionally filtered by year/month
readTranscript(path, offset?, limit?) Read a transcript in chunks (default first 200 lines)
searchCorpus(query) Grep across all transcripts for a query string

CLI:

bashnpx tsx ~/.claude/skills/snappy-corpus/api.ts list [year] [month]
npx tsx ~/.claude/skills/snappy-corpus/api.ts read <path> [offset] [--limit N]
npx tsx ~/.claude/skills/snappy-corpus/api.ts search <query>

Storage paths (memorize)#

  • Transcripts: ~/.claude/corpus/krisp/YYYY/MM/DD-<slug>.md
  • Nuggets sidecar: same path with .nuggets.json suffix
  • Dedup index: ~/.claude/corpus/krisp/index.json -- { "meeting_id": "relative/path/to/file.md" }
  • Skipped log: ~/.claude/corpus/krisp/skipped.log
  • Usage ledger: ~/.claude/corpus/usage.jsonl

DO NOT mine ~/.claude/skills/snappy-course/data/krisp-teaching-by-person.json -- see warning header in that file. Its verbatim_quote fields contain host speech mis-attributed to guests (Jordan fabrication root cause, pass-log 2026-04-13). Use quote-bank.json instead.

Krisp MCP -- the only ingest path#

  • mcp__claude_ai_Krisp__search_meetings -- list meetings OR fetch metadata. Always restrict fields to the cheap set: ["name", "date", "attendees", "transcript"]. Returns inline (small). This is the ONLY way to get meeting name/date/attendees for frontmatter -- get_multiple_documents only returns {id, document}.
  • mcp__claude_ai_Krisp__get_multiple_documents -- full doc by id. Hard cap: 10 ids per call.
  • Skip any meeting where transcript.status != "uploaded". Log to skipped.log with reason.

CRITICAL: responses spill to tool-results files#

A 10-id get_multiple_documents batch is ~500KB / ~140k tokens. It will ALWAYS exceed the inline response limit and auto-spill to a file at ~/.claude/projects/<session>/tool-results/mcp-claude_ai_Krisp-get_multiple_documents-<ts>.txt. You cannot read this file via Read (too big) and you must NOT try to load it into context.

The only working pattern is Bash + Python:

  1. Call get_multiple_documents -- you get back an error-style message with the spill file path.
  2. Call Bash to run python3 ~/.claude/skills/snappy-corpus/scripts/persist-batch.py <spill_file> <metadata_json>.
  3. The script parses the spill, writes each transcript as markdown with frontmatter, updates index.json.

This means ingest only works in contexts where Bash + python3 are available. Subagents with Bash denied CANNOT do ingest -- they must be dispatched with Bash permissions, or ingest must run in the parent context. If your sandbox blocks Bash, stop and report -- do not attempt to read the spill file.

Metadata JSON shape (input to persist-batch.py)#

Build a metadata JSON file BEFORE calling get_multiple_documents, using the cheap search_meetings call:

json{
  "019d683e...": {"name": "...", "date": "2026-04-07T10:00:18-04:00", "attendees": ["Robert Boulos"]},
  ...
}

Ingest playbook (one transcript)#

  1. Check index.json -- if meeting_id already present, skip.
  2. Slugify the meeting name: lowercase, alphanumerics + hyphens, max 60 chars. Strip emojis and special chars.
  3. Build path: ~/.claude/corpus/krisp/YYYY/MM/DD-<slug>.md from the meeting date.
  4. Classify type from name + attendees: dev-sync | mastermind | customer | prospect | sales | team | solo | unknown. Use heuristics: "Mastermind" → mastermind, names with @snappy.ai → team, solo recordings (no other attendees) → solo, etc. When uncertain → unknown.
    • Collision-proof: if a different meeting_id already wrote to the same YYYY/MM/DD-<slug>.md path (happens with two same-named recurring meetings on the same day, e.g. "State Change Mastermind" twice), append -<last-6-of-meeting-id> to the slug. persist-batch.py already does this automatically.
  5. Write the file with YAML frontmatter (see SKILL.md for exact shape) followed by the Krisp document body verbatim.
  6. Update index.json with the new entry.

Batching#

  • Always use get_multiple_documents with up to 10 ids at a time. One call per batch, not one call per meeting.
  • Between batches, write files immediately -- do not buffer all results in memory.

Frontmatter classification rules#

  • attendees: [Robert Boulos] only → solo
  • Name contains "Mastermind" → mastermind
  • Name contains "Sync", "Dev", "Working Session" + internal team member → dev-sync
  • Name contains "Call", "Discovery", "Demo", external email domain → prospect or sales
  • Default fallback → unknown (do not guess; mining can re-classify later)

Rules#

  • Do not summarize, edit, or "clean up" the transcript body. It is the receipt. Persist verbatim.
  • Do not write nuggets during ingest. Nugget extraction is a separate pass.
  • Do not delete or rewrite existing transcript files. Idempotent re-runs only add new ones.
  • Do not call get_multiple_documents with more than 10 ids per call.
  • Do not auto-publish anything. Ever. Mining and ranking are fine; publishing is gated on Robert.

When you finish an ingest run#

Report:

  • N meetings discovered in window
  • N already in index (skipped)
  • N successfully written
  • N skipped due to transcript status (with reason)
  • Total bytes written
  • Path to a sample file so Robert can spot-check

How to report loader gaps (self-healing feedback)#

If this AGENTS.md does not cover the case you are working on and you had to read other files to find the answer, before you finish, append one line to ~/.claude/logs/agents-md-feedback.log via Bash:

bashecho "[$(date -u +%FT%TZ)] snappy-corpus: <what was missing in the loader>" >> ~/.claude/logs/agents-md-feedback.log

One line per gap. Be specific.

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

[snappy-corpus Index]|root: ~/.claude/skills/snappy-corpus|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#

  • snappy-course

<!-- 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 year?, month? read npx tsx ~/.claude/skills/snappy-corpus/api.ts list
read path, offset? read npx tsx ~/.claude/skills/snappy-corpus/api.ts read <path>
search query read npx tsx ~/.claude/skills/snappy-corpus/api.ts search "<query>"

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-corpus
role: Loader for the Krisp transcript corpus + nugget pipeline. Use when ingesting transcripts, extracting nuggets, or mining the corpus for content.
loaded-by: PreToolUse hook (auto-injected when "snappy-corpus" is mentioned)
Triggers on: Krisp transcripts, corpus ingest, meetings, nuggets, transcript search
---

# snappy-corpus -- loader

You are working inside Robert's content engine. Every published artifact (carousel, blog, DM, sales asset) must ultimately trace back to something Robert actually said in a Krisp transcript. This loader covers the rules. Read SKILL.md only if you need the full architecture rationale.

## API module

```typescript
import { listTranscripts, readTranscript, searchCorpus } from "../snappy-corpus/api.ts";
```

| Function | Purpose |
|----------|---------|
| `listTranscripts(year?, month?)` | List transcript .md files, optionally filtered by year/month |
| `readTranscript(path, offset?, limit?)` | Read a transcript in chunks (default first 200 lines) |
| `searchCorpus(query)` | Grep across all transcripts for a query string |

CLI:
```bash
npx tsx ~/.claude/skills/snappy-corpus/api.ts list [year] [month]
npx tsx ~/.claude/skills/snappy-corpus/api.ts read <path> [offset] [--limit N]
npx tsx ~/.claude/skills/snappy-corpus/api.ts search <query>
```

## Storage paths (memorize)

- Transcripts: `~/.claude/corpus/krisp/YYYY/MM/DD-<slug>.md`
- Nuggets sidecar: same path with `.nuggets.json` suffix
- Dedup index: `~/.claude/corpus/krisp/index.json` -- `{ "meeting_id": "relative/path/to/file.md" }`
- Skipped log: `~/.claude/corpus/krisp/skipped.log`
- Usage ledger: `~/.claude/corpus/usage.jsonl`

**DO NOT mine `~/.claude/skills/snappy-course/data/krisp-teaching-by-person.json`** -- see warning header in that file. Its `verbatim_quote` fields contain host speech mis-attributed to guests (Jordan fabrication root cause, pass-log 2026-04-13). Use `quote-bank.json` instead.

## Krisp MCP -- the only ingest path

- `mcp__claude_ai_Krisp__search_meetings` -- list meetings OR fetch metadata. Always restrict `fields` to the cheap set: `["name", "date", "attendees", "transcript"]`. Returns inline (small). **This is the ONLY way to get meeting name/date/attendees for frontmatter** -- `get_multiple_documents` only returns `{id, document}`.
- `mcp__claude_ai_Krisp__get_multiple_documents` -- full doc by id. **Hard cap: 10 ids per call.**
- Skip any meeting where `transcript.status != "uploaded"`. Log to `skipped.log` with reason.

### CRITICAL: responses spill to tool-results files

A 10-id `get_multiple_documents` batch is ~500KB / ~140k tokens. **It will ALWAYS exceed the inline response limit and auto-spill to a file at `~/.claude/projects/<session>/tool-results/mcp-claude_ai_Krisp-get_multiple_documents-<ts>.txt`.** You cannot read this file via `Read` (too big) and you must NOT try to load it into context.

**The only working pattern is Bash + Python:**

1. Call `get_multiple_documents` -- you get back an error-style message with the spill file path.
2. Call `Bash` to run `python3 ~/.claude/skills/snappy-corpus/scripts/persist-batch.py <spill_file> <metadata_json>`.
3. The script parses the spill, writes each transcript as markdown with frontmatter, updates `index.json`.

**This means ingest only works in contexts where Bash + python3 are available.** Subagents with Bash denied CANNOT do ingest -- they must be dispatched with Bash permissions, or ingest must run in the parent context. If your sandbox blocks Bash, stop and report -- do not attempt to read the spill file.

### Metadata JSON shape (input to persist-batch.py)

Build a metadata JSON file BEFORE calling get_multiple_documents, using the cheap search_meetings call:

```json
{
  "019d683e...": {"name": "...", "date": "2026-04-07T10:00:18-04:00", "attendees": ["Robert Boulos"]},
  ...
}
```

## Ingest playbook (one transcript)

1. Check `index.json` -- if `meeting_id` already present, skip.
2. Slugify the meeting name: lowercase, alphanumerics + hyphens, max 60 chars. Strip emojis and special chars.
3. Build path: `~/.claude/corpus/krisp/YYYY/MM/DD-<slug>.md` from the meeting `date`.
4. Classify `type` from name + attendees: `dev-sync` | `mastermind` | `customer` | `prospect` | `sales` | `team` | `solo` | `unknown`. Use heuristics: "Mastermind" → mastermind, names with @snappy.ai → team, solo recordings (no other attendees) → solo, etc. When uncertain → `unknown`.
   - **Collision-proof**: if a different meeting_id already wrote to the same `YYYY/MM/DD-<slug>.md` path (happens with two same-named recurring meetings on the same day, e.g. "State Change Mastermind" twice), append `-<last-6-of-meeting-id>` to the slug. `persist-batch.py` already does this automatically.
5. Write the file with YAML frontmatter (see SKILL.md for exact shape) followed by the Krisp document body verbatim.
6. Update `index.json` with the new entry.

## Batching

- Always use `get_multiple_documents` with up to 10 ids at a time. One call per batch, not one call per meeting.
- Between batches, write files immediately -- do not buffer all results in memory.

## Frontmatter classification rules

- `attendees: [Robert Boulos]` only → `solo`
- Name contains "Mastermind" → `mastermind`
- Name contains "Sync", "Dev", "Working Session" + internal team member → `dev-sync`
- Name contains "Call", "Discovery", "Demo", external email domain → `prospect` or `sales`
- Default fallback → `unknown` (do not guess; mining can re-classify later)

## Rules

- Do not summarize, edit, or "clean up" the transcript body. It is the receipt. Persist verbatim.
- Do not write nuggets during ingest. Nugget extraction is a separate pass.
- Do not delete or rewrite existing transcript files. Idempotent re-runs only add new ones.
- Do not call `get_multiple_documents` with more than 10 ids per call.
- Do not auto-publish anything. Ever. Mining and ranking are fine; publishing is gated on Robert.

## When you finish an ingest run

Report:
- N meetings discovered in window
- N already in index (skipped)
- N successfully written
- N skipped due to transcript status (with reason)
- Total bytes written
- Path to a sample file so Robert can spot-check

---

## How to report loader gaps (self-healing feedback)

If this AGENTS.md does not cover the case you are working on and you had to read other files to find the answer, **before you finish**, append one line to `~/.claude/logs/agents-md-feedback.log` via Bash:

```bash
echo "[$(date -u +%FT%TZ)] snappy-corpus: <what was missing in the loader>" >> ~/.claude/logs/agents-md-feedback.log
```

One line per gap. Be specific.

<!-- SKILL-INDEX-START -->
[snappy-corpus Index]|root: ~/.claude/skills/snappy-corpus|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

- `snappy-course`

<!-- 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` | `year?`, `month?` | `read` | `npx tsx ~/.claude/skills/snappy-corpus/api.ts list` |
| `read` | `path`, `offset?` | `read` | `npx tsx ~/.claude/skills/snappy-corpus/api.ts read <path>` |
| `search` | `query` | `read` | `npx tsx ~/.claude/skills/snappy-corpus/api.ts search "<query>"` |

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