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.

Commands and settings below are quoted from the project README and the commented example config. They were not executed while building this page.

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.

config file and override
SettingPiClaude 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.

configuration keys
KeyDefaultWhat 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.

fixed limits
LimitValue
search_skills results8 max, 5 by default
list_skills page size20 by default, 30 max
Human listing page size10
Result description budgets220 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