@llblab/pi-actors 0.29.2 → 0.30.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/AGENTS.md +16 -1
- package/BACKLOG.md +89 -206
- package/CHANGELOG.md +9 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +71 -315
- package/dist/lib/actor-inspector-tui.d.ts +35 -0
- package/dist/lib/actor-inspector-tui.js +159 -1
- package/dist/lib/observability.d.ts +34 -0
- package/dist/lib/observability.js +103 -1
- package/dist/lib/paths.d.ts +9 -0
- package/dist/lib/paths.js +15 -0
- package/dist/lib/pi.d.ts +19 -0
- package/dist/lib/pi.js +21 -0
- package/dist/lib/runtime.d.ts +5 -0
- package/dist/lib/runtime.js +48 -0
- package/dist/lib/tools.d.ts +9 -0
- package/dist/lib/tools.js +58 -8
- package/dist/skills/actors/SKILL.md +10 -116
- package/dist/skills/swarm/SKILL.md +20 -1
- package/docs/README.md +1 -0
- package/docs/actors-deep-reference.md +66 -0
- package/index.ts +99 -379
- package/lib/actor-inspector-tui.ts +221 -1
- package/lib/observability.ts +194 -34
- package/lib/paths.ts +27 -0
- package/lib/pi.ts +47 -0
- package/lib/runtime.ts +55 -0
- package/lib/tools.ts +119 -24
- package/package.json +1 -1
- package/skills/actors/SKILL.md +10 -116
- package/skills/swarm/SKILL.md +20 -1
package/lib/tools.ts
CHANGED
|
@@ -27,6 +27,34 @@ export type RegisterToolInput = Registry.RegisterToolInput;
|
|
|
27
27
|
export type RegisterToolRuntimeDeps<TContext> =
|
|
28
28
|
Registry.RegisterToolRuntimeDeps<TContext>;
|
|
29
29
|
|
|
30
|
+
export interface CoreActorToolDefinitionDeps<TContext extends AsyncRunToolContext> {
|
|
31
|
+
configPath: string;
|
|
32
|
+
getActiveTools: () => string[];
|
|
33
|
+
getRuntimeTool: (name: string) => unknown;
|
|
34
|
+
registryRuntime: Pick<
|
|
35
|
+
RegisterToolRuntimeDeps<TContext>,
|
|
36
|
+
| "getExternalToolConflict"
|
|
37
|
+
| "getTools"
|
|
38
|
+
| "notify"
|
|
39
|
+
| "registerRuntimeTool"
|
|
40
|
+
>;
|
|
41
|
+
setActiveTools: (toolNames: string[]) => void;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const RESERVED_TOOL_NAMES = new Set([
|
|
45
|
+
"read",
|
|
46
|
+
"write",
|
|
47
|
+
"edit",
|
|
48
|
+
"bash",
|
|
49
|
+
"find",
|
|
50
|
+
"grep",
|
|
51
|
+
"ls",
|
|
52
|
+
"register_tool",
|
|
53
|
+
"message",
|
|
54
|
+
"spawn",
|
|
55
|
+
"inspect",
|
|
56
|
+
]);
|
|
57
|
+
|
|
30
58
|
type JsonSchema = Record<string, unknown>;
|
|
31
59
|
|
|
32
60
|
function stringSchema(description: string): JsonSchema {
|
|
@@ -183,7 +211,8 @@ function compactAsyncRunStatus(value: unknown): string {
|
|
|
183
211
|
tokens.push(`failures=${failures}`);
|
|
184
212
|
if (result.code !== undefined) tokens.push(`code=${String(result.code)}`);
|
|
185
213
|
if (result.killed === true) tokens.push("killed=true");
|
|
186
|
-
if (status.candidate_recipe)
|
|
214
|
+
if (status.candidate_recipe)
|
|
215
|
+
tokens.push(`candidate_recipe=${String(status.candidate_recipe)}`);
|
|
187
216
|
return `\n${tokens.join(" ")}`;
|
|
188
217
|
}
|
|
189
218
|
|
|
@@ -448,10 +477,17 @@ function compactSessionRuns(
|
|
|
448
477
|
summary: Record<string, unknown> = {},
|
|
449
478
|
): string {
|
|
450
479
|
const suffix = [
|
|
451
|
-
summary.other_sessions !== undefined
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
480
|
+
summary.other_sessions !== undefined
|
|
481
|
+
? `other_sessions=${String(summary.other_sessions)}`
|
|
482
|
+
: "",
|
|
483
|
+
summary.other_runs !== undefined
|
|
484
|
+
? `other_runs=${String(summary.other_runs)}`
|
|
485
|
+
: "",
|
|
486
|
+
]
|
|
487
|
+
.filter(Boolean)
|
|
488
|
+
.join(" ");
|
|
489
|
+
if (runs.length === 0)
|
|
490
|
+
return `\nsession=${session} runs=0${suffix ? ` ${suffix}` : ""}`;
|
|
455
491
|
return `\nsession=${session} runs=${runs.length}${suffix ? ` ${suffix}` : ""}\n${runs
|
|
456
492
|
.map((run) => {
|
|
457
493
|
const tokens = [
|
|
@@ -471,14 +507,21 @@ function getPiActorsRuntimeStatus(): Record<string, unknown> {
|
|
|
471
507
|
const packageRoot = dirname(packagedRecipeRoot);
|
|
472
508
|
const packageJsonPath = join(packageRoot, "package.json");
|
|
473
509
|
const packageJson = existsSync(packageJsonPath)
|
|
474
|
-
? JSON.parse(readFileSync(packageJsonPath, "utf8")) as Record<
|
|
510
|
+
? (JSON.parse(readFileSync(packageJsonPath, "utf8")) as Record<
|
|
511
|
+
string,
|
|
512
|
+
unknown
|
|
513
|
+
>)
|
|
475
514
|
: {};
|
|
476
515
|
let git_commit: string | undefined;
|
|
477
516
|
try {
|
|
478
|
-
git_commit = execFileSync(
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
517
|
+
git_commit = execFileSync(
|
|
518
|
+
"git",
|
|
519
|
+
["-C", packageRoot, "rev-parse", "--short", "HEAD"],
|
|
520
|
+
{
|
|
521
|
+
encoding: "utf8",
|
|
522
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
523
|
+
},
|
|
524
|
+
).trim();
|
|
482
525
|
} catch {
|
|
483
526
|
git_commit = undefined;
|
|
484
527
|
}
|
|
@@ -510,12 +553,13 @@ function compactToolActor(name: string, tool: Record<string, unknown>): string {
|
|
|
510
553
|
|
|
511
554
|
function compactRecipeImports(summary: Record<string, unknown>): string {
|
|
512
555
|
const active = Array.isArray(summary.active)
|
|
513
|
-
? summary.active as Array<Record<string, unknown>>
|
|
556
|
+
? (summary.active as Array<Record<string, unknown>>)
|
|
514
557
|
: [];
|
|
515
558
|
const lines = active.flatMap((entry) => {
|
|
516
559
|
const imports = asRecord(entry.imports);
|
|
517
560
|
return Object.entries(imports).map(([alias, value]) => {
|
|
518
|
-
const binding =
|
|
561
|
+
const binding =
|
|
562
|
+
typeof value === "string" ? { from: value } : asRecord(value);
|
|
519
563
|
return `recipe=${String(entry.id ?? "<unknown>")} alias=${alias} from=${String(binding.from ?? value)}`;
|
|
520
564
|
});
|
|
521
565
|
});
|
|
@@ -552,7 +596,10 @@ function compactRecipeDoctor(summary: Record<string, unknown>): string {
|
|
|
552
596
|
);
|
|
553
597
|
}
|
|
554
598
|
for (const item of remediations.slice(0, 8)) {
|
|
555
|
-
const action = compactPreview(
|
|
599
|
+
const action = compactPreview(
|
|
600
|
+
item.action,
|
|
601
|
+
Limits.DOCTOR_ACTION_PREVIEW_CHARS,
|
|
602
|
+
);
|
|
556
603
|
const blocked = item.blocked_candidate
|
|
557
604
|
? ` blocked=${compactPreview(item.blocked_candidate, Limits.DOCTOR_ACTION_PREVIEW_CHARS)}`
|
|
558
605
|
: "";
|
|
@@ -717,7 +764,11 @@ function formatToolActorFailure(
|
|
|
717
764
|
function shadowedRecipeLaunchDiagnostic(
|
|
718
765
|
recipe: unknown,
|
|
719
766
|
): Record<string, unknown> | undefined {
|
|
720
|
-
if (
|
|
767
|
+
if (
|
|
768
|
+
typeof recipe !== "string" ||
|
|
769
|
+
recipe.includes("/") ||
|
|
770
|
+
recipe.includes("~")
|
|
771
|
+
)
|
|
721
772
|
return undefined;
|
|
722
773
|
const discovery = RecipeDiscovery.discoverRecipeSources([
|
|
723
774
|
{ root: Paths.getRecipeRoot(), defaultTool: true, mutableUsage: true },
|
|
@@ -730,7 +781,9 @@ function candidateRecipeName(run: string): string {
|
|
|
730
781
|
return `${run.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "spawn"}.json`;
|
|
731
782
|
}
|
|
732
783
|
|
|
733
|
-
function candidateRecipeDefaults(
|
|
784
|
+
function candidateRecipeDefaults(
|
|
785
|
+
values: Record<string, unknown>,
|
|
786
|
+
): Record<string, unknown> | undefined {
|
|
734
787
|
const ignored = new Set([
|
|
735
788
|
"actor_address",
|
|
736
789
|
"communication_file",
|
|
@@ -753,7 +806,11 @@ function writeSpawnCandidateRecipe(
|
|
|
753
806
|
process.env.PI_ACTORS_ENABLE_SPAWN_CANDIDATES_IN_TEST !== "1"
|
|
754
807
|
)
|
|
755
808
|
return undefined;
|
|
756
|
-
if (
|
|
809
|
+
if (
|
|
810
|
+
input.template === undefined ||
|
|
811
|
+
input.file !== undefined ||
|
|
812
|
+
input.recipe !== undefined
|
|
813
|
+
)
|
|
757
814
|
return undefined;
|
|
758
815
|
const root = Paths.getRecipeCandidateRoot();
|
|
759
816
|
mkdirSync(root, { recursive: true });
|
|
@@ -772,7 +829,8 @@ function writeSpawnCandidateRecipe(
|
|
|
772
829
|
|
|
773
830
|
function enhanceSpawnRecipeError(error: unknown, recipe: unknown): Error {
|
|
774
831
|
const diagnostic = shadowedRecipeLaunchDiagnostic(recipe);
|
|
775
|
-
if (!diagnostic)
|
|
832
|
+
if (!diagnostic)
|
|
833
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
776
834
|
const original = error instanceof Error ? error.message : String(error);
|
|
777
835
|
return Object.assign(
|
|
778
836
|
new Error(
|
|
@@ -832,12 +890,17 @@ async function routeBranchEnvelope(
|
|
|
832
890
|
try {
|
|
833
891
|
return await AsyncRuns.sendRunMessage(runId, JSON.stringify(branchMessage));
|
|
834
892
|
} catch (error) {
|
|
835
|
-
const record =
|
|
893
|
+
const record =
|
|
894
|
+
error && typeof error === "object"
|
|
895
|
+
? (error as Record<string, unknown>)
|
|
896
|
+
: {};
|
|
836
897
|
if (record.queued === true) {
|
|
837
898
|
return {
|
|
838
899
|
control_path: record.control_path,
|
|
839
900
|
control_type: record.control_type,
|
|
840
|
-
delivery_error:
|
|
901
|
+
delivery_error:
|
|
902
|
+
record.delivery_error ??
|
|
903
|
+
(error instanceof Error ? error.message : String(error)),
|
|
841
904
|
inbox_id: record.inbox_id,
|
|
842
905
|
queued: true,
|
|
843
906
|
run: runId,
|
|
@@ -1070,7 +1133,12 @@ export function createInspectToolDefinition<TContext = unknown>(
|
|
|
1070
1133
|
const target = String(input.target ?? "");
|
|
1071
1134
|
const view = String(input.view ?? "");
|
|
1072
1135
|
if (target === "recipes" || target === "recipe-registry") {
|
|
1073
|
-
if (
|
|
1136
|
+
if (
|
|
1137
|
+
view !== "status" &&
|
|
1138
|
+
view !== "summary" &&
|
|
1139
|
+
view !== "doctor" &&
|
|
1140
|
+
view !== "imports"
|
|
1141
|
+
) {
|
|
1074
1142
|
throw new Error(
|
|
1075
1143
|
"inspect recipes supports view=status, view=summary, view=doctor, or view=imports.",
|
|
1076
1144
|
);
|
|
@@ -1086,7 +1154,9 @@ export function createInspectToolDefinition<TContext = unknown>(
|
|
|
1086
1154
|
const recipeRoot = deps.recipeRoot ?? Paths.getRecipeRoot();
|
|
1087
1155
|
const summary = {
|
|
1088
1156
|
...RecipeDiscovery.summarizeDiscovery(discovered),
|
|
1089
|
-
candidates: RecipeDiscovery.listCandidateRecipes(
|
|
1157
|
+
candidates: RecipeDiscovery.listCandidateRecipes(
|
|
1158
|
+
join(recipeRoot, "candidates"),
|
|
1159
|
+
),
|
|
1090
1160
|
};
|
|
1091
1161
|
return {
|
|
1092
1162
|
content: [
|
|
@@ -1147,9 +1217,10 @@ export function createInspectToolDefinition<TContext = unknown>(
|
|
|
1147
1217
|
const runs = allRuns.filter(
|
|
1148
1218
|
(run) => address.value === "all" || run.ownerId === address.value,
|
|
1149
1219
|
);
|
|
1150
|
-
const sessionSummary =
|
|
1151
|
-
|
|
1152
|
-
|
|
1220
|
+
const sessionSummary =
|
|
1221
|
+
address.value === "all"
|
|
1222
|
+
? {}
|
|
1223
|
+
: summarizeOtherSessions(address.value || "", allRuns);
|
|
1153
1224
|
return {
|
|
1154
1225
|
content: [
|
|
1155
1226
|
{
|
|
@@ -1725,6 +1796,30 @@ export function createActorMessageToolDefinition<TContext = unknown>(
|
|
|
1725
1796
|
};
|
|
1726
1797
|
}
|
|
1727
1798
|
|
|
1799
|
+
export function createCoreActorToolDefinitions<TContext extends AsyncRunToolContext>(
|
|
1800
|
+
deps: CoreActorToolDefinitionDeps<TContext>,
|
|
1801
|
+
): any[] {
|
|
1802
|
+
return [
|
|
1803
|
+
createRegisterToolDefinition<TContext>({
|
|
1804
|
+
configPath: deps.configPath,
|
|
1805
|
+
getActiveTools: deps.getActiveTools,
|
|
1806
|
+
getExternalToolConflict: deps.registryRuntime.getExternalToolConflict,
|
|
1807
|
+
getTools: deps.registryRuntime.getTools,
|
|
1808
|
+
notify: deps.registryRuntime.notify,
|
|
1809
|
+
registerRuntimeTool: deps.registryRuntime.registerRuntimeTool,
|
|
1810
|
+
reservedToolNames: RESERVED_TOOL_NAMES,
|
|
1811
|
+
setActiveTools: deps.setActiveTools,
|
|
1812
|
+
}),
|
|
1813
|
+
createSpawnToolDefinition<TContext>(),
|
|
1814
|
+
createActorMessageToolDefinition<TContext>({
|
|
1815
|
+
getTool: (name) => deps.getRuntimeTool(name),
|
|
1816
|
+
}),
|
|
1817
|
+
createInspectToolDefinition<TContext>({
|
|
1818
|
+
getTool: (name) => deps.getRuntimeTool(name),
|
|
1819
|
+
}),
|
|
1820
|
+
];
|
|
1821
|
+
}
|
|
1822
|
+
|
|
1728
1823
|
export function createRuntimeToolDefinition(
|
|
1729
1824
|
cfg: RegisteredTool,
|
|
1730
1825
|
exec: Execution.RegisteredToolExec,
|
package/package.json
CHANGED
package/skills/actors/SKILL.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: actors
|
|
3
3
|
description: Highest-density practical guide for pi-actors. Read this skill whenever prompt and tools are not enough for spawn, message, inspect, actor runs, tools, recipes, command templates, async lifecycle, mailboxes, artifacts, and local orchestration mechanics.
|
|
4
4
|
metadata:
|
|
5
|
-
version: 0.
|
|
5
|
+
version: 0.30.0
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Actors (pi-actors)
|
|
@@ -132,38 +132,15 @@ The table is compact and optimistic by default: bounded body previews, capped no
|
|
|
132
132
|
|
|
133
133
|
Let terminal notifications arrive; avoid sleep-poll loops except during diagnosis.
|
|
134
134
|
|
|
135
|
-
##
|
|
135
|
+
## Runtime Communication Rules
|
|
136
136
|
|
|
137
|
-
- Prefer independent read-only reviewers for review swarms. Use shared room messages for coordination signals and observability, not for letting reviewers converge early, unless the task explicitly asks for collaborative discussion.
|
|
138
|
-
- Treat inspector-visible communication logs as recipe-quality evidence. Full room/direct timelines show whether recipes coordinate clearly, emit useful summaries, over-chat, miss handoffs, choose poor message types, or need better mailbox/artifact conventions. Use `inspect room:<run> view=messages|previews`, `inspect run:<id> view=communication`, and the actor inspector table/full-message views to improve recipes after real runs.
|
|
139
|
-
- Smoke-test provider/model availability before launching expensive fanout, or choose a provider known to be configured in this environment. A failed provider fanout creates noisy run transitions without useful review signal.
|
|
140
137
|
- Keep one public communication model: `spawn` creates actors, `message` sends typed envelopes, and `inspect` observes. Avoid adding public side channels or storage nouns when a normal actor address/view can express the operation.
|
|
141
138
|
- Keep route and semantic type separate. Direct, room, coordinator, and session messages may share `type`; delivery behavior comes from `to`.
|
|
139
|
+
- Treat inspector-visible communication logs as recipe evidence. Use `inspect room:<run> view=messages|previews`, `inspect run:<id> view=communication`, and the actor inspector table/full-message views to improve mailbox/artifact conventions after real runs.
|
|
142
140
|
- Any UI, summary, or aggregate view that scans run directories must apply coordinator/session ownership filters before exposing summaries or body previews.
|
|
143
141
|
- Treat `communication.json` as visible actor context, not a global mutable truth table. Run-level snapshots should identify the run actor; branch-local snapshots should identify the branch actor.
|
|
144
142
|
- Prefer same-run provenance checks on lateral actor routes. If `from` is accepted for room or branch routes, validate that it belongs to the addressed run.
|
|
145
143
|
|
|
146
|
-
## Persistent Backlog Implementers
|
|
147
|
-
|
|
148
|
-
When using actors as backlog implementers, avoid one-shot subagents that exit after one task. Use long-lived branch actors and keep task selection with the coordinator:
|
|
149
|
-
|
|
150
|
-
1. Coordinator assigns a concrete backlog slice with `task.assign`.
|
|
151
|
-
2. Actor posts `task.claim` to `room:<run>` before editing.
|
|
152
|
-
3. Actor executes and validates the slice.
|
|
153
|
-
4. Actor posts `task.result` and `awaiting_assignment`.
|
|
154
|
-
5. Actor stays alive until the coordinator sends another `task.assign` or an explicit `control.kill`.
|
|
155
|
-
|
|
156
|
-
Use `front`/`back` actors for opposite backlog ends when reducing overlap. Implementer workflows should be packaged as reusable recipe composition, not bespoke scripts: use `coordinator-locker` for queue/assignment/locking, subagent launcher recipes for execution cells, actor-message utility recipes for structured handoffs, and `lib/mailbox-loop.ts` helpers when writing mailbox-consuming workers. Mailbox loops should claim one run or branch inbox message at a time, mark success as `handled`, mark exceptions as `failed`, and treat only `control.kill` as the generic loop termination message; `control.stop` and `control.cancel` are actor-domain messages only when the recipe declares and handles them. Bounded drains may process available work until `control.kill` or a max-message guard. If the existing recipe library cannot express the scenario, add missing reusable component recipes first, then compose the higher-level workflow from them. Supervisors should route coordinator assignments by `body.actor`, preserve the assignment as an object rather than a JSON string, and keep stopped-worker summaries tied to the original actor list.
|
|
157
|
-
|
|
158
|
-
Current packaged building blocks:
|
|
159
|
-
|
|
160
|
-
- `coordinator-locker`: long-lived queue/lock coordinator for assignment and resource ownership.
|
|
161
|
-
- `subagent-prompt`, `subagent-tools`, `subagents-prompts`: execution launchers for one or many agent prompts.
|
|
162
|
-
- `utility-actor-message`: deterministic actor-message envelope construction for handoffs/results.
|
|
163
|
-
- `utility-run-ops-snapshot` and `pipeline-async-run-ops`: inspect live runs/messages before deciding the next assignment.
|
|
164
|
-
|
|
165
|
-
The missing higher-level persistent backlog-implementer workflow is intentionally future work until it can be expressed from reusable recipe cells.
|
|
166
|
-
|
|
167
144
|
## Command Template Standard
|
|
168
145
|
|
|
169
146
|
Forms:
|
|
@@ -273,102 +250,19 @@ Tool templates may be:
|
|
|
273
250
|
|
|
274
251
|
The user recipe root is the default tool set by location. It accepts canonical JSON recipes and literate Markdown recipes with frontmatter plus fenced `template`/`json recipe` blocks; same-id JSON shadows Markdown in the same priority layer. Packaged recipes are lower-priority standard-library components and are not tools unless copied or registered into the agent recipe root. Ideal runtime behavior is reactive: create/edit/delete recipe files, validate them, then connect valid tools or surface diagnostics without requiring agents to hand-maintain a separate registry.
|
|
275
252
|
|
|
276
|
-
##
|
|
253
|
+
## Top Recipes
|
|
277
254
|
|
|
278
|
-
Use packaged recipes by name with `spawn file=<name>` for async actors, or register/call them as tools when repeated use deserves a stable shortcut.
|
|
255
|
+
Use packaged recipes by name with `spawn file=<name>` for async actors, or register/call them as tools when repeated use deserves a stable shortcut.
|
|
279
256
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
- [`coordinator-locker`](../../recipes/coordinator-locker.json): queue + acquire/renew/release lease locks + journaled coordinator messages + platform-adapted control metadata.
|
|
283
|
-
- [`locker`](../../recipes/locker.json): modular queue + acquire/renew/release lease locks + journaled locker messages + platform-adapted control metadata.
|
|
284
|
-
- [`utility-coordinator-lock-snapshot`](../../recipes/utility-coordinator-lock-snapshot.json): one-shot JSON snapshot of a coordinator-locker state directory.
|
|
285
|
-
- [`music-player`](../../recipes/music-player.json): background local/URL/directory/playlist playback actor controlled by messages.
|
|
286
|
-
- [`actor-worker`](../../recipes/actor-worker.json): canonical mailbox-backed branch worker reference that claims branch inbox work, emits room-visible task lifecycle messages, writes compact `worker-status.json`, optionally writes per-task result artifacts under `worker-artifacts/`, surfaces stale-claim counts when `stale_claim_ms` is set, and terminates on `control.kill`.
|
|
287
|
-
|
|
288
|
-
### Subagent Atoms
|
|
289
|
-
|
|
290
|
-
- Launchers: [`subagent-prompt`](../../recipes/subagent-prompt.json), [`subagent-tools`](../../recipes/subagent-tools.json), [`subagents-prompts`](../../recipes/subagents-prompts.json).
|
|
291
|
-
- Review chain: [`subagent-review`](../../recipes/subagent-review.json), [`subagent-verify`](../../recipes/subagent-verify.json), [`subagent-merge`](../../recipes/subagent-merge.json), [`subagent-judge`](../../recipes/subagent-judge.json), [`subagent-normalize`](../../recipes/subagent-normalize.json).
|
|
292
|
-
- Planning/evidence: [`subagent-plan`](../../recipes/subagent-plan.json), [`subagent-task-card`](../../recipes/subagent-task-card.json), [`subagent-evidence-map`](../../recipes/subagent-evidence-map.json), [`subagent-contradiction-map`](../../recipes/subagent-contradiction-map.json), [`subagent-critic`](../../recipes/subagent-critic.json).
|
|
293
|
-
- Handoffs: [`subagent-checkpoint`](../../recipes/subagent-checkpoint.json), [`subagent-followup`](../../recipes/subagent-followup.json), [`subagent-message`](../../recipes/subagent-message.json), [`subagent-artifact`](../../recipes/subagent-artifact.json), [`subagent-conflict-report`](../../recipes/subagent-conflict-report.json).
|
|
294
|
-
- Composition: [`subagent-quorum`](../../recipes/subagent-quorum.json), [`subagent-review-coordinator`](../../recipes/subagent-review-coordinator.json), [`lens-swarm`](../../recipes/lens-swarm.json).
|
|
295
|
-
|
|
296
|
-
### Pipelines
|
|
297
|
-
|
|
298
|
-
- [`pipeline-release-readiness`](../../recipes/pipeline-release-readiness.json): changelog/package/skill/validation evidence → release review → artifact report.
|
|
299
|
-
- [`pipeline-release-summary`](../../recipes/pipeline-release-summary.json): evidence-only release summary, risk checklist, and PR body draft artifact without release side effects.
|
|
257
|
+
- [`pipeline-room-swarm`](../../recipes/pipeline-room-swarm.json): room-visible swarm coordination with roles, rounds, optional locker, artifact synthesis, and `subagent_ttl_ms` for hard participant budgets.
|
|
300
258
|
- [`pipeline-repo-health`](../../recipes/pipeline-repo-health.json): git/doc/validation evidence → normalized repository health report.
|
|
301
|
-
- [`pipeline-
|
|
302
|
-
- [`
|
|
303
|
-
-
|
|
304
|
-
- Review gates: [`pipeline-quorum-review`](../../recipes/pipeline-quorum-review.json), [`pipeline-review-readiness`](../../recipes/pipeline-review-readiness.json).
|
|
305
|
-
- Task-first workflows: [`pipeline-architect-coordinator`](../../recipes/pipeline-architect-coordinator.json), [`pipeline-research-synthesis`](../../recipes/pipeline-research-synthesis.json), [`pipeline-development-tasking`](../../recipes/pipeline-development-tasking.json), [`pipeline-checkpoint-continuation`](../../recipes/pipeline-checkpoint-continuation.json), [`pipeline-media-library`](../../recipes/pipeline-media-library.json), [`pipeline-room-swarm`](../../recipes/pipeline-room-swarm.json). For room swarms, choose `mode` from `consensus`, `pipeline`, `fanout`, or `pool`; prefer `roles_path` for custom role JSON and keep role `name` ASCII-safe for branch addresses. Set `subagent_ttl_ms` when participant processes need a hard kill budget. Use `locker=true` when the swarm needs a coordinator-locker-backed artifact lock and journal.
|
|
306
|
-
|
|
307
|
-
### Utilities
|
|
308
|
-
|
|
309
|
-
- Repo/release evidence: [`utility-git-status`](../../recipes/utility-git-status.json), [`utility-git-log`](../../recipes/utility-git-log.json), [`utility-changelog-head`](../../recipes/utility-changelog-head.json), [`utility-changelog-section`](../../recipes/utility-changelog-section.json), [`utility-package-summary`](../../recipes/utility-package-summary.json), [`utility-skill-summary`](../../recipes/utility-skill-summary.json).
|
|
310
|
-
- Validation/state: [`utility-validation-wrapper`](../../recipes/utility-validation-wrapper.json), [`utility-validate-recipe`](../../recipes/utility-validate-recipe.json), [`utility-run-summary`](../../recipes/utility-run-summary.json), [`utility-run-ops-snapshot`](../../recipes/utility-run-ops-snapshot.json), [`utility-run-state-files`](../../recipes/utility-run-state-files.json), [`utility-jsonl-tail`](../../recipes/utility-jsonl-tail.json).
|
|
311
|
-
- Artifacts/media/messages: [`utility-artifact-manifest`](../../recipes/utility-artifact-manifest.json), [`utility-artifact-write`](../../recipes/utility-artifact-write.json), [`utility-actor-message`](../../recipes/utility-actor-message.json), [`utility-markdown-index`](../../recipes/utility-markdown-index.json), [`utility-playlist-scan`](../../recipes/utility-playlist-scan.json), [`utility-playlist-build`](../../recipes/utility-playlist-build.json).
|
|
312
|
-
|
|
313
|
-
Deep inventory: [`docs/recipe-library.md`](../../docs/recipe-library.md).
|
|
314
|
-
|
|
315
|
-
## Operating Patterns
|
|
316
|
-
|
|
317
|
-
- **Short deterministic command**: call foreground registered tool or command template.
|
|
318
|
-
- **Long job/service/fanout**: `spawn` async recipe, then inspect/messages/artifacts.
|
|
319
|
-
- **One-off experiment**: inline `template`; promote after repeat use.
|
|
320
|
-
- **Reusable workflow**: packaged or user recipe with public knobs, mailbox, artifacts, docs.
|
|
321
|
-
- **Subagent/swarm execution**: compose packaged recipes/pipelines from smaller recipe cells; add missing generic cells to the extension rather than creating one-off external orchestration scripts.
|
|
322
|
-
- **Consensus-first build**: when many lenses should shape one artifact, have proposer subagents post room messages, then one named implementer writes, one QA reviewer checks, and one finalizer emits `run.done`; do not ask every lens to mutate the same artifact.
|
|
323
|
-
- **Coordinated workers**: spawn `coordinator-locker` when several actors need a shared queue, acquire/renew/release resource leases, or a journaled coordination point.
|
|
324
|
-
- **Release/review pipeline**: pi-actors can prepare evidence, summaries, and artifacts; external actions such as commit, PR, merge, tag, and publish require the appropriate gated release workflow.
|
|
325
|
-
|
|
326
|
-
## Complementary Methodology Engines
|
|
327
|
-
|
|
328
|
-
pi-actors is the local execution engine for methodology skills. A methodology skill can define abstract patterns such as lens swarm, quorum, task cards, lock discipline, consensus-first build, or clean-context merge; pi-actors turns those patterns into concrete local actors, recipes, queues, leases, artifacts, and messages.
|
|
329
|
-
|
|
330
|
-
Example mapping:
|
|
331
|
-
|
|
332
|
-
```text
|
|
333
|
-
methodology says: protect shared files
|
|
334
|
-
pi-actors does: spawn coordinator-locker, enqueue tasks, lease resources
|
|
335
|
-
|
|
336
|
-
methodology says: run reviewers then merge
|
|
337
|
-
pi-actors does: spawn review pipeline, inspect messages/artifacts
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
Keep the split clean: methodology chooses coordination shape; pi-actors supplies addressable local machinery.
|
|
341
|
-
|
|
342
|
-
## Lifecycle Discipline
|
|
343
|
-
|
|
344
|
-
1. Choose existing recipe/tool when available.
|
|
345
|
-
2. Spawn with a stable actor id for observable work.
|
|
346
|
-
3. Inspect `status` after launch.
|
|
347
|
-
4. Use notifications and `inspect`; do not busy-poll.
|
|
348
|
-
5. Read `messages` and `artifacts`, not only stdout.
|
|
349
|
-
6. Use `message` for explicit control or domain commands; treat direct branch messages as intended initiating work. Direct branch envelopes are queued under the recipient branch inbox and can be inspected with `inspect branch:<run>/<branch> view=mailbox`; queued entries have stable `id` values and internal `claimed` / `handled` / `failed` states for worker protocols and retries. Room messages are shared transcript/context.
|
|
350
|
-
7. Promote repeated inline forms to recipes.
|
|
351
|
-
8. Keep recipes small and shallow: files over 1 MiB or import chains deeper than 32 are rejected.
|
|
352
|
-
9. Update docs/context when changing public behavior; if the change affects how agents operate this extension, update this skill and the bundled prompt guidance too.
|
|
353
|
-
|
|
354
|
-
## Common Pitfalls
|
|
355
|
-
|
|
356
|
-
- Treating actor mechanics as multi-agent methodology.
|
|
357
|
-
- Repeating inline templates instead of promoting recipes.
|
|
358
|
-
- Creating task-specific external orchestration scripts when the scenario belongs in pi-actors as a reusable recipe/pipeline with prompts, roles, artifact paths, and model/tool policy passed as args.
|
|
359
|
-
- Embedding complex shell loops or Bash `${...}` parameter expansion directly in command templates; braces are pi-actors placeholders too, so put only generic trusted helper cells in packaged scripts when command-template composition is not enough.
|
|
360
|
-
- Omitting stable run ids for work that needs follow-up.
|
|
361
|
-
- Sending domain messages without checking `mailbox`.
|
|
362
|
-
- Expecting current room messages to wake prompt-only subagents; use direct branch messages or a runner protocol for initiating work.
|
|
363
|
-
- Reading only stdout and missing actor messages/artifacts.
|
|
364
|
-
- Assuming every packaged message-controlled script is native-Windows-ready; core run control is platform-adapted, but Unix-tool scripts must be migrated recipe by recipe.
|
|
365
|
-
- Baking local absolute paths into published docs or reusable recipes.
|
|
366
|
-
- Creating recipes that perform external side effects without explicit operator gates.
|
|
367
|
-
- Letting project insights live only in chat instead of updating BACKLOG/CHANGELOG/docs and, when agent behavior changes, the packaged skill or prompt guidance.
|
|
368
|
-
- Preserving old runtime/event/FIFO vocabulary instead of `spawn`/`message`/`inspect` and actor messages.
|
|
259
|
+
- [`pipeline-release-readiness`](../../recipes/pipeline-release-readiness.json): changelog/package/skill/validation evidence → release review → artifact report.
|
|
260
|
+
- [`actor-worker`](../../recipes/actor-worker.json): canonical mailbox-backed branch worker reference for claim/handle/status/artifact patterns.
|
|
261
|
+
- [`coordinator-locker`](../../recipes/coordinator-locker.json): queue + lease locks + journaled coordinator messages for multi-actor ownership.
|
|
369
262
|
|
|
370
263
|
## Deep References
|
|
371
264
|
|
|
265
|
+
- `docs/actors-deep-reference.md` — recipe navigator, operating patterns, lifecycle discipline, pitfalls.
|
|
372
266
|
- `docs/command-templates.md` — execution graph semantics.
|
|
373
267
|
- `docs/template-recipes.md` — recipe storage, imports, defaults, references.
|
|
374
268
|
- `docs/async-runs.md` — detached lifecycle, state, cancellation, observability.
|
package/skills/swarm/SKILL.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: swarm
|
|
3
3
|
description: Subagent orchestration with scoped locks and quorum consensus. Use for multi-model review, parallel scoped work, delegated audit, and coordinated subagent execution.
|
|
4
4
|
metadata:
|
|
5
|
-
version: 0.
|
|
5
|
+
version: 0.30.0
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Swarm
|
|
@@ -285,6 +285,25 @@ Async run management is an adapter concern, not a portable Swarm script requirem
|
|
|
285
285
|
|
|
286
286
|
`Reference binding`: Use a local generic async-run runtime or tool registry adapter. If the local runtime exposes a single action tool, bind these verbs as actions rather than adding more Swarm scripts. Swarm scripts themselves should stay atomic and narrowly specialized.
|
|
287
287
|
|
|
288
|
+
## Stable Multi-Agent Review Rules
|
|
289
|
+
|
|
290
|
+
- Prefer independent read-only reviewers for review swarms. Use shared room messages for coordination signals and observability, not for letting reviewers converge early, unless the task explicitly asks for collaborative discussion.
|
|
291
|
+
- Treat communication logs as recipe-quality evidence. Timelines show whether agents coordinate clearly, emit useful summaries, over-chat, miss handoffs, choose poor message types, or need better mailbox/artifact conventions.
|
|
292
|
+
- Smoke-test provider/model availability before launching expensive fanout, or choose a provider known to be configured in the environment. A failed provider fanout creates noisy run transitions without useful review signal.
|
|
293
|
+
- Keep methodology and runtime split: Swarm chooses decomposition, quorum, lenses, lock discipline, and merge shape; the local runtime supplies actors, messages, files, locks, artifacts, and cancellation.
|
|
294
|
+
|
|
295
|
+
## Persistent Implementer Pattern
|
|
296
|
+
|
|
297
|
+
Use this pattern only when the work benefits from long-lived workers rather than one-shot subagents. Keep task selection with the coordinator and use reusable adapter cells for queues, locks, messages, and mailbox loops.
|
|
298
|
+
|
|
299
|
+
1. Coordinator assigns a concrete task with `task.assign` or an adapter-equivalent envelope.
|
|
300
|
+
2. Actor claims before editing or mutating shared state.
|
|
301
|
+
3. Actor executes and validates the slice.
|
|
302
|
+
4. Actor posts a result plus an explicit availability/blocked status.
|
|
303
|
+
5. Actor stays alive until another assignment or an explicit runtime/domain stop.
|
|
304
|
+
|
|
305
|
+
Use opposite-end or lens-specific implementers only to reduce overlap, not as a default. If a host adapter cannot express this scenario from reusable cells, add missing generic cells before packaging a broad workflow.
|
|
306
|
+
|
|
288
307
|
## `swarm_quorum`
|
|
289
308
|
|
|
290
309
|
Multi-model review by independent subagents.
|