.pptx files
reads nearly the same as the one that authors them. Ask for a pitch deck and the agent
may load the wrong one. On a turn where no skill fits at all, it may still load
one anyway, because a list of names invites a guess.
This cookbook leaves the descriptions alone and uses progressive disclosure instead,
reading all 182 skills cheaply and then reading three of them in detail. Two TypeSafe
requests go in front of the decision on which skill to load, if any. The first ranks every
skill in the roster against the user’s turn and answers whether the turn needs a skill at
all. The second re-reads only the top three, now with each skill’s full description and the
opening of its instructions, and is free to reject all of them.
The winner’s name goes into one extra line of the agent’s system prompt for that turn:
claude-haiku-4-5-20251001, using skills from the
Hermes roster:
The third row shows the floor for making mistakes is not zero, because an agent given the
right skill still does not always load it, and no selection method, however good, gets past
that.
You end up with a
suggest() function that returns at most one skill name, a
suggestion_block() that wraps it for the system prompt, and the harness that produced the
table above, ready to point at your own roster.
Setup
- Install the TypeSafe client, the Anthropic client, and the shared cookbook helpers.
- Set a TypeSafe API key, and an Anthropic key for the agent being measured.
Note: the code blocks below are one script, in order. To follow along, put them in a single file in the order shown.
Caching results
JsonCache saves each call’s result, keyed on its inputs, so re-running replays the
numbers below instead of calling either API. Delete json_cache.json to run live. The
published run used jev-1.12 and claude-haiku-4-5-20251001, rendered 2026-07-31.
Step 1: load the roster
hermes_roster.json holds the 182 skills of
NousResearch/hermes-agent (MIT) at one
pinned commit. Each record holds a skill’s name and category, the description as the index
shows it, the full description, and the opening of its SKILL.md.
The index below, and the instructions above it in the prompt, are copied from Hermes.
Step 2: score the agent on its own
requests.json holds 488 single-turn requests, 315 of them covered by exactly one skill
and the other 173 covered by nothing.
The covered requests were written by Claude Sonnet 5 from each skill’s own SKILL.md, so
the labels are trustworthy and the requests are easier than the ones users send.
The 173 uncovered ones were all written to punish guessing: 85 everyday requests, 42
technical questions no skill serves (explain what a monad is), and 46 that ask for
something specific the roster has no skill for, like post this to Mastodon on a roster
that covers X and nothing else.
Scoring reads the agent’s first response only. Both numbers are error rates, so lower is
better on each:
- wrong load: of the covered requests, the share where the first
skill_viewcall was not the covering skill. A turn that loaded nothing at all counts as a miss. - needless load: of the uncovered requests, the share where the agent called
skill_viewat all.
skill_view to load a skill using a
free-text name. The name must match the skill exactly for a correct load.
Step 3: rank the whole roster
One request carries two kinds of question:whichis aChoiceover all 182 skill names, with the index description as each option’s criteria (the same text the agent itself gets). Its probabilities are the ranking.- three
Nouls about the request, printed below, each asking a different way whether it wants an action taken rather than an explanation given.prose_sufficescounts the other way round. Their mean decides whether to suggest anything at all, and under 0.30 nothing is suggested.
Choice holds a roster this size comfortably. A few times larger and you would
split it into chunks and rank each one, then run this same shortlist step over the winners.
.pptx skills, and on 60 characters the wide Choice
puts the editing skill ahead of the authoring one, for a request about authoring a deck.
Step 4: rerank the top three
Three options leave room for the full description plus the opening of each skill’s ownSKILL.md, so the second request puts the same question to better evidence:
whichis aChoiceover the shortlist, with that longer text as each option’s criteria.fits::{name}is oneNoulper candidate: does this skill do the specific thing the request asks for? Each is answered on its own, so they can all come back low, and a shortlist whose highest one lands under 0.30 gets dropped entirely.
.pptx skills separate once each one brings its own text: the deck request flips
to the authoring skill.
The fits nouls and the Choice disagree there: the nouls score the editing skill higher
while the Choice picks the authoring one. They are deciding different things. The Choice
settles which skill, and the nouls settle whether to say anything at all.
The Mastodon request survives both checks. Its best fits noul lands above 0.30, so the
recipe suggests the X skill for a request about Mastodon. Most requests like it do get
caught, but a second pass can only reject what the wide ranking hands it, and here that was
three near-misses.
The function below is the whole recipe: two requests and two thresholds, with at most one
skill name coming back.
To point it at your own roster, replace hermes_roster.json. Every question above reads
name, description, description_full, and body out of that file, and nothing else
knows about Hermes.
Step 5: measure the suggestion
Each of the 488 requests goes to the agent three times, one measured turn each. The runs differ only in what the agent is told:
The third is not achievable; it is the ceiling the other two get measured against.
The wording of that suggestion is doing two jobs. It says the suggestion can be ignored,
because pushing harder wins compliance on wrong suggestions too, and a wrong one is worse
than none. And a turn with nothing to suggest still sends a sentence saying so; sending
nothing at all would leave the roster’s own “err on the side of loading” instruction
unopposed.

What the results show
- Wrong loads fell from 16.8% to 7.3% and needless ones from 9.8% to 4.0%, which is most of the gap between guessing from a truncated index and being handed the answer.
- Some requests the agent had right on its own come back wrong once a suggestion is attached. Counts are above.

