Skills: three-level progressive disclosure
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.