.pi/skills/create-specialized-subagent/SKILL.md
Create specialized subagents within the subagents extension. Use when asked to create a new subagent like scout, librarian, oracle, etc.
npx skillsauth add aliou/pi-extensions create-specialized-subagentInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Create subagents within extensions/subagents/subagents/.
Subagents are autonomous agents with their own tools, system prompt, and model. They run as Pi tools, streaming progress and rendering results.
extensions/subagents/subagents/<name>/
├── index.ts # Main tool definition (createXxxTool, executeXxx, XXX_GUIDANCE)
├── system-prompt.ts # System prompt string
├── types.ts # XxxInput, XxxDetails interfaces
├── tool-formatter.ts # formatXxxToolCall() for display
└── tools/
├── index.ts # createXxxTools() aggregator
└── <tool>.ts # Individual tool definitions
Note: Subagents do not use a separate config.ts file. Model configuration is handled in index.ts or imported from shared configuration.
XxxInput: Parameters the parent agent provides
skills?: string[] for optional skill passthroughXxxDetails: State for UI rendering, must include:
toolCalls: SubagentToolCall[]spinnerFrame: numberresponse?: stringaborted?: booleanerror?: stringusage?: SubagentUsageskills?: string[] - Requested skill names (from input)skillsResolved?: number - Number of skills successfully resolvedskillsNotFound?: string[] - Skill names that were not foundMODEL: Provider and model IDformatXxxToolCall(tc): Returns { label, detail } for human-readable displaylabel: Action name ("Search", "Fetch")detail: Context (hostname, query, repo path)cost in details for cost aggregation:
return {
content: [...],
details: { ..., cost: response.costDollars?.total },
};
Exports:
createXxxTool(): Tool definition with execute, renderCall, renderResultexecuteXxx(): Direct execution without tool wrapperXXX_GUIDANCE: Markdown guidance for parent agent's system promptconst { skills: skillNames } = args;
let resolvedSkills: Skill[] = [];
let notFoundSkills: string[] = [];
if (skillNames && skillNames.length > 0) {
const result = resolveSkillsByName(skillNames, ctx.cwd);
resolvedSkills = result.skills;
notFoundSkills = result.notFound;
}
finallyif (notFoundSkills.length > 0) {
userMessage += `\n\n**Note:** The following skills were not found and could not be loaded: ${notFoundSkills.join(", ")}`;
}
executeSubagent() with:
skills: resolvedSkills in configonTextUpdate and onToolUpdate callbacks that include skill info in detailsresult.toolCalls for failure checksusage from result (include skill info)Use shared UI abstractions from @aliou/pi-utils-ui. Do not hand-roll tool header/body/footer for new subagents.
Always use this header shape:
[Tool Name]: [Action] [Main arg] [Option args]In subagents, use ToolCallHeader:
return new ToolCallHeader(
{
toolName: "Scout", // display name, not snake_case tool id
// action only when meaningful (e.g. process start/output/kill)
mainArg: "short primary arg",
optionArgs: [{ label: "cwd", value: args.cwd ?? "" }],
longArgs: [{ label: "prompt", value: args.prompt }],
},
theme,
);
Rules:
longArgs.Scout, Read Session), not raw tool id.Use ToolBody + footer component (SubagentFooter for model-backed subagents).
return new ToolBody({ fields, footer }, options, theme);
Footer spacing is standardized. Keep footer data concise and machine-skim-friendly.
| State | Display |
|-------|---------|
| Aborted | Warning "Aborted" + optional completion count |
| Error | Error message |
| Running + collapsed | Spinner + current tool name |
| Running + expanded | Status line + all tool calls with indicators |
| Done + collapsed | ✓ or ✗ (if all failed) + stats |
| Done + expanded | Stats + tool summary + failed tool details + markdown response |
In extensions/subagents/index.ts:
SUBAGENT_GUIDANCES arraypi.registerTool(createXxxTool())checkApiKeys()See the existing registration pattern in the file.
If your subagent requires external API keys, validate them at extension load time. This prevents the extension from loading if required keys are missing.
Add your required keys to checkApiKeys() in extensions/subagents/index.ts. See the existing implementation for the pattern.
subagents/<name>/types.ts with Input and Details interfaces
skills?: string[] to Input interfaceskills?, skillsResolved?, skillsNotFound? to Details interfaceconfig.ts with model configurationsystem-prompt.ts with subagent instructionstools/ directory with subagent's toolstool-formatter.ts for display formattingindex.ts with createXxxTool, executeXxx, XXX_GUIDANCE
resolveSkillsByName and Skill type from libskills parameter to TypeBox schemaskills: resolvedSkills to executeSubagentToolCallHeader in renderCall and follow standard line patternToolBody + SubagentFooter in renderResultextensions/subagents/index.tspnpm typechecktoolCalls, spinnerFrame, response, aborted, error, usage, and skill tracking fieldsskills parameter for specialized contextcost in details for aggregationextensions: [])result.toolCalls if present to decide failure stateresolveSkillsByName() from lib to convert skill names to Skill objectsSubagents can emit notifications to alert users. This is useful for long-running subagent tasks or when user attention is needed.
const NOTIFICATION_EVENT = "ad:notification";
interface NotificationEvent {
message: string;
sound?: string;
}
// In execute function, after completion
pi.events.emit(NOTIFICATION_EVENT, {
message: "Research completed",
sound: "/System/Library/Sounds/Blow.aiff",
});
ask_user)Refer to the scout subagent for complete implementation:
testing
Review and manage pull requests from external contributors. Use when checking out, reviewing, editing, or merging a PR from a fork.
tools
Use when work should span one or more detached tasks but still behave like one job with a single owner context. TaskFlow is the durable flow substrate under authoring layers like Lobster, ACPX, plugins, or plain code. Keep conditional logic in the caller; use TaskFlow for flow identity, child-task linkage, waiting state, revision-checked mutations, and user-facing emergence.
tools
# Lobster Lobster executes multi-step workflows with approval checkpoints. Use it when: - User wants a repeatable automation (triage, monitor, sync) - Actions need human approval before executing (send, post, delete) - Multiple tool calls should run as one deterministic operation ## When to use Lobster | User intent | Use Lobster? | | ------------------------------------------------------ | --------------------------
tools
# Lobster Lobster executes multi-step workflows with approval checkpoints. Use it when: - User wants a repeatable automation (triage, monitor, sync) - Actions need human approval before executing (send, post, delete) - Multiple tool calls should run as one deterministic operation ## When to use Lobster | User intent | Use Lobster? | | ------------------------------------------------------ | --------------------------