skilled-labour

内容来源:README.md(说明文档) · 原始地址 · 查看安装指南

原始内容

skilled-labour

A pi extension that makes small models actually load skills by leveraging their ability to issue tool calls.

How skills work

Pi implements a skills system. At startup, it builds an <available_skills> block, summarizing each discovered skill's name and when to load, and telling the model where the skill is to be found. The model is then told (in text) to:

  • consider whether any skill(s) are relevant to present tasks
  • load those skill(s) by calling the read tool to read the SKILL.md file first
    • (potentially reading supporting files, depending on the skill)

The problem

  • Models excel at what they were trained on.
  • Even small models are trained heavily on tool-calling
  • Local models are bad at using skills; probably no trained to do so

The solution

Make loading a skill a tool call - leverage existing strengths


What skilled-labour does

  1. Strips pi's skills block and instructions from the system prompt.
  2. Appends a compact replacement carrying only skill names and descriptions.
  3. Registers a load_skill(NAME) tool for the LLM to load a skill
    • the tool resolves the path to the skills SKILL.md and loads it
    • the response explicitly tells the LLM the skill's directory so referenced supporting files can be loaded if need be.

load_skill is idempotent: a re-call for an already-loaded skill no-ops (so the model's reflexive re-calls don't bloat context), and session_compact clears the "loaded" set so a post-compaction call re-injects the full body exactly when re-injection is needed.


Install

Place this directory in your pi extensions folder:

  • Linux/MacOS: ~/.pi/agent/extensions
  • Windows: %USERPROFILE%\.pi\agent\extensions\

Implementation Details

Before - (default SKILLs implementation)

Injected into the system prompt verbatim. One <skill> block per skill, each carrying a <location> path the model is expected to copy into a read call:

The following skills provide specialized instructions for specific tasks.
Use the read tool to load a skill's file when the task matches its description.
When a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.

<available_skills>
  <skill>
    <name>odin-programming</name>
    <description>Write, create, and edit Odin programs...</description>
    <location>/home/nixos/.pi/agent/skills/odin-programming/SKILL.md</location>
  </skill>
  <skill>
    <name>nix-flakes-editor</name>
    <description>Write, create, and edit Nix flakes...</description>
    <location>/home/nixos/.pi/agent/skills/nix-flakes-editor/SKILL.md</location>
  </skill>
</available_skills>

The model is then expected to read prose instructions and spontaneously issue a read tool call against one of those <location> paths. Small models don't.

After — (skilled-labour)

The verbose block is stripped and replaced with a compact one-line-per-skill section (no <location> — the tool resolves it) plus a pointer to load_skill:

<available_skills>
  <skill name="odin-programming">Write, create, and edit Odin programs...</skill>
  <skill name="nix-flakes-editor">Write, create, and edit Nix flakes...</skill>
</available_skills>
Call the load_skill tool with a skill's name to load its full instructions, BEFORE acting on a task the skill covers. It is cheap and strongly recommended. If a skill's instructions are already in the conversation above (loaded earlier this session), do not reload it.

And load_skill is registered as a real tool whose description and guidelines carry the same nudge — reconsidered by the model every turn:

pi.registerTool({
  name: "load_skill",
  description:
    "Load a skill's full instructions by name. Call this BEFORE acting on any task that a listed skill covers — it is cheap (one call) and nearly always improves results. No-op if the skill is already loaded. Pass the exact skill name from the <available_skills> list in the system prompt.",
  promptGuidelines: [
    "Before acting on a task, check the <available_skills> list in the system prompt. If any skill matches the task, call load_skill with its name FIRST, then follow the instructions it returns. Do not write code or run commands for a skill-covered task without loading the skill first.",
  ],
  parameters: Type.Object({
    name: Type.String({ description: 'Exact skill name from the <available_skills> list, e.g. "odin-programming".' }),
  }),
  async execute(_toolCallId, params) { /* resolve name -> read file -> return body */ },
});