@llblab/pi-actors
v0.37.0
Published
Local Actor Kernel for Pi
Downloads
11,559
Maintainers
Readme
pi-actors
Local Actor Kernel for Pi

pi-actors turns trusted local programs, scripts, recipes, services, pipelines, and sub-agents into addressable actors that agents can spawn, message, inspect, and compose.
It is not just a command registry. A tool is a verb. An actor is a noun with time: address, lifecycle, state, logs, mailbox, artifacts, and an interaction contract.
program / process / service
→ command template
→ actor recipe
→ spawn
→ run:<id>
→ message / inspect / artifactsCore Contract
pi-actors compresses local agent orchestration to three durable verbs:
spawn create an addressable actor
message send one typed envelope to one address
inspect intentionally read state, logs, messages, contracts, or artifactsEverything else is an adapter until proven otherwise.
Use spawn when work may outlive the current turn. Use message when the actor should be steered rather than restarted. Use inspect at decision points, after actor follow-ups, or during diagnosis. For non-trivial actor use, load the bundled actors skill before improvising. Do not build polling loops as the default coordination pattern.
When To Use Actors
Use actor-mode instead of ad hoc shell backgrounding when work is:
- Long-running or likely to outlive this agent turn.
- Stateful, resumable, or something you will need to inspect later.
- Expected to produce named artifacts or follow-up messages.
- A service, worker, media process, fanout, subagent, or pipeline.
- A repeatable local capability worth promoting into recipe memory.
Keep ordinary foreground tools for short checks such as rg, ls, quick tests, and one-shot transforms. The golden path is:
create actor -> spawn
steer actor -> message
read state/results -> inspect
repeatable pattern -> promote to recipe/tool memoryInstall
pi install npm:@llblab/pi-actorsOr from git:
pi install git:github.com/llblab/pi-actorsThe npm package is dist-first for JavaScript-only runtimes: default Pi metadata points at compiled dist/ entrypoints and mirrored runtime assets. Source TypeScript and source skills remain in the package for TypeScript-native runtimes through optional source metadata. When the source checkout is auto-discovered as an extension, it also contributes its co-located skills/ directory during Pi resource discovery so the actors and swarm skills travel with the extension.
Address Surface
Core actor addresses stay small:
run:<id> one detached actor run
tool:<name> executable registered tool actorAdvanced coordination/debug addresses are available when a recipe or workflow needs them:
branch:<run>/<branch> branch-local worker endpoint
room:<run> group-message timeline plus roster for one run
coordinator compatibility alias for the current session coordination path
session: current session actor surface
session:all cross-session inventory surface for diagnosticsActor messages use one envelope shape:
{
"to": "run:review",
"from": "coordinator",
"type": "control.continue",
"summary": "Continue after checkpoint",
"body": "continue",
"reply_to": "msg_123",
"correlation_id": "task_456",
"metadata": {}
}Routing is inferred from to, actor ownership, and runtime policy. Recipes should expose semantic message types, not transport knobs.
Golden Path
Create a reusable async actor recipe in the user recipe root:
mkdir -p ~/.pi/agent/recipes
cat > ~/.pi/agent/recipes/docs_review.json <<'JSON'
{
"description": "Start an async docs review actor",
"async": true,
"args": ["scope:path", "model:string"],
"mailbox": {
"accepts": ["control.kill", "control.continue"],
"emits": ["review.completed", "run.failed"]
},
"template": "pi -p --model {model} --no-tools \"Review {scope} for unclear actor-runtime onboarding. Return concise findings.\""
}
JSONBecause it lives under ~/.pi/agent/recipes/, the file becomes a persistent agent tool by location. The filename is the tool id.
Start it:
docs_review scope="README.md" model="current-review-model" run_id=docs_reviewInspect only when there is a reason:
inspect target=tool:pi-actors view=triage
inspect target=run:docs_review view=status
inspect target=run:docs_review view=tail lines=80
inspect target=run:docs_review view=messages
inspect target=run:docs_review view=mailboxSteer it through messages:
message to=run:docs_review type=control.continue body=continue
message to=run:docs_review type=control.kill body=stopGroup Messaging And Roster
Every spawned run can have advanced group messaging at room:<run>. Treat this as a run-local timeline plus roster for coordinated actors, not as a core chat/broker concept.
Actors can join, post, leave, and discover peers:
message \
to=room:review \
from=branch:review/security \
type=actor.join \
summary="Security reviewer joined" \
body='{"role":"reviewer","caps":["security-review"],"claim":"Review auth boundary risks"}'Inspect group messages and roster intentionally:
inspect target=room:review view=status
inspect target=room:review view=previews
inspect target=room:review view=roster
inspect target=room:review view=contacts
inspect target=room:review view=messagesGroup posts require a same-run sender, so unrelated runs do not pollute the roster. Direct messages and group messages use the same envelope; only the address changes. Direct branch:<run>/<branch> messages are private: they are forwarded through the parent run mailbox and recorded in the recipient branch inbox for worker protocols that consume queued branch work. For selected-recipient multicast, send to room:<run> with metadata.recipients set to same-run branch:<run>/<branch> addresses; this keeps one visible transcript entry while forwarding branch-targeted copies.
Actor Inspector
The terminal actor inspector is hidden by default. When opened without an explicit size, it shows 12 log rows by default. Use it when async actors are actively coordinating:
/actors-inspector-toggle
/actors-inspector-toggle 20
/actors-inspector-filter room
/actors-inspector-filter direct
/actors-inspector-filter unread
/actors-inspector-filter branch front
/actors-inspector-filter mention checkpoint
/actors-inspect 3The table is compact and optimistic by default: bounded route/type/summary/body previews, capped noisy room rows, branch-local inbox previews, stable event ids in selected-message details, and an inline roster summary in the form name/role that wraps only when needed. Active roster members use the target color; members that sent actor.leave remain visible as inactive/muted participants from the current run. Use unread to focus queued branch inbox work and branch <name> / current-branch <name> to focus one branch's room/direct/inbox traffic. Rows with metadata.requires_response=true show a ! attention marker. /actors-inspect <number> opens the selected row as a full-message view and marks it read for the current session filter; toggle again to return to the table or close it. Actor display names come from room actor.join roster metadata or branch addresses, keeping debugger output plain and name-driven.
Registry Model
The persistent tool surface is file-discovered:
~/.pi/agent/recipes/*.json
~/.pi/agent/recipes/*.mdThat directory is operator-managed executable memory.
Rules:
- User recipes in
~/.pi/agent/recipes/are tools by location; - Recipe filenames define tool ids;
- User recipes override same-name lower-priority recipes;
- Same-id JSON recipes shadow Markdown recipes in the same priority layer;
- Packaged recipes are standard-library components, not automatically installed operator policy;
- Draft recipes in
~/.pi/agent/recipes/drafts/are replayable memory, not active tools; register_toolcreates, updates, lists, deletes, or explicitly promotes draft recipe files through the normal agent interface.
Example foreground tool:
register_tool name=transcribe_audio \
description="Transcribe a local audio file" \
template="~/bin/transcribe {file:path} {lang=ru} {model:string}"Example recipe-backed tool:
register_tool name=docs_review \
description="Start an async docs review actor" \
template="docs_review" \
args="scope:path,model:string"Promote a successful captured draft only after an explicit operator decision:
register_tool name=docs_review draft=~/.pi/agent/recipes/drafts/spawned-run.jsonPromotion validates the draft, writes ~/.pi/agent/recipes/<name>.json, preserves the draft, and rejects collisions unless update=true is supplied.
Inspect the discovered registry:
inspect target=recipes view=status
inspect target=recipes view=summary verbose=trueCommand Templates
A command template is the portable launch substrate. It can be a string, a sequence, or a composed graph.
Templates support:
- Named placeholders:
{file},{model},{prompt}; - Compact types:
string,path,int,number,bool,enum(a,b); - Defaults:
{lang=ru},{dry_run:bool=true}; - Fallback and small ternary forms;
- Sequences with stdin flow;
- Parallel nodes;
- Retries, recovery, failure policy, delays, and guarded execution;
- Async run values such as
{run_id},{state_dir},{actor_address},{default_room}, and{communication_file}.
The template owns execution shape. The recipe owns saved metadata, defaults, imports, mailbox, and artifacts. JSON is the canonical precise recipe format; Markdown recipes use frontmatter plus fenced template/json recipe blocks for literate authoring and compile into the same model. The run actor owns detached lifecycle, state, messages, cancellation, and inspection. File-backed async recipes also provide child pi -p actors with a bounded JSONL recipe context bundle by default, including raw entry/import recipe records and a "you_are_here": true marker for the recipe node that launched the child. Set "actor_context": false or "off" in a recipe to suppress that context for minimal prompts.
Recipe Library
Packaged recipes live under recipes/ and helper scripts live under scripts/.
The library includes:
- Sub-agent launchers;
- Review, critic, planner, verifier, merger, judge, normalizer, and artifact atoms;
- Quorum and lens-style pipelines;
- Repo-health, release-summary, research-synthesis, development-tasking, docs-maintenance, and room-swarm pipelines;
- Coordinator-locker and actor-message utilities;
- Local music-player actor recipe.
Packaged recipes are building blocks. Copy them into ~/.pi/agent/recipes/ or register tools that point at them when they should become durable operator-facing capabilities.
When To Use What
Use a foreground registered tool when the work is short, bounded, and does not need lifecycle.
Use an async recipe or spawn when the work is long-running, service-like, parallel, agentic, artifact-producing, or needs later control. When a directly spawned inline/ad hoc actor or a recipe outside the user recipe root completes successfully, pi-actors sends the launching agent a follow-up note to offer saving that pattern as a durable recipe/tool under ~/.pi/agent/recipes; the agent should ask first and never auto-save.
Use room:<run> when multiple actors in the same run need shared context, roster discovery, or group-visible progress.
Use artifacts when outputs should survive context compression.
Use mailbox declarations when an actor has a stable conversational surface.
Platform Support
Core actor state, inspection, foreground tools, and basic async runs are portable Node.js behavior. Run-local messaging and stop/kill use a platform adapter under the same message API: Unix-compatible recipes can use their existing local control endpoint, while native Windows recipes can expose a Windows-native endpoint in run state. Some packaged scripts still depend on Unix tools and are WSL/Linux/macOS-only until migrated; their public recipe surface should stay spawn / message / inspect either way.
| Surface | Linux/macOS/WSL | Native Windows | | --- | --- | --- | | Foreground tools, recipe discovery, inspect | Supported | Supported | | Async runs and file-backed state | Supported | Supported | | Mailbox-only actors and worker recipe | Supported | Supported | | FIFO control endpoints | Supported | Not supported; use mailbox or named pipe | | Named-pipe control endpoints | Not needed | Supported when recipe exposes one | | Process cancel/kill | Process group signal with pid fallback | Windows process-tree adapter |
Packaged recipes should prefer mailbox/wake behavior for portable control. Recipes that require FIFO, Unix shell tools, or platform-specific media backends should make that limitation visible in docs or diagnostics before launch.
Safety Boundary
pi-actors is local-first, not sandbox-first.
Commands execute directly without shell evaluation where possible, but trusted executables still run with the same system permissions as Pi. Only register commands, scripts, recipes, and paths you trust.
High-risk templates such as shells, interpreter eval modes, and broad filesystem mutation may surface warnings, but the runtime is not a security boundary. Recipe doctor also exposes advisory labels like risk.shell, risk.eval, risk.destructive_fs, risk.network, and risk.external_side_effect for operator review.
Prefer:
- Narrow commands;
- Explicit paths;
- Typed args;
- Bounded timeouts for bounded work;
- Explicit tool allowlists for sub-agents;
- Deterministic utility recipes for filesystem writes;
- Human approval for destructive or external side effects.
Non-Goals
pi-actors is NOT:
- A generic workflow DSL;
- A remote agent interoperability protocol;
- A heavyweight broker or chat subsystem;
- A sandbox;
- A facade that hides logs, artifacts, ownership, or local side effects;
- A polling-first async runner.
Its job is narrower: make trusted local capabilities addressable, messageable, inspectable, and reusable by agents.
Documentation
Start here:
Core docs:
License
MIT
