@sakiv/sagent

Governed multi-agent orchestration, map-reduce, and real-time status for Pi

Packages

Package details

extension

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

CI License: MIT

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

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, and sandboxed_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:

Requirements

  • Pi 0.84.2 or compatible
  • Node.js >=22.19.0
  • Bun 1.3.x for development
  • Git for worktree features
  • fd and rg for 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:

  • read
  • sandboxed_fd
  • sandboxed_rg
  • runtime-injected delegate_map_reduce when 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 8 shards per map
  • maximum 16 descendants per root
  • shared run-wide process semaphore
  • duplicate/recursive fingerprint rejection
  • ordered reducer input capped at 200 KB
  • best_effort or fail_fast policy
  • 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 status and --live open a focused in-place overlay in TUI (pnpm-like row updates). Escape closes it; the footer widget continues.
  • /sagent status --once prints one capabilities + snapshot dump.
  • In print/JSON/RPC modes, status emits one { "live": false, "snapshots": [...] } snapshot and does not create TUI components.
  • inspect includes 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:

  1. Explicit user billing override.
  2. OAuth in use and provider metadata declares isSubscription: true → subscription.
  3. 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.5 embeddings
  • real sqlite-vec KNN search
  • model/schema-triggered index rebuild
  • Project → Profile → Global precedence
  • explicit active AGENTS.md rules 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 directory fsync
  • 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:

  1. Orchestration profile / /sagent run --profile
  2. PI_PROFILE
  3. defaultProfile
  4. default

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 + directory fsync
  • 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 npm environment
  • 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_TOKEN fallback
  • 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 sagent extension 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