Playbooks & skills
Two kinds of reusable markdown document a routine run can pull in — one you push, one the model pulls.
Both are stored via CRUD endpoints (playbooks, skills), 16KB content limit each, with optional leading YAML frontmatter stored verbatim but not parsed.
Playbooks are PUSHED
You name them explicitly in a run's playbooks launch field (selection order = priority order); at most 4 per run. Each playbook has a routines field (["review"], ["bughunt"], or both) and is rejected at launch (400) if it doesn't apply to the kind you're launching, or doesn't exist.
Skills are PULLED
There is no launch field for skills — every run sees the full {name, description} catalog and the model itself picks at most 3 relevant ones by name (review: one small selection call up front; bug hunt: a load_skill(name) tool it can call mid-investigation).
# Create a playbook (applies to both routine kinds by default)
curl -X POST localhost:8000/routines/playbooks \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"name":"security-basics","content":"# Security basics\n\n- ...","routines":["review","bughunt"]}'
# Create a skill (description is what the model sees when deciding whether to load it)
curl -X POST localhost:8000/routines/skills \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"name":"sql-injection-review","description":"How to spot SQL injection in raw-query code paths.","content":"..."}'