The body is the dominant cost; the catalog line is negligible.
A user has a Friday ritual: a status summary, structured just so, pulling from the same three places every week. Where does that procedure live? Re-explained every Friday, it costs a paragraph of prompting and drifts a little each time. Baked into the system prompt, every user pays tokens for one user’s ritual. Stuffed into memory, it hits a wall by design — memory is for facts, hard-capped, written by the model. A procedure is a document, written by a person.
That’s the last row of the standing context: skills — reusable instructions users author to shape the agent’s behavior, deliberately, with a name. They complete a symmetry the series has been circling: memory is what the agent writes down about the world; skills are what people write down for the agent.
An index line the author can’t overflow
A skill is {title, description, body} plus an icon and a scope. The body is
markdown, stored as a blob in the object store — and it has no length cap.
The only validation on a skill is a non-empty title and description. Compare
that with memory’s hard field caps and the contrast is the
whole design philosophy in one line: when the model writes the index, you
budget by construction; when a person writes the payload, you let them write —
and make sure the standing context only ever carries one line of it.
That line is the entire per-skill footprint, rendered every turn:
## Skills
Skills are reusable instructions the user has authored to shape your
behavior. This is the complete catalog for the current scope (id — title:
when it applies). …
- prj-status — Project status: Use when the user asks for their status
Seven characters of structure per skill, plus content. The catalog never
touches bodies at all — listing goes through a summary shape with no body
field, precisely so a catalog render doesn’t pay one object-store read per
skill. The body stays behind an address until someone dereferences it, which
by part 3’s vocabulary makes a skill a pointer with a title.
Two prompt-design details here are worth stealing. The section announces
itself as the complete catalog — and it renders even when empty, on
purpose. The code comment: the empty section “tells the model the
application already checked every applicable scope and prevents speculative
list_skills lookups.” A missing section invites the model to go looking; an
empty one closes the world. And the description is taught to authors as a
selection signal — name the trigger condition, not the skill’s title —
because its one job is to let a model decide whether to activate without
reading the body.
Activation: the pull, and what it costs after
The epigraph is a verbatim design comment, and it answers a question you might not think to ask: why aren’t activated skills removed from the catalog? Because it isn’t worth a line of code. “Activated skills are intentionally NOT filtered out — their body re-injection is the dominant cost; the catalog line is negligible.” Optimize the dominant cost; don’t polish the negligible one. The dominant cost is real: once activated, the body is replayed into context on every subsequent call for the life of the conversation — which is exactly right for instructions that must stay in effect, and exactly why the budget-conscious unit is the activation, not the catalog entry.
The mechanics tie back through the whole series:
activate_skillis part of part 2’s always-declared scaffolding — so matching a skill costs zero discovery round-trips. The five skill-management tools (define_skill,edit_skill,delete_skill,get_skill,list_skills) are not: managing skills is rare, so it pays the normal search → activate path. Frequency of use decides what’s standing.- The tool is
internalandtrusted: a control action, invisible to external callers, never gated on approval. An unknown id fails with a pointer back to the catalog. - There are two activation paths with opposite freshness semantics — a genuinely sneaky detail. Model-initiated activation returns the body as a tool result: frozen at activation time, replayed verbatim from the transcript. User-initiated activation persists only the skill id, and the provider re-resolves the body on every call: live, so edits propagate into running conversations and a deleted skill silently drops out. Same feature, two consistency models, each matching who initiated it.
Who sees which skills
Scope is three nullable axes — template, project, user — where null means “not restricted by this axis” and a skill is visible iff every axis it does set matches the caller:
The interesting case is the second row: a skill authored once on a template reaches every project that adopts that template — instructions distributed through the same adoption relationship the rest of the product already uses, with a per-project include/exclude selection as the throttle. Teaching scales the way configuration scales.
One more mirror of part 4: if the skill catalog can’t be loaded at wake-up, the harness fails the whole turn and lets message-bus redelivery retry, rather than proceeding without it. The doc comment: skills are user-authored instructions, so “no caller silently proceeds without them.” Tool discovery degrades gracefully; user-taught behavior does not get to silently vanish. Machine-derived context fails soft; human-authored context fails hard.
The agent as author
The loop closes in a pleasing way: define_skill is an agent tool. A user
can demonstrate a procedure once in conversation and ask the agent to make it
a skill — the model drafts the body, and is instructed to write the
description as the trigger condition it would itself want to read next time.
The agent authors its own future context, in the one place where authored
context is designed to be cheap until used.
The honest costs, since unbounded trust cuts both ways: a user can paste a small book into a body and pay for it on every turn after activation — the system trusts authors rather than capping them. Activating the same skill twice injects the body twice; nothing dedupes it. And the empty-catalog paragraph is a short standing cost paid by everyone, purchased to prevent something more expensive — speculative search calls.
The series, whole
Five mechanisms, one principle applied at five altitudes:
| Mechanism | Standing cost | Payload | Pull |
|---|---|---|---|
| Ontology | 13 one-liners · ≈340 tok | the concept graph | explore_ontology |
| Tools | capability line + ~12 schemas | 169 schemas · ≈21k tok | search_tools → activate_tool |
| Values | previews + $ref stubs | unbounded bytes | $ref resolution |
| Memory | a capped {key, description} index | capped records | recall_memories |
| Skills | one line per skill | unbounded bodies | activate_skill |
And underneath all five, the same two commitments. Defer, don’t truncate: nothing in this harness is thrown away to make room — it’s parked behind an address. That’s why the shrinking is not a trade-off against capability but a second win: the window the model reads is all signal, nothing it might need has been omitted, and both the token bill and the error rate go down together. Keep the prefix byte-stable: sorted declarations, WeakMap-cached schemas, the one varying line last — deferral constantly mutates the prompt, and these small disciplines are what keep the automatic prefix cache paying for it.
The honest bill, series-wide: every deferral is a round trip the model must decide to make, so the harness spends prompt text teaching it to search, drill, forward and activate; transcripts are less self-contained; and all of it is real engineering — indexes, projections, resolvers, digests, catalogs, and their tests — where a small product could paste its five tools and one page of notes into the prompt and be correct. Do that as long as you can. We couldn’t. If your catalog has three digits, your domain has its own vocabulary, your tools move megabytes, or your users have things to teach, I hope these five parts read as one pattern applied five times — an index in context, a payload behind a pull, and a model that navigates by address instead of by copy. Pointers, not payloads, all the way down.