deferred skill catalog · assembly order
Getting started.
Five steps. Pick your harness in step 2 — Pi and Claude Code are set up differently, because they defer the catalog differently.
Check what you already have
The package is a Pi package and a Claude Code plugin. You need one of the two harnesses, and nothing else for Pi. The Claude Code plugin runs straight from its install directory on Node 24+, which strips TypeScript types natively.
Skills are read from disk, so there is nothing to import or convert. If you already have a skills directory, the catalog can search it.
Install for your harness
These are two separate setups, not a sequence. Read the one for the harness you use.
Pi
Install the package:
pi install git:github.com/slogsdon/deferred-skill-catalog
Or try it for one run, without installing:
pi -e git:github.com/slogsdon/deferred-skill-catalog
Restart Pi after installing or after changing configuration.
Turning deferral on. Nothing to switch on. Pi's
<available_skills> block is replaced in
before_agent_start with a short pointer to
search_skills and list_skills, controlled by the
stripStaticCatalog key, which defaults to
true. Set it to false to leave Pi's prompt
untouched and treat this package as search-only.
The limit of that. Stripping the static catalog hides
skills that aren't in your roots. If Pi loads skills from a location you
didn't list, they leave the prompt and don't enter this catalog. Either
add those locations to roots, or set
stripStaticCatalog to false.
Check it.
/skills --config
That prints the resolved config, so you can see which roots were picked up and which exclude rules survived validation.
Claude Code
Add the marketplace, then install the plugin:
claude plugin marketplace add slogsdon/deferred-skill-catalog
claude plugin install deferred-skill-catalog@deferred-skill-catalog
Turning deferral on. This is a second, separate step.
Claude Code has no hook that can rewrite its system prompt, so the plugin
can't remove the listing on its own. Add this to
~/.claude/settings.json:
{ "skillListingBudgetFraction": 0.0001 }
When the skill listing exceeds that budget, Claude Code drops descriptions
and lists - name only. At 0.0001 the budget is
smaller than the names alone, so every description goes; the plugin then
serves those descriptions on demand. Restart Claude Code afterwards.
The limit of that. Names stay in the prompt — only descriptions are removed. A few thousand tokens of names remain for a few hundred skills, which is also what lets a search result go straight to the Skill tool. Claude Code's own bundled skills keep their descriptions, because it exempts them from the budget.
Check it.
/deferred-skill-catalog:skills --config
That shows whether the setting is in effect, alongside the resolved configuration and sources.
Point it at your skill directories
Everything in this step is optional. Without a config file both harnesses use their defaults.
| Setting | Pi | Claude Code |
|---|---|---|
| Config file | ~/.pi/agent/deferred-skill-catalog.json |
~/.claude/deferred-skill-catalog.json ($CLAUDE_CONFIG_DIR respected) |
| Override env var | PI_DEFERRED_SKILL_CATALOG_CONFIG |
CLAUDE_DEFERRED_SKILL_CATALOG_CONFIG |
Default roots |
~/.pi/agent/skills, ~/.agents/skills |
none — Claude Code's own sources are always indexed |
The env var names a file and bypasses discovery. If that file doesn't exist, the defaults are used and the problem is reported.
One file can serve both harnesses. Symlink it into both places. In Claude Code, a root skill is dropped when its bare name matches an indexed Claude skill, so Pi's clone of an installed plugin doesn't double every search result. The Claude copy is the one the Skill tool loads.
The file is JSON with // comments and trailing commas allowed, so
it can explain itself. The
commented example config
carries every key with its default.
| Key | Default | What it does |
|---|---|---|
roots |
see above | Skill directories, searched in order; the first root wins when two roots define the same name. Replaces the defaults. In Claude Code these are extra roots. Accepts ~, $VAR, ${VAR}, absolute paths, and paths relative to the config file. |
exclude |
[] |
Blacklist rules. A bare string blacklists that skill name in every root; the object form adds pathIncludes, a plain case-sensitive substring of the absolute path (not a glob). Excluding removes a skill from search only. |
skipDirectories |
[".git", "node_modules"] |
Directory names the walk never descends into. Replaces the defaults. |
maxDepth |
12 |
Maximum directory levels below each root. 0 reads the root itself. Guards against a root that points at a huge tree. |
stripStaticCatalog |
true |
Pi only. Replace Pi's static catalog block with the deferral notice. Set false to leave Pi's prompt untouched. |
Shortened from the commented example: a minimal file that adds one shared tree and drops two vendored skills.
{
"roots": ["~/.pi/agent/skills", "~/.agents/skills", "~/.claude/skills"],
"exclude": [
"some-skill-you-never-use",
{ "pathIncludes": "/vendor/makerskills/skills/", "names": ["decide", "ingest"] }
]
}
Restart the harness after editing. Discovery is cached for the life of the process, and rooted walks are lazy: roots are read on first use, not at startup.
Know the limits you can't configure
These values are baked into the tool schemas and descriptions the model sees,
so they are deliberately not configurable. The deferral knobs are the only
tuning surface: stripStaticCatalog in this package's config for
Pi, and skillListingBudgetFraction in Claude Code's own settings
for Claude Code.
| Limit | Value |
|---|---|
search_skills results | 8 max, 5 by default |
list_skills page size | 20 by default, 30 max |
| Human listing page size | 10 |
| Result description budgets | 220 chars (search_skills), 120 (list_skills), 80 (listing) |
Two more edges are fixed by the harness rather than by this package. In
Claude Code, claude.ai-synced plugins aren't indexed: their skills are still
listed name-only, but search won't find them unless you add their directories
to roots. And the MCP tools may themselves be deferred behind
ToolSearch — if so, the server's instructions say to load
search_skills through ToolSearch first.
Search or list the catalog
Ask the model for a capability and it calls search_skills; ask
what's installed and it calls list_skills. To look yourself, use
the human listing — a query, a page number, or both:
/skills pdf
/deferred-skill-catalog:skills pdf page=2
From a checkout of the repository, the same listing runs directly. This is the example the README's development section uses, and it needs a clone:
node claude/server.ts --list pdf
A search result names the skill, gives a trimmed description, and says how to
load it. Claude Code skills — project, user, and enabled plugins — say
Load with the Skill tool: <name>, so arguments,
allowed-tools, and ${CLAUDE_PLUGIN_ROOT} work as
normal. Everything else, including Pi skills and extra roots in Claude Code,
says Read <path>/SKILL.md before applying it.
That last distinction is the one worth internalising: search is a pointer, not a loader. The skill file is read before it is applied.
where to go
after setup-
Project introduction
What the package is, and what it does not claim.
-
Source on GitHub
README, the Pi extension, the Claude Code plugin, and the test suites.
-
Commented example config
Every key with its default, including the exclusion rules.