snappy-sensors skill
dumpreadsection namereadstaleread$ npx snappy-skills install snappy-sensors
You are carrying an ambient awareness of classroom state. Every agent with snappy-sensors loaded has just seen (or is about to run) status.sh, a deterministic dump of:
shipped (has skool_url: in frontmatter) vs drafted (no skool_url:). Ground truth is disk. snappy-course/scripts/backfill-ship-state.sh patches frontmatter from pass-log after each ship. body tagslint-draft.sh --all)pass-log.mdsnappy-course/data/pass-log.mdThis is the team-leader's dashboard. When a user asks "what's the state of the classroom" or you're dispatched into a cron loop, the sensor dump is the first thing you read.
Read the most recent === snappy-sensors @ <ts> === block in your context. If the timestamp is stale (> 10 min old) and you need fresh readings, run:
bashbash ~/.claude/skills/snappy-sensors/status.sh
It is safe to run any time. File-only reads, no network, no browser, <2s on a warm cache.
typescriptimport { dump, parseDump, section, isStale } from "../snappy-sensors/api.ts";
| Function | Purpose |
|---|---|
dump() |
Run status.sh and return stdout as a string |
parseDump(text) |
Parse the dump into { timestamp, sections } |
section(text, name) |
Return body lines for a single named section (e.g. lint, covers) |
isStale(timestamp) |
True if the dump timestamp is missing or older than 10 minutes |
CLI:
bashnpx tsx ~/.claude/skills/snappy-sensors/api.ts dump
npx tsx ~/.claude/skills/snappy-sensors/api.ts section lint
npx tsx ~/.claude/skills/snappy-sensors/api.ts stale # exit 0 fresh, 1 stale
Sensors live in ~/.claude/skills/snappy-sensors/scripts/. The rules:
time on it). The whole dump has a 2s budget.[<name>]. No JSON, no colors, no unicode glyphs. Greppable.status.sh and update this file's section list above.data/ files that sensors can read.This skill lives in always-inject.txt so every agent — subagent, cron wake, manual invocation — sees classroom state in its first context block. Passive context > active retrieval (Vercel agents research: 100% vs 53% pass rate). An agent that has to decide whether to run status.sh often won't; an agent that already has the dump in front of it always acts on it.
<!-- SKILL-INDEX-START -->
[snappy-sensors Index]|root: ~/.claude/skills/snappy-sensors|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 -->
Nothing in the collection names this skill.
<!-- SNAPPY-CONTRACT-VERBS-START -->
Generated from api.ts HAND_CONTRACT. Do not hand-edit this block.
| Verb | Contract arguments | Effect | First call |
|---|---|---|---|
dump |
— | read |
npx tsx ~/.claude/skills/snappy-sensors/api.ts dump |
section |
name |
read |
npx tsx ~/.claude/skills/snappy-sensors/api.ts section "<name>" |
stale |
— | read |
npx tsx ~/.claude/skills/snappy-sensors/api.ts stale |
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-sensors
role: Ambient classroom-state sensor layer — loaded into every agent so the team leader always sees live state
loaded-by: preload-skill-context hook (via always-inject.txt)
---
# snappy-sensors — The Sensor Layer
You are carrying an ambient awareness of classroom state. Every agent with snappy-sensors loaded has just seen (or is about to run) `status.sh`, a deterministic dump of:
- **[courses]** — per-course lesson count and when each course was last touched
- **[draft-state]** — per course: needs-image / needs-ground / complete counts
- **[ship-state]** — per course: `shipped` (has `skool_url:` in frontmatter) vs `drafted` (no `skool_url:`). Ground truth is disk. `snappy-course/scripts/backfill-ship-state.sh` patches frontmatter from pass-log after each ship.
- **[words]** — per course: short (<500) / target (500-1200) / long (>1200)
- **[inline-illos]** — long lessons (>500w) with fewer than 2 `` body tags
- **[lint]** — D1-D6 pass/fail counts per course (runs the canonical `lint-draft.sh --all`)
- **[covers]** — any locally-cached cover whose pixel dims are NOT a standard size (1080x1080, 1920x1080, 1940x1000, 1080x1440). Silence here means no known squishers in cache.
- **[logo-opps]** — lessons mentioning tools (Xano/Supabase/etc.) without logo refs in frontmatter
- **[gap-flags]** — unresolved gap flags grepped from `pass-log.md`
- **[pass-log]** — last 10 pod runs from `snappy-course/data/pass-log.md`
This is the team-leader's dashboard. When a user asks "what's the state of the classroom" or you're dispatched into a cron loop, the sensor dump is the first thing you read.
## How to use the dump
Read the most recent `=== snappy-sensors @ <ts> ===` block in your context. If the timestamp is stale (> 10 min old) and you need fresh readings, run:
```bash
bash ~/.claude/skills/snappy-sensors/status.sh
```
It is safe to run any time. File-only reads, no network, no browser, <2s on a warm cache.
## API module
```typescript
import { dump, parseDump, section, isStale } from "../snappy-sensors/api.ts";
```
| Function | Purpose |
|---|---|
| `dump()` | Run `status.sh` and return stdout as a string |
| `parseDump(text)` | Parse the dump into `{ timestamp, sections }` |
| `section(text, name)` | Return body lines for a single named section (e.g. `lint`, `covers`) |
| `isStale(timestamp)` | True if the dump timestamp is missing or older than 10 minutes |
CLI:
```bash
npx tsx ~/.claude/skills/snappy-sensors/api.ts dump
npx tsx ~/.claude/skills/snappy-sensors/api.ts section lint
npx tsx ~/.claude/skills/snappy-sensors/api.ts stale # exit 0 fresh, 1 stale
```
## Decision shortcuts (read the dump, act)
- **Courses with 0 last-touch in > 48h** and existing lint failures: candidate for a polish pod
- **[lint] fail count > 0 on any course**: block shipping that course until D1-D6 clean
- **[covers] section is not empty**: dispatch a squished-cover audit+fix pod before any new cover generation
- **[pass-log] top entry is a gap flag without a follow-up**: that gap needs closing before new work
## Inventing new sensors
Sensors live in `~/.claude/skills/snappy-sensors/scripts/`. The rules:
1. File reads only. No network, no browser, no paid API calls. A sensor must never cost money to read.
2. Under 500ms per sensor (run `time` on it). The whole dump has a 2s budget.
3. Deterministic output. Same inputs → same bytes out. This is what makes ambient context cacheable.
4. Plain text with a fixed section header like `[<name>]`. No JSON, no colors, no unicode glyphs. Greppable.
5. When you add a sensor, wire it into `status.sh` and update this file's section list above.
## What this skill does NOT do
- It does not dispatch pods. The team leader (the outer agent context) does that based on reading the dump.
- It does not fetch state from Skool, Notion, or any external service. Use dedicated skills for that and mirror their cached state into `data/` files that sensors can read.
- It does not judge content quality. It reports measurements — D-lint pass/fail, last-touched, dim mismatches. Taste calls stay with the team leader.
## Why this is kernel-level
This skill lives in `always-inject.txt` so every agent — subagent, cron wake, manual invocation — sees classroom state in its first context block. Passive context > active retrieval (Vercel agents research: 100% vs 53% pass rate). An agent that has to decide whether to run `status.sh` often won't; an agent that already has the dump in front of it always acts on it.
<!-- SKILL-INDEX-START -->
[snappy-sensors Index]|root: ~/.claude/skills/snappy-sensors|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 |
|---|---|---|---|
| `dump` | — | `read` | `npx tsx ~/.claude/skills/snappy-sensors/api.ts dump` |
| `section` | `name` | `read` | `npx tsx ~/.claude/skills/snappy-sensors/api.ts section "<name>"` |
| `stale` | — | `read` | `npx tsx ~/.claude/skills/snappy-sensors/api.ts stale` |
## 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 -->