(AI generated. Not reviewed.)
Pi Agent Harness Architecture
Status: design doc for #2071. No runtime implementation in this change. Date: 2026-06-14. Scope: how Fichero adopts Pi (
pi.dev) as the in-app agent harness while preserving the existing local-model, action-registry, audit, ACL, and undo architecture.
Decision
Adopt Pi as Fichero’s in-app agent loop harness, hosted behind Fichero’s backend contracts and local-model policy.
Pi should sit between the selected model profile and Fichero’s audited tool surface:
Fichero app
-> Fichero backend agent-run API
-> local provider profile / app-managed MLX-oMLX service
-> Pi runner process
-> Fichero Pi packages
-> action-registry-backed tools
The important boundary is not “Pi can call tools.” The important boundary is that Pi can only mutate a library through the same action registry used by the UI, CLI, workflows, App Intents, tests, audit log, ACL checks, and undo path.
Source Facts and Constraints
The manager-verified Pi read for this issue:
- Pi is a minimal terminal coding harness.
- Pi supports TypeScript extensions, skills, prompt templates, themes, packages, custom models/providers, programmatic SDK, RPC, and JSON event stream modes.
- Pi intentionally omits sub-agents and plan mode so users or packages can add those in the shape they want.
- OpenClaw is the reference real-world SDK integration.
- OpenClaw’s docs emphasize runtime boundaries and plugin SDK boundaries.
Fichero’s already-shipped constraints:
-
2058: dynamic model profiles and provider selection exist.
-
1814 / #2199: local inference profiles, typed local-inference contracts, and
an app-managed local-service manager exist for local MLX/oMLX-style providers. -
1848:
ActionRegistryis the single audited write path. -
2015: registry-driven undo exists for undoable action audits.
-
2022 / #2023 / #2024: accounts, actor attribution, and ACL checks are part
of the write boundary. -
2074: grouped undo is the right follow-up for agent-run-level reversal.
Goals
- Run the in-app agent on the selected local model profile by default.
- Keep local-only / no-cloud enforcement in the backend, not in the UI or prompt.
- Let Pi provide the loop, package, skill, prompt-template, event-stream, and extension machinery.
- Expose Fichero domain tools through Pi packages generated from typed backend contracts.
- Make manager-with-workers and plan mode Fichero-owned Pi extensions.
- Stream agent sessions, plan state, worker activity, model calls, and tool calls into the app through backend event contracts.
- Treat agents as accountable principals, not anonymous background code.
- Make agent writes auditable, ACL-checked, and undoable by construction.
Non-Goals
- No Mac/SwiftUI implementation in this design slice.
- No direct runtime Pi integration in this design slice.
- No cloud-provider enablement.
- No second mutation registry, filesystem-write API, shell bridge, or hidden local bypass for Pi.
- No replacement of the existing
llm.py, local-inference, workflow, action, auth, or change-stream primitives.
Embedding Choice: RPC Boundary, SDK Inside the Runner
Use Pi RPC / JSON event stream as Fichero’s embedding boundary.
Use the Pi SDK inside a small TypeScript Pi runner/package layer, not as a library imported directly into the Python backend.
Rationale:
- Fichero’s backend is Python/FastAPI with typed Pydantic/OpenAPI contracts.
- Pi’s extension/package ecosystem is TypeScript-native.
- RPC keeps the Python backend and Pi runtime as separate failure domains.
- JSON event streaming matches Fichero’s existing SSE/change-stream direction.
- The SDK remains useful where it belongs: inside the Pi runner and Fichero Pi packages that adapt Pi extension APIs to backend HTTP/action contracts.
Concretely:
- The backend owns
AgentRuncreation, profile resolution, ACL context, and event persistence/stream fan-out. - The backend launches or connects to a Pi runner process with a resolved local model endpoint and a Fichero package manifest.
- The Pi runner uses Pi’s SDK/package APIs to run the loop and emit structured events.
- Fichero consumes the Pi event stream and republishes app-facing typed events.
- Tool calls from Pi go back through backend action/tool endpoints, never directly to DuckDB, LanceDB, or library files.
Model and Privacy Boundary
The selected Fichero model profile is the authority. Pi must not independently decide to use a cloud model when the run is local-only.
Run startup order:
- Resolve the requested model profile through Fichero’s existing provider profile machinery.
- If the profile is local-managed, ensure the local MLX/oMLX service is healthy through the local-inference service manager.
- Reject startup if
local_only=Trueand the resolved provider is not builtin/local/loopback. - Pass Pi only the effective model endpoint and credentials allowed by the profile.
- Record the effective provider, model, profile id, local-only flag, and fallback policy in agent-run metadata.
Rules:
- A local-only Pi run fails loudly if the local service is unavailable.
- Pi packages must not carry their own cloud API keys.
- Remote model providers are allowed only in an explicitly cloud-permitting profile selected by the user.
- Paid fallback remains profile-gated and visible. It is never a package-level convenience fallback.
- Package install/update operations are not runtime model-provider authority.
Fichero Pi Packages
Fichero should ship Pi packages in narrow layers:
| Package | Responsibility | Boundary |
|---|---|---|
fichero-tools |
Read tools and action-registry-backed write tools | Calls backend typed endpoints only |
fichero-skills |
Domain skills for research, transcription, extraction, curation, reconciliation | Prompts/workflows; no direct mutation |
fichero-planner |
Plan mode, task decomposition, approval checkpoints | Emits plan events; delegates writes to tools |
fichero-workers |
Manager-with-workers orchestration | Bounded worker sessions; inherits run policy |
fichero-themes |
Optional Pi terminal/app presentation themes | No tool authority |
Package rules:
- Packages declare capabilities they need: read, write, network, model, worker, package-install.
- Write-capable package tools are generated from the backend action registry or hand-authored as thin wrappers over registered actions.
- Read tools may use typed backend read endpoints and search/KG APIs.
- Packages do not get raw filesystem access to library package contents.
- Packages do not get database handles.
- Packages do not get unrestricted shell execution.
- Package version, checksum/source, enabled state, and requested capabilities should be persisted so an agent run is reproducible and auditable.
Tool Surface: Action Registry Only for Mutation
Pi’s tool list should be derived from Fichero’s backend tool authority:
- Read-only tools: search, KG lookup, document/page read, model-comparison summaries, workflow status, and safe metadata inspection.
- Write tools: only
ActionRegistryactions exposed through typed schemas. - Workflow tools: allowed when they already enforce model/profile policy and emit activity/progress events.
Write call flow:
Pi tool call
-> Fichero Pi tool wrapper
-> backend action invoke route
-> ActionRegistry.invoke(...)
-> authz / ACL checks
-> domain action
-> ActionAudit row with actor + run_id
-> change-stream event
-> optional undo path
Disallowed:
- Direct DuckDB/LanceDB writes from Pi packages.
- Direct file mutation in
.ficherolibraries. - A Pi-local “actions” registry with different permissions semantics.
- Tool arguments hidden in
additionalPropertiesinstead of declared schemas. - Best-effort audit on successful mutation. If audit fails, the action fails.
Plan Mode and Manager-Worker Mode
Pi intentionally omits plan mode and sub-agents. Fichero should add them as Pi packages/extensions so the behavior matches Fichero’s manager/worker operating model instead of importing a generic agent hierarchy.
Plan mode package:
- Builds a typed plan with steps, required tools, risk flags, and approval checkpoints.
- Emits plan events before execution.
- Can be paused, revised, approved, rejected, or converted into worker tasks.
- Must perform privacy/cost preflight before any model/tool execution that could leave the machine or mutate the library.
Manager-worker package:
- One manager owns the user-facing run and event stream.
- Workers inherit the manager’s model profile, local-only policy, package allowlist, actor context, ACL scope, and run id.
- Workers can be restricted by tool subset, document scope, and budget.
- Workers cannot escalate model locality, install packages, or widen ACL scope.
- Worker outputs return to the manager as events/artifacts before any write is executed.
This maps the current session-start-manager/worker discipline into the app: planning and delegation are product features, but mutation remains a backend action.
Event and Session Streaming
Fichero should normalize Pi events into backend-owned agent events before the app renders them.
Minimum event kinds:
agent.run.startedagent.plan.proposedagent.plan.updatedagent.worker.queuedagent.worker.startedagent.model.requestedagent.model.completedagent.tool.requestedagent.tool.validatedagent.action.executedagent.approval.requiredagent.package.loadedagent.package.rejectedagent.undo.group.createdagent.run.completedagent.run.failed
Each event should carry:
run_idsession_idparent_run_id | Noneworker_id | Noneactor_idprofile_idprovidermodellocal_onlypackage_id | Nonetool_name | Noneaction_audit_id | Noneundo_group_id | None- redacted payload / summary
The app should subscribe to the backend event stream, not directly to a Pi process. That lets Fichero persist, redact, replay, and authorize event data consistently.
Agents as Principals
Agent runs must be accountable identities at the action boundary.
Recommended model:
- The authenticated human user remains the owner/on-behalf-of principal.
- Each agent run gets an
agent:<run_id>principal derived from that user. - Each worker gets an
agent:<run_id>:worker:<worker_id>actor id. ActionContext.actorrecords the effective agent actor.- Audit metadata records the human initiator, agent actor, role, profile, model, package versions, and run id.
- ACL checks use the effective actor plus the user’s delegated scope. Agents do
not bypass
authz.assert_can_write.
This keeps actor attribution transparent: a user can distinguish “Daniel edited this” from “agent run 123 worker 2 edited this on Daniel’s behalf.”
Grouped Undo Implications
Current registry-driven undo is per action audit. Agent runs need a grouped layer on top, not a replacement.
Target behavior:
- Every write action inside a Pi run stores
run_id. - A grouped undo record orders the action audit ids created by the run.
- “Undo run” applies inverse actions in reverse order through the existing undo endpoint/path.
- Partial failure leaves a visible grouped-undo state, not silent cleanup.
- A user can still inspect and undo individual actions when that is safer than undoing the full run.
Design implication for #2074:
- Add
undo_group_idor equivalent grouping metadata before large agent-write surfaces ship. - Grouping should be run-scoped and optionally phase-scoped: plan, worker, final-apply.
- Grouped undo must preserve the per-action audit chain and redo semantics from #2015.
OpenClaw Reference Lessons
Use OpenClaw as an integration reference, but do not clone its product shape. The lessons to carry over:
- Keep the host application boundary explicit.
- Put plugin/SDK capabilities behind declared interfaces.
- Treat runtime process boundaries as safety boundaries.
- Stream activity as structured events, not terminal text scraping.
- Keep package/plugin authority narrower than application authority.
For Fichero this means Pi is a harness under Fichero’s policy, not the policy engine. The backend remains the authority for model profile, local-only mode, actions, ACL, audit, and undo.
Staged Backend Implementation Slices
P0. Architecture and contracts
- Land this document and architecture links.
- Define
AgentRun,AgentSession,AgentEvent,AgentPrincipal, andAgentPackageRefPydantic shapes. - Define allowed event kinds and redaction rules.
- Decide the persisted location for agent-run metadata versus ephemeral stream buffers.
P1. Pi runner process boundary
- Add a backend
PiRunnerabstraction with fake runner tests. - Launch/connect to a local Pi runner process via RPC/JSON event stream.
- Pass only backend-resolved model endpoint/profile metadata to the runner.
- Refuse startup when local-only/profile invariants fail.
- Normalize runner events into Fichero
AgentEventrecords.
P2. Fichero tools package
- Generate or hand-author the first
fichero-toolspackage from a small allowlist of action-registry actions plus read-only tools. - Validate tool arguments against declared Pydantic/OpenAPI schemas.
- Thread
ActionContext(actor, run_id, origin_window, library_path)through every write tool. - Test that attempted direct mutation and unknown tools are rejected.
P3. Session streaming and audit UI contract
- Persist agent-run events enough for replay/inspection.
- Stream normalized events to the app-facing endpoint.
- Include model/provider/profile/package/action audit metadata in events.
- Add redaction tests for prompt/tool payload fields that may contain user data.
P4. Plan and manager-worker packages
- Implement plan mode as a Fichero Pi package with typed plan events.
- Implement manager-with-workers as a Fichero Pi package.
- Enforce inherited policy for workers.
- Add tests for worker scope, budget, model-profile inheritance, and forbidden policy escalation.
P5. Grouped undo and agent principals
- Add grouped undo metadata for run-scoped action audits.
- Add explicit agent principal records or derivation helpers.
- Prove ACL checks still run for agent actions.
- Prove “undo run” reuses the existing audited undo path in reverse order.
P6. Package lifecycle hardening
- Persist package source/version/checksum/capabilities.
- Add package allowlist and capability approval.
- Add package reload/update behavior that cannot silently widen authority for an already-running agent session.
Test Plan for Runtime Follow-Ups
- Unit tests for model-profile/local-only enforcement before Pi startup.
- Fake Pi runner tests for start, event stream, malformed event, crash, and timeout handling.
- Contract tests for
AgentRun/AgentEventPydantic models and OpenAPI schema generation. - Action tool tests proving writes go through
ActionRegistry.invoke. - Authz tests proving agent actors cannot write outside delegated scope.
- Actor attribution tests proving audit rows store agent actor and human initiator metadata.
- Grouped undo tests across multiple action domains.
- No-network tests proving local-only Pi runs cannot resolve cloud providers or package-supplied cloud keys.
- Package capability tests for read-only, write, worker, package-install, and network permissions.
Open Questions
- Exact Pi runner installation location and packaging mechanism for the Mac app.
- Whether package install/update should be app-managed only or exposed to advanced users inside Fichero.
- How much of existing LangGraph-based workflow agent tooling should be retired, wrapped, or kept as workflow-only once Pi is the app agent harness.
- Event retention policy for large agent runs that may emit many model/tool events.
- Whether package capability approval is global, per-library, or per-run.
Decision Summary
Pi becomes the loop and package harness. Fichero remains the authority.
The safe architecture is:
- backend-resolved local model profile
- RPC/JSON boundary to a Pi runner
- Pi SDK inside Fichero Pi packages
- action registry as the only mutation tool surface
- backend-normalized event streaming
- agent actors with ACL and audit context
- grouped undo layered over existing per-action undo
This gives Fichero Pi’s customization model without weakening the existing local-only, typed-contract, audit, and undo commitments.