pi-fabric 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.
Files changed (203) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +635 -0
  3. package/THIRD_PARTY_NOTICES.md +9 -0
  4. package/dist/activity/store.d.ts +27 -0
  5. package/dist/activity/store.d.ts.map +1 -0
  6. package/dist/activity/store.js +474 -0
  7. package/dist/activity/store.js.map +1 -0
  8. package/dist/activity/types.d.ts +101 -0
  9. package/dist/activity/types.d.ts.map +1 -0
  10. package/dist/activity/types.js +2 -0
  11. package/dist/activity/types.js.map +1 -0
  12. package/dist/actors/context.d.ts +13 -0
  13. package/dist/actors/context.d.ts.map +1 -0
  14. package/dist/actors/context.js +155 -0
  15. package/dist/actors/context.js.map +1 -0
  16. package/dist/actors/manager.d.ts +33 -0
  17. package/dist/actors/manager.d.ts.map +1 -0
  18. package/dist/actors/manager.js +751 -0
  19. package/dist/actors/manager.js.map +1 -0
  20. package/dist/actors/types.d.ts +67 -0
  21. package/dist/actors/types.d.ts.map +1 -0
  22. package/dist/actors/types.js +2 -0
  23. package/dist/actors/types.js.map +1 -0
  24. package/dist/capture/catalog.d.ts +23 -0
  25. package/dist/capture/catalog.d.ts.map +1 -0
  26. package/dist/capture/catalog.js +53 -0
  27. package/dist/capture/catalog.js.map +1 -0
  28. package/dist/capture/interceptor.d.ts +13 -0
  29. package/dist/capture/interceptor.d.ts.map +1 -0
  30. package/dist/capture/interceptor.js +130 -0
  31. package/dist/capture/interceptor.js.map +1 -0
  32. package/dist/commands/fabric.d.ts +14 -0
  33. package/dist/commands/fabric.d.ts.map +1 -0
  34. package/dist/commands/fabric.js +237 -0
  35. package/dist/commands/fabric.js.map +1 -0
  36. package/dist/config.d.ts +89 -0
  37. package/dist/config.d.ts.map +1 -0
  38. package/dist/config.js +255 -0
  39. package/dist/config.js.map +1 -0
  40. package/dist/core/action-registry.d.ts +71 -0
  41. package/dist/core/action-registry.d.ts.map +1 -0
  42. package/dist/core/action-registry.js +273 -0
  43. package/dist/core/action-registry.js.map +1 -0
  44. package/dist/core/approval-controller.d.ts +11 -0
  45. package/dist/core/approval-controller.d.ts.map +1 -0
  46. package/dist/core/approval-controller.js +45 -0
  47. package/dist/core/approval-controller.js.map +1 -0
  48. package/dist/core/pi-tools.d.ts +4 -0
  49. package/dist/core/pi-tools.d.ts.map +1 -0
  50. package/dist/core/pi-tools.js +11 -0
  51. package/dist/core/pi-tools.js.map +1 -0
  52. package/dist/core/tool-ownership.d.ts +12 -0
  53. package/dist/core/tool-ownership.d.ts.map +1 -0
  54. package/dist/core/tool-ownership.js +41 -0
  55. package/dist/core/tool-ownership.js.map +1 -0
  56. package/dist/execution-service.d.ts +41 -0
  57. package/dist/execution-service.d.ts.map +1 -0
  58. package/dist/execution-service.js +210 -0
  59. package/dist/execution-service.js.map +1 -0
  60. package/dist/fabric-state.d.ts +38 -0
  61. package/dist/fabric-state.d.ts.map +1 -0
  62. package/dist/fabric-state.js +275 -0
  63. package/dist/fabric-state.js.map +1 -0
  64. package/dist/index.d.ts +4 -0
  65. package/dist/index.d.ts.map +1 -0
  66. package/dist/index.js +491 -0
  67. package/dist/index.js.map +1 -0
  68. package/dist/mesh/store.d.ts +68 -0
  69. package/dist/mesh/store.d.ts.map +1 -0
  70. package/dist/mesh/store.js +387 -0
  71. package/dist/mesh/store.js.map +1 -0
  72. package/dist/protocol.d.ts +62 -0
  73. package/dist/protocol.d.ts.map +1 -0
  74. package/dist/protocol.js +3 -0
  75. package/dist/protocol.js.map +1 -0
  76. package/dist/providers/agents-provider.d.ts +15 -0
  77. package/dist/providers/agents-provider.d.ts.map +1 -0
  78. package/dist/providers/agents-provider.js +393 -0
  79. package/dist/providers/agents-provider.js.map +1 -0
  80. package/dist/providers/captured-tools-provider.d.ts +23 -0
  81. package/dist/providers/captured-tools-provider.d.ts.map +1 -0
  82. package/dist/providers/captured-tools-provider.js +170 -0
  83. package/dist/providers/captured-tools-provider.js.map +1 -0
  84. package/dist/providers/mcp-provider.d.ts +15 -0
  85. package/dist/providers/mcp-provider.d.ts.map +1 -0
  86. package/dist/providers/mcp-provider.js +289 -0
  87. package/dist/providers/mcp-provider.js.map +1 -0
  88. package/dist/providers/mesh-provider.d.ts +13 -0
  89. package/dist/providers/mesh-provider.d.ts.map +1 -0
  90. package/dist/providers/mesh-provider.js +175 -0
  91. package/dist/providers/mesh-provider.js.map +1 -0
  92. package/dist/providers/pi-tools-provider.d.ts +14 -0
  93. package/dist/providers/pi-tools-provider.d.ts.map +1 -0
  94. package/dist/providers/pi-tools-provider.js +200 -0
  95. package/dist/providers/pi-tools-provider.js.map +1 -0
  96. package/dist/runtime/guest-types.d.ts +3 -0
  97. package/dist/runtime/guest-types.d.ts.map +1 -0
  98. package/dist/runtime/guest-types.js +313 -0
  99. package/dist/runtime/guest-types.js.map +1 -0
  100. package/dist/runtime/quickjs-runtime.d.ts +18 -0
  101. package/dist/runtime/quickjs-runtime.d.ts.map +1 -0
  102. package/dist/runtime/quickjs-runtime.js +538 -0
  103. package/dist/runtime/quickjs-runtime.js.map +1 -0
  104. package/dist/runtime/type-checker.d.ts +10 -0
  105. package/dist/runtime/type-checker.d.ts.map +1 -0
  106. package/dist/runtime/type-checker.js +71 -0
  107. package/dist/runtime/type-checker.js.map +1 -0
  108. package/dist/subagents/budget-ledger.d.ts +61 -0
  109. package/dist/subagents/budget-ledger.d.ts.map +1 -0
  110. package/dist/subagents/budget-ledger.js +92 -0
  111. package/dist/subagents/budget-ledger.js.map +1 -0
  112. package/dist/subagents/manager.d.ts +27 -0
  113. package/dist/subagents/manager.d.ts.map +1 -0
  114. package/dist/subagents/manager.js +497 -0
  115. package/dist/subagents/manager.js.map +1 -0
  116. package/dist/subagents/semaphore.d.ts +7 -0
  117. package/dist/subagents/semaphore.d.ts.map +1 -0
  118. package/dist/subagents/semaphore.js +54 -0
  119. package/dist/subagents/semaphore.js.map +1 -0
  120. package/dist/subagents/transports/localterm-transport.d.ts +7 -0
  121. package/dist/subagents/transports/localterm-transport.d.ts.map +1 -0
  122. package/dist/subagents/transports/localterm-transport.js +54 -0
  123. package/dist/subagents/transports/localterm-transport.js.map +1 -0
  124. package/dist/subagents/transports/process-transport.d.ts +7 -0
  125. package/dist/subagents/transports/process-transport.d.ts.map +1 -0
  126. package/dist/subagents/transports/process-transport.js +17 -0
  127. package/dist/subagents/transports/process-transport.js.map +1 -0
  128. package/dist/subagents/transports/process-utils.d.ts +16 -0
  129. package/dist/subagents/transports/process-utils.d.ts.map +1 -0
  130. package/dist/subagents/transports/process-utils.js +57 -0
  131. package/dist/subagents/transports/process-utils.js.map +1 -0
  132. package/dist/subagents/transports/screen-transport.d.ts +7 -0
  133. package/dist/subagents/transports/screen-transport.d.ts.map +1 -0
  134. package/dist/subagents/transports/screen-transport.js +33 -0
  135. package/dist/subagents/transports/screen-transport.js.map +1 -0
  136. package/dist/subagents/transports/tmux-transport.d.ts +7 -0
  137. package/dist/subagents/transports/tmux-transport.d.ts.map +1 -0
  138. package/dist/subagents/transports/tmux-transport.js +41 -0
  139. package/dist/subagents/transports/tmux-transport.js.map +1 -0
  140. package/dist/subagents/types.d.ts +132 -0
  141. package/dist/subagents/types.d.ts.map +1 -0
  142. package/dist/subagents/types.js +2 -0
  143. package/dist/subagents/types.js.map +1 -0
  144. package/dist/subagents/worktree-manager.d.ts +12 -0
  145. package/dist/subagents/worktree-manager.d.ts.map +1 -0
  146. package/dist/subagents/worktree-manager.js +53 -0
  147. package/dist/subagents/worktree-manager.js.map +1 -0
  148. package/dist/ui/controller.d.ts +14 -0
  149. package/dist/ui/controller.d.ts.map +1 -0
  150. package/dist/ui/controller.js +153 -0
  151. package/dist/ui/controller.js.map +1 -0
  152. package/dist/ui/dashboard.d.ts +36 -0
  153. package/dist/ui/dashboard.d.ts.map +1 -0
  154. package/dist/ui/dashboard.js +620 -0
  155. package/dist/ui/dashboard.js.map +1 -0
  156. package/dist/ui/fabric-render.d.ts +28 -0
  157. package/dist/ui/fabric-render.d.ts.map +1 -0
  158. package/dist/ui/fabric-render.js +280 -0
  159. package/dist/ui/fabric-render.js.map +1 -0
  160. package/dist/ui/format.d.ts +7 -0
  161. package/dist/ui/format.d.ts.map +1 -0
  162. package/dist/ui/format.js +57 -0
  163. package/dist/ui/format.js.map +1 -0
  164. package/dist/ui/highlight.d.ts +13 -0
  165. package/dist/ui/highlight.d.ts.map +1 -0
  166. package/dist/ui/highlight.js +337 -0
  167. package/dist/ui/highlight.js.map +1 -0
  168. package/dist/ui/settings.d.ts +21 -0
  169. package/dist/ui/settings.d.ts.map +1 -0
  170. package/dist/ui/settings.js +480 -0
  171. package/dist/ui/settings.js.map +1 -0
  172. package/dist/ui/snapshot.d.ts +5 -0
  173. package/dist/ui/snapshot.d.ts.map +1 -0
  174. package/dist/ui/snapshot.js +120 -0
  175. package/dist/ui/snapshot.js.map +1 -0
  176. package/dist/ui/types.d.ts +57 -0
  177. package/dist/ui/types.d.ts.map +1 -0
  178. package/dist/ui/types.js +11 -0
  179. package/dist/ui/types.js.map +1 -0
  180. package/dist/ui/widget.d.ts +16 -0
  181. package/dist/ui/widget.d.ts.map +1 -0
  182. package/dist/ui/widget.js +199 -0
  183. package/dist/ui/widget.js.map +1 -0
  184. package/dist/util.d.ts +2 -0
  185. package/dist/util.d.ts.map +1 -0
  186. package/dist/util.js +10 -0
  187. package/dist/util.js.map +1 -0
  188. package/dist/worker.d.ts +3 -0
  189. package/dist/worker.d.ts.map +1 -0
  190. package/dist/worker.js +478 -0
  191. package/dist/worker.js.map +1 -0
  192. package/package.json +87 -0
  193. package/skills/fabric-advisor/SKILL.md +53 -0
  194. package/skills/fabric-ambient/SKILL.md +84 -0
  195. package/skills/fabric-council/SKILL.md +37 -0
  196. package/skills/fabric-exec/SKILL.md +39 -0
  197. package/skills/fabric-exec/references/agents.md +78 -0
  198. package/skills/fabric-exec/references/mcp.md +46 -0
  199. package/skills/fabric-exec/references/mesh.md +42 -0
  200. package/skills/fabric-rlm/SKILL.md +84 -0
  201. package/skills/fabric-supervisor/SKILL.md +63 -0
  202. package/skills/fabric-swarm/SKILL.md +85 -0
  203. package/skills/fabric-workflow/SKILL.md +69 -0
@@ -0,0 +1,84 @@
1
+ ---
2
+ name: fabric-ambient
3
+ description: Creates an emergent supervisor or advisor as a persistent Pi Fabric actor. Use when the user asks for ambient supervision, ongoing peer review, an advisor, or a goal watcher without installing a separate extension.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # Fabric Ambient Actors
8
+
9
+ This is the meta-pattern for custom ambient roles. Prefer `/skill:fabric-supervisor` or `/skill:fabric-advisor` when either dedicated pattern matches exactly.
10
+
11
+ Create the requested behavior with `fabric_exec` and `agents.create()`. Do not install or load pi-supervisor, pi-advisor, or another orchestration extension.
12
+
13
+ The first skill argument selects the pattern:
14
+
15
+ - `supervisor <goal>`: watch until the goal is achieved; steer only when work is incomplete or drifting.
16
+ - `advisor [focus]`: peer-review turns and surface only material advice.
17
+
18
+ If the pattern is omitted, infer it from the request. If a supervisor goal is omitted, derive a concrete goal from the current user request. Do not ask for details that are already in the conversation.
19
+
20
+ Pass long instructions through the `strings` parameter and reference them as `π.instructions`. Use one Fabric call shaped like this:
21
+
22
+ ```ts
23
+ await workflow.configure({
24
+ name: `Ambient · ${π.name}`,
25
+ description: "Persistent event-driven actor setup",
26
+ });
27
+ await phase("Start actor", { total: 1 });
28
+ const current = await agents.actors();
29
+ const duplicate = current.find((actor) => actor.name === π.name && actor.status !== "stopped");
30
+ if (duplicate) return { reused: true, actor: duplicate };
31
+
32
+ const actor = await agents.create({
33
+ name: π.name,
34
+ instructions: π.instructions,
35
+ events: ["agent_settled", "tool_error"],
36
+ responseMode: "directive",
37
+ delivery: "steer",
38
+ triggerTurn: true,
39
+ coalesce: true,
40
+ tools: ["read", "grep", "find", "ls"],
41
+ });
42
+ return {
43
+ started: true,
44
+ actor,
45
+ inspect: `/fabric messages ${actor.id.slice(0, 8)}`,
46
+ stop: `/fabric stop ${actor.id.slice(0, 8)}`,
47
+ };
48
+ ```
49
+
50
+ For an advisor, change the event list to `["turn_end"]` and set `triggerTurn: false` so advice does not create an interruption loop.
51
+
52
+ ## Supervisor instructions
53
+
54
+ Build `π.instructions` from the goal and these rules:
55
+
56
+ ```text
57
+ You are an ambient supervisor for this goal:
58
+
59
+ <goal>
60
+ GOAL
61
+ </goal>
62
+
63
+ Review the supplied parent-session event and recent transcript. You are an outside observer, not a second implementer.
64
+
65
+ Return {"action":"silent"} while work is productively advancing and after the goal is verifiably complete. Return {"action":"message","message":"..."} only when the main agent is idle with material work missing, is drifting from the goal, is stuck after a tool error, or needs one concrete next action. Keep messages direct and at most three sentences. Do not repeat a prior steer. Never request credentials or invent user decisions. Once the goal is clearly complete, return {"action":"stop","message":"Goal verified complete."}.
66
+ ```
67
+
68
+ Replace `GOAL` with the actual goal before passing the string.
69
+
70
+ ## Advisor instructions
71
+
72
+ Build `π.instructions` from the optional focus and these rules:
73
+
74
+ ```text
75
+ You are an ambient peer advisor reviewing the main coding agent one turn at a time. Focus on correctness, missed constraints, risky assumptions, and cheaper paths to the user's outcome. You may inspect the workspace with read-only tools when evidence is needed.
76
+
77
+ Prefer silence. Return {"action":"silent"} when the agent is on track. Return {"action":"message","message":"..."} only for a concrete, material observation that could prevent wasted work or a defect. State the evidence and recommendation tersely; frame it as advice to weigh, not an order. Do not repeat advice already present in the recent transcript.
78
+ ```
79
+
80
+ Append the user's requested focus when present.
81
+
82
+ ## After creation
83
+
84
+ Tell the user the actor name, short ID, subscribed events, and the `/fabric messages` and `/fabric stop` commands. Do not wait for the actor: it is session-persistent and event-driven.
@@ -0,0 +1,37 @@
1
+ ---
2
+ name: fabric-council
3
+ description: Runs a bounded multi-perspective Pi Fabric council with independent reviewers and an optional synthesis decision. Use for architecture choices, plans, reviews, and adversarial cross-checking.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # Fabric Council
8
+
9
+ Use one `fabric_exec` call and `council.run()`. Choose roles that disagree usefully rather than duplicating one another.
10
+
11
+ ```ts
12
+ const roles = JSON.parse(π.roles) as string[];
13
+ await workflow.configure({
14
+ name: "Council review",
15
+ description: `${roles.length} independent perspectives with synthesis`,
16
+ });
17
+ await phase("Deliberate", { total: roles.length });
18
+ const decision = await council.run({
19
+ task: π.task,
20
+ roles,
21
+ tools: ["read", "grep", "find", "ls"],
22
+ synthesize: true,
23
+ });
24
+ return decision;
25
+ ```
26
+
27
+ Pass the full task and role array through `strings`. Usually use three to five roles. Examples:
28
+
29
+ - implementation correctness reviewer
30
+ - security and abuse-case reviewer
31
+ - test and operability reviewer
32
+ - simplicity and maintenance reviewer
33
+ - user-requirements skeptic
34
+
35
+ Council members must inspect evidence independently. The synthesizer must preserve material disagreement, reject unsupported claims, and make a concrete recommendation. Use `synthesize: false` only when the user asked for raw independent opinions.
36
+
37
+ Do not use a council for a simple lookup or a decision with no meaningful competing considerations.
@@ -0,0 +1,39 @@
1
+ ---
2
+ name: fabric-exec
3
+ description: >-
4
+ Reference for writing `fabric_exec` TypeScript programs in the QuickJS
5
+ sandbox: the mental model (one program, return only the final value), the
6
+ core `pi` tools (read/bash/edit/write/grep/find/ls) with exact signatures,
7
+ `tools` discovery and introspection, `π` named strings,
8
+ and the validate, describe, retry error loop. Load before your first
9
+ `fabric_exec` call and whenever a call errors on argument shape. For MCP,
10
+ agents/rlm, and mesh, see `references/mcp.md`, `references/agents.md`, `references/mesh.md`.
11
+ ---
12
+
13
+ # fabric_exec — core reference
14
+
15
+ One type-checked TS program in a QuickJS sandbox. Only the `return` value reaches the model; `print()`/`console.log` go to the activity panel. `π` is not a tool.
16
+
17
+ ## `pi` core tools (full code mode only)
18
+ `pi.<tool>(arg)` — single arg: bare string (primary field) or options object; `edit`/`write` need an object. No positional args: `pi.grep(p, path)` → `pi.grep({ pattern: p, path })`.
19
+
20
+ | Tool | Form | Returns |
21
+ |------|------|---------|
22
+ | `read` | `path` \| `{path,offset?,limit?}` | `string` |
23
+ | `bash` | `command` \| `{command,timeout?}` | `{ok,output,details}` |
24
+ | `grep` | `pattern` \| `{pattern,path?,glob?,ignoreCase?,literal?,context?,limit?}` | `string` |
25
+ | `find` | `pattern` \| `{pattern,path?,limit?}` | `string` |
26
+ | `ls` | `path?` \| `{path?,limit?}` | `string` |
27
+ | `edit` | `{path,edits:[{oldText,newText}]}` \| `{path,oldText,newText}` | `{ok,output,details}` |
28
+ | `write` | `{path,content}` | `{ok,output,details}` |
29
+
30
+ Aliases: `cmd`→`command`, `query`→`pattern`, `file`→`path`, `dir`→`path`.
31
+
32
+ ## `tools` — discovery & generic calls
33
+ Refs namespaced: `pi.grep`, `extensions.<tool>`, `mcp.<server>.<tool>`; bare names rejected. `tools.providers()`→`[{name,description}]` · `tools.search({query,limit?})`→`FabricAction[]`(`ref,name,description,inputSchema,risk`) · `tools.describe({ref})`→full `FabricAction` (read `inputSchema` first) · `tools.call({ref,args?})` · `tools.list({provider?,namespace?,query?,limit?})` · `extensions.<tool>(args)` (full code mode only).
34
+
35
+ ## Error recovery: read, describe, retry
36
+ Read the line-numbered error → `await tools.describe({ref})` for the schema → match `inputSchema`, rerun (don't guess). Common mistakes: two positional args; bare ref (`grep`→`pi.grep`).
37
+
38
+ ## Other surfaces
39
+ `references/mcp.md` (mcp.*) · `references/agents.md` (agents/actors/rlm) · `references/mesh.md` (topics/cas state). Workflow/councils → `/skill:fabric-workflow`, `/skill:fabric-council`.
@@ -0,0 +1,78 @@
1
+ # Agents and rlm reference
2
+
3
+ `fabric_exec` can spawn one-shot child agents, create persistent event-driven actors, and run recursive queries. For the sandbox model and `tools` discovery, see the parent `fabric-exec` skill; for actor coordination across sessions, see `mesh.md`.
4
+
5
+ Every method takes a single options object.
6
+
7
+ ## One-shot child agents
8
+
9
+ - `agents.run(args)` runs to completion and returns `FabricAgentResult` with `{ id, status, text, value?, error?, usage, turns, toolCalls }`.
10
+ - `agents.spawn(args)` returns a background `FabricAgentHandle` with an `id`. Then use `agents.wait({ id })`, `agents.status({ id })`, `agents.stop({ id })`.
11
+ - `agents.list()` returns all children.
12
+ - `agents.cleanup({ id, deleteBranch? })` returns `{ cleaned }` and removes a worktree branch.
13
+
14
+ `args` is a `FabricAgentRequest`: `{ task, name?, transport?, model?, thinking?, tools?, timeoutMs?, extensions?, recursive?, worktree?, schema? }`.
15
+
16
+ - `transport` is one of `auto`, `process`, `tmux`, `screen`, `localterm` (default `process`). `auto` tries LocalTerm, tmux, screen, then process.
17
+ - `tools` defaults to `subagents.defaultTools`. Children inherit the parent model unless `model` is set.
18
+ - `schema` is a JSON Schema; the worker returns validated structured data in `result.value`.
19
+ - `worktree: true` creates a dedicated Git worktree on branch `pi-fabric/<name>-<id>`, retained until `agents.cleanup()`.
20
+
21
+ ```ts
22
+ const result = await agents.run({
23
+ name: "security-review",
24
+ task: "Review the current diff for concrete security defects. Do not edit files.",
25
+ tools: ["read", "grep", "find", "ls"],
26
+ });
27
+ return result;
28
+ ```
29
+
30
+ ```ts
31
+ const handle = await agents.spawn({ task: "Map the persistence layer.", transport: "tmux" });
32
+ // independent work here
33
+ return await agents.wait({ id: handle.id });
34
+ ```
35
+
36
+ Use `/fabric agents` to list children and `/fabric attach <id>` for the attach command. Abort signals propagate to the transport and child Pi process.
37
+
38
+ ## Persistent actors
39
+
40
+ `agents.create(args)` returns `FabricActorInfo`. An actor has its own Pi session, a serial mailbox, and optional subscriptions to parent events or durable mesh topics. It processes messages one at a time, coalesces repeated host events by default, and resumes when the same Pi session reopens in a trusted project.
41
+
42
+ `args` is a `FabricActorRequest`: `{ name, instructions, events?, topics?, delivery?, responseMode?, triggerTurn?, coalesce?, model?, thinking?, tools?, transport?, timeoutMs? }`.
43
+
44
+ - `events` is a subset of `input`, `turn_end`, `agent_settled`, `tool_error`, `session_compact` (host events to subscribe to).
45
+ - `topics` lists durable mesh topics to subscribe to (see `mesh.md`).
46
+ - `responseMode` is `text` (every non-empty response becomes an outbox message) or `directive` (validated `{ action, message?, data? }` where `action` is `silent`, `message`, or `stop`; the actor decides whether to intervene).
47
+ - `delivery` is `mailbox`, `steer`, `followUp`, or `nextTurn`; fixed at creation, an actor cannot escalate it.
48
+ - `triggerTurn` fires on the first event of a coalesced burst; `coalesce` is on by default.
49
+
50
+ ```ts
51
+ return agents.create({
52
+ name: "auth-supervisor",
53
+ instructions: "Watch the main session until the auth migration is complete and tested. Prefer silence; reply with a directive only for material drift, a blocker, or verified completion.",
54
+ events: ["agent_settled", "tool_error"],
55
+ responseMode: "directive",
56
+ delivery: "steer",
57
+ triggerTurn: true,
58
+ tools: ["read", "grep", "find", "ls"],
59
+ });
60
+ ```
61
+
62
+ Mailbox:
63
+
64
+ - `agents.ask({ id, message, data? })` returns a `FabricActorMessage` (blocking exchange).
65
+ - `agents.tell({ id, message, data? })` returns `{ queued, messageId }` (fire and forget).
66
+ - `agents.actorStatus({ id })` and `agents.actors()` return actor info.
67
+ - `agents.messages({ id, limit? })` returns message history.
68
+ - `agents.remove({ id })` returns `{ removed }`.
69
+
70
+ ## Recursive queries
71
+
72
+ `rlm.query(args)` is `agents.run({ ...args, recursive: true })` with Fabric enabled in the child. Recursion is rejected at `subagents.maxDepth`. Approving the initial recursive call delegates only the `agent` risk capability to recursive children; network, execution, and write approvals are not inherited. Each Fabric process enforces its own concurrency and timeout limits.
73
+
74
+ ```ts
75
+ return rlm.query({ task: "Decompose this repository and produce a compact architecture map.", transport: "process" });
76
+ ```
77
+
78
+ `council.run({ task, roles, synthesize?, ...agentOptions })` runs several `agents.run` calls concurrently under the subagent semaphore and optionally synthesizes them; load `/skill:fabric-council` for the pattern.
@@ -0,0 +1,46 @@
1
+ # MCP surface reference
2
+
3
+ MCP tools are available inside `fabric_exec` through the `mcp` surface, backed by the public `mcporter` runtime (config discovery, imports, OAuth cache, connection pooling). For the sandbox model and `tools` discovery, see the parent `fabric-exec` skill.
4
+
5
+ ## Call a tool
6
+
7
+ `mcp.<server>.<tool>(args)` takes a single options object matching the tool input schema. The server and tool names are whatever mcporter loaded.
8
+
9
+ ```ts
10
+ const result = await mcp.context7.resolve_library_id({ libraryName: "react", query: "hooks" });
11
+ return result;
12
+ ```
13
+
14
+ ## Server management
15
+
16
+ - `mcp.servers()` returns server metadata `{ name, description, transport }` (description may be null; transport is "http" or "stdio"). Credentials are never exposed.
17
+ - `mcp.reload()` returns `{ servers }`. Call it after changing mcporter configuration.
18
+ - `mcp.register({ name, description?, command?, args?, cwd?, baseUrl?, headers?, env?, overwrite? })` returns `{ registered }`. Register an ephemeral server in the pooled runtime after host approval. HTTP servers use `baseUrl` instead of `command`. Dynamic definitions live until `mcp.reload()` or session shutdown; they are not written to config.
19
+
20
+ ```ts
21
+ await mcp.register({ name: "project-docs", command: "npx", args: ["-y", "@example/docs-mcp"], cwd: "." });
22
+ return mcp.project_docs.search({ query: "authentication" });
23
+ ```
24
+
25
+ ## Generic call
26
+
27
+ `mcp.call({ server, tool, args? })` is for when a server or tool name cannot be expressed as property access.
28
+
29
+ ```ts
30
+ return mcp.call({ server: "my-server", tool: "weird-tool-name", args: { q: "x" } });
31
+ ```
32
+
33
+ ## Introspect an uncertain tool
34
+
35
+ MCP tools are discoverable through the generic `tools` surface; refs are `mcp.<server>.<tool>`.
36
+
37
+ ```ts
38
+ const schema = await tools.describe({ ref: "mcp.context7.resolve_library_id" });
39
+ // schema.inputSchema is the tool JSON Schema
40
+ ```
41
+
42
+ ## Notes
43
+
44
+ - When `mcp.disableOAuth` is configured, calls may use cached credentials but cannot launch a new interactive OAuth flow.
45
+ - Call timeout is bounded by `mcp.callTimeoutMs`.
46
+ - Set `mcp.enabled: false` to disable the MCP surface.
@@ -0,0 +1,42 @@
1
+ # Durable coordination reference
2
+
3
+ `mesh` is a project-scoped, event-sourced coordination substrate. With persistent actors (see `agents.md`) it is sufficient to express messenger-style swarms without a daemon or fixed planner/worker roles. For the sandbox model, see the parent `fabric-exec` skill.
4
+
5
+ Every method takes a single options object. Mesh data defaults to `<project>/.pi/fabric/mesh`; relocate it with `mesh.root` in config, and add `.pi/fabric/mesh/` to your ignore file unless you intentionally version the coordination log.
6
+
7
+ ## Identity and presence
8
+
9
+ - `mesh.self()` returns `{ id, name, kind, sessionId? }` where `kind` is `main`, `actor`, or `agent`.
10
+ - `mesh.members({ limit? })` returns actor presence across live Fabric sessions as entries with `{ key, value, version, updatedAt, updatedBy }` (the `value` is a `FabricActorInfo`).
11
+
12
+ ## Topics (durable channels)
13
+
14
+ - `mesh.publish({ topic, kind?, to?, text?, data? })` returns a `FabricMeshEvent`. Use `to` for a direct message.
15
+ - `mesh.read({ after?, topic?, to?, limit? })` returns `FabricMeshEvent[]` by cursor, topic, or recipient. Each event has `{ id, sequence, topic, kind, from, to?, text?, data?, createdAt }`.
16
+
17
+ Topics provide durable channel and direct-message semantics with sequence cursors.
18
+
19
+ ```ts
20
+ await mesh.publish({ topic: "team.auth", kind: "finding", text: "Refresh-token rotation is not atomic", data: { path: "src/auth/refresh.ts" } });
21
+ const events = await mesh.read({ topic: "team.auth", limit: 50 });
22
+ ```
23
+
24
+ ## Shared state (compare-and-swap)
25
+
26
+ - `mesh.get({ key })` returns a `FabricMeshStateEntry` or null.
27
+ - `mesh.put({ key, value, ifVersion? })` creates or updates; `ifVersion` enables optimistic compare-and-swap.
28
+ - `mesh.delete({ key, ifVersion? })` returns `{ deleted, version? }`.
29
+ - `mesh.list({ prefix?, limit? })` returns matching entries.
30
+
31
+ Each entry is `{ key, value, version, updatedAt, updatedBy }`. Use `ifVersion` for task claims, leases, reservations, and decisions: create with `ifVersion: 0`, claim by passing the current `version`.
32
+
33
+ ```ts
34
+ const task = await mesh.put({ key: "tasks/auth-review", value: { status: "ready", owner: null }, ifVersion: 0 });
35
+ const claimed = await mesh.put({ key: task.key, value: { status: "claimed", owner: "security-reviewer" }, ifVersion: task.version });
36
+ return claimed;
37
+ ```
38
+
39
+ ## Notes
40
+
41
+ - Actors subscribe to topics via `agents.create({ topics: [...] })` (see `agents.md`); published events are delivered as `mesh:<topic>` messages.
42
+ - Set `mesh.enabled: false` in config to disable both mesh actions and ambient actor restoration.
@@ -0,0 +1,84 @@
1
+ ---
2
+ name: fabric-rlm
3
+ description: Recursively decomposes a large task by delegating bounded subtasks to child Pi agents via rlm.query(), where each child gets a fresh context window and can itself recurse. Use for tasks too big for one context window — whole-repo audits, massive-context analysis, multi-file refactors.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # Fabric Recursive Decomposition (RLM)
8
+
9
+ Inspired by Recursive Language Models: an LLM with a sub-call function can recursively decompose problems by self-delegation. `rlm.query()` is `agents.run()` with `recursive: true` — it spawns a child Pi agent with a fresh context window that can call `rlm.query()` again, bounded by `subagents.maxDepth`.
10
+
11
+ Recurse not because a task is hard, but because it is too big for one context window. Each child gets a fresh context budget; you get back only its compact answer instead of all the raw material.
12
+
13
+ ## Core pattern: size up → search → delegate → combine
14
+
15
+ 1. **Size up** — `wc -l`, `wc -c`, file counts, grep scope. If it fits one context window, do it directly; do not delegate.
16
+ 2. **Search** — `grep`, `find`, `ls`, `read` to orient before delegating.
17
+ 3. **Delegate** — hand clear, bounded subtasks to children. Use `rlm.query()` when the child should be able to recurse again; use `agent()` for a one-shot leaf worker that does not need to recurse.
18
+ 4. **Combine** — aggregate, deduplicate, resolve conflicts, produce the final output.
19
+ 5. **Do it directly when it's small** — never delegate what you can do in one step.
20
+
21
+ ## One fabric_exec program
22
+
23
+ Turn the request into a single type-checked `fabric_exec` program. The program holds the decomposition loop and branches. Pass the root task through `strings.task`.
24
+
25
+ ```ts
26
+ await workflow.configure({
27
+ name: "Recursive decomposition",
28
+ description: "Size up, delegate bounded subtasks, combine",
29
+ });
30
+
31
+ // Size up and orient with read-only tools before delegating.
32
+ await phase("Orient", { total: 1 });
33
+ const scope = await agent<{ paths: string[] }>(
34
+ `Identify the bounded set of files relevant to this task. Return structured output.\n\nTask:\n${π.task}`,
35
+ {
36
+ label: "scope",
37
+ tools: ["read", "grep", "find", "ls"],
38
+ schema: {
39
+ type: "object",
40
+ properties: { paths: { type: "array", items: { type: "string" } } },
41
+ required: ["paths"],
42
+ additionalProperties: false,
43
+ },
44
+ },
45
+ );
46
+
47
+ // Delegate each bounded subtask to a recursive child. Each child gets a fresh
48
+ // context window and may call rlm.query() again up to subagents.maxDepth.
49
+ await phase("Decompose", { total: scope.paths.length });
50
+ const findings = await parallel(
51
+ scope.paths.map((p) => () =>
52
+ rlm.query({
53
+ task: `Analyze ${p} for this objective and report concrete, bounded findings.\n\nObjective:\n${π.task}`,
54
+ name: `analyze ${p}`.slice(0, 50),
55
+ tools: ["read", "grep", "find", "ls"],
56
+ }),
57
+ ),
58
+ { concurrency: 4 },
59
+ );
60
+
61
+ await phase("Combine", { total: 1 });
62
+ const summary = await agent(
63
+ `Synthesize these independent findings into one compact result. Drop unsupported claims and resolve conflicts:\n${JSON.stringify(findings)}`,
64
+ { label: "combine", tools: ["read", "grep", "find", "ls"] },
65
+ );
66
+ return summary;
67
+ ```
68
+
69
+ Adapt the phases, tools, and fan-out to the request. Use `schema` on a worker when machine-readable output makes aggregation safer.
70
+
71
+ ## When to recurse vs do it directly
72
+
73
+ - A 30-line file or a single function: read it and act directly. No delegation.
74
+ - A multi-file refactor: delegate per file or per module and combine.
75
+ - A whole-repo audit or massive-context analysis: size up first, fan out bounded subtasks, then synthesize.
76
+
77
+ ## Guardrails
78
+
79
+ - `subagents.maxDepth` bounds recursion depth; `subagents.budgetUsd` optionally bounds total USD spend across the whole tree (0 disables it).
80
+ - When a budget is active, each recursive result carries a `budget` summary (`limit`, `spent`, `remaining`, `tokens`). Stop spawning children when `remaining` is low and finish the remaining work directly.
81
+ - Approving the initial recursive call delegates only the `agent` risk capability to children; network, execution, and write approvals are not inherited. Give children edit tools only when they must change files.
82
+ - Deeper children should be more conservative: fewer sub-calls, more direct action. Teach the pattern once — size-first → search → chunk → delegate → combine — and let it repeat at every depth.
83
+ - For edits, partition ownership by path or set `worktree: true`; never let concurrent recursive children edit the same files.
84
+ - The pre-spawn budget check is best-effort (concurrent children can overshoot slightly); the race-free ceiling is `subagents.maxPerExecution`.
@@ -0,0 +1,63 @@
1
+ ---
2
+ name: fabric-supervisor
3
+ description: Starts a persistent, event-driven Pi Fabric supervisor that watches the main session toward a concrete goal and steers only when needed. Use for long-running goal supervision without another extension.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # Fabric Supervisor
8
+
9
+ Start an emergent supervisor using `fabric_exec`; never install or invoke an external supervisor extension.
10
+
11
+ Derive the goal from the skill arguments. If arguments are empty, use the active user request and conversation. Make the goal concrete and measurable without asking for information already present.
12
+
13
+ Call `fabric_exec` once. Put the completed supervisor prompt in `strings.instructions` and the stable name `supervisor` in `strings.name`, then execute:
14
+
15
+ ```ts
16
+ await workflow.configure({
17
+ name: `Supervisor · ${π.name}`,
18
+ description: "Persistent ambient goal supervision",
19
+ });
20
+ await phase("Start actor", { total: 1 });
21
+ const current = await agents.actors();
22
+ const existing = current.find((actor) => actor.name === π.name && actor.status !== "stopped");
23
+ if (existing) return { reused: true, actor: existing };
24
+
25
+ const actor = await agents.create({
26
+ name: π.name,
27
+ instructions: π.instructions,
28
+ events: ["agent_settled", "tool_error"],
29
+ responseMode: "directive",
30
+ delivery: "steer",
31
+ triggerTurn: true,
32
+ coalesce: true,
33
+ tools: ["read", "grep", "find", "ls"],
34
+ });
35
+ return {
36
+ started: true,
37
+ actor,
38
+ inspect: `/fabric messages ${actor.id.slice(0, 8)}`,
39
+ stop: `/fabric stop ${actor.id.slice(0, 8)}`,
40
+ };
41
+ ```
42
+
43
+ Use this prompt, replacing `GOAL`:
44
+
45
+ ```text
46
+ You are an ambient supervisor for this goal:
47
+
48
+ <goal>
49
+ GOAL
50
+ </goal>
51
+
52
+ Review each supplied parent-session event and recent transcript as an outside observer, not a second implementer.
53
+
54
+ Return {"action":"silent"} while work is productively advancing. Return {"action":"message","message":"..."} only when the main agent is idle with material work missing, is drifting from the goal, is stuck after a tool error, or needs one concrete next action. Keep a steer direct and at most three sentences. Do not repeat prior guidance. Never request credentials or invent a decision only the user can make.
55
+
56
+ The goal is complete only when the requested result and its relevant validation are evident in the transcript. At that point return {"action":"stop","message":"Goal verified complete."}.
57
+ ```
58
+
59
+ ## Heuristic: steer on good signals, not every turn
60
+
61
+ The supervisor subscribes to `agent_settled` and `tool_error`, not `turn_end` or `input`. It runs at decision points (idle and on failures) and stays silent while work is productively advancing, so it does not invoke a model review on every turn. Intervene only on a concrete, high-confidence signal: material work missing at idle, drift from the goal, a stuck state after a tool error, or verified completion.
62
+
63
+ After creation, report the goal, actor short ID, and inspect/stop commands. Do not wait for it; host events drive it across later turns.
@@ -0,0 +1,85 @@
1
+ ---
2
+ name: fabric-swarm
3
+ description: Creates a self-organizing team of persistent Pi Fabric actors with durable topics, direct mailboxes, and compare-and-swap shared tasks. Use for messenger-like multi-agent collaboration and long-lived delegated work.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # Fabric Swarm
8
+
9
+ Build the team from Pi Fabric primitives; do not install or invoke pi-messenger or another swarm extension.
10
+
11
+ Use:
12
+
13
+ - `agents.create()` for persistent identities and mailbox processors.
14
+ - `agents.tell()` for asynchronous direct delegation.
15
+ - `agents.ask()` only when the coordinator truly must block for a response.
16
+ - `mesh.publish()` for durable channel-like events.
17
+ - `mesh.read()` for feed history and cursors.
18
+ - `mesh.members()` for project-wide actor presence.
19
+ - `mesh.put(..., ifVersion)` for atomic task claims, leases, and shared decisions.
20
+
21
+ Choose a short run key and topic, such as `team.auth-migration`. Seed task records under `runs/<run-key>/tasks/<task-id>` with `ifVersion: 0`. Each value should include `title`, `status`, `owner`, `dependencies`, `progress`, and `result`.
22
+
23
+ Create role-shaped actors subscribed to the team topic. Their instructions must require:
24
+
25
+ 1. Read the assigned task from mesh state.
26
+ 2. Claim it with compare-and-swap using the observed version; do not work after a failed claim.
27
+ 3. Publish progress to the team topic.
28
+ 4. Update the task with compare-and-swap when blocked or complete.
29
+ 5. Address questions with `mesh.publish({ topic, to, ... })`.
30
+ 6. Avoid files owned by another task or actor.
31
+ 7. Return a directive message only for a blocker or final result; otherwise stay silent.
32
+
33
+ Example coordinator skeleton:
34
+
35
+ ```ts
36
+ const run = π.run;
37
+ const topic = `team.${run}`;
38
+ await workflow.configure({
39
+ name: `Swarm · ${run}`,
40
+ description: "Persistent actors coordinating through durable shared tasks",
41
+ });
42
+
43
+ const tasks = JSON.parse(π.tasks) as Array<{ id: string; title: string; detail: string }>;
44
+ await phase("Seed tasks", { total: tasks.length });
45
+ for (const task of tasks of JSON.parse(π.tasks) as Array<{ id: string; title: string; detail: string }>) {
46
+ await mesh.put({
47
+ key: `runs/${run}/tasks/${task.id}`,
48
+ value: { ...task, status: "ready", owner: null, progress: [], result: null },
49
+ ifVersion: 0,
50
+ });
51
+ }
52
+
53
+ await phase("Create actors", { total: (JSON.parse(π.roles) as unknown[]).length });
54
+ const actors = await Promise.all(
55
+ (JSON.parse(π.roles) as Array<{ name: string; instructions: string }>).map((role) =>
56
+ agents.create({
57
+ name: role.name,
58
+ instructions: role.instructions,
59
+ topics: [topic],
60
+ responseMode: "directive",
61
+ delivery: "mailbox",
62
+ coalesce: false,
63
+ }),
64
+ ),
65
+ );
66
+
67
+ await phase("Dispatch", { total: actors.length });
68
+ for (const actor of actors) {
69
+ await agents.tell({
70
+ id: actor.id,
71
+ message: `Join ${topic}. Inspect ready tasks under runs/${run}/tasks/ and atomically claim one matching your role.`,
72
+ });
73
+ }
74
+
75
+ await mesh.publish({
76
+ topic,
77
+ kind: "run.started",
78
+ data: { run, actors: actors.map(({ id, name }) => ({ id, name })) },
79
+ });
80
+
81
+ await workflow.event({ message: `${actors.length} actors dispatched`, level: "success" });
82
+ return { run, topic, actors, taskPrefix: `runs/${run}/tasks/` };
83
+ ```
84
+
85
+ Pass generated role instructions and tasks through `strings`, not large inline literals. Keep the coordinator pull-based: inspect `mesh.read({ topic })`, task state, and actor mailboxes at decision points rather than continuously polling in one Fabric execution.
@@ -0,0 +1,69 @@
1
+ ---
2
+ name: fabric-workflow
3
+ description: Runs a Claude Code-style dynamic workflow in Pi Fabric using code-held phases, fan-out, pipelines, structured agents, and synthesis. Use for large audits, migrations, parallel research, or explicit workflow requests.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # Fabric Dynamic Workflow
8
+
9
+ Turn the request into one type-checked `fabric_exec` program. The program, not the parent context, must hold the loop and branches.
10
+
11
+ Use these globals:
12
+
13
+ - `workflow.agent(prompt, options)` or `agent(...)` for one worker. Set `label` on every call.
14
+ - `workflow.parallel(thunks, { concurrency })` or `parallel(...)` for fan-out. Pass functions, not promises.
15
+ - `workflow.pipeline(items, ...stages)` or `pipeline(...)` for per-item sequential stages with cross-item concurrency.
16
+ - `workflow.configure({ name, description })` to name the general-purpose Fabric dashboard.
17
+ - `workflow.phase(name, { id?, description?, total? })` or `phase(...)` for progress groups.
18
+ - `workflow.item(...)` for non-agent work items whose status changes over time.
19
+ - `workflow.event(...)` for notable milestones in the dashboard feed.
20
+ - `workflow.log(...)` for compact progress notes.
21
+ - `workflow.budget` for token-budget observations.
22
+
23
+ Use `schema` in agent options when machine-readable output will make aggregation safer. It is ordinary JSON Schema.
24
+
25
+ A good shape is:
26
+
27
+ ```ts
28
+ await workflow.configure({
29
+ name: "Request analysis",
30
+ description: "Discover, analyze, and adversarially verify bounded work items",
31
+ });
32
+
33
+ await phase("Discover", { total: 1 });
34
+ const inventory = await agent<{ items: string[] }>(
35
+ "Discover the bounded work items for this request. Return structured output.",
36
+ {
37
+ label: "inventory",
38
+ tools: ["read", "grep", "find", "ls"],
39
+ schema: {
40
+ type: "object",
41
+ properties: { items: { type: "array", items: { type: "string" } } },
42
+ required: ["items"],
43
+ additionalProperties: false,
44
+ },
45
+ },
46
+ );
47
+
48
+ await phase("Analyze", { total: inventory.items.length });
49
+ const findings = await parallel(
50
+ inventory.items.map((item) => () =>
51
+ agent(`Analyze this bounded item and report evidence: ${item}`, {
52
+ label: `analyze ${item}`.slice(0, 50),
53
+ tools: ["read", "grep", "find", "ls"],
54
+ }),
55
+ ),
56
+ { concurrency: 8 },
57
+ );
58
+
59
+ await phase("Verify", { total: 1 });
60
+ const result = await agent(
61
+ `Adversarially verify and synthesize these findings. Remove unsupported claims:\n${JSON.stringify(findings)}`,
62
+ { label: "verify synthesis", tools: ["read", "grep", "find", "ls"] },
63
+ );
64
+
65
+ await workflow.event({ message: "Verification complete", level: "success" });
66
+ return { ok: true, result };
67
+ ```
68
+
69
+ Adapt the phases and worker tools to the request. For edits, partition ownership by path or use `worktree: true`; never have concurrent agents edit the same files. Include a final verifier or synthesizer when conclusions come from multiple workers. Set `agentBudget` and `tokenBudget` on `fabric_exec` when the requested scale is potentially large.