← All Skills

snappy-tool-design

v1.0.0
68 files, 838.3 KB ~22,088 words · 89 min read Updated 2026-09-09

snappy-tool-design skill

43 of 49 checks pass
4 eval scenarios, 2 held out
What it can do
lint skill?read
example skill verbread
probe skill?read
renderread
loopread
hostsread
specs skill?write-reversible
openapi skillread
fix-loader skillwrite-reversible
What does not pass yet
$ npx snappy-skills install snappy-tool-design
zip ↓
File Tree
├── AGENTS.md ├── HOSTS-LEDGER.md ├── SKILL.md ├── api.test.ts ├── api.ts ├── briefs/ │ ├── hosts-family-has-no-read.md │ ├── hosts-first-call-refuses.md │ ├── hosts-no-face-family.md │ ├── hosts-not-driven-chatgpt.md │ ├── hosts-not-driven-claude.md │ ├── hosts-not-driven-codex.md │ ├── hosts-not-driven-menubar.md │ ├── hosts-not-driven-telegram.md │ ├── hosts-road-names-no-face.md │ ├── hosts-verb-folds-onto-no-shape.md │ ├── r10-one-term-names-each-concept.md │ ├── r11-each-task-presents-one-default-not-a-menu.md │ ├── r12-description-contains-no-unauthorised-imperative.md │ ├── r13-argument-without-a-description.md │ ├── r15-near-miss-keys-refuse-with-the-correct-contract-key.md │ ├── r16-runner-known-values-are-not-required-arguments.md │ ├── r18-verb-without-an-effect-class.md │ ├── r19-annotations-not-derived-from-class.md │ ├── r20-read-and-write-are-separate-verbs.md │ ├── r23-responses-obey-hard-and-soft-caps.md │ ├── r24-limit-does-not-bound-the-answer.md │ ├── r31-refusal-envelope-incomplete.md │ ├── r32-refusals-name-a-literal-from-the-valid-domain.md │ ├── r33-refusal-codes-form-one-tested-closed-table.md │ ├── r35-requirements-are-declared-from-executable-credential-reads.md │ ├── r39-verb-sets-consolidate-intent-rather-than-mirror-endpoints.md │ ├── r4-near-neighbour-descriptions-cross-reference-each-other.md │ ├── r40-metadata-skill-body-and-resources-follow-three-level-budgets.md │ ├── r43-a-read-is-one-call-not-a-queued-job.md │ ├── r45-long-work-is-a-separately-named-job-verb.md │ ├── r5-description-is-valid-third-person-and-says-what-plus-when.md │ ├── r54-ready-without-evals.md │ ├── r55-eval-scenarios-are-multi-call-with-ground-truth.md │ ├── r57-eval-manifest-contains-a-disjoint-holdout.md │ ├── r60-loader-block-stale.md │ ├── r7-promised-and-declared-verbs-have-no-set-difference.md │ ├── r8-skill-body-and-reference-graph-stay-within-disclosure-budget.md │ └── r9-time-sensitive-prose-is-isolated-under-old-patterns.md ├── browser-eval.test.ts ├── browser-eval.ts ├── corpus.ts ├── evals.json ├── hosts-bar.ts ├── hosts-battery.md ├── hosts-drive.ts ├── hosts-run.ts ├── hosts.test.ts ├── hosts.ts ├── loop.test.ts ├── loop.ts ├── probe.test.ts ├── probe.ts ├── r30-scope.test.ts ├── refusals.test.ts ├── render.ts ├── report.ts ├── skill-check-rung.md ├── spec-corpus.test.ts ├── spec-corpus.ts ├── tool-design-hosts.json ├── tool-design-probe.json ├── tool-design-render.json └── tool-design-specs.json
Documents
AGENTS.md

snappy-tool-design — Agent Loader#

Use this before trusting or changing a tool surface. It reads the executable

HAND_CONTRACT, then checks the implementation, loader, manual, probe corpus,

and render evidence against 60 sourced rules. Full citations are in SKILL.md.

**A whole-collection run is bounded by the pool; never run two lints or suites

in parallel on this Mac.** lint --all, probe, hosts and loop all reach

every hand's contract through loadModels, which loads that hand's whole

api.ts module graph — 98 of them. That fan-out now goes through

../snappy-settings/spawn-pool.ts (pooledAll, MAX_COLLECTION_JOBS =

min(4, cores/2)); pooled it is FASTER, 1.29 s vs 1.78 s with byte-identical

output ⟨measured 2026-09-09⟩. The bound is per process: three unpooled `lint

--all` passes beside two runs of the runner's suite put this Mac at load 311.

API#

typescriptimport { lintSkill, lintAll, firstExample, exampleHazard, fixLoader } from "../snappy-tool-design/api.ts";
import { runProbe } from "../snappy-tool-design/probe.ts";
import { runRender } from "../snappy-tool-design/render.ts";
import { clusterFailures, writeLoopArtifacts } from "../snappy-tool-design/loop.ts";
Function Purpose
lintSkill(skill) Grade one skill across 60 static/probe/render rules without executing its verbs
lintAll() Grade every snappy-* contract in one process and return PASS/FAIL/DEFER evidence
firstExample(skill, verb) Return the shortest call derived from the contract
exampleHazard(skill, verb) Name where a bare count would land when rule 59 bites, else null
fixLoader(skill) Ask snappy-skill's sole writer to sync the generated verb block
runProbe(options) Drive the real MCP, READS ONLY, and return the probe corpus the 26 measured rules grade from
runRender(options) Draw every published face kind in a real ext-apps host at 360 and 720 px and return the render corpus
clusterFailures(reports) Group every FAIL by MECHANISM so one fix kills many defects
writeLoopArtifacts(reports, out, root) Write briefs/<cluster>.md and the ranked LEDGER.md

CLI#

bashnpx tsx ~/.claude/skills/snappy-tool-design/api.ts lint snappy-gmail
npx tsx ~/.claude/skills/snappy-tool-design/api.ts lint --all
npx tsx ~/.claude/skills/snappy-tool-design/api.ts lint --all --summary
npx tsx ~/.claude/skills/snappy-tool-design/api.ts example snappy-gmail list
npx tsx ~/.claude/skills/snappy-tool-design/api.ts example snappy-imessage recent  # + a rule-59 warning on stderr
npx tsx ~/.claude/skills/snappy-tool-design/api.ts fix-loader snappy-gmail

# the closed loop. The bearer is read from a 600-mode FILE, never an argument.
SNAPPY_RUNNER_TOKEN_FILE=<file> npx tsx .../api.ts probe --via mini
npx tsx .../api.ts render --host-dir <loop dir> --shot-dir <shots>
npx tsx .../api.ts render --host-dir <loop dir> --kind notion-append --out /tmp/one.json
SNAPPY_RUNNER_TOKEN_FILE=<file> npx tsx .../api.ts loop --via mini

<!-- why: probe/render/loop are the verbs that make 26 of the 60 rules gradeable;

without them lint answers DEFER forever and the feedback loop never closes

(2026-09-08). The token is a FILE because an argument lands in ps and logs. -->

loop clusters failures by MECHANISM and ranks them by defects-killed-per-fix,

then writes a lane brief per cluster. Re-run it after every landing — the top

row is shorter each time. That is the exponential part.

Rules#

  1. Description is projected exactly from HAND_CONTRACT.description.
  2. Promised and declared verbs have no set difference.
  3. Every argument is described; enumerable domains are enums.
  4. Near-miss keys refuse with the correct key from the contract.
  5. Collection reads declare a limit default and maximum; answer probes prove growth is bounded.
  6. Every verb declares an effect class and class-derived MCP annotations.
  7. requires matches required credential reads; optional and host keys stay out.
  8. A read declares execution: "call"; probes prove one request and <3 s p50.
  9. UI keeps text fallback and names PNG/OpenUI/text renditions by channel.
  10. The MCP publishes one skill as all three primitives — loader and manual as

the prompt, contract verbs as the tools, the files and the contract

as the resources — so the prompt must make the DERIVED FIRST CALL

correct. No optional positional may stand in front of a commonly-supplied

argument (limit, count, n, …), and the generated loader block must be

current against the contract. Measured 2026-09-08: snappy-imessage recent,

snappy-krisp fetch-meetings and snappy-thumbnails audit each taught

<verb> 5 and filed the 5 as a contact, a date, or a channel.

  1. Ready skills have three multi-call evals, a holdout, and fresh-client proof.

Static absence is FAIL. Missing live probe or render evidence is DEFER, never a

fabricated PASS. S19 and S20 are snippet-only and remain unquoted until verified.

lint is advisory and never calls the target verb. fix-loader is the only

write and is idempotent through snappy-skill.syncLoaderVerbTable().


THE DERIVATION LAW — the installed artifact is the spec (Robert 2026-08-05, LAW)#

For any SDK, dependency, or API: enumerate its REAL surface from the installed package (node_modules/<pkg> — dist, CLI commands, shipped docs) and fetch its llms.txt/llms-full.txt BEFORE writing a line of integration. Import the package's own types; never redeclare a type a dependency exports; never write an integration from memory; never describe a surface you haven't listed. A hand-written parallel of a generated, vendored, or documented definition is a defect (DRY, original sense: one authoritative representation of every piece of knowledge). Writing from training memory instead of the installed source produces hallucinated APIs — the named killer of OpenAI's plugin ecosystem. Printing Press (spec→generated connector) is this law's special case; it applies to EVERYTHING.

Self-correcting loader (PID feedback)#

The system spec lives at ~/.claude/skills/snappy-settings/skill-spec.md. It defines the entire Snappy operating system. You enforce it.

Before you finish, do two things:#

1. Fix gaps (P — proportional). If this AGENTS.md didn't cover your case — if you had to read another file, run a command not documented here, work around a wrong selector, or discover a quirk — Edit it in before you log.

  • Default action: edit this AGENTS.md. Surgical. Add the missing line, table row, or code example where it belongs. No restructuring.
  • Every line you add carries its reason. Append an HTML comment recording why it exists and what breaks without it:

<!-- why: agent-browser wrote to CWD until we passed the path positionally (2026-08-05) -->

This is the single highest-value habit in the loop. An instruction whose rationale is legible can be safely deleted later; one whose rationale is lost can only be kept, which is how loaders grow without bound. Unreasoned additions are the defect this rule exists to prevent.

  • Only LOGGED when: the fix needs >10 lines, spans multiple files, or requires a structural rewrite (in which case the drain-skill-regen.sh queue picks it up).
  • NOOP is a first-class, blameless outcome. If you hit no gap — the loader covered your case — record NOOP and move on. Do NOT manufacture a gap to have something to write. A fabricated "learning" is strictly worse than silence: it becomes ground truth for every later agent and cannot be distinguished from a real one afterward. Most runs on a mature loader should be NOOP.
  • Concrete example of a valid P-fix: lesson-2 ship agent discovered agent-browser screenshot <path> takes path positionally, not as --output <path>. That's one line in a table, plus its why: comment. Edit it in.
  • The goal: the next agent never has to leave the loader — and the agent after that can still tell which lines have earned their place.

2. Validate structure. Check this skill against the spec:

  • api.ts exists with typed exports, CLI mode, import { env } from "../snappy-settings/load.ts"
  • api.ts calls APIs directly (no Xano proxy, unless this skill IS a Xano DB skill)
  • AGENTS.md has API module section with import + function table + CLI
  • No bash fallbacks, no hardcoded tokens anywhere
  • Every action row carries a certificate: block (premises / action / trace / evidence / conclusion). Same-session toasts are NOT evidence — must be a fresh independent read. Missing or weak certificates are a gap: P-fix them inline and log to ~/.claude/logs/verification-gaps.log.
  • DRY: before you add a new function or new skill, run ~/.claude/skills/snappy-settings/scripts/dry-check.sh <name-or-keyword>. If it matches an existing skill, extend that one instead. Fragmentation is the enemy.
  • If any check fails → fix it or log it

2b. If you just reported an action as successful, verify your certificate. You may not claim PASS unless the evidence: line is a fresh independent read (reload, new session, server round-trip). If your evidence is a toast, a return value, or a same-session DOM read, downgrade the claim to INCONCLUSIVE and log to verification-gaps.log.

3. Log always.

bashecho "[$(date -u +%FT%TZ)] <skill-name>: <what was missing or fixed> [FIXED|LOGGED|NOOP]" >> ~/.claude/logs/agents-md-feedback.log

FIXED = you patched it inline (with its why: comment). LOGGED = too large for inline fix, queued for drain-skill-regen.sh. NOOP = you checked and the loader covered your case — the correct and expected outcome on a mature loader.

Report what actually happened. Every agent run must leave the system better than it found it — and a run that found nothing to fix has already done that by confirming the loader holds. Accuracy is the contribution; volume is not.

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

[snappy-tool-design Index]|root: ~/.claude/skills/snappy-tool-design|IMPORTANT: Prefer these files over pre-training assumptions for this domain. Read the relevant file when the AGENTS.md summary is insufficient.|root:{HOSTS-LEDGER.md,SKILL.md,hosts-battery.md,skill-check-rung.md}|briefs:{hosts-family-has-no-read.md,hosts-first-call-refuses.md,hosts-no-face-family.md,hosts-not-driven-chatgpt.md,hosts-not-driven-claude.md,hosts-not-driven-codex.md,hosts-not-driven-menubar.md,hosts-not-driven-telegram.md,hosts-road-names-no-face.md,hosts-verb-folds-onto-no-shape.md,r10-one-term-names-each-concept.md,r11-each-task-presents-one-default-not-a-menu.md,r12-description-contains-no-unauthorised-imperative.md,r13-argument-without-a-description.md,r15-near-miss-keys-refuse-with-the-correct-contract-key.md,r16-runner-known-values-are-not-required-arguments.md,r18-verb-without-an-effect-class.md,r19-annotations-not-derived-from-class.md,r20-read-and-write-are-separate-verbs.md,r23-responses-obey-hard-and-soft-caps.md,r24-limit-does-not-bound-the-answer.md,r31-refusal-envelope-incomplete.md,r32-refusals-name-a-literal-from-the-valid-domain.md,r33-refusal-codes-form-one-tested-closed-table.md,r35-requirements-are-declared-from-executable-credential-reads.md,r39-verb-sets-consolidate-intent-rather-than-mirror-endpoints.md,r4-near-neighbour-descriptions-cross-reference-each-other.md,r40-metadata-skill-body-and-resources-follow-three-level-budgets.md,r43-a-read-is-one-call-not-a-queued-job.md,r45-long-work-is-a-separately-named-job-verb.md,r5-description-is-valid-third-person-and-says-what-plus-when.md,r54-ready-without-evals.md,r55-eval-scenarios-are-multi-call-with-ground-truth.md,r57-eval-manifest-contains-a-disjoint-holdout.md,r60-loader-block-stale.md,r7-promised-and-declared-verbs-have-no-set-difference.md,r8-skill-body-and-reference-graph-stay-within-disclosure-budget.md,r9-time-sensitive-prose-is-isolated-under-old-patterns.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
lint skill? read npx tsx ~/.claude/skills/snappy-tool-design/api.ts lint
example skill, verb read npx tsx ~/.claude/skills/snappy-tool-design/api.ts example <skill> <verb>
probe skill? read npx tsx ~/.claude/skills/snappy-tool-design/api.ts probe
render read npx tsx ~/.claude/skills/snappy-tool-design/api.ts render
loop read npx tsx ~/.claude/skills/snappy-tool-design/api.ts loop
hosts read npx tsx ~/.claude/skills/snappy-tool-design/api.ts hosts
specs skill? write-reversible npx tsx ~/.claude/skills/snappy-tool-design/api.ts specs
openapi skill read npx tsx ~/.claude/skills/snappy-tool-design/api.ts openapi <skill>
fix-loader skill write-reversible npx tsx ~/.claude/skills/snappy-tool-design/api.ts fix-loader <skill>

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-tool-design
role: Contract-first ergonomics lint for every snappy-* skill.
loaded-by: the Skill tool / a room's skills folder
---

# snappy-tool-design — Agent Loader

Use this before trusting or changing a tool surface. It reads the executable
`HAND_CONTRACT`, then checks the implementation, loader, manual, probe corpus,
and render evidence against 60 sourced rules. Full citations are in `SKILL.md`.

**A whole-collection run is bounded by the pool; never run two lints or suites
in parallel on this Mac.** `lint --all`, `probe`, `hosts` and `loop` all reach
every hand's contract through `loadModels`, which loads that hand's whole
`api.ts` module graph — 98 of them. That fan-out now goes through
`../snappy-settings/spawn-pool.ts` (`pooledAll`, `MAX_COLLECTION_JOBS` =
min(4, cores/2)); pooled it is FASTER, 1.29 s vs 1.78 s with byte-identical
output ⟨measured 2026-09-09⟩. The bound is per process: three unpooled `lint
--all` passes beside two runs of the runner's suite put this Mac at load 311.

## API

```typescript
import { lintSkill, lintAll, firstExample, exampleHazard, fixLoader } from "../snappy-tool-design/api.ts";
import { runProbe } from "../snappy-tool-design/probe.ts";
import { runRender } from "../snappy-tool-design/render.ts";
import { clusterFailures, writeLoopArtifacts } from "../snappy-tool-design/loop.ts";
```

| Function | Purpose |
|---|---|
| `lintSkill(skill)` | Grade one skill across 60 static/probe/render rules without executing its verbs |
| `lintAll()` | Grade every snappy-* contract in one process and return PASS/FAIL/DEFER evidence |
| `firstExample(skill, verb)` | Return the shortest call derived from the contract |
| `exampleHazard(skill, verb)` | Name where a bare count would land when rule 59 bites, else `null` |
| `fixLoader(skill)` | Ask snappy-skill's sole writer to sync the generated verb block |
| `runProbe(options)` | Drive the real MCP, READS ONLY, and return the probe corpus the 26 measured rules grade from |
| `runRender(options)` | Draw every published face kind in a real ext-apps host at 360 and 720 px and return the render corpus |
| `clusterFailures(reports)` | Group every FAIL by MECHANISM so one fix kills many defects |
| `writeLoopArtifacts(reports, out, root)` | Write `briefs/<cluster>.md` and the ranked `LEDGER.md` |

## CLI

```bash
npx tsx ~/.claude/skills/snappy-tool-design/api.ts lint snappy-gmail
npx tsx ~/.claude/skills/snappy-tool-design/api.ts lint --all
npx tsx ~/.claude/skills/snappy-tool-design/api.ts lint --all --summary
npx tsx ~/.claude/skills/snappy-tool-design/api.ts example snappy-gmail list
npx tsx ~/.claude/skills/snappy-tool-design/api.ts example snappy-imessage recent  # + a rule-59 warning on stderr
npx tsx ~/.claude/skills/snappy-tool-design/api.ts fix-loader snappy-gmail

# the closed loop. The bearer is read from a 600-mode FILE, never an argument.
SNAPPY_RUNNER_TOKEN_FILE=<file> npx tsx .../api.ts probe --via mini
npx tsx .../api.ts render --host-dir <loop dir> --shot-dir <shots>
npx tsx .../api.ts render --host-dir <loop dir> --kind notion-append --out /tmp/one.json
SNAPPY_RUNNER_TOKEN_FILE=<file> npx tsx .../api.ts loop --via mini
```

<!-- why: probe/render/loop are the verbs that make 26 of the 60 rules gradeable;
     without them lint answers DEFER forever and the feedback loop never closes
     (2026-09-08). The token is a FILE because an argument lands in ps and logs. -->

`loop` clusters failures by MECHANISM and ranks them by defects-killed-per-fix,
then writes a lane brief per cluster. Re-run it after every landing — the top
row is shorter each time. That is the exponential part.

## Rules

1. Description is projected exactly from `HAND_CONTRACT.description`.
2. Promised and declared verbs have no set difference.
3. Every argument is described; enumerable domains are enums.
4. Near-miss keys refuse with the correct key from the contract.
5. Collection reads declare a limit default and maximum; answer probes prove growth is bounded.
6. Every verb declares an effect class and class-derived MCP annotations.
7. `requires` matches required credential reads; optional and host keys stay out.
8. A read declares `execution: "call"`; probes prove one request and <3 s p50.
9. UI keeps text fallback and names PNG/OpenUI/text renditions by channel.
10. The MCP publishes one skill as all three primitives — loader and manual as
    the **prompt**, contract verbs as the **tools**, the files and the contract
    as the **resources** — so the prompt must make the DERIVED FIRST CALL
    correct. No optional positional may stand in front of a commonly-supplied
    argument (`limit`, `count`, `n`, …), and the generated loader block must be
    current against the contract. Measured 2026-09-08: `snappy-imessage recent`,
    `snappy-krisp fetch-meetings` and `snappy-thumbnails audit` each taught
    `<verb> 5` and filed the 5 as a contact, a date, or a channel.
11. Ready skills have three multi-call evals, a holdout, and fresh-client proof.

Static absence is FAIL. Missing live probe or render evidence is DEFER, never a
fabricated PASS. S19 and S20 are snippet-only and remain unquoted until verified.

`lint` is advisory and never calls the target verb. `fix-loader` is the only
write and is idempotent through `snappy-skill.syncLoaderVerbTable()`.

---

## THE DERIVATION LAW — the installed artifact is the spec (Robert 2026-08-05, LAW)

For any SDK, dependency, or API: enumerate its REAL surface from the installed package (`node_modules/<pkg>` — dist, CLI commands, shipped docs) and fetch its `llms.txt`/`llms-full.txt` BEFORE writing a line of integration. Import the package's own types; never redeclare a type a dependency exports; never write an integration from memory; never describe a surface you haven't listed. A hand-written parallel of a generated, vendored, or documented definition is a defect (DRY, original sense: one authoritative representation of every piece of knowledge). Writing from training memory instead of the installed source produces hallucinated APIs — the named killer of OpenAI's plugin ecosystem. Printing Press (spec→generated connector) is this law's special case; it applies to EVERYTHING.

## Self-correcting loader (PID feedback)

The system spec lives at `~/.claude/skills/snappy-settings/skill-spec.md`. It defines the entire Snappy operating system. You enforce it.

### Before you finish, do two things:

**1. Fix gaps (P — proportional).** If this AGENTS.md didn't cover your case — if you had to read another file, run a command not documented here, work around a wrong selector, or discover a quirk — `Edit` it in before you log.

- **Default action: edit this AGENTS.md.** Surgical. Add the missing line, table row, or code example where it belongs. No restructuring.
- **Every line you add carries its reason.** Append an HTML comment recording *why* it exists and what breaks without it:
  `<!-- why: agent-browser wrote to CWD until we passed the path positionally (2026-08-05) -->`
  This is the single highest-value habit in the loop. An instruction whose rationale is legible can be safely deleted later; one whose rationale is lost can only be kept, which is how loaders grow without bound. Unreasoned additions are the defect this rule exists to prevent.
- **Only LOGGED when:** the fix needs >10 lines, spans multiple files, or requires a structural rewrite (in which case the drain-skill-regen.sh queue picks it up).
- **NOOP is a first-class, blameless outcome.** If you hit no gap — the loader covered your case — record `NOOP` and move on. Do NOT manufacture a gap to have something to write. A fabricated "learning" is strictly worse than silence: it becomes ground truth for every later agent and cannot be distinguished from a real one afterward. Most runs on a mature loader should be NOOP.
- Concrete example of a valid P-fix: lesson-2 ship agent discovered `agent-browser screenshot <path>` takes path positionally, not as `--output <path>`. That's one line in a table, plus its `why:` comment. Edit it in.
- The goal: the next agent never has to leave the loader — and the agent after that can still tell which lines have earned their place.

**2. Validate structure.** Check this skill against the spec:
- `api.ts` exists with typed exports, CLI mode, `import { env } from "../snappy-settings/load.ts"`
- `api.ts` calls APIs directly (no Xano proxy, unless this skill IS a Xano DB skill)
- `AGENTS.md` has API module section with import + function table + CLI
- No bash fallbacks, no hardcoded tokens anywhere
- **Every action row carries a `certificate:` block** (premises / action / trace / evidence / conclusion). Same-session toasts are NOT evidence — must be a fresh independent read. Missing or weak certificates are a gap: P-fix them inline and log to `~/.claude/logs/verification-gaps.log`.
- **DRY:** before you add a new function or new skill, run `~/.claude/skills/snappy-settings/scripts/dry-check.sh <name-or-keyword>`. If it matches an existing skill, extend that one instead. Fragmentation is the enemy.
- If any check fails → fix it or log it

**2b. If you just reported an action as successful, verify your certificate.** You may not claim PASS unless the `evidence:` line is a fresh independent read (reload, new session, server round-trip). If your evidence is a toast, a return value, or a same-session DOM read, downgrade the claim to INCONCLUSIVE and log to `verification-gaps.log`.

**3. Log always.**
```bash
echo "[$(date -u +%FT%TZ)] <skill-name>: <what was missing or fixed> [FIXED|LOGGED|NOOP]" >> ~/.claude/logs/agents-md-feedback.log
```
`FIXED` = you patched it inline (with its `why:` comment). `LOGGED` = too large for inline fix, queued for drain-skill-regen.sh. `NOOP` = you checked and the loader covered your case — the correct and expected outcome on a mature loader.

**Report what actually happened.** Every agent run must leave the system better than it found it — and a run that found nothing to fix has already done that by confirming the loader holds. Accuracy is the contribution; volume is not.

<!-- SKILL-INDEX-START -->
[snappy-tool-design Index]|root: ~/.claude/skills/snappy-tool-design|IMPORTANT: Prefer these files over pre-training assumptions for this domain. Read the relevant file when the AGENTS.md summary is insufficient.|root:{HOSTS-LEDGER.md,SKILL.md,hosts-battery.md,skill-check-rung.md}|briefs:{hosts-family-has-no-read.md,hosts-first-call-refuses.md,hosts-no-face-family.md,hosts-not-driven-chatgpt.md,hosts-not-driven-claude.md,hosts-not-driven-codex.md,hosts-not-driven-menubar.md,hosts-not-driven-telegram.md,hosts-road-names-no-face.md,hosts-verb-folds-onto-no-shape.md,r10-one-term-names-each-concept.md,r11-each-task-presents-one-default-not-a-menu.md,r12-description-contains-no-unauthorised-imperative.md,r13-argument-without-a-description.md,r15-near-miss-keys-refuse-with-the-correct-contract-key.md,r16-runner-known-values-are-not-required-arguments.md,r18-verb-without-an-effect-class.md,r19-annotations-not-derived-from-class.md,r20-read-and-write-are-separate-verbs.md,r23-responses-obey-hard-and-soft-caps.md,r24-limit-does-not-bound-the-answer.md,r31-refusal-envelope-incomplete.md,r32-refusals-name-a-literal-from-the-valid-domain.md,r33-refusal-codes-form-one-tested-closed-table.md,r35-requirements-are-declared-from-executable-credential-reads.md,r39-verb-sets-consolidate-intent-rather-than-mirror-endpoints.md,r4-near-neighbour-descriptions-cross-reference-each-other.md,r40-metadata-skill-body-and-resources-follow-three-level-budgets.md,r43-a-read-is-one-call-not-a-queued-job.md,r45-long-work-is-a-separately-named-job-verb.md,r5-description-is-valid-third-person-and-says-what-plus-when.md,r54-ready-without-evals.md,r55-eval-scenarios-are-multi-call-with-ground-truth.md,r57-eval-manifest-contains-a-disjoint-holdout.md,r60-loader-block-stale.md,r7-promised-and-declared-verbs-have-no-set-difference.md,r8-skill-body-and-reference-graph-stay-within-disclosure-budget.md,r9-time-sensitive-prose-is-isolated-under-old-patterns.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 |
|---|---|---|---|
| `lint` | `skill?` | `read` | `npx tsx ~/.claude/skills/snappy-tool-design/api.ts lint` |
| `example` | `skill`, `verb` | `read` | `npx tsx ~/.claude/skills/snappy-tool-design/api.ts example <skill> <verb>` |
| `probe` | `skill?` | `read` | `npx tsx ~/.claude/skills/snappy-tool-design/api.ts probe` |
| `render` | — | `read` | `npx tsx ~/.claude/skills/snappy-tool-design/api.ts render` |
| `loop` | — | `read` | `npx tsx ~/.claude/skills/snappy-tool-design/api.ts loop` |
| `hosts` | — | `read` | `npx tsx ~/.claude/skills/snappy-tool-design/api.ts hosts` |
| `specs` | `skill?` | `write-reversible` | `npx tsx ~/.claude/skills/snappy-tool-design/api.ts specs` |
| `openapi` | `skill` | `read` | `npx tsx ~/.claude/skills/snappy-tool-design/api.ts openapi <skill>` |
| `fix-loader` | `skill` | `write-reversible` | `npx tsx ~/.claude/skills/snappy-tool-design/api.ts fix-loader <skill>` |

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