pi-fabric 0.21.2 → 0.21.4

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 (42) hide show
  1. package/README.md +56 -681
  2. package/dist/activity/store.d.ts.map +1 -1
  3. package/dist/activity/store.js +3 -0
  4. package/dist/activity/store.js.map +1 -1
  5. package/dist/activity/types.d.ts +2 -0
  6. package/dist/activity/types.d.ts.map +1 -1
  7. package/dist/audit/projection.d.ts.map +1 -1
  8. package/dist/audit/projection.js +1 -9
  9. package/dist/audit/projection.js.map +1 -1
  10. package/dist/audit/trace.d.ts.map +1 -1
  11. package/dist/audit/trace.js.map +1 -1
  12. package/dist/core/action-registry.d.ts.map +1 -1
  13. package/dist/core/action-registry.js +7 -3
  14. package/dist/core/action-registry.js.map +1 -1
  15. package/dist/core/call-preview.d.ts.map +1 -1
  16. package/dist/core/call-preview.js +1 -0
  17. package/dist/core/call-preview.js.map +1 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +60 -8
  20. package/dist/index.js.map +1 -1
  21. package/dist/ui/dashboard.d.ts +2 -0
  22. package/dist/ui/dashboard.d.ts.map +1 -1
  23. package/dist/ui/dashboard.js +272 -74
  24. package/dist/ui/dashboard.js.map +1 -1
  25. package/dist/ui/fabric-render.d.ts +27 -1
  26. package/dist/ui/fabric-render.d.ts.map +1 -1
  27. package/dist/ui/fabric-render.js +217 -1
  28. package/dist/ui/fabric-render.js.map +1 -1
  29. package/dist/ui/snapshot.d.ts.map +1 -1
  30. package/dist/ui/snapshot.js +1 -0
  31. package/dist/ui/snapshot.js.map +1 -1
  32. package/dist/ui/structured.d.ts +2 -0
  33. package/dist/ui/structured.d.ts.map +1 -0
  34. package/dist/ui/structured.js +17 -0
  35. package/dist/ui/structured.js.map +1 -0
  36. package/dist/ui/types.d.ts +1 -0
  37. package/dist/ui/types.d.ts.map +1 -1
  38. package/dist/ui/types.js.map +1 -1
  39. package/dist/ui/widget.d.ts.map +1 -1
  40. package/dist/ui/widget.js +62 -14
  41. package/dist/ui/widget.js.map +1 -1
  42. package/package.json +3 -2
package/README.md CHANGED
@@ -19,733 +19,108 @@ _One type-checked program for tools, MCP, agents, workflows, actors, mesh, counc
19
19
 
20
20
  ---
21
21
 
22
- Pi Fabric turns tool use into code. The model sees one `fabric_exec` tool and writes type-checked TypeScript that can compose Pi's core tools, lazily captured extension tools, MCP servers, child agents, persistent actors, and durable coordination. Intermediate values stay inside a QuickJS sandbox; only the final result returns to the model context.
22
+ You keep talking to Pi the way you always do. Fabric gives the model **one programmable tool** — `fabric_exec` that it uses to compose Pi's core tools, MCP servers, captured extension tools, child agents, persistent actors, and durable coordination into a single type-checked TypeScript program. The program runs in a QuickJS sandbox; only the final result comes back to the conversation. Branching, loops, fan-out, and data flow become code the model writes and type-checks — not a stack of separate tool calls you have to orchestrate.
23
23
 
24
24
  ## Why Fabric?
25
25
 
26
26
  | | Capability | What it unlocks |
27
27
  | :-: | ---------- | --------------- |
28
28
  | ⚡ | **Code mode** | One flat tool schema; branching, loops, fan-out, and data flow live in checked TypeScript. |
29
- | 🧰 | **Capability routing** | Call Pi core tools, captured extension tools, MCP servers, or explicit Fabric providers through one runtime. |
30
- | 🧑‍🤝‍🧑 | **Agent runtime** | Run one-shot workers, persistent event-driven actors, councils, and bounded recursive queries. |
31
- | 🕸️ | **Workflows + mesh** | Track phases and progress while coordinating durable topics, shared tasks, and compare-and-swap state. |
32
- | 🛡️ | **Guardrails** | Enforce approvals, isolation, timeouts, concurrency, recursion depth, and shared cost budgets at the host bridge. |
33
- | 🎛️ | **Native TUI** | See structured nested previews, live activity, an interactive dashboard, and settings without leaving Pi. |
29
+ | 🧰 | **Capability routing** | Call Pi core tools, MCP servers, captured extension tools, or Fabric providers through one runtime. |
30
+ | 🧑‍🤝‍🧑 | **Agent runtime** | One-shot workers, persistent event-driven actors, councils, and bounded recursive queries. |
31
+ | 🕸️ | **Workflows + mesh** | Phased progress plus durable topics, shared tasks, and compare-and-swap state. |
32
+ | 🛡️ | **Guardrails** | Approvals, isolation, timeouts, concurrency, recursion depth, and shared cost budgets. |
33
+ | 🎛️ | **Native TUI** | Live activity, an interactive dashboard, and settings without leaving Pi. |
34
34
 
35
- ## Install
36
-
37
- From npm:
35
+ ## How it works
38
36
 
39
- ```bash
40
- pi install npm:pi-fabric
41
- ```
42
-
43
- From GitHub:
44
-
45
- ```bash
46
- pi install git:github.com/monotykamary/pi-fabric
47
- ```
48
-
49
- From a local checkout:
50
-
51
- ```bash
52
- pnpm install
53
- pnpm build
54
- pi install /absolute/path/to/pi-fabric
55
- ```
56
-
57
- For one development run:
58
-
59
- ```bash
60
- pi -e /absolute/path/to/pi-fabric
61
- ```
37
+ 1. **You ask** in plain language, as usual.
38
+ 2. **Pi writes one program** that calls the tools, agents, and MCP servers it needs. The program is type-checked before it runs.
39
+ 3. **Only the result returns** to your conversation. Intermediate work stays in the sandbox and surfaces in the activity panel and dashboard.
62
40
 
63
- Requires Node.js 24 or newer and Pi 0.80.6 or newer.
64
-
65
- ## Quick start
66
-
67
- Ask Fabric to compose multiple operations in one call:
41
+ Under the hood, the model writes something like this — you don't:
68
42
 
69
43
  ```ts
70
44
  const [manifest, sources] = await Promise.all([
71
45
  pi.read({ path: "package.json" }),
72
46
  pi.find({ pattern: "**/*.ts", path: "src" }),
73
47
  ]);
74
-
75
48
  return {
76
49
  package: JSON.parse(manifest).name,
77
50
  sourceCount: sources.split("\n").filter(Boolean).length,
78
51
  };
79
52
  ```
80
53
 
81
- Only the returned value enters the parent model's context. Everything else stays inside the execution.
82
-
83
- ## Code API
84
-
85
- With the default full code mode, `fabric_exec` exclusively owns Pi core tool execution. The parent model sees one programmable tool instead of direct `read`, `bash`, `edit`, `write`, `grep`, `find`, and `ls` schemas. Fabric programs use those capabilities through `pi.*`:
86
-
87
- ```ts
88
- const files = await pi.find({ pattern: "**/*.ts", path: "src" });
89
- const matches = await pi.grep({ pattern: "TODO", path: "src" });
90
- return { files, matches };
91
- ```
92
-
93
- Independent calls should be parallel:
94
-
95
- ```ts
96
- const [packageJson, readme] = await Promise.all([
97
- pi.read({ path: "package.json" }),
98
- pi.read({ path: "README.md" }),
99
- ]);
100
- return {
101
- package: JSON.parse(packageJson).name,
102
- readmeLines: readme.split("\n").length,
103
- };
104
- ```
105
-
106
- ### Full code mode
107
-
108
- `fullCodeMode: true` is the default. Fabric removes active Pi core tools from the parent model and exposes their implementations only inside `fabric_exec` through `pi.*`. Registered overrides such as security gates and code previews are captured too, so `pi.read()` continues to route through the override rather than bypassing it.
109
-
110
- Fabric remembers which native core tools were active before taking ownership. Switching to orchestration-only mode or unloading Fabric restores that selection. Full-mode ownership is reasserted before user input and agent startup, so tools manually re-enabled during the session do not leak back into the parent schema.
111
-
112
- ### Orchestration-only mode
113
-
114
- Users who want Fabric for MCP, agents, ambient actors, parallel workflows, councils, and recursive delegation—but want Pi's core tools to remain entirely native—can opt out of full code mode:
115
-
116
- ```json
117
- {
118
- "fullCodeMode": false
119
- }
120
- ```
121
-
122
- In orchestration-only mode:
123
-
124
- - Pi's `read`, `bash`, `edit`, `write`, `grep`, `find`, and `ls` tools stay on Pi's normal model-facing and execution paths.
125
- - Registered extension tools also remain in Pi's native registry; Fabric does not hide, wrap, or expose them through `extensions.*`.
126
- - `pi.*`, `extensions.*`, and equivalent `tools.call()` references are unavailable inside `fabric_exec`, including when TypeScript checks are bypassed.
127
- - MCP providers, one-shot and recursive agents, persistent ambient actors, dynamic workflows, mesh coordination, councils, explicit Fabric providers, and the Fabric TUI remain available.
128
- - Child agents continue using their allowed Pi tools directly, so parallel and ambient setups do not route their coding operations back through Fabric code mode.
129
-
130
- The default is `true`. A project can set the flag in `.pi/fabric.json`, or a user can set it globally in `~/.pi/agent/fabric.json`.
131
-
132
- ### Discovery and generic calls
133
-
134
- ```ts
135
- const providers = await tools.providers();
136
- const candidates = await tools.search({ query: "GitHub issues" });
137
- const schema = await tools.describe({ ref: candidates[0].ref });
138
- const result = await tools.call({
139
- ref: schema.ref,
140
- args: { query: "is:open label:bug" },
141
- });
142
- return result;
143
- ```
144
-
145
- ### Captured extension tools
146
-
147
- When `fullCodeMode` is enabled, Fabric intercepts Pi's `ExtensionRunner.getAllRegisteredTools()` registry chokepoint. This captures tools registered by other extensions at startup or later through `pi.registerTool()`, regardless of whether those extensions load before or after Fabric.
148
-
149
- Captured custom tools are removed from Pi's model-facing registry by default, so their schemas, snippets, and guidelines do not consume the parent model context. The extension itself remains loaded: its commands, event handlers, state, and UI continue to work. Only tool discovery and invocation become lazy.
150
-
151
- ```ts
152
- const matches = await tools.search({ query: "deployment status" });
153
- const schema = await tools.describe({ ref: matches[0].ref });
154
- const result = await tools.call({
155
- ref: schema.ref,
156
- args: { environment: "staging" },
157
- });
158
- return result;
159
- ```
160
-
161
- For tool names valid as JavaScript properties, use the shorter proxy:
162
-
163
- ```ts
164
- const result = await extensions.project_status({ verbose: true });
165
- return result.text;
166
- ```
167
-
168
- The result preserves `content`, text content as `text`, `details`, `isError`, `terminate`, and source provenance. Fabric runs the captured definition's `prepareArguments()` and original executor with its owning extension context. Pi's `tool_call`, `tool_result`, and `tool_execution_*` lifecycle handlers are also applied to nested captured calls.
169
-
170
- Extension overrides of core tools are captured and hidden with their built-in counterparts in full code mode. Inside Fabric, `pi.read`, `pi.bash`, and the other built-ins automatically route through a captured override when one exists; `extensions.read` exposes the override's full native result shape. `capture.keepVisible` can retain non-core extension tools in Pi's direct registry, but core tool names are always excluded while full code mode owns them.
171
-
172
- ### MCP through mcporter
173
-
174
- Pi Fabric uses the public [`mcporter`](https://github.com/openclaw/mcporter) runtime. It inherits mcporter's config discovery, imports, OAuth cache, and connection pooling.
175
-
176
- ```ts
177
- const servers = await mcp.servers(); // names and transport metadata; credentials are never exposed
178
- const result = await mcp.context7.resolve_library_id({
179
- libraryName: "react",
180
- query: "hooks documentation",
181
- });
182
- return result;
183
- ```
184
-
185
- Use `await mcp.reload()` after changing mcporter configuration. `mcp.call({ server, tool, args })` is available when a server or tool name cannot be expressed conveniently as property access.
186
-
187
- A program can register an ephemeral server directly in mcporter's pooled runtime after host approval:
188
-
189
- ```ts
190
- await mcp.register({
191
- name: "project-docs",
192
- command: "npx",
193
- args: ["-y", "@example/docs-mcp"],
194
- cwd: ".",
195
- });
196
- return mcp.project_docs.search({ query: "authentication" });
197
- ```
198
-
199
- HTTP servers use `baseUrl` instead of `command`. Dynamic definitions live until `mcp.reload()` or session shutdown; they are not written to config.
200
-
201
- ### Dynamic workflows
202
-
203
- Fabric programs already keep orchestration and intermediate values in code. The workflow globals add Claude Code-style names and progress phases without introducing a second JavaScript runtime:
204
-
205
- ```ts
206
- await workflow.configure({
207
- name: "Authentication audit",
208
- description: "Discover relevant files, audit them in parallel, then verify findings",
209
- });
210
-
211
- await phase("Discover", { total: 1 });
212
- const inventory = await agent<{ files: string[] }>(
213
- "List source files relevant to authentication.",
214
- {
215
- label: "auth inventory",
216
- tools: ["read", "grep", "find", "ls"],
217
- schema: {
218
- type: "object",
219
- properties: { files: { type: "array", items: { type: "string" } } },
220
- required: ["files"],
221
- additionalProperties: false,
222
- },
223
- },
224
- );
225
-
226
- await phase("Audit", { total: inventory.files.length });
227
- const findings = await parallel(
228
- inventory.files.map(
229
- (file) => () =>
230
- agent(`Audit ${file} for concrete auth defects.`, {
231
- label: `audit ${file}`,
232
- tools: ["read", "grep", "find", "ls"],
233
- }),
234
- ),
235
- { concurrency: 8 },
236
- );
237
-
238
- await phase("Verify", { total: 1 });
239
- return agent(`Verify and synthesize these findings: ${JSON.stringify(findings)}`, {
240
- label: "verify findings",
241
- tools: ["read", "grep", "find", "ls"],
242
- });
243
- ```
244
-
245
- Available helpers are `workflow.agent()`, `workflow.parallel()`, `workflow.pipeline()`, `workflow.configure()`, `workflow.phase()`, `workflow.item()`, `workflow.event()`, `workflow.log()`, and `workflow.budget`. `configure()` names the activity surface; phase options accept `id`, `description`, and an expected `total`. `item()` lets arbitrary non-agent work report status, detail, and progress without requiring a bespoke renderer. `event()` adds a bounded milestone to the run feed. The shorter `agent()`, `parallel()`, `pipeline()`, `phase()`, `log()`, and `budget` aliases are equivalent. `fabric_exec` accepts optional `agentBudget` and `tokenBudget` limits; configuration supplies a hard per-execution agent cap.
246
-
247
- A JSON Schema on an agent request makes the worker return validated structured data through `result.value`. Workflow helpers return that value directly and otherwise return the agent's final text.
248
-
249
- ### Subagents
250
-
251
- ```ts
252
- const result = await agents.run({
253
- name: "security-review",
254
- task: "Review the current diff for concrete security defects. Do not edit files.",
255
- transport: "localterm",
256
- tools: ["read", "grep", "find", "ls"],
257
- });
258
- return result;
259
- ```
260
-
261
- Background handles are explicit:
262
-
263
- ```ts
264
- const handle = await agents.spawn({
265
- task: "Map the persistence layer and identify its public entry points.",
266
- transport: "tmux",
267
- });
268
-
269
- // Do independent work here.
270
-
271
- return await agents.wait({ id: handle.id });
272
- ```
273
-
274
- `runner` is `"pi"` or `"claude"` and defaults to `subagents.runner` (`"pi"`). Pi children use `subagents.model` or inherit the parent model unless `model` is specified. Claude children use `subagents.claude.model` or Claude Code's own runtime default. Their tool allowlist defaults to `subagents.defaultTools`. Reasoning effort defaults to `subagents.thinking` (`medium`); Pi clamps it to model support, while Claude forwards it through `--effort` (`off`/`minimal` map to `low`).
275
-
276
- #### Claude Code runner
54
+ Independent calls run in parallel; only the returned object enters the model context.
277
55
 
278
- Install and authenticate the official Claude Code CLI (`claude`) normally; Fabric invokes that binary rather than Anthropic's Agent SDK or a third-party API client. Select it per call or globally:
279
-
280
- ```ts
281
- const models = await agents.models({ runner: "claude" });
282
- const haiku = models.find((model) => model.key === "claude/haiku");
283
- return agents.run({
284
- runner: "claude",
285
- model: haiku?.key,
286
- task: "Review the current diff. Do not edit files.",
287
- tools: ["read", "grep", "find", "ls"],
288
- });
289
- ```
290
-
291
- `agents.models({ runner: "claude" })` asks the installed CLI for its initialization model catalog, including aliases, resolved IDs, descriptions, and supported effort levels. The list is not hard-coded and the handshake sends no user prompt or model inference request, so model discovery itself is not billable. Because it launches the configured local binary, model-authored `agents.models` calls carry Fabric's `execute` risk. Fabric caches it for 60 seconds. Claude model keys use `claude/<runtime-value>` (for example `claude/default`, `claude/sonnet`, or `claude/haiku`); Fabric strips that namespace before `--model`.
292
-
293
- Claude runs use `claude -p` with stream-JSON input/output, partial messages, `--permission-mode dontAsk`, and both `--tools` and `--allowedTools`. Fabric maps its portable core allowlist as follows:
294
-
295
- | Fabric tool | Claude Code tool |
296
- | ------------ | ---------------- |
297
- | `read` | `Read` |
298
- | `grep` | `Grep` |
299
- | `find`, `ls` | `Glob` |
300
- | `bash` | `Bash` |
301
- | `edit` | `Edit` |
302
- | `write` | `Write` |
303
-
304
- Unknown tools fail before launch. `extensions: false` starts Claude in safe mode; the default `true` preserves the user's normal Claude Code customizations while the explicit tool list still controls model-facing tools. JSON schemas use Claude's native `--json-schema`; usage, cost, turns, tool activity, errors, and Claude's session ID are normalized into the ordinary Fabric result and dashboard transcript. One-shot runs add `--no-session-persistence`.
305
-
306
- Claude-backed children are intentionally **not recursively Fabric-equipped**: `recursive: true`, `fabric_exec`, and direct `mesh.*` access are rejected. Use `runner: "pi"` for RLM/recursive Fabric, or use a Claude-backed persistent actor for host-managed mailbox/event coordination.
307
-
308
- Supported transports:
309
-
310
- | Transport | Behavior | Attach command |
311
- | ----------- | ---------------------------------------------------------- | ---------------------------- |
312
- | `process` | Detached local worker process; default and lowest overhead | none |
313
- | `tmux` | One detached tmux session per child | `tmux attach-session -t …` |
314
- | `screen` | One detached GNU Screen session per child | `screen -r …` |
315
- | `localterm` | One pinned LocalTerm PTY per child | `localterm session attach …` |
316
- | `auto` | Tries LocalTerm, tmux, screen, then process | transport-specific |
56
+ ## Install
317
57
 
318
- LocalTerm already exposes the needed tmux-parity primitives: detached creation, pinning, listing, capture, exec, attach, and kill. Pi Fabric therefore requires no LocalTerm patch. Start its daemon before selecting it:
58
+ Requires Node.js 24+ and Pi 0.80.6+.
319
59
 
320
60
  ```bash
321
- localterm start
322
- ```
323
-
324
- Use `/fabric agents` to list children and `/fabric attach <id>` to display the appropriate attach command. Abort signals propagate to the transport and selected child process. When a program uses orchestration entry points (`agent`/`workflow.agent`, `agents.run`/`agents.wait`/`agents.ask`, `council.run`, `rlm.query`)—including `agents.*` refs invoked through `tools.call()` and refs computed at runtime—Fabric raises the whole-program `executor.timeoutMs` to at least `subagents.timeoutMs`, so the parent deadline cannot stop children that are still within their own per-agent budget.
325
-
326
- Set `worktree: true` to create a dedicated Git worktree and `pi-fabric/<name>-<id>` branch. Worktrees are retained for inspection until `agents.cleanup()` is called.
327
-
328
- ### Steering running agents
329
-
330
- Any Fabric-equipped agent can steer a running one-shot subagent **between its turns** instead of stopping and respawning it, preserving the child's accumulated context — mirroring Pi core's RPC `steer`/`follow_up` queue:
331
-
332
- ```ts
333
- const handle = await agents.spawn({ task: "Audit auth flows.", tools: ["read", "grep", "find", "ls"] });
334
- const s = await agents.status({ id: handle.id });
335
- if (s.text.includes("rotating refresh tokens")) {
336
- await agents.steer({ id: handle.id, message: "Skip refresh-token rotation; focus on session expiry only." });
337
- await agents.setSteeringMode({ id: handle.id, mode: "all" });
338
- }
339
- return await agents.wait({ id: handle.id });
340
- ```
341
-
342
- `agents.steer({ id, message })` is delivered after the current turn's tool calls, before the next LLM call; `agents.followUp({ id, message })` is delivered after the agent finishes; `agents.setSteeringMode`/`setFollowUpMode` set `"all"` vs `"one-at-a-time"` delivery. Pi uses its RPC queue; Claude uses additional user records on the same `claude -p` stream so the session and context are preserved. `agents.status({ id }).pendingMessages` shows the live queue. For an id not local to this process, `agents.steer` publishes a `fabric.steer` mesh event the owning process relays — so an agent in one Pi process can steer an agent in another. See `skills/fabric-exec/references/agents.md`.
343
-
344
- ### Persistent actors and ambient agents
345
-
346
- `agents.create()` creates a named actor with a fixed runner, a persistent runner session, a serial mailbox, and optional subscriptions to parent-session events or durable mesh topics:
347
-
348
- ```ts
349
- return agents.create({
350
- name: "auth-supervisor",
351
- instructions: `Watch the main session until the auth migration is complete and tested.
352
- Prefer silence. Reply with a directive only for material drift, a blocker, or verified completion.`,
353
- events: ["agent_settled", "tool_error"],
354
- responseMode: "directive",
355
- delivery: "steer",
356
- triggerTurn: true,
357
- thinking: "high",
358
- tools: ["read", "grep", "find", "ls"],
359
- });
360
- ```
361
-
362
- A host-managed Claude actor uses the same mailbox and event surface while retaining Claude Code context across activations:
363
-
364
- ```ts
365
- return agents.create({
366
- name: "claude-reviewer",
367
- runner: "claude",
368
- model: "claude/haiku",
369
- instructions: "Review each delivered event and report only concrete regressions.",
370
- events: ["agent_settled", "tool_error"],
371
- responseMode: "directive",
372
- delivery: "steer",
373
- tools: ["read", "grep", "find", "ls"],
374
- });
375
- ```
376
-
377
- Claude actors can retain context, inspect/edit with mapped Claude Code tools, consume host events and mesh messages delivered by Fabric, and return text or directives. They cannot themselves call `fabric_exec`, `agents.*`, or `mesh.*`; use a Pi actor when the actor must recursively coordinate through Fabric. If Claude's private session has been removed, the next activation fails clearly rather than silently discarding actor context. Recreate the actor to start a fresh Claude session.
378
-
379
- This is the primitive behind emergent supervisors and advisors; neither requires another extension. Host events include a bounded recent-session snapshot. Actors process messages one at a time, coalesce repeated host events by default, and restore with the trusted project actor registry. Pi actors keep model context in their Fabric-owned Pi session file. Claude actors persist the session ID emitted by the official CLI, reapply tools/permissions/schema/system-prompt flags on every activation, and use `--resume <id>` after the first message; Fabric also keeps a runner-neutral stream transcript instead of reading Claude's private JSONL format. Each actor's reasoning effort is its `thinking` level (`off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`), defaulting to `subagents.thinking` (`medium`); set it at creation or change it later with `e` from the dashboard.
380
-
381
- Two response modes are available:
382
-
383
- - `text`: every non-empty response becomes an actor outbox message.
384
- - `directive`: validated `{ action: "silent" | "message" | "stop", message?, data? }` output lets the actor decide whether intervention is useful.
385
-
386
- Delivery can remain in `mailbox` or enter the main session as `steer`, `followUp`, or `nextTurn`. The creator fixes delivery policy; an actor cannot escalate it in a response. Use `agents.ask()` for a blocking exchange, `agents.tell()` for fire-and-forget mail, `agents.messages()` for history, and `agents.remove()` for cleanup.
387
-
388
- ### Global actor templates
389
-
390
- Persistent actors live in a project mesh, but a persona worth reusing across projects belongs in a project-independent **template library** stored in your agent dir (`~/.pi/agent/fabric/actors/`). Templates carry only an actor definition — name, instructions, subscriptions, and run settings — never any history (mailbox, session transcript, or run logs). They are not live; you stamp one into a project to make it run.
391
-
392
- ```ts
393
- // Save a reusable persona to the global registry (not a live actor).
394
- return agents.create({
395
- name: "security-reviewer",
396
- instructions: "Review changes for security defects. Reply with a directive only for material drift.",
397
- events: ["agent_settled"],
398
- responseMode: "directive",
399
- scope: "global",
400
- });
401
-
402
- // List templates, then stamp one into the current project as a fresh actor.
403
- const [template] = agents.actors({ scope: "global" });
404
- return agents.import({ name: template.name }); // fresh: no inherited history
405
- return agents.import({ name: "security-reviewer", as: "security-reviewer-2" }); // rename on collision
406
-
407
- // Promote a tuned project actor back to the global library (no history).
408
- return agents.export({ id: actorId, overwrite: true });
409
-
410
- // Refine a template's default instruction (the persona / system-prompt body).
411
- return agents.setInstructions({ id: template.id, instructions: "Be brief.", scope: "global" });
412
- ```
413
-
414
- `agents.setInstructions` also edits a live project actor (`scope: "project"`, the default); the new instruction takes effect on the actor's next queued message. History never crosses the project⇄global boundary — import and export move only the definition. Slash commands mirror the API: `/fabric global` lists templates, `/fabric import <name> [as <new>]` stamps one into the project, and `/fabric export <id> [--overwrite]` promotes a project actor. The dashboard lists global templates alongside live actors and lets you import, export, delete, and edit instructions without writing code.
415
-
416
- ### Durable mesh coordination
417
-
418
- The `mesh` API is a project-scoped, event-sourced coordination substrate:
419
-
420
- ```ts
421
- const event = await mesh.publish({
422
- topic: "team.auth",
423
- kind: "finding",
424
- text: "Refresh-token rotation is not atomic",
425
- data: { path: "src/auth/refresh.ts" },
426
- });
427
-
428
- const task = await mesh.put({
429
- key: "tasks/auth-review",
430
- value: { status: "ready", owner: null },
431
- ifVersion: 0,
432
- });
433
-
434
- const claimed = await mesh.put({
435
- key: task.key,
436
- value: { status: "claimed", owner: "security-reviewer" },
437
- ifVersion: task.version,
438
- });
439
- return { event, claimed };
440
- ```
441
-
442
- Topics provide durable channel and direct-message semantics with sequence cursors. `mesh.members()` discovers actor presence across live Fabric sessions. Versioned `get`/`put`/`delete` operations provide compare-and-swap state for task claims, leases, reservations, and decisions. Together with persistent actors, these are sufficient to express messenger-style swarms in Fabric code without a daemon or fixed planner/worker roles.
443
-
444
- ### Councils
445
-
446
- ```ts
447
- return council.run({
448
- task: "Review the current implementation and recommend whether it is ready to merge.",
449
- roles: ["correctness reviewer", "security reviewer", "test reviewer"],
450
- transport: "localterm",
451
- synthesize: true,
452
- });
453
- ```
454
-
455
- Council members run concurrently under the global subagent semaphore. With `synthesize: true`, a final child agent reconciles their reports.
456
-
457
- ### Recursive queries
458
-
459
- ```ts
460
- return rlm.query({
461
- runner: "pi",
462
- task: "Recursively decompose this repository and produce a compact architecture map.",
463
- transport: "process",
464
- });
61
+ pi install npm:pi-fabric
465
62
  ```
466
63
 
467
- `rlm.query()` is `agents.run({ runner: "pi", recursive: true })` with Fabric enabled in the child. Claude runners are intentionally rejected for recursive Fabric. Recursion is rejected at `subagents.maxDepth`. Approval of 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 configured concurrency and timeout limits. When `subagents.budgetUsd` is set, a shared append-only cost ledger bounds total spend across the whole recursion tree: every node records the cost of the children it spawns into one ledger file inherited via environment, and each node rejects a new child when the accumulated spend reaches the budget. The check is best-effort (concurrent children can each pass before any cost lands, so a tree may slightly overshoot); the race-free ceiling remains `subagents.maxPerExecution`. The result and live status of every recursive child carry a `budget` summary (`limit`, `spent`, `remaining`, `tokens`).
468
-
469
- `subagents.maxTokensPerChild` (0 = disabled) bounds each child's cumulative token usage. The wall-clock `timeoutMs` and the cost `budgetUsd` bound time and money; this bounds a single runaway child's context before the host session compacts, terminating it with the same `timed_out` status and a `token limit` error.
470
-
471
- ## Included skills
472
-
473
- Pi discovers these package skills automatically:
474
-
475
- | Command | Pattern |
476
- | ---------------------------------- | ----------------------------------------------------------------------- |
477
- | `/skill:fabric-supervisor <goal>` | Persistent goal watcher driven by `agent_settled` and tool-error events |
478
- | `/skill:fabric-advisor [focus]` | Decision-point peer reviewer (idle and tool errors) that prefers silence |
479
- | `/skill:fabric-ambient <role>` | Meta-pattern for custom event-driven ambient actors |
480
- | `/skill:fabric-workflow <task>` | Code-held phases, fan-out, pipelines, structured output, and synthesis |
481
- | `/skill:fabric-rlm <task>` | Recursive self-delegation via `rlm.query()` for tasks too big for one context window |
482
- | `/skill:fabric-swarm <objective>` | Persistent actors, durable topics, and CAS-based shared tasks |
483
- | `/skill:fabric-council <decision>` | Bounded independent perspectives plus synthesis |
484
- | `/skill:fabric-fusion <task>` | Multi-model deliberation: parallel panel plus a compare-not-merge judge |
485
-
486
- `fabric-exec` is the one discoverable reference skill: it holds the full `fabric_exec` API (core `pi.*` tools, `tools` discovery, `π` strings, error recovery) plus `references/` files for MCP, agents/rlm, and mesh loaded by relative path (not separate skills). It appears in `<available_skills>`; load it via `read` before your first `fabric_exec` call or when a call errors.
64
+ <details>
65
+ <summary>Other install methods</summary>
487
66
 
488
- Supervisor and advisor are deliberately skills rather than hard-coded host services: the skill writes ordinary Fabric code over the same actor primitive available to every other pattern.
489
-
490
- ## Visual integration
491
-
492
- `fabric_exec` uses the public `pi-code-previews` cooperative shell. It inherits the user's border/background mode, collapsed-result behavior, error styling, and tool-call timing without taking ownership of Pi's built-in tool renderers. Its renderer adds a numbered TypeScript preview, live phase/call activity, and compact phase/nested-call summaries. Nested `pi.read`/`pi.bash`/`pi.grep`/`pi.find`/`pi.ls`/`pi.write`/`pi.edit` calls render as structured previews (path/command headers, numbered content) instead of raw JSON. `pi.read` and `pi.write` content is syntax-highlighted with the same shiki theme configured for `pi-code-previews`, so colors match Pi's native tool previews; `pi.bash` commands are highlighted in the call title and `pi.edit` operations render as a `+`/`-` line diff (with shared context) using Pi core's diff colors. The highlighter initializes lazily and falls back to plain text until ready. Collapsed previews show the configured expand keybinding (e.g. `Ctrl-O`) to expand, matching Pi's built-in tool previews. Users do not need to install `pi-code-previews` separately.
493
-
494
- Fabric also owns a general-purpose, theme-aware activity surface for any agent setup:
495
-
496
- - A compact widget above the chat (like `pi-supervisor`) follows the current phase and shows active agents, actors, tools, custom items, shared tasks, token use, and elapsed time. It disappears after ordinary runs become quiet, while persistent actors remain visible as a compact ambient row.
497
- - `/fabric dashboard` opens a responsive interactive overlay. Wide terminals use an activity-group pane beside agents and work items; narrow terminals stack the same panels. Explicit workflow phases remain distinct, while direct calls, items, and agents launched without a phase appear under **Run activity** instead of disappearing. Activity groups show agent count, token use, and elapsed time; agent rows prioritize attention and summarize current work, errors, or results. Agent detail includes task, model, current tool, usage, result, worktree, and attach metadata. Press Space on an agent for a live transcript peek, or press `t` in its detail to switch between summary and transcript. The bounded ring-buffer transcript renders Pi RPC and Claude stream-JSON assistant text with Pi's native Markdown treatment while keeping tool activity as compact one-line markers; common credential fields and token shapes are redacted from tool previews. Oldest activity rolls off the top, scrolling pauses follow mode, and `G` resumes it. One-shot agent model and thinking settings are fixed when spawned, but selected agents can be steered, given a queued follow-up, or safely stopped from the dashboard. Persistent actors are editable: select an actor to see the available shortcuts, then press `m` for its model, `e` for thinking (reasoning effort), `v` for host events, or `i` for its default instruction. Model/thinking changes persist to the actor registry and take effect on the actor's next run; the model picker uses Pi's registry for Pi actors and Claude's runtime catalog for Claude actors, and Inherit falls back to that runner's Fabric/runtime default. Actor mailboxes, mesh state, recent mesh events, and global actor templates use the same view rather than role-specific screens. Press `x` to export a project actor to the global library, `p` to import a global template as a fresh project actor, or `d` to delete a global template.
498
- - `/fabric settings` opens an inline settings view that mirrors Pi core's `/settings` (top and bottom borders, fuzzy search, section submenus) and writes changes to `fabric.json`. Trusted projects write to `<project>/.pi/fabric.json`; untrusted sessions write to the global `~/.pi/agent/fabric.json`. Full code mode, capture, executor, approvals, and UI changes apply immediately; mesh, subagent, and MCP changes persist and take effect on the next `/fabric reload`. The Subagents section selects the default runner and keeps independent Pi and runtime-enumerated Claude model pickers. List editors for `subagents.defaultTools` and `capture.keepVisible` toggle known tools on and off; `keepVisible` candidates include `fabric_exec` plus every captured extension tool.
499
- - `↑`/`↓` or `j`/`k` select, `←`/`→` or Tab switch panes, Enter drills into details, `f` cycles status filters, `[` selects an older retained run, `]` a newer one, and `?` opens contextual help. On one-shot agents, Space peeks at the live transcript, `t` toggles transcript/summary detail, `s` opens a steer editor, `u` queues a follow-up, and pressing `x` twice stops an active run. On actors, `m` changes the model, `e` thinking, `v` host events, and `i` instructions; `x` exports to global, `p` imports a global template, `d` deletes one, and Esc backs out or closes.
500
-
501
- The surface is data-driven. Fabric automatically instruments nested provider calls, subagents, persistent actors, and task-shaped mesh entries. A workflow can add domain-specific labels and arbitrary progress without adding extension UI code:
502
-
503
- ```ts
504
- await workflow.configure({ name: "Release train", description: "Build, verify, and publish" });
505
- await phase("Build", { total: packages.length });
506
- await workflow.item({
507
- id: "docs",
508
- label: "Documentation",
509
- status: "running",
510
- completed: 2,
511
- total: 5,
512
- });
513
- await workflow.event({ message: "Canary passed", level: "success" });
514
- ```
67
+ From GitHub:
515
68
 
516
- External Fabric providers can emit structured `context.activity()` updates for an entity, progress message, or metrics. This keeps the TUI generic while allowing a virtual provider to expose richer live state.
517
-
518
- ## Configuration
519
-
520
- Pi Fabric reads:
521
-
522
- 1. `~/.pi/agent/fabric.json`
523
- 2. `<project>/.pi/fabric.json`, only for trusted projects
524
-
525
- Project values override global values.
526
-
527
- ```json
528
- {
529
- "fullCodeMode": true,
530
- "executor": {
531
- "timeoutMs": 120000,
532
- "memoryLimitBytes": 67108864,
533
- "maxOutputChars": 100000,
534
- "maxNestedResultChars": 2000000
535
- },
536
- "approvals": {
537
- "read": "allow",
538
- "write": "allow",
539
- "execute": "allow",
540
- "network": "allow",
541
- "agent": "allow"
542
- },
543
- "capture": {
544
- "enabled": true,
545
- "hideFromModel": true,
546
- "keepVisible": ["fabric_exec"],
547
- "defaultRisk": "execute",
548
- "risks": {
549
- "read": "read",
550
- "grep": "read",
551
- "find": "read",
552
- "ls": "read",
553
- "edit": "write",
554
- "write": "write",
555
- "bash": "execute"
556
- }
557
- },
558
- "mcp": {
559
- "enabled": true,
560
- "disableOAuth": true,
561
- "allowDynamicServers": true,
562
- "callTimeoutMs": 120000
563
- },
564
- "subagents": {
565
- "enabled": true,
566
- "runner": "pi",
567
- "transport": "process",
568
- "claude": {
569
- "binary": "claude"
570
- },
571
- "thinking": "medium",
572
- "maxConcurrent": 4,
573
- "maxPerExecution": 100,
574
- "maxDepth": 2,
575
- "timeoutMs": 3600000,
576
- "extensions": true,
577
- "defaultTools": ["read", "bash", "edit", "write", "grep", "find", "ls"],
578
- "retainRuns": false,
579
- "notifyOnComplete": true,
580
- "budgetUsd": 0,
581
- "maxTokensPerChild": 0
582
- },
583
- "ui": {
584
- "enabled": true,
585
- "widget": "auto",
586
- "maxRows": 6,
587
- "refreshMs": 500,
588
- "lingerMs": 10000,
589
- "eventHistory": 80
590
- },
591
- "compaction": {
592
- "engine": "fabric"
593
- },
594
- "mesh": {
595
- "enabled": true,
596
- "actorScope": "project",
597
- "maxEventBytes": 262144,
598
- "maxReadEvents": 500,
599
- "actorPollMs": 250,
600
- "actorQueueLimit": 32,
601
- "eventContextChars": 40000
602
- }
603
- }
69
+ ```bash
70
+ pi install git:github.com/monotykamary/pi-fabric
604
71
  ```
605
72
 
606
- The deterministic, LLM-free compaction engine is default-on. Set `compaction.engine` to `"pi"` to restore pi-core compaction. When pi-vcc is also installed, Fabric takes precedence for automatic compaction, while an explicit `/pi-vcc` command always uses pi-vcc's engine.
607
-
608
- `subagents.runner` selects the default harness (`"pi"` or `"claude"`). `subagents.model` is the optional Pi `provider/id` override; `subagents.claude.model` is the optional canonical Claude runtime key. `subagents.claude.binary` defaults to `claude` and can be an absolute path or wrapper; `PI_FABRIC_CLAUDE_BINARY` overrides it for the current process. `/fabric settings` enumerates Claude models from that binary and stores the two runner defaults independently.
609
-
610
- `fullCodeMode` defaults to `true`. Full mode deactivates native core tools in the parent session and makes `fabric_exec` their exclusive model-facing owner. When false, Fabric uses orchestration-only mode: native Pi and registered extension tools remain direct, capture is disabled, and Fabric's internal registry omits the `pi` and `extensions` providers.
611
-
612
- Fabric risk classes are `read`, `write`, `execute`, `network`, and `agent`; approval policy values are `allow`, `ask`, or `deny`. Captured tools default to the conservative `execute` risk because Pi tool definitions do not declare effects. Add exact tool-name overrides under `capture.risks`. Set `capture.hideFromModel` to `false` to index non-core extension tools without hiding them. `capture.keepVisible` names stay in both Fabric and Pi's direct registry, except that Pi core names are always Fabric-owned in full code mode. An `ask` policy is fail-closed in headless modes without interactive UI. Approval is cached by risk class for one `fabric_exec` execution.
613
-
614
- When `mcp.disableOAuth` is true, MCP calls may use cached credentials but cannot launch a new interactive OAuth flow.
615
-
616
- The UI `widget` mode is `auto`, `always`, or `hidden`. `auto` shows active work, recent completion, and live persistent actors. The widget renders above the chat (like `pi-supervisor`); set `ui.enabled` to `false` to disable both the widget and dashboard controller.
617
-
618
- Mesh data defaults to `<project>/.pi/fabric/mesh`. Set `mesh.root` to a relative or absolute path to relocate durable topics, shared state, and actor sessions. Add `.pi/fabric/mesh/` to the project's ignore file unless the coordination log is intentionally versioned. Set `mesh.enabled` to `false` to disable both mesh actions and ambient actor restoration.
619
-
620
- `mesh.actorScope` controls where persistent actor definitions, mailboxes, and child sessions are stored and restored from. The default `"project"` keeps a single shared actor registry at `.pi/fabric/mesh/actors/`, so actors survive `/new` and carry over between Pi sessions in the same project without redefinition. Set it to `"session"` to isolate actors per Pi session (under `.pi/fabric/mesh/actors/<sessionId>/`), the previous default; use this when you run concurrent Pi sessions in one project and want each to own its own actors. With project scope, one Pi process should own the actor registry at a time — concurrent sessions sharing a registry may race on writes.
621
-
622
- ## External provider protocol
623
-
624
- Normal `pi.registerTool()` tools are captured automatically. Extensions can still opt into the versioned provider protocol when they need to expose non-tool capabilities, richer risk declarations, or a large virtual action catalog without registering one Pi tool per action:
73
+ From a local checkout:
625
74
 
626
- ```ts
627
- import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
628
- import {
629
- FABRIC_PROVIDER_DISCOVER_EVENT,
630
- FABRIC_PROVIDER_REGISTER_EVENT,
631
- type FabricProvider,
632
- type FabricProviderDiscovery,
633
- } from "pi-fabric/protocol";
634
-
635
- export default function extension(pi: ExtensionAPI) {
636
- const provider: FabricProvider = {
637
- name: "example",
638
- description: "Example actions",
639
- async list() {
640
- return [];
641
- },
642
- async describe() {
643
- return undefined;
644
- },
645
- async invoke() {
646
- return null;
647
- },
648
- };
649
-
650
- pi.events.emit(FABRIC_PROVIDER_REGISTER_EVENT, {
651
- version: 1,
652
- provider,
653
- overwrite: true,
654
- });
655
-
656
- pi.events.on(FABRIC_PROVIDER_DISCOVER_EVENT, (event: FabricProviderDiscovery) => {
657
- event.register(provider, { overwrite: true });
658
- });
659
- }
75
+ ```bash
76
+ pnpm install
77
+ pnpm build
78
+ pi install /absolute/path/to/pi-fabric
660
79
  ```
661
80
 
662
- Providers own their schemas, state, and execution semantics. Pi Fabric validates arguments, enforces the declared risk policy, records nested-call audits, and propagates cancellation. A provider can enrich the generic activity surface without registering a TUI component:
663
-
664
- ```ts
665
- async invoke(actionName, args, context) {
666
- context.activity?.({ type: "entity", id: job.id, kind: "custom", name: job.name });
667
- context.activity?.({ type: "progress", message: "Indexing package 3/12" });
668
- context.activity?.({ type: "metrics", tokens: 4200, toolCalls: 9 });
669
- return job.result;
670
- }
671
- ```
81
+ For one development run:
672
82
 
673
- ## Commands
674
-
675
- ```text
676
- /fabric status
677
- /fabric dashboard
678
- /fabric settings
679
- /fabric reload
680
- /fabric providers
681
- /fabric captured [query]
682
- /fabric agents
683
- /fabric actors
684
- /fabric messages <actor-id>
685
- /fabric attach <subagent-id>
686
- /fabric stop <actor-or-subagent-id>
83
+ ```bash
84
+ pi -e /absolute/path/to/pi-fabric
687
85
  ```
688
86
 
689
- ## Headless focused agents
690
-
691
- Pi already runs one-shot, non-interactive agents with `pi -p` (`--print`), and it reads piped stdin as part of the prompt — so a focused agent composes with pipes, cron, git hooks, and CI like a Unix program, with no wrapper needed:
87
+ </details>
692
88
 
693
- ```bash
694
- git diff | pi -p --no-session -t read,grep "Review this diff for concrete defects."
695
- pi -p --no-session --mode json -e <path-to-pi-fabric> "Map the persistence layer."
696
- ```
89
+ ## What you can ask for
697
90
 
698
- `--no-session` keeps the run ephemeral, `-t` restricts the tool allowlist, `--mode json` emits a structured event stream for scripting (`| jq`), and `-e <pi-fabric>` loads Fabric so the agent can use `fabric_exec`. The process exits non-zero on failure. See `pi --help` for the full flag list.
699
-
700
- ## Architecture
701
-
702
- ```text
703
- fabric_exec
704
-
705
-
706
- TypeScript checker → QuickJS sandbox
707
- │ JSON-only host bridge
708
-
709
- ActionRegistry
710
- ├── pi.* built-in Pi tool definitions
711
- ├── extensions.* captured pi.registerTool definitions
712
- ├── mcp.* pooled mcporter runtime
713
- ├── agents.* one-shot workers + persistent mailbox actors
714
- ├── mesh.* durable topics + compare-and-swap state
715
- └── external explicit pi.events providers
716
-
717
- ActivityStore → compact widget + footer status + interactive dashboard
718
- ```
91
+ Every pattern below is a skill Pi loads on demand. Invoke it with `/skill:<name>`, or just describe the task and let Pi pick it up.
719
92
 
720
- Guest code has no `process`, `require`, filesystem, network, or subprocess globals. All effects cross the host bridge, where schemas, approvals, audit records, timeouts, and cancellation apply. Each execution receives a fresh QuickJS context. Named strings passed in the `strings` tool parameter are available as `π.key`; accessing a key that was not provided throws a clear, actionable error listing the provided keys rather than silently returning `undefined`.
93
+ | You want | Ask for | Skill |
94
+ | -------- | ------- | ----- |
95
+ | Parallel audits, migrations, or research with phased progress and a final synthesis | “Audit every auth file in parallel and synthesize findings.” | `/skill:fabric-workflow` |
96
+ | Work too big for one context window, decomposed recursively | “Produce a compact architecture map of this repo.” | `/skill:fabric-rlm` |
97
+ | A persistent watcher that steers only when you drift | “Watch this migration until it's complete and tested.” | `/skill:fabric-supervisor` |
98
+ | A quiet decision-point reviewer | “Review my decisions at idle and tool-error points.” | `/skill:fabric-advisor` |
99
+ | Several reviewers reconciled into one verdict | “Run correctness, security, and test reviewers, then merge.” | `/skill:fabric-council` |
100
+ | Multi-model deliberation with a compare-not-merge judge | “Deliberate this design across models.” | `/skill:fabric-fusion` |
101
+ | A durable team coordinating through shared tasks | “Stand up a team that claims tasks atomically and reports progress.” | `/skill:fabric-swarm` |
102
+ | Edits gated behind typed evidence and postconditions | “Make this parser change only if focused tests stay green.” | `/skill:fabric-schema` |
721
103
 
722
- ## Tool-call robustness
104
+ The foundation is the `fabric-exec` reference skill: the model loads it before its first `fabric_exec` call and again when a call errors on argument shape.
723
105
 
724
- The model-facing `fabric_exec` schema is intentionally flat — one large `code` string plus scalar/optional parameters — with no nested arrays-of-objects containing escaped content. Newer SOTA models are post-trained on one dominant harness's flat tool shapes and can invent trailing keys at the highest-entropy point of a nested escaped-JSON field (e.g. right after closing a long multiline string), which a strict schema rejects. The only nested field, `display`, ignores unknown keys: extras are accepted by the schema and filtered to `{ name, description }` before execution, mirroring the silent-filter behavior the dominant harness's client is trained against.
106
+ ## The dashboard
725
107
 
726
- fabric's architecture is itself a mitigation for this class of bug. The model authors TypeScript that calls tools, so it never has to faithfully emit an alternative tool schema under sampling pressure; nested object construction happens in deterministic, type-checked code. The residual failure mode is incorrect TypeScript, caught by the QuickJS type-checker with an actionable, line-numbered error — the validate/report/retry loop at the code level rather than the JSON-schema level.
108
+ Fabric adds a live activity surface to Pi, no extra extension required:
727
109
 
728
- For sessions that also call pi tools directly (`read`/`write`/`edit`/`grep`/`find`/`ls`/`bash`), install [pi-tool-repair](https://github.com/monotykamary/pi-tool-repair) as a companion. It validates-then-repairs the finite set of tool-call mistakes those direct calls make — invented keys, wrong field names, stringified arrays, anchor bleed, and leaked tool-call grammars before tools execute. It hooks `before_provider_request`/`message_end`/`tool_call`; fabric registers a tool, so the two do not conflict.
110
+ - A compact widget above the chat (like `pi-supervisor`) that follows the current phase and shows one priority activity at a time.
111
+ - `/fabric dashboard` — a phase sidebar, per-agent detail with live transcripts, and controls to steer, queue follow-ups, or stop runs.
112
+ - `/fabric settings` — mirrors Pi's `/settings` and writes changes to `fabric.json`.
729
113
 
730
- An external lever outside fabric's control is enabling Anthropic strict tool use at the provider, which prevents the server from sampling keys not in the schema. It is the strongest mitigation for schema drift but trades against Anthropic's complexity limits on strict tool definitions.
114
+ See the [interface & commands reference](docs/interface.md) for every view, keybinding, and slash command.
731
115
 
732
- ## Security and limitations
116
+ ## Reference
733
117
 
734
- - Pi Fabric invokes separately constructed Pi built-in definitions when no captured override exists. Those unoverridden built-in calls do not pass through Pi's top-level `tool_call` and `tool_result` hooks. Captured overrides and other extension calls do run those hooks; Fabric's approval and audit layer remains authoritative around every nested call.
735
- - Captured tools execute with the full privileges of their owning extension. Hiding a tool schema is context optimization, not sandboxing. Captured tools retain their definitions and native renderers, but nested calls render as part of the enclosing Fabric execution rather than as separate native tool rows.
736
- - Registry interception composes through the public `ExtensionRunner.getAllRegisteredTools()` method. An extension that replaces that method without delegating to the previous implementation can prevent capture.
737
- - MCP servers and external providers execute with their own host privileges. Review their configuration and code.
738
- - Type checking improves reliability but is not a security boundary; QuickJS isolation and the host capability bridge are the boundaries.
739
- - Child Pi processes load normal extensions by default so provider-backed models continue to work. Claude children use the official installed CLI and its existing authentication. Both runners restrict the active model-facing tools to `defaultTools`; Pi adds `fabric_exec` only for explicit recursion, while Claude rejects recursion and unmapped tools.
740
- - Claude `extensions: true` preserves the user's normal Claude Code customizations, including applicable settings and hooks; those hooks execute with their usual host privileges. Use `extensions: false` for Claude safe mode. `Bash` remains unrestricted inside the child when allowed, just as Fabric's `bash` capability is.
741
- - Claude model discovery uses a local initialization control request and does not invoke a model. Actual one-shot and actor activations use the account/API billing already configured in Claude Code; Fabric records the CLI's reported `total_cost_usd` in normal usage and budget ledgers.
742
- - A Git worktree isolates files, not credentials, network access, processes, or external services.
743
- - Agent transcripts are projected from local `events.jsonl` run logs. The dashboard redacts common credentials from compact tool previews, but the permission-restricted raw event log can contain assistant text, tool arguments/results, diagnostics, and extension protocol payloads; treat retained run directories as sensitive.
744
- - Background one-shot children are stopped when the parent Pi session shuts down. A detached `agents.spawn()` sends a follow-up completion message unless the caller later waits for it or `notifyOnComplete` is disabled. Completed worktrees are intentionally retained.
745
- - Persistent actors are suspended on shutdown and restored when project trust is active. Claude actor session IDs refer to Claude Code's own persisted session store; removing that private session makes resume fail, and removing a Fabric actor does not currently delete Claude Code's private transcript. By default (`mesh.actorScope: "project"`), their definitions, mailbox history, and child session files live under `.pi/fabric/mesh/actors/` and are shared across all Pi sessions in the project, so actors survive `/new`. Set `mesh.actorScope: "session"` to isolate actors per Pi session instead. Mesh topics and shared state are always project-scoped. Do not place secrets in actor prompts, messages, or mesh state.
746
- - Approving `agents.create()` delegates future subscribed events to that actor until it is stopped. Each activation uses the actor's fixed runner/tool allowlist and its persisted model setting; review them before approving a persistent actor.
747
- - Actor responses can enter the main context only through the delivery policy fixed at creation. Directive output is schema-validated, but it is still untrusted model output that the main agent should weigh.
748
- - One Pi process should own the actor registry at a time. This is especially important with project scope, where concurrent Pi sessions in the same project share one registry and may race on writes. Mesh topics are append-only and are not compacted automatically; archive or remove an old mesh root when its history is no longer useful.
118
+ - [Configuration](docs/configuration.md) `fabric.json`, code modes, tool capture, approvals, and budgets.
119
+ - [Interface & commands](docs/interface.md) dashboard, settings, keybindings, slash commands, and headless runs.
120
+ - [Agents, actors & mesh](docs/agents.md) subagents, the Claude runner, transports, steering, persistent actors, global templates, councils, recursive queries, and durable coordination.
121
+ - [External providers](docs/providers.md) the versioned provider protocol for extensions.
122
+ - [Architecture & security](docs/architecture.md) the host bridge, sandboxing, tool-call robustness, and limitations.
123
+ - [Skills](skills/) the model-invoked patterns and the full `fabric_exec` API reference.
749
124
 
750
125
  ## Development
751
126
 
@@ -756,7 +131,7 @@ pnpm test
756
131
  pnpm build
757
132
  ```
758
133
 
759
- The deterministic test suite covers configuration, schema validation, provider dispatch, registered-tool interception and execution, QuickJS isolation, Pi built-in invocation, direct-process subagents, fake Claude stream-JSON/model discovery, workflow helpers, durable mesh state, actor mailboxes, subscriptions, and Pi/Claude actor restoration. Claude fixtures never make a billable API request.
134
+ The test suite covers configuration, schema validation, provider dispatch, registered-tool interception and execution, QuickJS isolation, Pi built-in invocation, subagents, fake Claude stream-JSON and model discovery, workflows, durable mesh state, actor mailboxes and subscriptions, and Pi/Claude actor restoration. Claude fixtures never make a billable request.
760
135
 
761
136
  ## License
762
137