@jaggerxtrm/specialists 3.3.4 → 3.4.1
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/README.md +4 -2
- package/bin/install.js +15 -204
- package/config/hooks/specialists-session-start.mjs +3 -3
- package/config/skills/specialists-creator/SKILL.md +22 -1
- package/config/skills/using-specialists/SKILL.md +261 -50
- package/config/specialists/debugger.specialist.yaml +121 -0
- package/config/specialists/executor.specialist.yaml +257 -0
- package/config/specialists/explorer.specialist.yaml +13 -7
- package/config/specialists/memory-processor.specialist.yaml +15 -1
- package/config/specialists/overthinker.specialist.yaml +16 -3
- package/config/specialists/{parallel-runner.specialist.yaml → parallel-review.specialist.yaml} +15 -1
- package/config/specialists/planner.specialist.yaml +31 -24
- package/config/specialists/reviewer.specialist.yaml +142 -0
- package/config/specialists/specialists-creator.specialist.yaml +10 -2
- package/config/specialists/sync-docs.specialist.yaml +20 -5
- package/config/specialists/test-runner.specialist.yaml +8 -1
- package/config/specialists/xt-merge.specialist.yaml +97 -16
- package/dist/index.js +2775 -1120
- package/package.json +1 -1
- package/config/skills/specialists-usage-workspace/iteration-1/eval-bead-background/old_skill/outputs/result.md +0 -105
- package/config/skills/specialists-usage-workspace/iteration-1/eval-bead-background/with_skill/outputs/result.md +0 -93
- package/config/skills/specialists-usage-workspace/iteration-1/eval-fresh-setup/old_skill/outputs/result.md +0 -113
- package/config/skills/specialists-usage-workspace/iteration-1/eval-fresh-setup/with_skill/outputs/result.md +0 -131
- package/config/skills/specialists-usage-workspace/iteration-1/eval-yaml-debug/old_skill/outputs/result.md +0 -159
- package/config/skills/specialists-usage-workspace/iteration-1/eval-yaml-debug/with_skill/outputs/result.md +0 -150
- package/config/skills/specialists-usage-workspace/iteration-2/eval-bug-investigation/with_skill/outputs/result.md +0 -180
- package/config/skills/specialists-usage-workspace/iteration-2/eval-bug-investigation/with_skill/timing.json +0 -5
- package/config/skills/specialists-usage-workspace/iteration-2/eval-bug-investigation/without_skill/outputs/result.md +0 -223
- package/config/skills/specialists-usage-workspace/iteration-2/eval-bug-investigation/without_skill/timing.json +0 -5
- package/config/skills/specialists-usage-workspace/iteration-2/eval-code-review/with_skill/timing.json +0 -5
- package/config/skills/specialists-usage-workspace/iteration-2/eval-code-review/without_skill/outputs/result.md +0 -146
- package/config/skills/specialists-usage-workspace/iteration-2/eval-code-review/without_skill/timing.json +0 -5
- package/config/skills/specialists-usage-workspace/iteration-2/eval-test-coverage/with_skill/outputs/result.md +0 -89
- package/config/skills/specialists-usage-workspace/iteration-2/eval-test-coverage/with_skill/timing.json +0 -5
- package/config/skills/specialists-usage-workspace/iteration-2/eval-test-coverage/without_skill/outputs/result.md +0 -96
- package/config/skills/specialists-usage-workspace/iteration-2/eval-test-coverage/without_skill/timing.json +0 -5
- package/config/skills/specialists-usage-workspace/skill-snapshot/SKILL.md.old +0 -237
- package/config/specialists/auto-remediation.specialist.yaml +0 -70
- package/config/specialists/bug-hunt.specialist.yaml +0 -96
package/README.md
CHANGED
|
@@ -28,18 +28,20 @@ specialists list
|
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
30
|
sp list
|
|
31
|
-
sp run bug-hunt --bead <id>
|
|
31
|
+
sp run bug-hunt --bead <id>
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
Tracked work:
|
|
35
35
|
|
|
36
36
|
```bash
|
|
37
37
|
bd create "Investigate auth bug" -t bug -p 1 --json
|
|
38
|
-
specialists run bug-hunt --bead <id>
|
|
38
|
+
specialists run bug-hunt --bead <id>
|
|
39
39
|
specialists feed -f
|
|
40
40
|
bd close <id> --reason "Done"
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
+
`specialists run` prints `[job started: <id>]` early and also writes the id to `.specialists/jobs/latest`.
|
|
44
|
+
|
|
43
45
|
Ad-hoc work:
|
|
44
46
|
|
|
45
47
|
```bash
|
package/bin/install.js
CHANGED
|
@@ -1,209 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
chmodSync,
|
|
6
|
-
copyFileSync,
|
|
7
|
-
existsSync,
|
|
8
|
-
mkdirSync,
|
|
9
|
-
readdirSync,
|
|
10
|
-
readFileSync,
|
|
11
|
-
writeFileSync,
|
|
12
|
-
} from 'node:fs';
|
|
13
|
-
import { homedir } from 'node:os';
|
|
14
|
-
import { join } from 'node:path';
|
|
3
|
+
// DEPRECATED: This script is deprecated. Use `specialists init` instead.
|
|
15
4
|
|
|
16
|
-
const CWD = process.cwd();
|
|
17
|
-
const CLAUDE_DIR = join(CWD, '.claude');
|
|
18
|
-
const HOOKS_DIR = join(CLAUDE_DIR, 'hooks');
|
|
19
|
-
const SETTINGS_FILE = join(CLAUDE_DIR, 'settings.json');
|
|
20
|
-
const MCP_FILE = join(CWD, '.mcp.json');
|
|
21
|
-
const BUNDLED_HOOKS_DIR = new URL('../hooks', import.meta.url).pathname;
|
|
22
|
-
const BUNDLED_SPECIALISTS_DIR = new URL('../specialists', import.meta.url).pathname;
|
|
23
|
-
const USER_SPECIALISTS_DIR = join(homedir(), '.agents', 'specialists');
|
|
24
|
-
|
|
25
|
-
const dim = (s) => `\x1b[2m${s}\x1b[0m`;
|
|
26
|
-
const green = (s) => `\x1b[32m${s}\x1b[0m`;
|
|
27
|
-
const yellow = (s) => `\x1b[33m${s}\x1b[0m`;
|
|
28
5
|
const bold = (s) => `\x1b[1m${s}\x1b[0m`;
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
function section(label) {
|
|
32
|
-
const line = '─'.repeat(Math.max(0, 44 - label.length));
|
|
33
|
-
console.log(`\n${bold(`── ${label} ${line}`)}`);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function ok(label) { console.log(` ${green('✓')} ${label}`); }
|
|
37
|
-
function skip(label) { console.log(` ${yellow('○')} ${label}`); }
|
|
38
|
-
function info(label) { console.log(` ${dim(label)}`); }
|
|
39
|
-
function fail(label) { console.log(` ${red('✗')} ${label}`); }
|
|
40
|
-
|
|
41
|
-
function run(cmd, args, options = {}) {
|
|
42
|
-
return spawnSync(cmd, args, {
|
|
43
|
-
encoding: 'utf8',
|
|
44
|
-
stdio: 'pipe',
|
|
45
|
-
...options,
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function commandOk(cmd, args = ['--version']) {
|
|
50
|
-
const result = run(cmd, args);
|
|
51
|
-
return result.status === 0 && !result.error;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function loadJson(path, fallback) {
|
|
55
|
-
if (!existsSync(path)) return structuredClone(fallback);
|
|
56
|
-
try {
|
|
57
|
-
return JSON.parse(readFileSync(path, 'utf8'));
|
|
58
|
-
} catch {
|
|
59
|
-
return structuredClone(fallback);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function saveJson(path, value) {
|
|
64
|
-
writeFileSync(path, JSON.stringify(value, null, 2) + '\n', 'utf8');
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function sameFileContent(a, b) {
|
|
68
|
-
if (!existsSync(a) || !existsSync(b)) return false;
|
|
69
|
-
return readFileSync(a, 'utf8') === readFileSync(b, 'utf8');
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const HOOKS = [
|
|
73
|
-
{
|
|
74
|
-
event: 'UserPromptSubmit',
|
|
75
|
-
file: 'specialists-complete.mjs',
|
|
76
|
-
timeout: 5000,
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
event: 'SessionStart',
|
|
80
|
-
file: 'specialists-session-start.mjs',
|
|
81
|
-
timeout: 8000,
|
|
82
|
-
},
|
|
83
|
-
];
|
|
84
|
-
|
|
85
|
-
function findHookCommands(settings, event, fileName) {
|
|
86
|
-
const entries = settings?.hooks?.[event];
|
|
87
|
-
if (!Array.isArray(entries)) return [];
|
|
88
|
-
return entries.flatMap((entry) =>
|
|
89
|
-
(entry.hooks ?? [])
|
|
90
|
-
.map((hook) => hook.command)
|
|
91
|
-
.filter((command) => typeof command === 'string' && command.includes(fileName)),
|
|
92
|
-
);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function ensureHook(settings, hook) {
|
|
96
|
-
const dest = join(HOOKS_DIR, hook.file);
|
|
97
|
-
const source = join(BUNDLED_HOOKS_DIR, hook.file);
|
|
98
|
-
const existingCommands = findHookCommands(settings, hook.event, hook.file);
|
|
99
|
-
const externalOwner = existingCommands.find((command) => command !== dest);
|
|
100
|
-
|
|
101
|
-
if (externalOwner) {
|
|
102
|
-
skip(`${hook.file} already managed externally — deferring`);
|
|
103
|
-
info(`existing command: ${externalOwner}`);
|
|
104
|
-
return false;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
mkdirSync(HOOKS_DIR, { recursive: true });
|
|
108
|
-
const changed = !sameFileContent(source, dest);
|
|
109
|
-
if (changed) {
|
|
110
|
-
copyFileSync(source, dest);
|
|
111
|
-
chmodSync(dest, 0o755);
|
|
112
|
-
ok(`${hook.file} installed in .claude/hooks/`);
|
|
113
|
-
} else {
|
|
114
|
-
skip(`${hook.file} already up to date`);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
settings.hooks ??= {};
|
|
118
|
-
settings.hooks[hook.event] ??= [];
|
|
119
|
-
settings.hooks[hook.event] = settings.hooks[hook.event].filter(
|
|
120
|
-
(entry) => !(entry.hooks ?? []).some((h) => h.command === dest),
|
|
121
|
-
);
|
|
122
|
-
settings.hooks[hook.event].push({
|
|
123
|
-
hooks: [{ type: 'command', command: dest, timeout: hook.timeout }],
|
|
124
|
-
});
|
|
125
|
-
ok(`${hook.file} registered for ${hook.event}`);
|
|
126
|
-
return true;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function installBundledSpecialists() {
|
|
130
|
-
if (!existsSync(BUNDLED_SPECIALISTS_DIR)) {
|
|
131
|
-
skip('bundled specialists dir not found — skipping');
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
mkdirSync(USER_SPECIALISTS_DIR, { recursive: true });
|
|
135
|
-
const files = readdirSync(BUNDLED_SPECIALISTS_DIR).filter(f => f.endsWith('.specialist.yaml'));
|
|
136
|
-
for (const file of files) {
|
|
137
|
-
const source = join(BUNDLED_SPECIALISTS_DIR, file);
|
|
138
|
-
const dest = join(USER_SPECIALISTS_DIR, file);
|
|
139
|
-
if (sameFileContent(source, dest)) {
|
|
140
|
-
skip(`${file} already up to date`);
|
|
141
|
-
} else {
|
|
142
|
-
copyFileSync(source, dest);
|
|
143
|
-
ok(`${file} installed in ~/.agents/specialists/`);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function ensureMcpRegistration() {
|
|
149
|
-
const mcp = loadJson(MCP_FILE, { mcpServers: {} });
|
|
150
|
-
mcp.mcpServers ??= {};
|
|
151
|
-
const existing = mcp.mcpServers.specialists;
|
|
152
|
-
const desired = { command: 'specialists', args: [] };
|
|
153
|
-
|
|
154
|
-
if (
|
|
155
|
-
existing &&
|
|
156
|
-
existing.command === desired.command &&
|
|
157
|
-
Array.isArray(existing.args) &&
|
|
158
|
-
existing.args.length === 0
|
|
159
|
-
) {
|
|
160
|
-
skip('.mcp.json already registers specialists');
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
mcp.mcpServers.specialists = desired;
|
|
165
|
-
saveJson(MCP_FILE, mcp);
|
|
166
|
-
ok('registered specialists in .mcp.json');
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
console.log(`\n${bold('Specialists installer')}`);
|
|
170
|
-
console.log(dim('Project scope: prerequisite check, bundled specialists, hooks, MCP registration'));
|
|
171
|
-
|
|
172
|
-
section('Prerequisite check');
|
|
173
|
-
const prereqs = [
|
|
174
|
-
{ name: 'pi', ok: commandOk('pi', ['--version']), required: true, help: 'Install pi first.' },
|
|
175
|
-
{ name: 'bd', ok: commandOk('bd', ['--version']), required: true, help: 'Install beads (bd) first.' },
|
|
176
|
-
{ name: 'xt', ok: commandOk('xt', ['--version']), required: true, help: 'xtrm-tools is required for hooks and workflow integration.' },
|
|
177
|
-
];
|
|
178
|
-
|
|
179
|
-
let prereqFailed = false;
|
|
180
|
-
for (const prereq of prereqs) {
|
|
181
|
-
if (prereq.ok) {
|
|
182
|
-
ok(`${prereq.name} available`);
|
|
183
|
-
} else {
|
|
184
|
-
prereqFailed = prereqFailed || prereq.required;
|
|
185
|
-
fail(`${prereq.name} not found`);
|
|
186
|
-
info(prereq.help);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
if (prereqFailed) {
|
|
191
|
-
console.log(`\n${red('Install aborted: required prerequisites are missing.')}`);
|
|
192
|
-
process.exit(1);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
section('Specialists hooks');
|
|
196
|
-
mkdirSync(CLAUDE_DIR, { recursive: true });
|
|
197
|
-
const settings = loadJson(SETTINGS_FILE, {});
|
|
198
|
-
for (const hook of HOOKS) ensureHook(settings, hook);
|
|
199
|
-
saveJson(SETTINGS_FILE, settings);
|
|
200
|
-
ok(`updated ${SETTINGS_FILE}`);
|
|
201
|
-
|
|
202
|
-
section('Bundled specialists');
|
|
203
|
-
installBundledSpecialists();
|
|
204
|
-
|
|
205
|
-
section('MCP registration');
|
|
206
|
-
ensureMcpRegistration();
|
|
6
|
+
const yellow = (s) => `\x1b[33m${s}\x1b[0m`;
|
|
7
|
+
const dim = (s) => `\x1b[2m${s}\x1b[0m`;
|
|
207
8
|
|
|
208
|
-
console.log(
|
|
209
|
-
console.log(
|
|
9
|
+
console.log('');
|
|
10
|
+
console.log(yellow('⚠ DEPRECATED: `bin/install.js` is deprecated'));
|
|
11
|
+
console.log('');
|
|
12
|
+
console.log(` Use ${bold('specialists init')} instead.`);
|
|
13
|
+
console.log('');
|
|
14
|
+
console.log(' The init command handles all setup tasks:');
|
|
15
|
+
console.log(' • creates specialists/ and .specialists/ directories');
|
|
16
|
+
console.log(' • registers the MCP server in .mcp.json');
|
|
17
|
+
console.log(' • injects workflow context into AGENTS.md/CLAUDE.md');
|
|
18
|
+
console.log('');
|
|
19
|
+
console.log(` ${dim('Run: specialists init --help for full details')}`);
|
|
20
|
+
console.log('');
|
|
@@ -99,15 +99,15 @@ lines.push('');
|
|
|
99
99
|
lines.push('```');
|
|
100
100
|
lines.push('specialists list # discover available specialists');
|
|
101
101
|
lines.push('specialists run <name> --prompt "..." # run foreground (streams output)');
|
|
102
|
-
lines.push('specialists run <name> --prompt "..."
|
|
103
|
-
lines.push('specialists run <name> --
|
|
102
|
+
lines.push('process start "specialists run <name> --prompt "..."" name="sp-<name>" # async via process extension');
|
|
103
|
+
lines.push('specialists run <name> --prompt "..." # foreground stream');
|
|
104
104
|
lines.push('specialists feed <job-id> --follow # tail live events');
|
|
105
105
|
lines.push('specialists result <job-id> # read final output');
|
|
106
106
|
lines.push('specialists status # system health');
|
|
107
107
|
lines.push('specialists doctor # troubleshoot issues');
|
|
108
108
|
lines.push('```');
|
|
109
109
|
lines.push('');
|
|
110
|
-
lines.push('MCP tools: specialist_init · use_specialist · start_specialist ·
|
|
110
|
+
lines.push('MCP tools: specialist_init · use_specialist · start_specialist · feed_specialist · run_parallel');
|
|
111
111
|
|
|
112
112
|
// ── Output ─────────────────────────────────────────────────────────────────
|
|
113
113
|
if (lines.length === 0) process.exit(0);
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: specialists-creator
|
|
3
|
+
description: >
|
|
4
|
+
Use this skill when creating or fixing a specialist definition. It guides the
|
|
5
|
+
agent through writing a valid `.specialist.yaml`, choosing supported models,
|
|
6
|
+
validating against the schema, and avoiding common specialist authoring
|
|
7
|
+
mistakes.
|
|
8
|
+
version: 1.0
|
|
9
|
+
---
|
|
10
|
+
|
|
1
11
|
# Specialist Author Guide
|
|
2
12
|
|
|
3
13
|
> Source of truth: `src/specialist/schema.ts` | Runtime: `src/specialist/runner.ts`
|
|
@@ -73,7 +83,7 @@ Read both outputs carefully:
|
|
|
73
83
|
|------|-----------------------|------------------------|
|
|
74
84
|
| **Heavy** — deep reasoning, multi-phase, architecture | `overthinker`, `feature-design`, `bug-hunt`, `planner`, `parallel-review` | Opus / Pro / GLM-5 |
|
|
75
85
|
| **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
|
|
86
|
+
| **Light** — fast context, reporting, test runs | `init-session`, `report-generator`, `test-runner` | Haiku / Flash |
|
|
77
87
|
|
|
78
88
|
Adjust tiers based on what the user actually has installed. Custom specialists: read their `description` and `permission_required` to infer tier.
|
|
79
89
|
|
|
@@ -202,10 +212,20 @@ bun skills/specialist-author/scripts/validate-specialist.ts specialists/my-speci
|
|
|
202
212
|
| `mode` | enum | `auto` | `tool` \| `skill` \| `auto` |
|
|
203
213
|
| `timeout_ms` | number | `120000` | ms |
|
|
204
214
|
| `stall_timeout_ms` | number | — | kill if no event for N ms |
|
|
215
|
+
| `interactive` | boolean | `false` | enable multi-turn keep-alive by default |
|
|
205
216
|
| `response_format` | enum | `text` | `text` \| `json` \| `markdown` |
|
|
206
217
|
| `permission_required` | enum | `READ_ONLY` | see tier table below |
|
|
207
218
|
| `thinking_level` | enum | — | `off` \| `minimal` \| `low` \| `medium` \| `high` \| `xhigh` |
|
|
208
219
|
|
|
220
|
+
**When to use `execution.interactive`**
|
|
221
|
+
|
|
222
|
+
- Set `interactive: true` for specialists intended for multi-turn workflows (`resume`, iterative planning, long investigations).
|
|
223
|
+
- Leave it unset/`false` for one-shot specialists where each run should end immediately.
|
|
224
|
+
- Run-level overrides still apply:
|
|
225
|
+
- CLI: `--keep-alive` enables, `--no-keep-alive` disables.
|
|
226
|
+
- MCP `start_specialist`: `keep_alive` enables, `no_keep_alive` disables.
|
|
227
|
+
- Effective precedence: explicit disable (`--no-keep-alive` / `no_keep_alive`) → explicit enable (`--keep-alive` / `keep_alive`) → `execution.interactive` → one-shot default.
|
|
228
|
+
|
|
209
229
|
**Permission tiers** — controls which pi tools are available:
|
|
210
230
|
|
|
211
231
|
| Level | pi --tools | Use when |
|
|
@@ -410,6 +430,7 @@ specialist:
|
|
|
410
430
|
fallback_model: google-gemini-cli/gemini-3.1-pro-preview
|
|
411
431
|
timeout_ms: 300000
|
|
412
432
|
stall_timeout_ms: 60000
|
|
433
|
+
interactive: true # default keep-alive; supports resume flows
|
|
413
434
|
response_format: markdown
|
|
414
435
|
permission_required: READ_ONLY # not READ_WRITE
|
|
415
436
|
|