workflow-supervisor 0.1.0
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/LICENSE +21 -0
- package/README.md +266 -0
- package/adapters/claude-code/adapter.json +7 -0
- package/adapters/codex/adapter.json +8 -0
- package/adapters/hermesagent/adapter.json +8 -0
- package/adapters/opencode/adapter.json +8 -0
- package/assets/workflow-supervisor-hero.png +0 -0
- package/bin/workflow-skills +2 -0
- package/bin/workflow-skills.mjs +452 -0
- package/docs/artifacts.md +40 -0
- package/docs/cli.md +119 -0
- package/docs/compatibility.md +85 -0
- package/docs/skill-reference.md +33 -0
- package/docs/troubleshooting.md +38 -0
- package/package.json +45 -0
- package/skills/acceptance-matrix/SKILL.md +77 -0
- package/skills/acceptance-matrix/agents/openai.yaml +7 -0
- package/skills/dossier-builder/SKILL.md +93 -0
- package/skills/dossier-builder/agents/openai.yaml +7 -0
- package/skills/loop-policy/SKILL.md +103 -0
- package/skills/loop-policy/agents/openai.yaml +7 -0
- package/skills/source-corpus/SKILL.md +92 -0
- package/skills/source-corpus/agents/openai.yaml +7 -0
- package/skills/work-unit/SKILL.md +72 -0
- package/skills/work-unit/agents/openai.yaml +7 -0
- package/skills/worker-roles/SKILL.md +115 -0
- package/skills/worker-roles/agents/openai.yaml +7 -0
- package/skills/workflow-docs/SKILL.md +88 -0
- package/skills/workflow-docs/agents/openai.yaml +7 -0
- package/skills/workflow-docs/references/documentation-production.md +230 -0
- package/skills/workflow-docs/references/goal-resume.md +62 -0
- package/skills/workflow-docs/references/templates.md +53 -0
- package/skills/workflow-docs/references/workflow-control.md +276 -0
- package/skills/workflow-supervisor/SKILL.md +254 -0
- package/skills/workflow-supervisor/agents/openai.yaml +7 -0
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import crypto from "node:crypto";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const packageRoot = path.resolve(__dirname, "..");
|
|
10
|
+
const PACKAGE_NAME = "workflow-supervisor";
|
|
11
|
+
const PACKAGE_VERSION = "0.1.0";
|
|
12
|
+
const INSTALLABLE_AGENTS = ["codex", "claude-code", "opencode", "hermesagent"];
|
|
13
|
+
const AGENTS = new Set([...INSTALLABLE_AGENTS, "generic"]);
|
|
14
|
+
|
|
15
|
+
function usage() {
|
|
16
|
+
return `workflow-supervisor
|
|
17
|
+
|
|
18
|
+
Usage:
|
|
19
|
+
workflow-supervisor list [--root <path>]
|
|
20
|
+
workflow-supervisor validate [--root <path>]
|
|
21
|
+
workflow-supervisor doctor [--agent <agent|all>] [--scope user|project] [--project <path>] [--target <path>]
|
|
22
|
+
workflow-supervisor install --agent <agent|all> [--scope user|project] [--project <path>] [--target <path>] [--skills all|a,b] [--force] [--dry-run]
|
|
23
|
+
workflow-supervisor uninstall --agent <agent|all> [--scope user|project] [--project <path>] [--target <path>] [--skills all|a,b] [--dry-run]
|
|
24
|
+
workflow-supervisor emit-context --agent <agent> [--scope user|project] [--project <path>] [--target <path>] [--skills all|a,b] [--out <path>] [--root <path>]
|
|
25
|
+
|
|
26
|
+
Agents:
|
|
27
|
+
codex, claude-code, opencode, hermesagent, generic, all
|
|
28
|
+
|
|
29
|
+
Alias:
|
|
30
|
+
workflow-skills
|
|
31
|
+
|
|
32
|
+
Examples:
|
|
33
|
+
npx workflow-supervisor install --agent codex --scope user
|
|
34
|
+
npx workflow-supervisor install --agent all --scope project --project .
|
|
35
|
+
npx workflow-supervisor install --agent generic --target ./agent-skills
|
|
36
|
+
npx workflow-supervisor emit-context --agent opencode --skills workflow-supervisor,workflow-docs --out AGENTS.md
|
|
37
|
+
`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function parseArgs(argv) {
|
|
41
|
+
const result = { _: [] };
|
|
42
|
+
const booleans = new Set(["force", "dry-run", "help"]);
|
|
43
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
44
|
+
const arg = argv[i];
|
|
45
|
+
if (!arg.startsWith("--")) {
|
|
46
|
+
result._.push(arg);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const key = arg.slice(2);
|
|
50
|
+
if (booleans.has(key)) {
|
|
51
|
+
result[key] = true;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const next = argv[i + 1];
|
|
55
|
+
if (!next || next.startsWith("--")) throw new Error(`Missing value for --${key}`);
|
|
56
|
+
result[key] = next;
|
|
57
|
+
i += 1;
|
|
58
|
+
}
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function expandHome(input) {
|
|
63
|
+
if (!input) return input;
|
|
64
|
+
if (input === "~") return os.homedir();
|
|
65
|
+
if (input.startsWith("~/")) return path.join(os.homedir(), input.slice(2));
|
|
66
|
+
return input;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function skillsRoot(root = packageRoot) {
|
|
70
|
+
return path.join(root, "skills");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function listSkills(root = packageRoot) {
|
|
74
|
+
const rootDir = skillsRoot(root);
|
|
75
|
+
if (!fs.existsSync(rootDir)) throw new Error(`Missing skills directory: ${rootDir}`);
|
|
76
|
+
return fs
|
|
77
|
+
.readdirSync(rootDir, { withFileTypes: true })
|
|
78
|
+
.filter((entry) => entry.isDirectory())
|
|
79
|
+
.map((entry) => entry.name)
|
|
80
|
+
.sort();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function normalizeScope(scope = "user") {
|
|
84
|
+
if (scope !== "user" && scope !== "project") throw new Error("--scope must be user or project");
|
|
85
|
+
return scope;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function defaultTarget(agent, { scope = "user", project = process.cwd() } = {}) {
|
|
89
|
+
const home = os.homedir();
|
|
90
|
+
const resolvedScope = normalizeScope(scope);
|
|
91
|
+
const projectRoot = path.resolve(expandHome(project));
|
|
92
|
+
switch (agent) {
|
|
93
|
+
case "codex":
|
|
94
|
+
return resolvedScope === "project"
|
|
95
|
+
? path.join(projectRoot, ".agents", "skills")
|
|
96
|
+
: path.join(home, ".agents", "skills");
|
|
97
|
+
case "claude-code":
|
|
98
|
+
return resolvedScope === "project"
|
|
99
|
+
? path.join(projectRoot, ".claude", "skills")
|
|
100
|
+
: path.join(process.env.CLAUDE_HOME || path.join(home, ".claude"), "skills");
|
|
101
|
+
case "opencode":
|
|
102
|
+
return resolvedScope === "project"
|
|
103
|
+
? path.join(projectRoot, ".opencode", "skills")
|
|
104
|
+
: path.join(process.env.OPENCODE_HOME || path.join(home, ".config", "opencode"), "skills");
|
|
105
|
+
case "hermesagent":
|
|
106
|
+
return resolvedScope === "project"
|
|
107
|
+
? path.join(projectRoot, ".hermes", "skills")
|
|
108
|
+
: path.join(process.env.HERMESAGENT_HOME || process.env.HERMES_HOME || path.join(home, ".hermes"), "skills");
|
|
109
|
+
case "generic":
|
|
110
|
+
return null;
|
|
111
|
+
default:
|
|
112
|
+
throw new Error(`Unknown agent: ${agent}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function readText(file) {
|
|
117
|
+
return fs.readFileSync(file, "utf8");
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function parseFrontmatter(text) {
|
|
121
|
+
if (!text.startsWith("---\n")) return null;
|
|
122
|
+
const end = text.indexOf("\n---\n", 4);
|
|
123
|
+
if (end === -1) return null;
|
|
124
|
+
const raw = text.slice(4, end).trim().split(/\r?\n/);
|
|
125
|
+
const parsed = {};
|
|
126
|
+
for (const line of raw) {
|
|
127
|
+
const idx = line.indexOf(":");
|
|
128
|
+
if (idx === -1) return null;
|
|
129
|
+
parsed[line.slice(0, idx).trim()] = line.slice(idx + 1).trim();
|
|
130
|
+
}
|
|
131
|
+
return parsed;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function validateSkill(root, name) {
|
|
135
|
+
const skillDir = path.join(skillsRoot(root), name);
|
|
136
|
+
const skillFile = path.join(skillDir, "SKILL.md");
|
|
137
|
+
const errors = [];
|
|
138
|
+
if (!fs.existsSync(skillFile)) return ["missing SKILL.md"];
|
|
139
|
+
|
|
140
|
+
const text = readText(skillFile);
|
|
141
|
+
const frontmatter = parseFrontmatter(text);
|
|
142
|
+
if (!frontmatter) {
|
|
143
|
+
errors.push("invalid frontmatter");
|
|
144
|
+
} else {
|
|
145
|
+
const keys = Object.keys(frontmatter).sort();
|
|
146
|
+
if (keys.join(",") !== "description,name") errors.push("frontmatter must contain only name and description");
|
|
147
|
+
if (frontmatter.name !== name) errors.push(`frontmatter name ${frontmatter.name || "<missing>"} does not match folder ${name}`);
|
|
148
|
+
if (!frontmatter.description || frontmatter.description.length < 80) errors.push("description is missing or too short");
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (/\[TODO|TODO:|Structuring This Skill|Not every skill requires/.test(text)) errors.push("contains scaffold/TODO text");
|
|
152
|
+
|
|
153
|
+
const agentFile = path.join(skillDir, "agents", "openai.yaml");
|
|
154
|
+
if (fs.existsSync(agentFile)) {
|
|
155
|
+
const agentYaml = readText(agentFile);
|
|
156
|
+
if (!agentYaml.includes(`Use $${name}`)) errors.push("agents/openai.yaml default prompt must mention skill name");
|
|
157
|
+
if (!agentYaml.includes("allow_implicit_invocation: false")) errors.push("skills must be opt-in by default");
|
|
158
|
+
}
|
|
159
|
+
return errors;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function validate(root = packageRoot) {
|
|
163
|
+
const names = listSkills(root);
|
|
164
|
+
const allErrors = [];
|
|
165
|
+
for (const name of names) {
|
|
166
|
+
for (const error of validateSkill(root, name)) allErrors.push(`${name}: ${error}`);
|
|
167
|
+
}
|
|
168
|
+
if (names.length === 0) allErrors.push("no skills found");
|
|
169
|
+
if (allErrors.length > 0) throw new Error(`Validation failed:\n${allErrors.map((e) => `- ${e}`).join("\n")}`);
|
|
170
|
+
return names;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function selectSkills(root, raw) {
|
|
174
|
+
const names = listSkills(root);
|
|
175
|
+
if (!raw || raw === "all") return names;
|
|
176
|
+
const requested = raw.split(",").map((item) => item.trim()).filter(Boolean);
|
|
177
|
+
for (const name of requested) {
|
|
178
|
+
if (!names.includes(name)) throw new Error(`Unknown skill ${name}. Available: ${names.join(", ")}`);
|
|
179
|
+
}
|
|
180
|
+
return requested;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function walkFiles(dir) {
|
|
184
|
+
if (!fs.existsSync(dir)) return [];
|
|
185
|
+
const files = [];
|
|
186
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
187
|
+
const full = path.join(dir, entry.name);
|
|
188
|
+
if (entry.isDirectory()) files.push(...walkFiles(full));
|
|
189
|
+
if (entry.isFile()) files.push(full);
|
|
190
|
+
}
|
|
191
|
+
return files.sort();
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function hashDir(dir) {
|
|
195
|
+
const hash = crypto.createHash("sha256");
|
|
196
|
+
for (const file of walkFiles(dir)) {
|
|
197
|
+
hash.update(path.relative(dir, file));
|
|
198
|
+
hash.update("\0");
|
|
199
|
+
hash.update(fs.readFileSync(file));
|
|
200
|
+
hash.update("\0");
|
|
201
|
+
}
|
|
202
|
+
return hash.digest("hex");
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const SKILL_SUMMARIES = {
|
|
206
|
+
"workflow-supervisor": "coordinate open-ended agent loops and bind Codex goals when appropriate",
|
|
207
|
+
"source-corpus": "rank and reconcile sources when source authority affects safe next action",
|
|
208
|
+
"work-unit": "decompose broad objectives into bounded units",
|
|
209
|
+
"dossier-builder": "create a handoff contract for one already-bounded work unit",
|
|
210
|
+
"worker-roles": "separate implementer, verifier, repair, documentation, reviewer, and solo-mode responsibilities",
|
|
211
|
+
"acceptance-matrix": "create formal evidence-mapped acceptance criteria",
|
|
212
|
+
"loop-policy": "define retries, parallel safety, approval gates, and goal binding policy",
|
|
213
|
+
"workflow-docs": "create durable workflow-state or documentation-production artifacts",
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
function skillSummary(name) {
|
|
217
|
+
return SKILL_SUMMARIES[name] || "use the bundled SKILL.md instructions";
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function markdownResourceFiles(skillDir) {
|
|
221
|
+
const referencesDir = path.join(skillDir, "references");
|
|
222
|
+
return walkFiles(referencesDir).filter((file) => file.endsWith(".md"));
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function copyDir(src, dest, { force = false, dryRun = false } = {}) {
|
|
226
|
+
if (fs.existsSync(dest)) {
|
|
227
|
+
if (!force) throw new Error(`Destination exists: ${dest}. Use --force to overwrite.`);
|
|
228
|
+
if (!dryRun) fs.rmSync(dest, { recursive: true, force: true });
|
|
229
|
+
}
|
|
230
|
+
if (dryRun) return;
|
|
231
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
232
|
+
fs.cpSync(src, dest, { recursive: true });
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function resolveAgents(raw = "generic") {
|
|
236
|
+
if (raw === "all") return INSTALLABLE_AGENTS;
|
|
237
|
+
if (!AGENTS.has(raw)) throw new Error(`Unsupported agent: ${raw}`);
|
|
238
|
+
return [raw];
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function resolveTarget(args, agent) {
|
|
242
|
+
const scope = normalizeScope(args.scope || "user");
|
|
243
|
+
if (args.target) return path.resolve(expandHome(args.target));
|
|
244
|
+
const target = defaultTarget(agent, { scope, project: args.project || process.cwd() });
|
|
245
|
+
if (!target) throw new Error(`--target is required for --agent ${agent} with --scope ${scope}`);
|
|
246
|
+
return target;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function contextFor(agent, target, names = listSkills(packageRoot)) {
|
|
250
|
+
const title = agent === "generic" ? "Workflow Skill Pack" : `Workflow Skill Pack for ${agent}`;
|
|
251
|
+
const skillLines = names.map((name) => `- \`$${name}\`: ${skillSummary(name)}.`);
|
|
252
|
+
return `# ${title}
|
|
253
|
+
|
|
254
|
+
Installed skills:
|
|
255
|
+
|
|
256
|
+
\`${target || "<custom skill directory>"}\`
|
|
257
|
+
|
|
258
|
+
Use these skills explicitly for supervised, long-running, or handoff-heavy workflows:
|
|
259
|
+
|
|
260
|
+
${skillLines.join("\n")}
|
|
261
|
+
|
|
262
|
+
Do not use this pack for tiny direct tasks, ordinary README edits, one-off tests, or routine review unless a supervised workflow or durable handoff is explicitly needed.
|
|
263
|
+
`;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function portableContextFor(root, agent, target, names) {
|
|
267
|
+
const title = agent === "generic" ? "Workflow Skill Pack Portable Context" : `Workflow Skill Pack Portable Context for ${agent}`;
|
|
268
|
+
const sections = [
|
|
269
|
+
`# ${title}`,
|
|
270
|
+
"",
|
|
271
|
+
"This file embeds the selected Workflow Supervisor skills for agents that cannot discover `SKILL.md` folders directly.",
|
|
272
|
+
"",
|
|
273
|
+
"Use these skills explicitly for supervised, long-running, or handoff-heavy workflows. Loading or reading a skill does not by itself create a new thread, subagent, goal, commit, PR, publication, or other side effect; those actions require the governing environment tools and the gates described in the relevant skill.",
|
|
274
|
+
"",
|
|
275
|
+
`Expected skill directory: \`${target || "<custom skill directory>"}\``,
|
|
276
|
+
"",
|
|
277
|
+
"## Included Skills",
|
|
278
|
+
"",
|
|
279
|
+
...names.map((name) => `- \`$${name}\`: ${skillSummary(name)}.`),
|
|
280
|
+
"",
|
|
281
|
+
"Do not use this pack for tiny direct tasks, ordinary README edits, one-off tests, or routine review unless a supervised workflow or durable handoff is explicitly needed.",
|
|
282
|
+
"",
|
|
283
|
+
];
|
|
284
|
+
|
|
285
|
+
for (const name of names) {
|
|
286
|
+
const skillDir = path.join(skillsRoot(root), name);
|
|
287
|
+
const skillFile = path.join(skillDir, "SKILL.md");
|
|
288
|
+
sections.push(`## Skill: $${name}`, "");
|
|
289
|
+
sections.push(`Source: \`skills/${name}/SKILL.md\``, "");
|
|
290
|
+
sections.push(readText(skillFile).trim(), "");
|
|
291
|
+
|
|
292
|
+
for (const resourceFile of markdownResourceFiles(skillDir)) {
|
|
293
|
+
const relative = path.relative(skillDir, resourceFile);
|
|
294
|
+
sections.push(`### Bundled Reference: $${name}/${relative}`, "");
|
|
295
|
+
sections.push(readText(resourceFile).trim(), "");
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return `${sections.join("\n")}\n`;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function writeManifest(target, data, dryRun) {
|
|
303
|
+
if (dryRun) return;
|
|
304
|
+
fs.mkdirSync(target, { recursive: true });
|
|
305
|
+
fs.writeFileSync(path.join(target, ".workflow-skills-install.json"), JSON.stringify(data, null, 2) + "\n");
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function installOne(args, agent) {
|
|
309
|
+
const root = path.resolve(expandHome(args.root || packageRoot));
|
|
310
|
+
const scope = normalizeScope(args.scope || "user");
|
|
311
|
+
const target = resolveTarget(args, agent);
|
|
312
|
+
const names = selectSkills(root, args.skills || "all");
|
|
313
|
+
const dryRun = Boolean(args["dry-run"]);
|
|
314
|
+
const installed = [];
|
|
315
|
+
|
|
316
|
+
for (const name of names) {
|
|
317
|
+
const src = path.join(skillsRoot(root), name);
|
|
318
|
+
const dest = path.join(target, name);
|
|
319
|
+
copyDir(src, dest, { force: Boolean(args.force), dryRun });
|
|
320
|
+
installed.push({ name, checksum: hashDir(src) });
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (!dryRun) fs.writeFileSync(path.join(target, "WORKFLOW_SKILL_PACK.md"), contextFor(agent, target, names));
|
|
324
|
+
writeManifest(
|
|
325
|
+
target,
|
|
326
|
+
{
|
|
327
|
+
package: PACKAGE_NAME,
|
|
328
|
+
version: PACKAGE_VERSION,
|
|
329
|
+
agent,
|
|
330
|
+
scope,
|
|
331
|
+
project: scope === "project" ? path.resolve(expandHome(args.project || process.cwd())) : null,
|
|
332
|
+
target,
|
|
333
|
+
installedAt: new Date().toISOString(),
|
|
334
|
+
skills: installed,
|
|
335
|
+
},
|
|
336
|
+
dryRun
|
|
337
|
+
);
|
|
338
|
+
|
|
339
|
+
return { agent, target, skills: names, dryRun };
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function install(args) {
|
|
343
|
+
validate(path.resolve(expandHome(args.root || packageRoot)));
|
|
344
|
+
return resolveAgents(args.agent || "generic").map((agent) => installOne(args, agent));
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function uninstallOne(args, agent) {
|
|
348
|
+
const root = path.resolve(expandHome(args.root || packageRoot));
|
|
349
|
+
const target = resolveTarget(args, agent);
|
|
350
|
+
const names = selectSkills(root, args.skills || "all");
|
|
351
|
+
const dryRun = Boolean(args["dry-run"]);
|
|
352
|
+
for (const name of names) {
|
|
353
|
+
if (!dryRun) fs.rmSync(path.join(target, name), { recursive: true, force: true });
|
|
354
|
+
}
|
|
355
|
+
if (!dryRun) {
|
|
356
|
+
fs.rmSync(path.join(target, ".workflow-skills-install.json"), { force: true });
|
|
357
|
+
fs.rmSync(path.join(target, "WORKFLOW_SKILL_PACK.md"), { force: true });
|
|
358
|
+
}
|
|
359
|
+
return { agent, target, skills: names, dryRun };
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function uninstall(args) {
|
|
363
|
+
return resolveAgents(args.agent || "generic").map((agent) => uninstallOne(args, agent));
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function emitContext(args) {
|
|
367
|
+
const agent = args.agent || "generic";
|
|
368
|
+
if (!AGENTS.has(agent)) throw new Error(`Unsupported agent: ${agent}`);
|
|
369
|
+
const root = path.resolve(expandHome(args.root || packageRoot));
|
|
370
|
+
validate(root);
|
|
371
|
+
const names = selectSkills(root, args.skills || "all");
|
|
372
|
+
const target = args.target ? path.resolve(expandHome(args.target)) : defaultTarget(agent, { scope: args.scope || "user", project: args.project || process.cwd() });
|
|
373
|
+
const text = portableContextFor(root, agent, target, names);
|
|
374
|
+
if (args.out) {
|
|
375
|
+
const out = path.resolve(expandHome(args.out));
|
|
376
|
+
fs.mkdirSync(path.dirname(out), { recursive: true });
|
|
377
|
+
fs.writeFileSync(out, text);
|
|
378
|
+
return `Wrote ${out}`;
|
|
379
|
+
}
|
|
380
|
+
return text;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
function doctorOne(args, agent) {
|
|
384
|
+
const target = args.target ? path.resolve(expandHome(args.target)) : defaultTarget(agent, { scope: args.scope || "user", project: args.project || process.cwd() });
|
|
385
|
+
return {
|
|
386
|
+
packageRoot,
|
|
387
|
+
agent,
|
|
388
|
+
scope: args.scope || "user",
|
|
389
|
+
defaultTarget: target,
|
|
390
|
+
skills: validate(packageRoot),
|
|
391
|
+
targetExists: target ? fs.existsSync(target) : false,
|
|
392
|
+
manifestExists: target ? fs.existsSync(path.join(target, ".workflow-skills-install.json")) : false,
|
|
393
|
+
note: target ? "Override with --target if your agent uses a different skill directory." : "Provide --target for installation.",
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
function doctor(args) {
|
|
398
|
+
const agent = args.agent || "generic";
|
|
399
|
+
if (agent === "all") return JSON.stringify(INSTALLABLE_AGENTS.map((item) => doctorOne(args, item)), null, 2);
|
|
400
|
+
if (!AGENTS.has(agent)) throw new Error(`Unsupported agent: ${agent}`);
|
|
401
|
+
return JSON.stringify(doctorOne(args, agent), null, 2);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
function printInstallResults(results, verb) {
|
|
405
|
+
const pastTense = verb === "remove" ? "Removed" : "Installed";
|
|
406
|
+
for (const result of results) {
|
|
407
|
+
console.log(`${result.dryRun ? `Would ${verb}` : pastTense} ${result.skills.length} skills for ${result.agent} at ${result.target}`);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function main() {
|
|
412
|
+
const args = parseArgs(process.argv.slice(2));
|
|
413
|
+
const command = args._[0] || "help";
|
|
414
|
+
if (args.help || command === "help") {
|
|
415
|
+
console.log(usage());
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
if (command === "list") {
|
|
419
|
+
console.log(listSkills(path.resolve(expandHome(args.root || packageRoot))).join("\n"));
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
if (command === "validate") {
|
|
423
|
+
const root = path.resolve(expandHome(args.root || packageRoot));
|
|
424
|
+
const names = validate(root);
|
|
425
|
+
console.log(`Validated ${names.length} skills: ${names.join(", ")}`);
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
if (command === "doctor") {
|
|
429
|
+
console.log(doctor(args));
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
if (command === "install") {
|
|
433
|
+
printInstallResults(install(args), "install");
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
if (command === "uninstall") {
|
|
437
|
+
printInstallResults(uninstall(args), "remove");
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
if (command === "emit-context") {
|
|
441
|
+
console.log(emitContext(args));
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
throw new Error(`Unknown command: ${command}\n\n${usage()}`);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
try {
|
|
448
|
+
main();
|
|
449
|
+
} catch (error) {
|
|
450
|
+
console.error(error.message);
|
|
451
|
+
process.exit(1);
|
|
452
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Workflow And Documentation Artifacts
|
|
2
|
+
|
|
3
|
+
`$workflow-docs` creates only the smallest useful artifact set.
|
|
4
|
+
|
|
5
|
+
Default location: create Markdown workflow artifacts under `<workspace>/.workflow/`. Use another directory only when the user names one, the project already has a clearer workflow-state convention, or the artifact is a final deliverable that belongs elsewhere.
|
|
6
|
+
|
|
7
|
+
## Workflow Control
|
|
8
|
+
|
|
9
|
+
- `.workflow/WORKFLOW.md`
|
|
10
|
+
- `.workflow/SOURCE-CORPUS.md`
|
|
11
|
+
- `.workflow/WORK-UNITS.md`
|
|
12
|
+
- `.workflow/DOSSIER.md`
|
|
13
|
+
- `.workflow/THREAD-MAP.md`
|
|
14
|
+
- `.workflow/ACCEPTANCE-MATRIX.md`
|
|
15
|
+
- `.workflow/VERIFICATION-REPORT.md`
|
|
16
|
+
- `.workflow/REPAIR-TICKETS.md`
|
|
17
|
+
- `.workflow/DECISIONS.md`
|
|
18
|
+
- `.workflow/HANDOFF.md`
|
|
19
|
+
- `.workflow/OUTCOME.md`
|
|
20
|
+
- `.workflow/GOAL-STATE.md`
|
|
21
|
+
|
|
22
|
+
## Documentation Production
|
|
23
|
+
|
|
24
|
+
- `.workflow/DOCUMENTATION-BRIEF.md`
|
|
25
|
+
- `.workflow/CONTENT-INVENTORY.md`
|
|
26
|
+
- `.workflow/OUTLINE.md`
|
|
27
|
+
- `.workflow/CONTENT-DRAFT.md`
|
|
28
|
+
- `.workflow/CLAIMS-REGISTER.md`
|
|
29
|
+
- `.workflow/STYLE-GUIDE.md`
|
|
30
|
+
- `.workflow/GLOSSARY.md`
|
|
31
|
+
- `.workflow/ASSET-REGISTER.md`
|
|
32
|
+
- `.workflow/REVIEW-PLAN.md`
|
|
33
|
+
- `.workflow/REVISION-QUEUE.md`
|
|
34
|
+
- `.workflow/PUBLISHING-CHECKLIST.md`
|
|
35
|
+
- `.workflow/PUBLICATION-LOG.md`
|
|
36
|
+
- `.workflow/MAINTENANCE-PLAN.md`
|
|
37
|
+
|
|
38
|
+
## State Medium
|
|
39
|
+
|
|
40
|
+
Markdown is the default, but state may also be an inline brief, spreadsheet tab, ticket set, design annotation, CRM note, runbook, decision log, slide appendix, whiteboard note, or chat handoff.
|
package/docs/cli.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# CLI Reference
|
|
2
|
+
|
|
3
|
+
The package exposes two executables:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
workflow-supervisor
|
|
7
|
+
workflow-skills
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
When using `npx`, run:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npx workflow-supervisor <command>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Commands
|
|
17
|
+
|
|
18
|
+
### `list`
|
|
19
|
+
|
|
20
|
+
Print skills bundled with the package.
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
workflow-supervisor list
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### `validate`
|
|
27
|
+
|
|
28
|
+
Validate skill folder structure, `SKILL.md` frontmatter, required metadata, and opt-in policy.
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
workflow-supervisor validate
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### `doctor`
|
|
35
|
+
|
|
36
|
+
Print package, target, and skill discovery information.
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
workflow-supervisor doctor --agent codex
|
|
40
|
+
workflow-supervisor doctor --agent generic --target ./agent-skills
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### `install`
|
|
44
|
+
|
|
45
|
+
Install skills into an agent target.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
workflow-supervisor install --agent codex
|
|
49
|
+
workflow-supervisor install --agent claude-code --target ~/.claude/skills
|
|
50
|
+
workflow-supervisor install --agent opencode --target ~/.config/opencode/skills
|
|
51
|
+
workflow-supervisor install --agent hermesagent --target ~/.hermes/skills
|
|
52
|
+
workflow-supervisor install --agent generic --target ./agent-skills
|
|
53
|
+
workflow-supervisor install --agent all --scope project --project .
|
|
54
|
+
workflow-supervisor uninstall --agent codex --scope user
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Options:
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
--agent codex|claude-code|opencode|hermesagent|generic|all
|
|
61
|
+
--scope user|project Install to user-level or project-level location where supported.
|
|
62
|
+
--project <path> Project root for project-scope installs.
|
|
63
|
+
--target <path> Override install directory. Required for generic.
|
|
64
|
+
--skills all|a,b Install all skills or a comma-separated subset.
|
|
65
|
+
--force Replace existing installed skill folders.
|
|
66
|
+
--dry-run Validate and print intended action without writing.
|
|
67
|
+
--root <path> Use another package root.
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Default targets:
|
|
71
|
+
|
|
72
|
+
| Agent | Scope | Default |
|
|
73
|
+
|---|---|---|
|
|
74
|
+
| Codex | user | `~/.agents/skills` |
|
|
75
|
+
| Codex | project | `<project>/.agents/skills` |
|
|
76
|
+
| Claude Code | user | `${CLAUDE_HOME:-~/.claude}/skills` |
|
|
77
|
+
| Claude Code | project | `<project>/.claude/skills` |
|
|
78
|
+
| OpenCode | user | `${OPENCODE_HOME:-~/.config/opencode}/skills` |
|
|
79
|
+
| OpenCode | project | `<project>/.opencode/skills` |
|
|
80
|
+
| HermesAgent | user | `${HERMESAGENT_HOME:-${HERMES_HOME:-~/.hermes}}/skills` |
|
|
81
|
+
| HermesAgent | project | `<project>/.hermes/skills` |
|
|
82
|
+
| Generic | any | requires `--target` |
|
|
83
|
+
|
|
84
|
+
HermesAgent project scope is a package-local convention for portable installs. Use `--target` if your HermesAgent setup expects another directory.
|
|
85
|
+
|
|
86
|
+
### `uninstall`
|
|
87
|
+
|
|
88
|
+
Remove installed skill folders and package context files.
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
workflow-supervisor uninstall --agent codex --scope user
|
|
92
|
+
workflow-supervisor uninstall --agent generic --target ./agent-skills
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### `emit-context`
|
|
96
|
+
|
|
97
|
+
Create a portable instruction file for agents that do not natively discover `SKILL.md` folders. The output embeds the selected `SKILL.md` files and bundled Markdown references, so the receiving agent can use the skills without separately reading the skill directory.
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
workflow-supervisor emit-context --agent generic --target ./agent-skills --out AGENTS.md
|
|
101
|
+
workflow-supervisor emit-context --agent opencode --skills workflow-supervisor,workflow-docs --out AGENTS.md
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Options:
|
|
105
|
+
|
|
106
|
+
```text
|
|
107
|
+
--agent codex|claude-code|opencode|hermesagent|generic
|
|
108
|
+
--scope user|project
|
|
109
|
+
--project <path>
|
|
110
|
+
--target <path>
|
|
111
|
+
--skills all|a,b Embed all skills or a comma-separated subset.
|
|
112
|
+
--out <path> Write to a file instead of stdout.
|
|
113
|
+
--root <path> Use another package root.
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Exit Codes
|
|
117
|
+
|
|
118
|
+
- `0`: command succeeded
|
|
119
|
+
- `1`: validation, install, argument, or filesystem error
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Agent Compatibility
|
|
2
|
+
|
|
3
|
+
The pack is built around portable `SKILL.md` folders. Codex consumes those folders directly. Other agents can use the same content as explicit prompt skills, context packs, or project-local instructions.
|
|
4
|
+
|
|
5
|
+
## Skills, Threads, And Subagents
|
|
6
|
+
|
|
7
|
+
Loading a skill does not spawn a thread or subagent. A skill is instruction context for the current agent until the environment explicitly uses a separate execution tool.
|
|
8
|
+
|
|
9
|
+
`$workflow-supervisor` can plan worker threads or subagents, but they start only after complete intake, the workflow path gate, a concrete dossier, and target-environment delegation support are all satisfied. If those tools are unavailable or user-visible thread creation is not approved, use the generated handoff prompts or workflow docs as the fallback.
|
|
10
|
+
|
|
11
|
+
## Codex
|
|
12
|
+
|
|
13
|
+
Codex support is native:
|
|
14
|
+
|
|
15
|
+
- each skill has `SKILL.md`
|
|
16
|
+
- each skill has `agents/openai.yaml`
|
|
17
|
+
- all skills opt out of implicit invocation by default
|
|
18
|
+
- `$workflow-supervisor`, `$loop-policy`, and `$workflow-docs` include Codex goal lifecycle rules
|
|
19
|
+
|
|
20
|
+
Install:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx workflow-supervisor install --agent codex --scope user
|
|
24
|
+
npx workflow-supervisor install --agent codex --scope project --project .
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Use:
|
|
28
|
+
|
|
29
|
+
```text
|
|
30
|
+
Use $workflow-supervisor to supervise this migration. It should ask the complete intake before planning or work starts.
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Claude Code
|
|
34
|
+
|
|
35
|
+
Claude Code environments vary by local setup. Install to the skill or prompt directory your setup uses, or choose a project-local target.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npx workflow-supervisor install --agent claude-code --target ~/.claude/skills
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
If native discovery is unavailable, emit a context file:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npx workflow-supervisor emit-context --agent claude-code --target ~/.claude/skills --skills workflow-supervisor,workflow-docs --out CLAUDE.md
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Codex goal APIs degrade to `.workflow/GOAL-STATE.md` and workflow docs.
|
|
48
|
+
|
|
49
|
+
## OpenCode
|
|
50
|
+
|
|
51
|
+
Install to an OpenCode skill/prompt directory or project-local target:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npx workflow-supervisor install --agent opencode --target ~/.config/opencode/skills
|
|
55
|
+
npx workflow-supervisor install --agent opencode --scope project --project .
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
If OpenCode does not read `agents/openai.yaml`, ignore that file and invoke by explicit skill names from `SKILL.md`.
|
|
59
|
+
|
|
60
|
+
## HermesAgent
|
|
61
|
+
|
|
62
|
+
Install to the HermesAgent skill/prompt directory configured by your environment:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npx workflow-supervisor install --agent hermesagent --target ~/.hermes/skills
|
|
66
|
+
npx workflow-supervisor install --agent hermesagent --scope project --project .
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
User scope follows HermesAgent's documented `~/.hermes/skills` location. Project scope uses the package-local fallback `<project>/.hermes/skills` so `--agent all --scope project` can create a complete portable skill bundle.
|
|
70
|
+
|
|
71
|
+
If native discovery is unavailable:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
npx workflow-supervisor emit-context --agent hermesagent --target ~/.hermes/skills --skills workflow-supervisor,workflow-docs --out HERMES.md
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Generic Agent
|
|
78
|
+
|
|
79
|
+
Use `generic` for any agent that can read a directory of Markdown instructions.
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
npx workflow-supervisor install --agent generic --target ./agent-skills
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Then point the agent at `./agent-skills/WORKFLOW_SKILL_PACK.md` and the individual `SKILL.md` files.
|