Add agent-swarm skill

This commit is contained in:
Emil Shanaty
2026-10-27 18:50:15 +03:00
commit 54a5c849d4
14 changed files with 1285 additions and 0 deletions
+88
View File
@@ -0,0 +1,88 @@
// agent-swarm verification runner — copy into the `script` field of the workflow tool.
// args: {
// wave?: number,
// tasks: [{ id: string, review: string }], // review = .swarm/reviews/Vxx.md
// concurrency?: number // verifier slots; default 4, keep free slots
// }
//
// The detailed review is written to disk BEFORE the structured verdict is
// returned. The workflow schema is intentionally tiny: a long findings array is
// easy to get wrong and a schema miss must not destroy the verification work.
const VERDICT = {
type: "object",
properties: {
task_id: { type: "string" },
verdict: { type: "string", enum: ["pass", "pass_with_risks", "fail"] },
summary: { type: "string" },
review_file: { type: "string" }
},
required: ["task_id", "verdict", "summary", "review_file"]
};
const CONCURRENCY = Math.max(
1,
Math.min(Number(args.concurrency) || 4, 8)
);
const promptFor = (t, attempt) => [
`You are verifier ${t.id}. You did not write this work; do not fix it and do not edit product source, tests, docs or manifests.`,
`Read .swarm/brief.md, the relevant .swarm/tasks/*.md cards, .swarm/contracts.md, and the implementation.`,
`Work only in ${t.review} and .swarm/tmp/${t.id}/. Copy or hash-check generated files instead of rewriting the tree.`,
`Verify against the original acceptance criteria, not the worker's summary. Run the commands yourself and record exact commands + observed results. Findings need file:line, reproduction, expected vs actual.`,
`Freeze assumption: the tree is not being edited during this wave. If you see a stale/inconsistent build, say so; do not fix it.`,
`FIRST write the full review to ${t.review}. THEN return only {task_id, verdict, summary, review_file}; keep summary <= 2000 chars. The review file is the source of truth and must exist even if the structured reply fails.`,
`Verdict rules: "fail" for critical/major product gaps; "pass_with_risks" for minor or documented-scope risks; "pass" only when no material issue remains.`,
attempt > 1
? `The previous structured reply was unusable. Preserve the review file; return the four required fields only.`
: ""
].filter(Boolean).join("\n");
const failed = (t, why) => ({
task_id: t.id,
verdict: "fail",
summary: why,
review_file: t.review
});
async function runOne(t) {
for (let attempt = 1; attempt <= 2; attempt++) {
try {
const r = await agent(promptFor(t, attempt), {
label: t.id,
phase: `verify ${args.wave || ""}`.trim(),
schema: VERDICT
});
if (r && r.verdict) return r;
log(`${t.id}: attempt ${attempt} produced no usable verdict`);
} catch (error) {
const message = String(error && error.message ? error.message : error);
if (/(limit|spawn|could not start|active child|capacity|start a child)/i.test(message)) {
log(`${t.id}: scheduling error: ${message}`);
return failed(t, `scheduling error: ${message}`);
}
throw error;
}
}
return failed(t, "no usable structured verdict; see review file");
}
phase(`verify${args.wave ? ` ${args.wave}` : ""}`);
log(`Dispatching ${args.tasks.length} verifier(s) in batches of ${CONCURRENCY}`);
const results = [];
for (let start = 0; start < args.tasks.length; start += CONCURRENCY) {
const batch = args.tasks.slice(start, start + CONCURRENCY);
const batchResults = await parallel(batch.map((t) => () => runOne(t)));
results.push(...batchResults);
}
return {
wave: args.wave || null,
concurrency: CONCURRENCY,
total: results.length,
pass: results.filter((r) => r && r.verdict === "pass").length,
pass_with_risks: results.filter((r) => r && r.verdict === "pass_with_risks").length,
fail: results.filter((r) => !r || r.verdict === "fail").length,
results
};