Skills: three-level progressive disclosure

Updated · View the entry on sijie.xyz ↗

A skill is not one-tool-per-script (that explodes the tool list and bloats the system prompt) — and a skill is not a capability either: it's an authored artifact riding on capabilities (confusables). Instead, three levels:

  • L1 — only the skill's name + description sits in the system prompt
  • L2 — one skill_use(name) tool reveals the full SKILL.md on demand, when the agent judges it relevant
  • L3 — one skill_run_script(name, script, args) runs it in the sandbox

So the agent sees capability names first, reads the details only if interested, executes only if needed (backend/internal/routes/capload/capreg_skill_runner.go). SKILL.md is the canonical agent-facing contract; the DB row is just the management store — the same SKILL.md format is what the marketplace parses.

Class view

classDiagram
  class skillRunnerCapability {
    -deps skillRunnerDeps
    ONE capability, TWO generic tools
    SystemPromptFragment() = empty - L1 rides the persona
    per-skill ACL checked INSIDE each tool
  }
  class skillRunnerDeps {
    Skills conversation.SkillGetter
    Sandbox sandbox.Runner
  }
  class parseSkillName {
    <<func>>
    parses the skill_use args: {name}
  }
  class runScriptArgs {
    Name string
    Script string
    Args json.RawMessage
  }
  class renderSkillMD {
    <<func>>
    takes *domain.Skill, returns string
    YAML frontmatter + body + scripts section
  }
  class skillRunPayload {
    Stdout, Stderr string
    ExitCode int
    TimedOut bool
  }
  skillRunnerCapability *-- skillRunnerDeps
  skillRunnerCapability ..> parseSkillName : skill_use (L2)
  skillRunnerCapability ..> renderSkillMD : L2 output
  skillRunnerCapability ..> runScriptArgs : skill_run_script (L3)
  skillRunnerCapability --> skillRunPayload : L3 output

The class shape is the disclosure design: two generic tools instead of N per-script tools — the tool list stays O(1) in the number of skills.

Related notes