@jaggerxtrm/specialists 3.3.1 → 3.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/hooks/specialists-complete.mjs +60 -0
- package/config/hooks/specialists-session-start.mjs +120 -0
- package/config/skills/specialists-creator/SKILL.md +506 -0
- package/config/skills/specialists-creator/scripts/validate-specialist.ts +41 -0
- package/config/skills/specialists-usage-workspace/iteration-1/eval-bead-background/old_skill/outputs/result.md +105 -0
- package/config/skills/specialists-usage-workspace/iteration-1/eval-bead-background/with_skill/outputs/result.md +93 -0
- package/config/skills/specialists-usage-workspace/iteration-1/eval-fresh-setup/old_skill/outputs/result.md +113 -0
- package/config/skills/specialists-usage-workspace/iteration-1/eval-fresh-setup/with_skill/outputs/result.md +131 -0
- package/config/skills/specialists-usage-workspace/iteration-1/eval-yaml-debug/old_skill/outputs/result.md +159 -0
- package/config/skills/specialists-usage-workspace/iteration-1/eval-yaml-debug/with_skill/outputs/result.md +150 -0
- package/config/skills/specialists-usage-workspace/iteration-2/eval-bug-investigation/with_skill/outputs/result.md +180 -0
- package/config/skills/specialists-usage-workspace/iteration-2/eval-bug-investigation/with_skill/timing.json +5 -0
- package/config/skills/specialists-usage-workspace/iteration-2/eval-bug-investigation/without_skill/outputs/result.md +223 -0
- package/config/skills/specialists-usage-workspace/iteration-2/eval-bug-investigation/without_skill/timing.json +5 -0
- package/config/skills/specialists-usage-workspace/iteration-2/eval-code-review/with_skill/timing.json +5 -0
- package/config/skills/specialists-usage-workspace/iteration-2/eval-code-review/without_skill/outputs/result.md +146 -0
- package/config/skills/specialists-usage-workspace/iteration-2/eval-code-review/without_skill/timing.json +5 -0
- package/config/skills/specialists-usage-workspace/iteration-2/eval-test-coverage/with_skill/outputs/result.md +89 -0
- package/config/skills/specialists-usage-workspace/iteration-2/eval-test-coverage/with_skill/timing.json +5 -0
- package/config/skills/specialists-usage-workspace/iteration-2/eval-test-coverage/without_skill/outputs/result.md +96 -0
- package/config/skills/specialists-usage-workspace/iteration-2/eval-test-coverage/without_skill/timing.json +5 -0
- package/config/skills/specialists-usage-workspace/skill-snapshot/SKILL.md.old +237 -0
- package/config/skills/using-specialists/SKILL.md +158 -0
- package/config/skills/using-specialists/evals/evals.json +68 -0
- package/config/specialists/.serena/project.yml +151 -0
- package/config/specialists/auto-remediation.specialist.yaml +70 -0
- package/config/specialists/bug-hunt.specialist.yaml +96 -0
- package/config/specialists/explorer.specialist.yaml +79 -0
- package/config/specialists/memory-processor.specialist.yaml +140 -0
- package/config/specialists/overthinker.specialist.yaml +63 -0
- package/config/specialists/parallel-runner.specialist.yaml +61 -0
- package/config/specialists/planner.specialist.yaml +87 -0
- package/config/specialists/specialists-creator.specialist.yaml +82 -0
- package/config/specialists/sync-docs.specialist.yaml +53 -0
- package/config/specialists/test-runner.specialist.yaml +58 -0
- package/config/specialists/xt-merge.specialist.yaml +78 -0
- package/package.json +2 -3
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// specialists-complete — Claude Code UserPromptSubmit hook
|
|
3
|
+
// Checks .specialists/ready/ for completed background job markers and injects
|
|
4
|
+
// completion banners into Claude's context.
|
|
5
|
+
//
|
|
6
|
+
// Installed by: specialists install
|
|
7
|
+
|
|
8
|
+
import { existsSync, readdirSync, readFileSync, unlinkSync } from 'node:fs';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
|
|
11
|
+
const cwd = process.env.CLAUDE_PROJECT_DIR ?? process.cwd();
|
|
12
|
+
const readyDir = join(cwd, '.specialists', 'ready');
|
|
13
|
+
|
|
14
|
+
// Exit silently if no ready dir or nothing to report
|
|
15
|
+
if (!existsSync(readyDir)) process.exit(0);
|
|
16
|
+
|
|
17
|
+
let markers;
|
|
18
|
+
try {
|
|
19
|
+
markers = readdirSync(readyDir).filter(f => !f.startsWith('.'));
|
|
20
|
+
} catch {
|
|
21
|
+
process.exit(0);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (markers.length === 0) process.exit(0);
|
|
25
|
+
|
|
26
|
+
const banners = [];
|
|
27
|
+
|
|
28
|
+
for (const jobId of markers) {
|
|
29
|
+
const markerPath = join(readyDir, jobId);
|
|
30
|
+
const statusPath = join(cwd, '.specialists', 'jobs', jobId, 'status.json');
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
let specialist = jobId;
|
|
34
|
+
let elapsed = '';
|
|
35
|
+
|
|
36
|
+
if (existsSync(statusPath)) {
|
|
37
|
+
const status = JSON.parse(readFileSync(statusPath, 'utf-8'));
|
|
38
|
+
specialist = status.specialist ?? jobId;
|
|
39
|
+
elapsed = status.elapsed_s !== undefined ? `, ${status.elapsed_s}s` : '';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
banners.push(
|
|
43
|
+
`[Specialist '${specialist}' completed (job ${jobId}${elapsed}). Run: specialists result ${jobId}]`
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
// Delete marker so it only fires once
|
|
47
|
+
unlinkSync(markerPath);
|
|
48
|
+
} catch {
|
|
49
|
+
// Ignore malformed entries
|
|
50
|
+
try { unlinkSync(markerPath); } catch { /* ignore */ }
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (banners.length === 0) process.exit(0);
|
|
55
|
+
|
|
56
|
+
// UserPromptSubmit hooks inject content via JSON
|
|
57
|
+
process.stdout.write(JSON.stringify({
|
|
58
|
+
type: 'inject',
|
|
59
|
+
content: banners.join('\n'),
|
|
60
|
+
}) + '\n');
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// specialists-session-start — Claude Code SessionStart hook
|
|
3
|
+
// Injects specialists context at the start of every session:
|
|
4
|
+
// • using-specialists skill (behavioral delegation guide)
|
|
5
|
+
// • Active background jobs (if any)
|
|
6
|
+
// • Available specialists list
|
|
7
|
+
// • Key CLI commands reminder
|
|
8
|
+
//
|
|
9
|
+
// Installed by: specialists init
|
|
10
|
+
// Hook type: SessionStart
|
|
11
|
+
|
|
12
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
13
|
+
import { join } from 'node:path';
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
const cwd = process.env.CLAUDE_PROJECT_DIR ?? process.cwd();
|
|
17
|
+
const jobsDir = join(cwd, '.specialists', 'jobs');
|
|
18
|
+
const lines = [];
|
|
19
|
+
|
|
20
|
+
// ── 0. using-specialists skill ─────────────────────────────────────────────
|
|
21
|
+
// Inject the behavioral delegation guide so Claude knows when and how to
|
|
22
|
+
// use specialists without waiting for the user to ask.
|
|
23
|
+
const skillPath = join(cwd, '.specialists', 'default', 'skills', 'using-specialists', 'SKILL.md');
|
|
24
|
+
if (existsSync(skillPath)) {
|
|
25
|
+
const raw = readFileSync(skillPath, 'utf-8');
|
|
26
|
+
// Strip YAML frontmatter (--- ... ---) if present
|
|
27
|
+
const content = raw.startsWith('---')
|
|
28
|
+
? raw.replace(/^---[\s\S]*?---\n?/, '').trimStart()
|
|
29
|
+
: raw;
|
|
30
|
+
lines.push(content);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// ── 1. Active background jobs ──────────────────────────────────────────────
|
|
34
|
+
if (existsSync(jobsDir)) {
|
|
35
|
+
let entries = [];
|
|
36
|
+
try { entries = readdirSync(jobsDir); } catch { /* ignore */ }
|
|
37
|
+
|
|
38
|
+
const activeJobs = [];
|
|
39
|
+
for (const jobId of entries) {
|
|
40
|
+
const statusPath = join(jobsDir, jobId, 'status.json');
|
|
41
|
+
if (!existsSync(statusPath)) continue;
|
|
42
|
+
try {
|
|
43
|
+
const s = JSON.parse(readFileSync(statusPath, 'utf-8'));
|
|
44
|
+
if (s.status === 'running' || s.status === 'starting') {
|
|
45
|
+
const elapsed = s.elapsed_s !== undefined ? ` (${s.elapsed_s}s)` : '';
|
|
46
|
+
activeJobs.push(
|
|
47
|
+
` • ${s.specialist ?? jobId} [${s.status}]${elapsed} → specialists result ${jobId}`
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
} catch { /* malformed status.json */ }
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (activeJobs.length > 0) {
|
|
54
|
+
lines.push('## Specialists — Active Background Jobs');
|
|
55
|
+
lines.push('');
|
|
56
|
+
lines.push(...activeJobs);
|
|
57
|
+
lines.push('');
|
|
58
|
+
lines.push('Use `specialists feed <job-id> --follow` to stream events, or `specialists result <job-id>` when done.');
|
|
59
|
+
lines.push('');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ── 2. Available specialists (read YAML dirs directly) ────────────────────
|
|
64
|
+
function readSpecialistNames(dir) {
|
|
65
|
+
if (!existsSync(dir)) return [];
|
|
66
|
+
try {
|
|
67
|
+
return readdirSync(dir)
|
|
68
|
+
.filter(f => f.endsWith('.specialist.yaml'))
|
|
69
|
+
.map(f => f.replace('.specialist.yaml', ''));
|
|
70
|
+
} catch {
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const defaultNames = readSpecialistNames(join(cwd, '.specialists', 'default', 'specialists'));
|
|
76
|
+
const userNames = readSpecialistNames(join(cwd, '.specialists', 'user', 'specialists'));
|
|
77
|
+
|
|
78
|
+
// User takes precedence on name collision; merge and sort
|
|
79
|
+
const allNames = [...new Set([...userNames, ...defaultNames])].sort();
|
|
80
|
+
|
|
81
|
+
if (allNames.length > 0) {
|
|
82
|
+
lines.push('## Specialists — Available');
|
|
83
|
+
lines.push('');
|
|
84
|
+
if (defaultNames.length > 0) {
|
|
85
|
+
lines.push(`default (${defaultNames.length}): ${defaultNames.join(', ')}`);
|
|
86
|
+
}
|
|
87
|
+
if (userNames.length > 0) {
|
|
88
|
+
const extraUser = userNames.filter(n => !defaultNames.includes(n));
|
|
89
|
+
if (extraUser.length > 0) {
|
|
90
|
+
lines.push(`user (${extraUser.length}): ${extraUser.join(', ')}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
lines.push('');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ── 3. Key commands reminder ───────────────────────────────────────────────
|
|
97
|
+
lines.push('## Specialists — Session Quick Reference');
|
|
98
|
+
lines.push('');
|
|
99
|
+
lines.push('```');
|
|
100
|
+
lines.push('specialists list # discover available specialists');
|
|
101
|
+
lines.push('specialists run <name> --prompt "..." # run foreground (streams output)');
|
|
102
|
+
lines.push('specialists run <name> --prompt "..." --background # run async → returns job ID');
|
|
103
|
+
lines.push('specialists run <name> --follow # background + stream live output');
|
|
104
|
+
lines.push('specialists feed <job-id> --follow # tail live events');
|
|
105
|
+
lines.push('specialists result <job-id> # read final output');
|
|
106
|
+
lines.push('specialists status # system health');
|
|
107
|
+
lines.push('specialists doctor # troubleshoot issues');
|
|
108
|
+
lines.push('```');
|
|
109
|
+
lines.push('');
|
|
110
|
+
lines.push('MCP tools: specialist_init · use_specialist · start_specialist · poll_specialist · run_parallel');
|
|
111
|
+
|
|
112
|
+
// ── Output ─────────────────────────────────────────────────────────────────
|
|
113
|
+
if (lines.length === 0) process.exit(0);
|
|
114
|
+
|
|
115
|
+
process.stdout.write(JSON.stringify({
|
|
116
|
+
hookSpecificOutput: {
|
|
117
|
+
hookEventName: 'SessionStart',
|
|
118
|
+
additionalSystemPrompt: lines.join('\n'),
|
|
119
|
+
},
|
|
120
|
+
}) + '\n');
|
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
# Specialist Author Guide
|
|
2
|
+
|
|
3
|
+
> Source of truth: `src/specialist/schema.ts` | Runtime: `src/specialist/runner.ts`
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## ACTION REQUIRED BEFORE ANYTHING ELSE
|
|
8
|
+
|
|
9
|
+
Run these commands **right now**, before reading further, before writing any YAML, before doing anything else:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pi --list-models
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Read the output. Pick one primary model and one fallback from **different providers**. Then ping both:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pi --model <chosen-primary> --print "ping" # must print: pong
|
|
19
|
+
pi --model <chosen-fallback> --print "ping" # must print: pong
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
If a ping fails, pick the next best model in that tier and ping again. **Do not proceed until both return "pong".**
|
|
23
|
+
|
|
24
|
+
Model tiers:
|
|
25
|
+
- **Heavy** (deep reasoning, multi-phase): Opus / Pro / GLM-5
|
|
26
|
+
- **Standard** (authoring, review, codegen): Sonnet / Flash-Pro
|
|
27
|
+
- **Light** (fast context, reports, tests): Haiku / Flash
|
|
28
|
+
|
|
29
|
+
Rules:
|
|
30
|
+
- Always pick the **highest version** in a family (`claude-sonnet-4-6` not `4-5`, `gemini-3.1-pro-preview` not `gemini-2.5-pro`)
|
|
31
|
+
- `model` and `fallback_model` must be **different providers**
|
|
32
|
+
- Never write a model string you have not pinged in this session
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Model Setup (for a new specialist OR "setup my specialists models")
|
|
39
|
+
|
|
40
|
+
### Quick Reference: Specialists CLI
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
specialists list # all specialists + current model
|
|
44
|
+
specialists models # all pi models, flagged with thinking/images, shows current assignments
|
|
45
|
+
specialists edit <name> --model <value> # change primary model
|
|
46
|
+
specialists edit <name> --fallback-model <v> # change fallback model
|
|
47
|
+
specialists edit <name> --model <v> --dry-run # preview without writing
|
|
48
|
+
specialists edit <name> --permission HIGH # change permission level
|
|
49
|
+
specialists status # system health
|
|
50
|
+
specialists doctor # prereq + hook diagnostics
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
### Scenario: "Setup my specialists models"
|
|
56
|
+
|
|
57
|
+
When a user asks to set up or re-balance specialist models, run this workflow:
|
|
58
|
+
|
|
59
|
+
#### Step 1 — Inventory
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
specialists list # shows each specialist + its current model
|
|
63
|
+
specialists models # shows all available models on pi, with current assignments marked ←
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Read both outputs carefully:
|
|
67
|
+
- `specialists list` → what specialists exist and what they currently use
|
|
68
|
+
- `specialists models` → what models are available, and which specialists already use each one (the `←` markers show assignments)
|
|
69
|
+
|
|
70
|
+
#### Step 2 — Classify each specialist by tier
|
|
71
|
+
|
|
72
|
+
| Tier | Specialists (typical) | Recommended model class |
|
|
73
|
+
|------|-----------------------|------------------------|
|
|
74
|
+
| **Heavy** — deep reasoning, multi-phase, architecture | `overthinker`, `feature-design`, `bug-hunt`, `planner`, `parallel-review` | Opus / Pro / GLM-5 |
|
|
75
|
+
| **Standard** — code generation, review, authoring, docs | `codebase-explorer`, `specialist-author`, `sync-docs`, `xt-merge` | Sonnet / Flash-Pro |
|
|
76
|
+
| **Light** — fast context, reporting, test runs | `init-session`, `report-generator`, `test-runner`, `auto-remediation` | Haiku / Flash |
|
|
77
|
+
|
|
78
|
+
Adjust tiers based on what the user actually has installed. Custom specialists: read their `description` and `permission_required` to infer tier.
|
|
79
|
+
|
|
80
|
+
#### Step 3 — Select models with provider diversity
|
|
81
|
+
|
|
82
|
+
Rules:
|
|
83
|
+
1. **Pick the highest version in each family** — `glm-5` not `glm-4.7`, `claude-sonnet-4-6` not `4-5`, `gemini-3.1-pro-preview` not `gemini-2.5-pro`
|
|
84
|
+
2. **`model` and `fallback_model` must be different providers** — never stack two anthropic models
|
|
85
|
+
3. **Spread providers across tiers** — don't assign all specialists to anthropic; distribute across anthropic / google-gemini-cli / zai / openai-codex where available
|
|
86
|
+
4. **Match thinking capability to tier** — heavy specialists benefit from `thinking: yes` models
|
|
87
|
+
|
|
88
|
+
Example distribution (based on current `specialists models` output):
|
|
89
|
+
|
|
90
|
+
| Tier | model | fallback_model |
|
|
91
|
+
|------|-------|----------------|
|
|
92
|
+
| Heavy | `anthropic/claude-opus-4-6` | `google-gemini-cli/gemini-3.1-pro-preview` |
|
|
93
|
+
| Standard | `anthropic/claude-sonnet-4-6` | `google-gemini-cli/gemini-3-flash-preview` |
|
|
94
|
+
| Light | `anthropic/claude-haiku-4-5` | `zai/glm-5-turbo` |
|
|
95
|
+
|
|
96
|
+
If anthropic is not available, use `zai/glm-5` (heavy), `google-gemini-cli/gemini-3.1-pro-preview` (standard), `google-gemini-cli/gemini-3-flash-preview` (light).
|
|
97
|
+
|
|
98
|
+
#### Step 4 — ⛔ Ping each chosen model before assigning
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
# REQUIRED — do not skip, do not assume a model works without pinging
|
|
102
|
+
pi --model <provider>/<primary-model-id> --print "ping" # must return "pong"
|
|
103
|
+
pi --model <provider>/<fallback-model-id> --print "ping" # must return "pong"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Ping **both** primary and fallback. If ping fails → pick next best in that tier and ping again. Do not assign a model that did not respond.
|
|
107
|
+
|
|
108
|
+
#### Step 5 — Apply with `specialists edit`
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
# Example: upgrade heavy-tier specialists
|
|
112
|
+
specialists edit overthinker --model anthropic/claude-opus-4-6 --fallback-model google-gemini-cli/gemini-3.1-pro-preview
|
|
113
|
+
specialists edit feature-design --model anthropic/claude-opus-4-6 --fallback-model google-gemini-cli/gemini-3.1-pro-preview
|
|
114
|
+
specialists edit bug-hunt --model anthropic/claude-opus-4-6 --fallback-model google-gemini-cli/gemini-3.1-pro-preview
|
|
115
|
+
|
|
116
|
+
# Standard tier
|
|
117
|
+
specialists edit codebase-explorer --model anthropic/claude-sonnet-4-6 --fallback-model google-gemini-cli/gemini-3-flash-preview
|
|
118
|
+
specialists edit sync-docs --model anthropic/claude-sonnet-4-6 --fallback-model google-gemini-cli/gemini-3-flash-preview
|
|
119
|
+
|
|
120
|
+
# Light tier
|
|
121
|
+
specialists edit init-session --model anthropic/claude-haiku-4-5 --fallback-model zai/glm-5-turbo
|
|
122
|
+
specialists edit report-generator --model anthropic/claude-haiku-4-5 --fallback-model zai/glm-5-turbo
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Use `--dry-run` first to preview any change before writing.
|
|
126
|
+
|
|
127
|
+
#### Step 6 — Verify
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
specialists list # confirm all models updated correctly
|
|
131
|
+
specialists models # confirm assignments look balanced
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
### For a new specialist (single model selection)
|
|
137
|
+
|
|
138
|
+
> **See [⛔ MANDATORY FIRST STEP](#-mandatory-first-step--verify-models-before-writing-any-yaml) at the top of this skill.**
|
|
139
|
+
> Use `pi --list-models` (not `specialists models`) to discover models, ping both before writing YAML.
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
# 1. pi --list-models — see exactly what's available on pi right now
|
|
143
|
+
# 2. Pick tier + pick highest version in family
|
|
144
|
+
# 3. pi --model <primary> --print "ping" — must return "pong"
|
|
145
|
+
# 4. pi --model <fallback> --print "ping" — must return "pong"
|
|
146
|
+
# 5. Write YAML with verified model strings
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Rule:** Never hardcode a model without pinging it. If ping fails, try the next best in that tier.
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Quick Start: Minimal Skeleton
|
|
154
|
+
|
|
155
|
+
```yaml
|
|
156
|
+
specialist:
|
|
157
|
+
metadata:
|
|
158
|
+
name: my-specialist # kebab-case, required
|
|
159
|
+
version: 1.0.0 # semver, required
|
|
160
|
+
description: "One sentence." # required
|
|
161
|
+
category: workflow # required (free text)
|
|
162
|
+
|
|
163
|
+
execution:
|
|
164
|
+
model: anthropic/claude-sonnet-4-6 # run model setup workflow above to choose + verify
|
|
165
|
+
permission_required: READ_ONLY
|
|
166
|
+
|
|
167
|
+
prompt:
|
|
168
|
+
task_template: |
|
|
169
|
+
$prompt
|
|
170
|
+
|
|
171
|
+
Working directory: $cwd
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Validate before committing:
|
|
175
|
+
```bash
|
|
176
|
+
bun skills/specialist-author/scripts/validate-specialist.ts specialists/my-specialist.specialist.yaml
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Schema Reference
|
|
182
|
+
|
|
183
|
+
### `specialist.metadata` (required)
|
|
184
|
+
|
|
185
|
+
| Field | Type | Required | Notes |
|
|
186
|
+
|-------|------|----------|-------|
|
|
187
|
+
| `name` | string | yes | kebab-case: `[a-z][a-z0-9-]*` |
|
|
188
|
+
| `version` | string | yes | semver: `1.0.0` |
|
|
189
|
+
| `description` | string | yes | One sentence |
|
|
190
|
+
| `category` | string | yes | Free text (e.g. `workflow`, `analysis`, `codegen`) |
|
|
191
|
+
| `author` | string | no | Optional |
|
|
192
|
+
| `created` | string | no | Optional date |
|
|
193
|
+
| `updated` | string | no | Optional date, quote it: `"2026-03-22"` |
|
|
194
|
+
| `tags` | string[] | no | Optional list |
|
|
195
|
+
|
|
196
|
+
### `specialist.execution` (required)
|
|
197
|
+
|
|
198
|
+
| Field | Type | Default | Notes |
|
|
199
|
+
|-------|------|---------|-------|
|
|
200
|
+
| `model` | string | — | required — ping before using |
|
|
201
|
+
| `fallback_model` | string | — | must be a different provider |
|
|
202
|
+
| `mode` | enum | `auto` | `tool` \| `skill` \| `auto` |
|
|
203
|
+
| `timeout_ms` | number | `120000` | ms |
|
|
204
|
+
| `stall_timeout_ms` | number | — | kill if no event for N ms |
|
|
205
|
+
| `response_format` | enum | `text` | `text` \| `json` \| `markdown` |
|
|
206
|
+
| `permission_required` | enum | `READ_ONLY` | see tier table below |
|
|
207
|
+
| `thinking_level` | enum | — | `off` \| `minimal` \| `low` \| `medium` \| `high` \| `xhigh` |
|
|
208
|
+
|
|
209
|
+
**Permission tiers** — controls which pi tools are available:
|
|
210
|
+
|
|
211
|
+
| Level | pi --tools | Use when |
|
|
212
|
+
|-------|-----------|----------|
|
|
213
|
+
| `READ_ONLY` | `read,grep,find,ls` | Read-only analysis, no bash |
|
|
214
|
+
| `LOW` | `+bash` | Inspect/run commands, no file edits |
|
|
215
|
+
| `MEDIUM` | `+edit` | Can edit existing files |
|
|
216
|
+
| `HIGH` | `+write` | Full access — can create new files |
|
|
217
|
+
|
|
218
|
+
**Common pitfall:** `READ_WRITE` is **not** a valid value — use `LOW` or higher.
|
|
219
|
+
|
|
220
|
+
### `specialist.prompt` (required)
|
|
221
|
+
|
|
222
|
+
| Field | Type | Required | Notes |
|
|
223
|
+
|-------|------|----------|-------|
|
|
224
|
+
| `task_template` | string | yes | Template string with `$variable` substitution |
|
|
225
|
+
| `system` | string | no | System prompt / agents.md content |
|
|
226
|
+
| `skill_inherit` | string | no | Single skill folder/file injected via `pi --skill` (Agent Forge compat) |
|
|
227
|
+
| `output_schema` | object | no | JSON schema for structured output |
|
|
228
|
+
| `examples` | array | no | Few-shot examples |
|
|
229
|
+
|
|
230
|
+
### `specialist.skills` (optional)
|
|
231
|
+
|
|
232
|
+
```yaml
|
|
233
|
+
skills:
|
|
234
|
+
paths: # passed as pi --skill; folder (reads SKILL.md inside) or direct file
|
|
235
|
+
- skills/my-skill/ # folder — pi loads SKILL.md from inside
|
|
236
|
+
- ~/.agents/skills/domain/ # same
|
|
237
|
+
- skills/notes.md # direct file also accepted
|
|
238
|
+
scripts:
|
|
239
|
+
- run: ./scripts/pre-check.sh # file path OR shell command
|
|
240
|
+
phase: pre # "pre" or "post"
|
|
241
|
+
inject_output: true # true = stdout available as $pre_script_output
|
|
242
|
+
- run: "bd ready" # inline command — runs via shell
|
|
243
|
+
phase: pre
|
|
244
|
+
inject_output: true
|
|
245
|
+
- run: ./scripts/cleanup.sh
|
|
246
|
+
phase: post
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
`run` accepts either a **file path** (`./scripts/foo.sh`, `~/scripts/foo.sh`) or a **shell command** (`bd ready`, `git status`). Pre-run validation checks that file paths exist and shell commands are on `PATH`. Shebang typos (e.g. `pytho` instead of `python`) are caught and reported as errors before the session starts.
|
|
250
|
+
|
|
251
|
+
`path` is accepted as a deprecated alias for `run`.
|
|
252
|
+
|
|
253
|
+
### `specialist.capabilities` (optional)
|
|
254
|
+
|
|
255
|
+
Informational declarations used by pre-run validation and future tooling (e.g. `specialists doctor`).
|
|
256
|
+
|
|
257
|
+
```yaml
|
|
258
|
+
capabilities:
|
|
259
|
+
required_tools: [bash, read, grep, glob] # pi tools this specialist needs
|
|
260
|
+
external_commands: [bd, git, gh] # CLI binaries validated on PATH before run
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
`external_commands` causes a hard failure if any binary is not found on `PATH` — the session will not start.
|
|
264
|
+
|
|
265
|
+
### `specialist.output_file` (optional, top-level)
|
|
266
|
+
|
|
267
|
+
```yaml
|
|
268
|
+
output_file: .specialists/my-specialist-result.md
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Writes the final session output to this file path after the session completes. Relative to the working directory.
|
|
272
|
+
|
|
273
|
+
### `specialist.communication` (optional)
|
|
274
|
+
|
|
275
|
+
```yaml
|
|
276
|
+
communication:
|
|
277
|
+
next_specialists: planner # single specialist to chain after completion
|
|
278
|
+
# or an array:
|
|
279
|
+
next_specialists: [planner, test-runner]
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
`next_specialists` declares which specialist(s) should receive this specialist's output as `$previous_result`. Chaining is executed by the caller (e.g. `run_parallel` pipeline) — this field is declarative metadata.
|
|
283
|
+
|
|
284
|
+
### `specialist.validation` (optional)
|
|
285
|
+
|
|
286
|
+
Drives the staleness detection shown in `specialists status` and `specialists list`.
|
|
287
|
+
|
|
288
|
+
| Field | Type | Notes |
|
|
289
|
+
|-------|------|-------|
|
|
290
|
+
| `files_to_watch` | string[] | Paths to monitor. If any file's mtime is newer than `metadata.updated`, the specialist is marked **STALE** |
|
|
291
|
+
| `stale_threshold_days` | number | If the specialist has been STALE for more than N days, escalates to **AGED** |
|
|
292
|
+
| `references` | array | Accepted, currently unused |
|
|
293
|
+
|
|
294
|
+
**Staleness states:**
|
|
295
|
+
|
|
296
|
+
| State | Condition |
|
|
297
|
+
|-------|-----------|
|
|
298
|
+
| `OK` | No watched files changed, or no `files_to_watch` / `updated` set |
|
|
299
|
+
| `STALE` | A watched file's mtime > `metadata.updated` |
|
|
300
|
+
| `AGED` | STALE + days since `updated` > `stale_threshold_days` |
|
|
301
|
+
|
|
302
|
+
```yaml
|
|
303
|
+
specialist:
|
|
304
|
+
metadata:
|
|
305
|
+
updated: "2026-03-01"
|
|
306
|
+
|
|
307
|
+
validation:
|
|
308
|
+
files_to_watch:
|
|
309
|
+
- src/specialist/schema.ts
|
|
310
|
+
- src/specialist/runner.ts
|
|
311
|
+
stale_threshold_days: 30
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
This specialist goes STALE the moment `schema.ts` or `runner.ts` is modified after March 1st, and AGED if that condition persists for more than 30 days.
|
|
315
|
+
|
|
316
|
+
### `specialist.beads_integration` (optional)
|
|
317
|
+
|
|
318
|
+
| Value | Behavior |
|
|
319
|
+
|-------|----------|
|
|
320
|
+
| `auto` (default) | Create tracking bead when permission_required is LOW+ |
|
|
321
|
+
| `always` | Always create a tracking bead |
|
|
322
|
+
| `never` | Never create a tracking bead |
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
## Built-in Template Variables
|
|
327
|
+
|
|
328
|
+
These are **always available** in `task_template` — no configuration needed:
|
|
329
|
+
|
|
330
|
+
| Variable | Value |
|
|
331
|
+
|----------|-------|
|
|
332
|
+
| `$prompt` | The user's prompt passed to `use_specialist` |
|
|
333
|
+
| `$cwd` | `process.cwd()` at invocation time |
|
|
334
|
+
| `$pre_script_output` | Stdout of `pre` scripts with `inject_output: true` (empty string if none) |
|
|
335
|
+
|
|
336
|
+
**When invoked via `--bead`** (inputBeadId present):
|
|
337
|
+
|
|
338
|
+
| Variable | Value |
|
|
339
|
+
|----------|-------|
|
|
340
|
+
| `$bead_context` | Full bead content (replaces `$prompt`) |
|
|
341
|
+
| `$bead_id` | The bead ID |
|
|
342
|
+
|
|
343
|
+
**Custom variables** can be passed at invocation time via `--variables key=value` and accessed as `$key`.
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
## Skills Injection (`skills.paths`)
|
|
348
|
+
|
|
349
|
+
Files listed under `skills.paths` are read and appended to the system prompt at runtime:
|
|
350
|
+
|
|
351
|
+
```yaml
|
|
352
|
+
skills:
|
|
353
|
+
paths:
|
|
354
|
+
- skills/specialist-author/SKILL.md
|
|
355
|
+
- .claude/agents.md
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
Each file is appended as:
|
|
359
|
+
```
|
|
360
|
+
---
|
|
361
|
+
# Skill: <path>
|
|
362
|
+
|
|
363
|
+
<file content>
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
Missing files are silently skipped (no error).
|
|
367
|
+
|
|
368
|
+
`skill_inherit` (in `prompt:`) works the same way but for a single file — it is an Agent Forge compatibility field, appended under `# Service Knowledge`.
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
## Pre/Post Scripts
|
|
373
|
+
|
|
374
|
+
Scripts run **locally** (not inside the agent session):
|
|
375
|
+
|
|
376
|
+
```yaml
|
|
377
|
+
skills:
|
|
378
|
+
scripts:
|
|
379
|
+
- path: scripts/gather-context.sh
|
|
380
|
+
phase: pre
|
|
381
|
+
inject_output: true # stdout -> $pre_script_output in task_template
|
|
382
|
+
- path: scripts/notify.sh
|
|
383
|
+
phase: post
|
|
384
|
+
inject_output: false # runs after session, output discarded
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
- `pre` scripts run before the agent session starts; use `inject_output: true` to surface their stdout.
|
|
388
|
+
- `post` scripts run after the session completes (cleanup, notifications).
|
|
389
|
+
- Timeout: 30 seconds per script.
|
|
390
|
+
- Exit code is captured but does not abort the run.
|
|
391
|
+
|
|
392
|
+
---
|
|
393
|
+
|
|
394
|
+
## Annotated Full Example
|
|
395
|
+
|
|
396
|
+
```yaml
|
|
397
|
+
specialist:
|
|
398
|
+
metadata:
|
|
399
|
+
name: code-reviewer
|
|
400
|
+
version: 1.0.0
|
|
401
|
+
description: "Reviews a PR diff for correctness, style, and security issues."
|
|
402
|
+
category: code-quality
|
|
403
|
+
author: team@example.com
|
|
404
|
+
updated: "2026-03-22"
|
|
405
|
+
tags: [review, code-quality, security]
|
|
406
|
+
|
|
407
|
+
execution:
|
|
408
|
+
mode: tool
|
|
409
|
+
model: anthropic/claude-sonnet-4-6
|
|
410
|
+
fallback_model: google-gemini-cli/gemini-3.1-pro-preview
|
|
411
|
+
timeout_ms: 300000
|
|
412
|
+
stall_timeout_ms: 60000
|
|
413
|
+
response_format: markdown
|
|
414
|
+
permission_required: READ_ONLY # not READ_WRITE
|
|
415
|
+
|
|
416
|
+
prompt:
|
|
417
|
+
system: |
|
|
418
|
+
You are an expert code reviewer. Focus on correctness, maintainability, and security.
|
|
419
|
+
Do NOT modify any files -- output a markdown review only.
|
|
420
|
+
|
|
421
|
+
task_template: |
|
|
422
|
+
Review the following changes:
|
|
423
|
+
|
|
424
|
+
$prompt
|
|
425
|
+
|
|
426
|
+
$pre_script_output
|
|
427
|
+
|
|
428
|
+
Working directory: $cwd
|
|
429
|
+
|
|
430
|
+
Output a structured markdown review with sections: Summary, Issues, Suggestions.
|
|
431
|
+
|
|
432
|
+
skill_inherit: skills/code-review/guidelines.md
|
|
433
|
+
|
|
434
|
+
skills:
|
|
435
|
+
paths:
|
|
436
|
+
- skills/code-review/
|
|
437
|
+
scripts:
|
|
438
|
+
- run: scripts/get-diff.sh
|
|
439
|
+
phase: pre
|
|
440
|
+
inject_output: true
|
|
441
|
+
|
|
442
|
+
capabilities:
|
|
443
|
+
required_tools: [bash, read]
|
|
444
|
+
external_commands: [git]
|
|
445
|
+
|
|
446
|
+
communication:
|
|
447
|
+
next_specialists: [sync-docs]
|
|
448
|
+
|
|
449
|
+
output_file: .specialists/review.md
|
|
450
|
+
beads_integration: auto
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
---
|
|
454
|
+
|
|
455
|
+
## Common Errors and Fixes
|
|
456
|
+
|
|
457
|
+
| Zod Error | Cause | Fix |
|
|
458
|
+
|-----------|-------|-----|
|
|
459
|
+
| `Must be kebab-case` | `name` has uppercase or spaces | Use `my-specialist` not `MySpecialist` |
|
|
460
|
+
| `Must be semver` | `version: "v1.0"` | Use `version: 1.0.0` (no `v` prefix) |
|
|
461
|
+
| `Invalid enum value ... 'READ_WRITE'` | Wrong permission value | Use `READ_ONLY`, `LOW`, `MEDIUM`, or `HIGH` |
|
|
462
|
+
| `Invalid enum value ... 'auto'` on permission_required | Using `auto` for permission_required | `auto` is only valid for `beads_integration` |
|
|
463
|
+
| `Required` on `task_template` | `task_template` missing from `prompt:` | Add `task_template` (even if just `$prompt`) |
|
|
464
|
+
| `Required` on `model` | `model` missing from `execution:` | Add a model string |
|
|
465
|
+
| `Required` on `description` | Missing `description` in `metadata` | Add description string |
|
|
466
|
+
| `Required` on `category` | Missing `category` in `metadata` | Add category string |
|
|
467
|
+
| Silently ignored / no output | YAML valid but `task_template` doesn't use `$prompt` | Add `$prompt` to `task_template` |
|
|
468
|
+
| `defaults` key unrecognized | Using `defaults:` top-level key | Remove it; use `--variables` at invocation or built-ins |
|
|
469
|
+
|
|
470
|
+
---
|
|
471
|
+
|
|
472
|
+
## File Placement
|
|
473
|
+
|
|
474
|
+
Specialists are discovered from three scopes (highest priority first):
|
|
475
|
+
|
|
476
|
+
1. **Project**: `<project-root>/specialists/*.specialist.yaml`
|
|
477
|
+
2. **User**: `~/.agents/specialists/*.specialist.yaml`
|
|
478
|
+
3. **System**: package-bundled specialists
|
|
479
|
+
|
|
480
|
+
Name your file `<metadata.name>.specialist.yaml`.
|
|
481
|
+
|
|
482
|
+
---
|
|
483
|
+
|
|
484
|
+
## Validation Workflow
|
|
485
|
+
|
|
486
|
+
A bundled validator is included with this skill so the agent does not need to reconstruct the `bun -e` one-liner from memory. It prints `OK <file>` on success and a field-by-field error list on failure.
|
|
487
|
+
|
|
488
|
+
```bash
|
|
489
|
+
# 1. MANDATORY: discover + ping models (see top of this skill)
|
|
490
|
+
pi --list-models
|
|
491
|
+
pi --model <provider>/<primary-model-id> --print "ping" # must return "pong"
|
|
492
|
+
pi --model <provider>/<fallback-model-id> --print "ping" # must return "pong"
|
|
493
|
+
|
|
494
|
+
# 2. Write the YAML with the verified model
|
|
495
|
+
|
|
496
|
+
# 3. Validate schema with the bundled helper
|
|
497
|
+
bun skills/specialist-author/scripts/validate-specialist.ts specialists/my-specialist.specialist.yaml
|
|
498
|
+
|
|
499
|
+
# 4. List to confirm discovery
|
|
500
|
+
specialists list
|
|
501
|
+
|
|
502
|
+
# 5. Smoke test
|
|
503
|
+
specialists run my-specialist --prompt "ping" --no-beads
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
If you need the underlying implementation, read `skills/specialist-author/scripts/validate-specialist.ts`. It is a thin Bun/TypeScript wrapper over `parseSpecialist()` from `src/specialist/schema.ts`, which keeps the helper cross-platform for Windows, macOS, and Linux.
|