@sakiv/sagent
Governed multi-agent orchestration, map-reduce, and real-time status for Pi
Package details
Install @sakiv/sagent from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@sakiv/sagent- Package
@sakiv/sagent- Version
0.1.1- Published
- Aug 19, 2026
- Downloads
- 333/mo · 8/wk
- Author
- sakiv
- License
- MIT
- Types
- extension
- Size
- 268.3 KB
- Dependencies
- 4 dependencies · 3 peers
Pi manifest JSON
{
"extensions": [
"./extensions/sagent/index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
sagent — Smart Agent for Pi
sagent is a governed multi-agent orchestration extension for Pi. It runs specialized read-only agents in isolated Pi subprocesses, routes work across authenticated models, supports durable DAG and same-persona map-reduce execution, displays nested real-time status, and maintains local multi-tier knowledge.
The project is designed to fail closed: mutating agent dispatch and autonomous extension-code upgrades remain disabled until their separate safety gates are implemented and approved.
Contents
- Features
- Architecture
- Requirements
- Installation
- Quick start
- Agents
- Orchestration
- Real-time status
- Model routing and cost controls
- Knowledge system
- Governed self-improvement
- Commands
- Configuration
- Durable state and recovery
- Security model
- Development and testing
- Packaging and releases
- Troubleshooting
Features
| Capability | Status | Notes |
|---|---|---|
| Isolated read-only subagents | Enabled | Explorer, Architect, and human-approved read-only personas |
| Parallel and dependency-aware DAG tasks | Enabled | Up to configured global concurrency; eight-state durable lifecycle |
| Same-persona map-reduce | Enabled | Depth, shard, descendant, concurrency, spend, and recursion bounds |
| Provider/model load distribution | Enabled | Per-model/provider capacity, diverse fallback, and 429 cooldown |
| Real-time nested status | Enabled | Direct tasks, shards, reducers, tools, heartbeats, model, usage, and cost |
| Subscription-first model routing | Enabled | Live OAuth metadata; ambiguous auth defaults to metered |
| Metered spend approval | Enabled | Interactive pre-dispatch approval and delegated map budget |
| Git worktree and path-lease primitives | Implemented | Mutating dispatch remains gated |
| Project/Profile/Global knowledge | Enabled | Canonical Markdown/JSONL with local sqlite-vec cache |
| Persona candidates | Enabled with approval | Secret-scanned, digest-bound, strict read-only tools |
| Mutating builders | Disabled | No end-to-end mutating execution pipeline is active |
| Autonomous code upgrades | Disabled | /sagent upgrade reports the fail-closed gate only |
Architecture
User / Pi parent session
│
▼
sagent orchestrator
├── live model/auth router + spend gate
├── durable DAG manifest + leases/heartbeats
├── session-wide provider/model capacity manager
├── real-time status projection
└── isolated Pi subprocesses
├── Explorer
├── Architect
└── approved read-only personas
│
└── bounded same-persona map → reduce
Key safety properties:
- Child contexts are isolated Pi processes.
- Read-only personas receive only
read,sandboxed_fd, andsandboxed_rg. - Recursive map-reduce is injected at runtime from an HMAC-bound delegation envelope; personas cannot mint or expand it.
- Every task uses durable state transitions and bounded output.
- Provider/model concurrency and rate-limit state are shared within the Pi session.
- Vector indexes live outside synchronized knowledge roots.
- Code self-upgrades remain fail-closed.
Detailed design:
- Architecture blueprint
- Enhancement requirements
- Final architecture approval
- Self-improvement security boundary
Requirements
- Pi
0.84.2or compatible - Node.js
>=22.19.0 - Bun
1.3.xfor development - Git for worktree features
fdandrgfor sandboxed repository search- macOS or Linux; published CI covers Linux x64/arm64 and macOS arm64
The local vector worker uses better-sqlite3 and sqlite-vec. The npm installation must have native artifacts available for the host platform.
Installation
npm
The package name is @sakiv/sagent:
pi install npm:@sakiv/sagent
Current registry release: @sakiv/sagent@0.1.0 (v0.1.0 / a9b5266). This repository is 0.1.1 and is unpublished until a separate v0.1.1 tag and explicit publish.
Local package
git clone https://github.com/sakiv-io/sagent.git
cd sagent
bun install --frozen-lockfile
pi install "$PWD"
Temporary development load
pi -e ./extensions/sagent/index.ts
After installation in an already-running Pi session:
/reload
Verify:
/sagent status
Quick start
Ask Pi:
Use orchestrate with explorer to inspect this repository and summarize its architecture.
Or run through the command wrapper:
/sagent run Review the repository structure and identify the primary entrypoints.
/sagent run --profile engineering Review the repository structure.
Safe smoke test
This prompt creates a disposable fixture in the project, exercises both implemented built-in agents, and removes only the known fixture paths:
Run a safe sagent smoke test using the exact path .sagent-smoke-test.
Refuse if it already exists. Create README.md with SAGENT_SMOKE_TEST_MARKER,
src/example.ts with one exported pure function, and docs/notes.md.
Use one parallel orchestrate call with two Explorer tasks: inventory and marker/content search.
Then use Architect with the Explorer findings to propose a minimal CLI design.
Make no agent modifications. Finally remove only those three files, then the src, docs,
and fixture directories, and confirm test ! -e .sagent-smoke-test.
Agents
Explorer
Fast read-only reconnaissance and dependency mapping.
Tools:
readsandboxed_fdsandboxed_rg- runtime-injected
delegate_map_reducewhen depth remains
Architect
Read-only requirements analysis, architecture, task DAG, acceptance criteria, security considerations, rollback planning, and test strategy.
Tools are the same read-only set as Explorer.
Approved personas
/sagent approve promotes reviewed persona candidates to:
~/.pi/agent/agents/sagent/<name>.md
Approved personas are revalidated during discovery and cannot contain bash, write, edit, mutation, or candidate-only files.
Not active
Builder, Special Builder, QA, Accountant, Librarian, and Principal are architecture roles, but they are not dispatchable built-ins in this implementation. Do not assume they are active because they appear in design documents.
Orchestration
The orchestrate tool supports one direct task or a DAG of up to the configured limit.
Direct
{
"agent": "explorer",
"task": "Find the authentication entrypoints"
}
Parallel
{
"tasks": [
{ "id": "api", "agent": "explorer", "task": "Inspect the API layer" },
{ "id": "ui", "agent": "explorer", "task": "Inspect the UI layer" }
]
}
Dependency DAG
{
"tasks": [
{ "id": "verify", "agent": "explorer", "task": "Verify repository facts" },
{
"id": "plan",
"agent": "architect",
"task": "Produce the implementation plan from the supplied facts",
"dependsOn": ["verify"]
}
]
}
dependsOn controls scheduling; it does not automatically insert another task's output into the dependent task. Pass required findings explicitly when content chaining is needed.
Same-persona map-reduce
For genuinely complex independent work, an eligible child agent may call delegate_map_reduce. The dispatcher enforces:
- same persona as the parent
- maximum depth
2 - maximum
8shards per map - maximum
16descendants per root - shared run-wide process semaphore
- duplicate/recursive fingerprint rejection
- ordered reducer input capped at
200 KB best_effortorfail_fastpolicy- partial-coverage and provenance reporting
The model cannot add this tool through persona frontmatter. It is present only when a signed runtime envelope has remaining depth.
Metered map-reduce
Nested metered delegation defaults to $0. To permit it, the root tool call sets:
{
"mapReduceMeteredBudgetUsd": 1.0
}
Pi asks for interactive approval. Descendants reserve projected costs from the shared bound. Retries reserve additional projected cost conservatively.
Real-time status
While tasks run, the TUI shows a widget such as:
sagent swarm · 2 active · 3 tracked
▸ ● explorer/root · streaming … · 4s · Reading repository structure
↳ ✓ explorer/api · complete 1/1 · 3s · provider/model · $0.0004
↳ ● explorer/ui · map-streaming … · 2s · Searching UI files
Status comes from actual task transitions, process events, model attempts, tool start/end, heartbeats, shard/reducer events, and terminal states. Unknown progress remains indeterminate; elapsed time is never converted into a fake percentage.
Commands:
/sagent status
/sagent status --live
/sagent status --once
/sagent runs
/sagent inspect <run-id>
/sagent statusand--liveopen a focused in-place overlay in TUI (pnpm-like row updates). Escape closes it; the footer widget continues./sagent status --onceprints one capabilities + snapshot dump.- In print/JSON/RPC modes, status emits one
{ "live": false, "snapshots": [...] }snapshot and does not create TUI components. inspectincludes linked map manifests and artifact locations.
Activity/error summaries are secret-scanned and capped at 200 characters. Full prompts, environment variables, credentials, approval values, and raw stacks are excluded.
Model routing and cost controls
Routing uses Pi's live model registry:
- Explicit user billing override.
- OAuth in use and provider metadata declares
isSubscription: true→ subscription. - Everything else → metered.
The router scores task fit, preferred model, subscription availability, context/capabilities, throughput, and projected cost.
Defaults:
| Control | Default |
|---|---|
| Session metered limit | $2.00 |
| Confirmation on metered fallback | true |
| Parallel read-only processes | 4 |
| Concurrent requests per exact model | 2 |
| Concurrent requests per provider | 3 |
| Rate-limit cooldown | 60s |
If the preferred model or provider is saturated, sagent tries an eligible different provider/model before waiting. A 429/rate-limit result cools down that model and provider and triggers a diverse fallback when available. All fallbacks still obey scoped models, capabilities, billing approval, and the read-only failover boundary.
Inspect classifications:
/sagent models
Knowledge system
Canonical sources:
| Scope | Markdown | Event log |
|---|---|---|
| Project | ${cwd}/.pi/AGENTS.md |
${cwd}/.pi/knowledge-events.jsonl |
| Profile | ~/.pi/profiles/<profile>/AGENTS.md |
profile knowledge-events.jsonl |
| Global | ~/.pi/agent/AGENTS.md |
global knowledge-events.jsonl |
Derived vector indexes are strictly local:
~/.cache/sagent/vectors/projects/<project-hash>/db.sqlite
~/.cache/sagent/vectors/profiles/<profile>/db.sqlite
~/.cache/sagent/vectors/global/db.sqlite
Features:
- pre-write secret/high-entropy scanning
- append-only durable JSONL events
- deterministic UUIDv5 chunks
- tombstones
- threshold compaction at 300 lines or approximately 15,000 tokens
- local
Xenova/bge-small-en-v1.5embeddings - real
sqlite-vecKNN search - model/schema-triggered index rebuild
- Project → Profile → Global precedence
- explicit active
AGENTS.mdrules always outrank retrieved snippets
Commands:
/sagent knowledge rebuild project
/sagent knowledge rebuild profile
/sagent knowledge rebuild global
/sagent knowledge query "worktree policy"
The first BGE use may download model artifacts; inference is local afterward.
Governed self-improvement
Persona candidate lifecycle
/sagent candidate api-reader
/sagent approve api-reader <sha256-digest>
/sagent reject api-reader
Candidate properties:
- staged disabled as
.candidate.md - secret-scanned before write
- read-only tool subset only
- explicit
mutating: false - approval bound to one read-once buffer and exact SHA-256 digest
- atomic temporary write, file
fsync, rename, and directoryfsync - candidate file removed after promotion
Self-documentation
Candidate-only capability documents are stored beneath:
~/.local/share/sagent/candidates/self-docs/<run-id>/
Proposal fingerprints require at least three distinct evidence occurrences.
Code upgrades
/sagent upgrade
This command reports platform sandbox availability and the reason upgrades remain disabled. It does not build, approve, activate, reload, or roll back extension code. The supervisor described in the architecture is future gated work.
Commands
| Command | Purpose |
|---|---|
/sagent |
TUI command browser with shortcuts; help in non-TUI |
/sagent help |
Commands, shortcuts, examples, and package version |
/sagent status |
Live in-place agent overlay (default) |
/sagent status --live |
Alias of /sagent status |
/sagent status --once |
One-shot capabilities and snapshot |
/sagent run [--profile <name>] <task> |
Ask Pi to start orchestrated work |
/sagent runs |
List recent durable run summaries |
/sagent inspect <run-id> |
Show root and linked map tasks/artifacts |
/sagent models |
Show available model billing classifications |
/sagent knowledge rebuild <scope> |
Rebuild one local vector index |
/sagent knowledge query <text> |
Query Project/Profile/Global indexes |
/sagent candidate <name> |
Interactively stage a disabled persona |
/sagent approve <name> <digest> |
Promote exact reviewed persona bytes |
/sagent reject <name> |
Remove a candidate |
/sagent upgrade |
Show fail-closed upgrade status |
/reload |
Reload installed Pi resources/extensions |
Configuration
Shipped settings: extensions/sagent/config/settings.json.
| Key | Default | Meaning |
|---|---|---|
defaultProfile |
default |
Profile after explicit override and PI_PROFILE |
maxParallelReadOnlyAgents |
4 |
Run-wide process ceiling; hard maximum 8 |
maxConcurrentPerModel |
2 |
Session capacity per exact model; hard maximum 4 |
maxConcurrentPerProvider |
3 |
Session capacity per provider; hard maximum 8 and never below model limit |
rateLimitCooldownMs |
60000 |
Provider/model cooldown after 429 |
statusRetentionMs |
30000 |
Terminal rows retained in the TUI |
subagentStallTimeoutMs |
30000 |
No-event subprocess timeout |
searchTimeoutMs |
10000 |
fd/rg timeout |
enableMutatingAgents |
false |
Must remain false in this implementation |
enableAutonomousUpgrades |
false |
Must remain false in this implementation |
Billing policy: extensions/sagent/config/billing-policy.json.
Profile precedence:
- Orchestration
profile//sagent run --profile PI_PROFILEdefaultProfiledefault
The resolved PI_PROFILE is exported to child processes. PI_CODING_AGENT_DIR is not mutated.
Durable state and recovery
Run manifests and artifacts:
.pi/runs/<run-id>/manifest.json
.pi/runs/<run-id>/artifacts/
.pi/runs/<root-run-id>-map-<id>/
Properties:
- single-writer in-process update queue
- atomic temp write + file
fsync+ rename + directoryfsync - eight states:
PLANNED,READY,RUNNING,SUCCEEDED,FAILED,RETRYING,BLOCKED,CANCELED - process identity, heartbeat, and lease expiry
- parent/root/depth/task-kind/progress/activity fields
- startup state reclamation from dead owners and expired leases
Recovery is state reclamation, not automatic replay. Interrupted RUNNING tasks become RETRYING or FAILED; users must re-invoke orchestration because manifests do not yet persist a complete replay-safe prompt/routing envelope.
Runtime-owned .pi/runs/ and .pi/worktrees/ are excluded from clean-tree checks.
Security model
The approved threat model is Option B:
- The active human-approved extension and same-user interactive processes are trusted.
- Generated candidates, dependency scripts, builds, and test environments are untrusted.
- Current safeguards isolate read-only candidates and fail closed; they do not claim protection from a malicious active same-user extension.
Important controls:
- no-shell search process invocation
- lexical and realpath/symlink workspace confinement
- output, line, event, timeout, and concurrency bounds
- secret scanning for knowledge, status, candidates, and artifacts
- HMAC-bound delegation envelopes with expiry and depth
- cross-process stale-owner reclamation
- provider/model capacity and cooldown
- explicit metered approval
- digest-bound atomic persona promotion
- mutation and code-upgrade kill gates
Do not install untrusted Pi extensions. Pi extensions execute with the user account's system permissions.
Development and testing
git clone https://github.com/sakiv-io/sagent.git
cd sagent
bun install --frozen-lockfile
bun run verify
Useful scripts:
bun run check # TypeScript
bun test # Test suite
bun run verify # TypeScript + all tests
bun run verify:package # Pack and inspect the npm allowlist
bun run smoke:package # Install packed contents in a clean temporary Pi home
npm publish --dry-run --access public --ignore-scripts
Temporary load:
pi -e ./extensions/sagent/index.ts
The test suite covers path confinement, no-shell search, routing/billing, provider/model capacity, worktrees/leases, durable manifests, DAG/recovery, QA gates, knowledge/vector search, persona governance, map-reduce, status/TUI projection, and packaging workflows.
Packaging and releases
CI installs pinned fd/rg release binaries, then runs frozen install, tests, tarball verification, and packed-extension smoke tests on:
- Linux x64
- Linux arm64
- macOS arm64
Publication is explicit only:
- published GitHub Release or manually dispatched Publish npm package
- manual dispatch confirmation
PUBLISH - protected GitHub
npmenvironment - after a successful publish, annotated tag
v<package-version>is created on that commit if missing - existing npm version is rejected
- npm provenance enabled through Trusted Publishing
- publish-step-only
NPM_TOKENfallback - tarball and SHA-256 uploaded as workflow artifacts
No workflow publishes from an ordinary push to main, and no workflow automatically increments versions.
See RELEASING.md for setup, semantic versioning, first-publish confirmation, verification, deprecation, and rollback.
Troubleshooting
/sagent is missing
Confirm installation:
pi list
Then run /reload or restart Pi. For local development, use pi -e ./extensions/sagent/index.ts.
If profile routing is active, Pi may use another PI_CODING_AGENT_DIR with different settings. Inspect:
printenv PI_CODING_AGENT_DIR
A stale tmux server environment can preserve an old profile value. Start Pi with the intended profile or unset the variable before launch when appropriate.
orchestrate is not visible to the model
- Verify the
sagentextension appears in Pi's startup extension list. - Check active tools and reload.
- Confirm the current profile's package settings include sagent.
Metered dispatch is blocked
Use an interactive TUI session to approve metered work. Non-interactive modes fail closed. For nested metered map-reduce, explicitly provide and approve mapReduceMeteredBudgetUsd.
Vector worker fails
- Confirm Node
>=22.19.0. - Reinstall dependencies for the current OS/architecture.
- Run
bun run smoke:package. - Delete only the affected derived cache under
~/.cache/sagent/vectors/and rebuild; canonical Markdown/JSONL remains authoritative.
Worktree creation is refused
The primary Git workspace must be clean, and .pi/worktrees/ must be ignored. Commit or stash user changes first. sagent never auto-stashes a dirty tree.
Interrupted run shows RETRYING
This is reclaimed state, not automatic resumption. Re-run the original orchestration request.
Rate limits
sagent automatically limits concurrent identical model/provider requests, marks 429 cooldowns, and tries diverse eligible fallbacks. If all eligible models are cooling down or full, work waits for capacity or obeys cancellation.
License
MIT © 2026 Vikas Aggarwal