Skills System

One-line summary

The skills system loads SKILL.md files from three sources (bundled, workspace, plugins), builds a catalog with hard token limits, and injects it into the system prompt so the agent can discover and use specialized capabilities.

Responsibilities

  • Discover skills from bundled directory (52 skills), agent workspace, and plugin extensions
  • Parse SKILL.md frontmatter for metadata (requirements, invocation policy, description)
  • Build a skills catalog (name + description + path) for system prompt injection
  • Enforce hard limits on catalog size (max 150 skills, max 30,000 chars)
  • Compact skill paths (~ substitution) to save tokens
  • Support hot-reload via filesystem watchers and snapshot versioning

Architecture diagram

Key source files

FileLinesRole
src/agents/skills/workspace.ts760Core: skill discovery, loading, catalog building, compactSkillPaths(), applySkillsPromptLimits()
src/agents/skills/refresh.ts207Hot-reload: filesystem watchers, snapshot versioning
src/agents/skills/frontmatter.ts117Metadata: parse SKILL.md frontmatter, invocation policy resolution
src/agents/skills/config.ts102Configuration: bundled allowlist, eligibility checks (OS, env, paths)
src/agents/skills/filter.ts31Filtering: name-based skill matching
src/agents/skills/types.ts89Types: SkillSnapshot, skill metadata interfaces
src/agents/skills/serialize.ts14Serialization: queue-based loading coordination
src/agents/skills/env-overrides.ts196Environment: inject env vars required by skills
src/agents/skills/bundled-dir.tsBundled skill directory resolution
src/agents/skills/tools-dir.tsTool skill directory resolution

Token optimization impact

Hard limits (workspace.ts:95-98)

DEFAULT_MAX_CANDIDATES_PER_ROOT = 300     (discovery cap per directory)
DEFAULT_MAX_SKILLS_LOADED_PER_SOURCE = 200 (loading cap per source type)
DEFAULT_MAX_SKILLS_IN_PROMPT = 150         (prompt inclusion cap)
DEFAULT_MAX_SKILLS_PROMPT_CHARS = 30,000   (≈ 7,500 tokens hard limit)
DEFAULT_MAX_SKILL_FILE_BYTES = 256,000     (per-file size limit)

Token budget breakdown

52 bundled skills × ~30-50 tokens each = ~1,500-2,600 tokens (catalog)
+ workspace skills (variable)
+ plugin skills (variable)

Typical total: ~1,500-3,000 tokens for catalog
Maximum: ~7,500 tokens (30,000 chars / 4 chars per token)

Savings from compactSkillPaths(): ~400-600 tokens
  (5-6 tokens per skill path × 52+ skills)

Key optimization: catalog only, not full content

The system prompt contains only the catalog (name + description + file path), not the full SKILL.md content. The agent reads the full SKILL.md only when it selects a specific skill. This is a critical design decision that keeps the fixed token cost manageable.

Prompt instruction overhead

## Skills (mandatory)
Before replying: scan <available_skills> <description> entries.
- If exactly one skill clearly applies: read its SKILL.md at <location> with `read`, then follow it.
- If multiple could apply: choose the most specific one, then read/follow it.
- If none clearly apply: do not read any SKILL.md.
Constraints: never read more than one skill up front; only read after selecting.

~80 tokens for instructions + catalog tokens

disableModelInvocation frontmatter flag

Skills with disable-model-invocation: true are excluded from the model-facing catalog but remain available for user-invoked slash commands. This reduces catalog size for skills that should only be triggered explicitly.

Data flow

Loading

Startup / config change / file change

Discover SKILL.md files (max 300/root)

Load per source (max 200/source)

Parse frontmatter (requirements, description, invocation policy)

Check eligibility (OS, env vars, config paths, bundled allowlist)

Build catalog entries (name + description + path)

compactSkillPaths() → replace homedir with ~

applySkillsPromptLimits() → binary search for max skills within char budget

Inject into system prompt as <available_skills> block

Runtime selection

User sends message

Agent scans skill catalog in system prompt

If skill matches: agent calls read tool on SKILL.md path

Agent follows SKILL.md instructions

How it connects to other modules

  • Depends on:

    • config/ — skill settings, bundled allowlist
    • File system — SKILL.md discovery and watching
  • Depended by:

    • system-prompt.ts — receives skill prompt for injection
    • pi-embedded-runner/ — receives skills snapshot
    • auto-reply/skill-commands.ts — user-invoked skill commands

My blind spots

  • Exact binary search algorithm in applySkillsPromptLimits() — how it prioritizes which skills to include
  • Whether workspace skills override bundled skills with the same name
  • tools-dir.ts vs bundled-dir.ts — different discovery strategies
  • Skill snapshot caching behavior and invalidation triggers
  • How plugin-provided skills are registered and discovered
  • None yet

Change frequency

  • workspace.ts: Medium — limits tuning and loading logic evolve
  • refresh.ts: Low — watcher pattern is stable
  • frontmatter.ts: Low — metadata schema is additive
  • config.ts: Low — eligibility checks rarely change