skills/ holding a SKILL.md and,
beside it, a FACTS.md.
The twenty-one
The two rules for changing one
1. One skill, one editor, one commit. Do not edit a skill somebody else is editing. If you are adding a capability that touches three skills, commit them together: a reader who gets one skill from your commit and another from somebody else’s gets a contradiction. 2. A skill describes what the code DOES, today. Not what it will do, not what it used to do. Every claim should be checkable against a catalogue entry, a test, or a run, and when you change the code, the skill changes in the same commit or it starts lying. That second rule has already been broken once, expensively.limit-orders said
“there is no adapter that waits for a price, and you must not look for one” for
as long as that was true, and kept saying it after the feature shipped. An
agent reading it talked somebody out of the exact thing they were asking for.
A negative claim is the dangerous kind, because nothing fails when it goes stale.
What to change when
Grep first.
grep -rl "loan.close" skills/ costs nothing and finds the ones you
forgot.
Facts, beside the prose
Each skill has aFACTS.md: the same knowledge, in the shortest form that is
still true.
A section is prose, and prose earns its length; it carries the why, and the
sentences that tell a model how to say a thing are not compressible into claims
at all. But a question like “is gold borrowable on Aave v3” is answered by one
line, and answering it from prose alone costs the 542-word section that line sits
in.
So facts are indexed beside the prose rather than instead of it.
find_skill leads with facts and follows with the two best sections, which is
cheaper than five sections and finds more, because a fact is a small document
dense in the terms somebody actually searches for.
Two properties worth knowing:
- One fact, one fragment. Grouping a section’s facts into one row would return them the way prose is returned: all of a section, to answer one question, which is exactly the cost this removes.
- The heading is the join, and it is checked rather than trusted. A fact names the section it came from and the section supplies the line range, so a fact cites the prose that backs it. A heading that no longer exists is a build failure, not a fact that quietly outlives its source.
Writing for retrieval
The index searches sections, not whole files. Three arms rank them: an English-stemmed one, a literal one that keeps identifiers intact, and BM25: fused by reciprocal rank. Name the subject in the heading and in the first line of the body. The ranking cannot find a section that never says what it is about. Measured on this corpus: the best answer to “what is an approval gate” is a section headed “When a run stops and asks” which does not contain the stringapprov anywhere in it.
Keep sections short. BM25 divides by length, so a two-line answer beats an
essay that mentions the subject in passing, but only if those two lines exist as
their own section.
Write identifiers exactly: arm_schedule, limit_price, loan.close. The
literal arm exists so somebody typing a name finds it; an English stemmer mangles
those into something a search for the exact name no longer matches.
A skill may only name a tool that exists
And more sharply: a tool that spends is withheld from discussion. A skill telling the agent to call one while it is still working out what somebody wants is a skill describing something that will be refused. See the tool server for which five those are.The index rebuilds itself
The index is a derived cache in Postgres, and the repository wins on every boot: unchanged sections are not rewritten, and sections absent from disk are pruned, in one transaction.- Restart the tool server after editing a skill and the change is live. There is nothing to migrate and nothing to remember.
- If Postgres will not answer, the process falls back to reading the files. The table is never a source of truth.
- On staging, skills are baked into the image, so an edit there needs a rebuild rather than a restart. The boot line naming how many sections were indexed is the proof it took.
Before you commit
grep -rn "<the thing you changed>" skills/: did you get all of them?- Restart the server and ask the question a person would ask, in their words.
- If a section you expected did not come back, the heading is the problem, not the ranking.