Maia Agent architecture
Status: Source candidate: local maia agent on the official Pi SDK 1.0.0 with digest-pinned resources from .maia/maia.json, the maia-agent-worker managed worker, Node's two Pi Session adapters and maia login <model-provider> (current implementation). Planned: the context and resource contract (R1, R11 AG1–AG3), owner-aware Sessions and delegation (R3), maia session attach (S12), coordinator learning (R4), agent-callable evaluation (R10a) and the daily Pi-harness replacement (R11). Everything outside "Current implementation" is target design.
Outcome
maia agent is Pi rebranded for Maia: the official Pi SDK interaction and extension model behind Maia's one executable (decision). One kernel serves two uses:
- a local CLI process for Pi-style work;
- the worker that Maia Node runs for durable Agent Sessions.
Rules:
- Pi extensions are the only customization boundary. They register tools, slash commands, CLI flags, shortcuts, renderers, providers and lifecycle hooks through the upstream Pi API. Maia's own kernel extensions use the same API. There is no parallel plugin system.
- At runtime Maia never reads or writes
~/.pi. Pi Sessions use the Pi package bundled with Maia. Only the separately authorized Pi RPC runtime probe runs an installedpi, after matching it to a human-approvedpi-rpcintegration authorization. The R11 inventory is an explicitly authorized, read-only migration inspection outside runtime. - Maia owns its configuration and state paths, resource admission, authentication references, safety policy, receipts and lifecycle.
- Maia Node owns durability, Maia Swarm owns multi-Project orchestration and Providers owns Connections and login. Launch flags, interactive commands, model tools and JSON results are specified once in the CLI reference.
- There is no separate Fleet, Workflow, Task-graph or Subagent product.
taskis a Session-local work ledger, not Swarm scheduling truth. A sub-agent is a normal Agent Session linked byparentSessionId. - v1 workers are vendor executors (Codex CLI, Claude Code) (decision). Maia Agent becomes the native worker backend in later slices; its Node adapters are source candidates today.
- The daily Pi-harness replacement is a reviewed feature port, not a profile import: see the R11 migration procedure. The capability disposition is the only feature mapping.
Agent nouns (Workspace, Project and execution nouns are in product vocabulary):
| Concept | Meaning |
|---|---|
| Agent | Versioned model policy, tools, project-instruction policy, eligible Skills, limits and peer permissions |
| Agent Session | One stateful Agent instance with an exact resolved snapshot and an optional parent Session |
| Routine | Manual or cron trigger that starts an Agent Session or wakes one exact idle Session |
Current implementation
The Agent README is the package overview. The launch grammar is in the CLI reference.
- Every entry sets
PI_OFFLINE=1andPI_SKIP_VERSION_CHECK=1. That stops Pi's update, telemetry and tool-download traffic, not the model provider the user selects. Embed the package in a process dedicated to the agent. - Project extension code runs with the agent process's operating-system permissions, so review it before pinning its digest. Extensions cannot bypass the Node's authorization, confirmation, compare-and-set, idempotency or receipts.
Local maia agent
- A terminal runs Pi
InteractiveMode.--printand--json-eventsrun Pi print mode with text or JSON event output. MAIA_HOME(default~/.maia) holdsauth.json(provider credentials) andconfig.toml([agent] modelsets the default model) (decision).MAIA_AGENT_HOME(default$MAIA_HOME/agent) is Pi's agent directory. It holdsmodels.json, local session files undersessions/<sha256 of the working directory>/andtask/goalstate understate/sessions/<session id>/.--continueresumes the most recent local session for the working directory.--no-sessionkeeps the session in memory. Local session files are not Node Sessions: no recovery, background execution, ordered events or receipts.maia agent loginopens the interactive agent so the user can type/login.maia login <model-provider>(source candidate) uses the same Pi provider sign-in and stores one credential per provider in$MAIA_HOME/auth.json(decision).
Resource loading
- Pi resource discovery is off: no discovered extensions, Skills, prompt templates, themes, context files or
.pi/SYSTEM.mdandAPPEND_SYSTEM.mdprompt files. Settings are in memory, and Pi's agent directory is the Maia-owned one, never~/.pi/agent. - Pi's built-in codemode, llama.cpp, MCP and tool-search extensions never load: Maia does not register them and requests none (decision).
- Kernel extensions always load: destructive-command safety guard,
task,goal,processand bounds on Pi'sfindandgrep(80 hits by default, 200 at most, above 80 only with a path or glob), which stay inactive until Maia owns theirfdandrgbinaries. The standalonemaia agentalso gets the/goaland/taskscommands, boundedmaia_goalandmaia_tasksprompt sections (untrusted, digest-framed, at most 2 KiB each) and naming of an unnamed session from its first request; the managed worker leaves commands, context and Session metadata to the Node. These are reviewed ports with provenance (port record). - The nearest ancestor with
.maia/maia.jsonis the Project root. The file must setschemaVersion: 1,agent.runtime: "pi"andagent.transport: "managed".agent.resources.skillslists Skill paths under.maia/. Unless-neis set,agent.resourcesmust also setextensionPolicy: "explicit",extensionRoot(relative, inside.maia/) and anextensionslist of paths under that root. - Every listed path is relative, stays inside its root, contains no symbolic links and matches its
sha256:digest. A mismatch or an extension load error stops startup.maia agent extension digest <path>prints a digest. -e <path>adds an explicit extension.-neskips the configured Project extensions without resolving them; kernel extensions, explicit-epaths, Skills andAGENTS.mdstill load.AGENTS.md: everyAGENTS.mdfrom the Project root down to the working directory loads at startup. Without.maia/maia.json, the root is the nearest.gitancestor, else the working directory. This differs from the target: one root file plus at most one nearest nested file.- Agent definitions: S49's Agent definition is the one public contract. The managed worker's protocol
maia.agent-definition/v1, a compatibility contract that R11 AG1 maps onto S49 or retires, haskey,name,prompt(at most 16 KiB),provenance, up to 32requestedOperationIds, up to 32skillRefsandversion. Node resolves only the shippedmaiav1 definition.maia session create --agent-definition <key> --agent-definition-version <version> --agent-definition-digest <sha256>records that exact reference as metadata; starting a Session bound to a definition is refused withcommand_not_implemented.
Managed worker and Node adapters
maia-agent-worker(packages/agent/src/managed-worker/) runs one official Pi session over NDJSON protocol version 1. The Pi session and credentials stay in memory; durable history comes from Maia; the worker never writesauth.json.taskandgoalstate go under the Node-supplied agent directory. Protocol v1 bounds input frames to 64 KiB, prompts to 48 KiB, responses to 32 KiB and output to 1 MiB; the target worker protocol replaces it.- Node picks a Pi adapter by host (harness README):
- macOS:
harness/pi-rpc/runs the bundled official@earendil-works/pi-coding-agent1.0.0 CLI in--mode rpcunder the cooperativecooperative_pi_rpc_conversationtier, with tools, extensions (Pi's built-in ones included), Skills, prompt templates, themes and context files disabled. Node issues each launch authorization itself. - Linux x64 and Windows x64:
harness/pi-managed/launches the packagedmaia-agent-workerunder hard containment.
- macOS:
- Without a tool projection the worker builds the same kernel session as local mode. The internal
session.show/v1selector instead gives it only a zero-argumentsession_showtool backed by an operation port to Node. Node-bound activation stays denied pending policy integration.
Runtime compositions
Local mode
terminal -> maia agent -> Maia Agent kernel -> Pi SDK session -> model and tools
Local mode uses the same Pi interaction and extension contracts as managed mode. Its session files never claim Node recovery, background execution, ordered events or receipts.
Managed mode
maia CLI/SDK -> Maia Node durable Agent Session -> disposable worker -> Maia Agent kernel -> Pi SDK session
The worker receives one exact activation, rebuilds bounded history from the agent's own Pi session through its reader, checked against the Node's trace (AG3a, D-168), streams structured events and closes the Pi session. It never owns durable identity or SQLite state.
Peer and coordinator Sessions (R3)
- An Agent may start same-Project child or eligible peer Sessions through the registry-backed agent tools (
start_agentand its siblings) (one peer-agent protocol). Node and Swarm admit and persist managed requests. Local in-process supervision claims no durability or isolation. - Delegation only narrows authority. Swarm's peer-agent protocol owns the admission limits; the Agent definition narrows them further.
- Cross-owner work uses parent-mediated delegation, never a sibling grant. Maia is the coordination hub through which agents and harnesses delegate (decision).
- Maia, Workspace and Project coordinators reuse the kernel as separate owners: each has its own principal, Session, context, instructions, Skills, tool manifest, credential handles and budgets (decision). Reuse never shares a conversation. A Project reads no sibling Project's history, titles, memory or content, and discovers siblings only through the bounded peer directory when both Projects allow Workspace reach (D-166); a Workspace sees only its own Projects. Workspace and global variants need explicit schemas before activation. Runtime isolation also needs the Node containment contract.
- Ordinary Workspace Sessions follow the ownership contract. Activation binds the real Workspace owner, never a fabricated Project. A conversation-only activation grants no shell or file access.
Agent-callable evaluation (R10a)
Explicitly granted coordinators and bots may call the shared evaluation service. Execution workers get no evaluation tools; central services use it on their behalf. Rules are in agent use and bounded composition. No tool name is claimed until the protocol-to-agent slice passes.
Agent definitions
Target definitions live in .maia/agents/<id>/agent.jsonc (layout, schemas). How the target schema relates to the current maia.agent-definition/v1 (requestedOperationIds versus toolGrants, skillRefs versus skills.eligibleRefs) is open for R3 to decide. Target fields:
schemaVersion,idanddisplayNameidentify the definition.modelselects an allowedconnectionRefand amodelIdresolved at validation.roledescribes the Agent; it grants nothing.toolGrantslists exact operation IDs. Each agent tool registers only when its mappedsession.*operation is granted.skills.eligibleRefslists exact Skill references. A definition cannot preload Skill bodies.peerPolicylistsmayStartRefsandmayMessageRefs.homeSession: trueasks Swarm for one canonical home Session per exact owner and definition (home Sessions).childCompletionPolicyiswait(default),request-stopordetach-to-project. A child may only narrow it (detach-to-projecttorequest-stoptowait). On parent completion Node recordssession.child.waiting,session.child.stop-requestedorsession.child.detachedwith both Session revisions and a receipt. Detach clearsparentSessionIdonly after Project admission succeeds; on failure the child stays attached and parent completion is blocked.limitssetsmaxChildDepth,maxLiveChildren,maxWallTimeMsandmaxOutputBytes.
EVAL.md (planned; scheduled by roadmap slice S62) sits beside an Agent or Routine definition. It is evaluator-only and never enters operational context. Its closed frontmatter declares schemaVersion, subject, traceClasses, sampling (algorithm, maxCases) and rubric (id, weight). Unknown trace classes, unbounded sampling or executable content fail validation. Evaluation runs are owned by Node.
Resolution order is fixed:
discover explicit roots -> parse closed schemas -> canonicalize and contain paths
-> resolve exact namespaced references -> apply typed narrowing
-> validate hard gates -> compile context and resource manifests
-> freeze snapshot digest -> authorize and admit or reject
Configuration resolution
Schemas and the resource resolution order are in configuration contracts. Authority layers apply in this order:
- immutable Maia safety and default contract;
- Node operator policy;
- admitted user preferences and explicitly referenced user resources from
~/.maia/; - Project configuration and resources;
- exact activation overrides.
Merge rules:
- Later layers may narrow authority and choose among allowed Connections and models. They cannot raise operator limits.
- Scalar preferences take the highest allowed layer. A resource reference resolves to one exact namespaced resource and digest; definitions never deep-merge.
- Permission and capability sets intersect. Limits take the strictest value. Secrets stay references.
- A live or queued Session never changes snapshot. A config change creates a new snapshot.
- User Agents and Skills under
~/.maia/are indexed as metadata only; nothing from the user scope enters context without an explicit reference.~/.maia/projects.jsoncis Swarm locator input, never Agent context. - Hard schema and safety failures block activation. Local mode uses the same resolver in memory.
Minimal-context contract
Context is a scarce resource: every loaded byte needs an owner and a reason. The prompt contract is one root AGENTS.md plus progressively loaded Skills, with no rules/ tree (decision).
Instruction sources
Only these sources may enter a native Agent context:
- a small versioned Maia core system prompt;
- the resolved Agent definition summary;
- the repository root
AGENTS.md; - at most one nearest nested
AGENTS.mdfor the active path scope, only when the Project enables it; - bodies of explicitly selected Skills;
- the current user or Routine instruction;
- bounded, labelled runtime projections from typed services.
No Markdown glob, rules/ traversal, Skill-body preload, extension-owned global append or home-directory discovery. Nested AGENTS.md loading is off by default; when enabled, Maia resolves the nearest file once for the turn's declared path scope and records it in the manifest. It never walks the tree.
What belongs where:
- Core prompt: runtime identity, trust model, tool protocol, authority invariants.
AGENTS.md: stable repository constraints, conventions and verification rules; no long procedures, tool grants or credentials.- Skill: one task procedure and its reviewed resources; no hidden authority or automatic execution.
- Agent definition: model, tool and Skill allowlists and limits; no credentials or unbounded prompt text.
- Routine instruction: desired outcome and trigger context; no scripted model steps or escalation.
Trust classes, as recorded in each manifest source entry:
| Source | contentDisposition | Handling |
|---|---|---|
| Maia core contract | instruction | immutable versioned system section; cannot replace server policy |
Agent definition, AGENTS.md, Skill, Routine/user instruction | untrusted-instruction | attributed delimiters; guides reasoning only |
| repository file, tool output, web, MCP, memory | untrusted-data | opaque data delimiters; never a grant or configuration |
| peer/A2A message, Cursor event or artifact | untrusted-external-message | sender attribution, bounded and redacted |
trace, EVAL.md, evaluation evidence | untrusted-evaluation-data | evaluator isolation; no operational tools |
Only the core contract has trust: "system" and authorityClass: "authority-contract"; every other source has trust: "untrusted" and authorityClass: "none". Every loader declares one class; an unknown or mismatched class fails compilation. No text can select Connections, add tools, change budgets, confirm mutations or activate configuration. Authorization stays outside the model.
Context lint reports a block whose normalized digest appears in both AGENTS.md and a Skill. Conflicting values for a closed-schema field are an error unless a narrower scope may override. Natural-language contradiction checks are optional advisories and never block activation.
Progressive Skill loading
This section owns the loader. What a Skill is, its scopes, pins and updates: Skills.
- Startup indexes only bounded Skill metadata: ID, description, source, digest and eligibility.
- A Skill body loads only by an explicit eligible Skill ID from the user, a Routine or the Agent, through the typed Skill loader. The Agent may pick a Skill from metadata without the user naming it; picking never grants eligibility.
- Supporting resources load one at a time, only when the selected Skill references them.
- A Skill never executes. The Agent reasons over it and calls typed tools.
- Built-in Skills are exceptional: only those needed to operate Maia.
- Selection, body load and resource load each emit a context-manifest event.
- R4 adds learned Skills under a separate eligibility class and provenance variant; the coordinator learning contract owns them. The baseline schema must deny that path.
Every Skill and extension resolves to a provenance record before indexing:
interface ResourceProvenanceV1 {
readonly resourceId: string;
readonly kind: "skill" | "extension" | "instruction" | "supporting-resource";
readonly source: "builtin" | "user" | "project";
readonly canonicalLocator: string;
readonly contentDigest: string;
readonly manifestDigest: string;
readonly signerKeyId: string | null;
readonly trustDecision: "reviewed-builtin" | "explicitly-pinned" | "rejected";
readonly reviewedAt: string | null;
}
Built-ins are release-artifact files covered by the package digest. User and Project resources need an exact configured digest; a signature never replaces explicit admission. Directory traversal, symlink escape, duplicate canonical ID, mutable remote URL, digest drift or unsupported executable content rejects the resource. An executable Pi extension runs only in a worker whose execution profile admits its digest; managed mode never loads ambient or unsigned extension code.
Prompt composition order
- core system prompt;
- tool names and compact descriptions;
- Agent limits and model policy;
- root
AGENTS.md; - active path-scoped
AGENTS.md, if any; - selected Skill bodies, then individually requested Skill resources;
- bounded runtime projections framed as untrusted data: at most one active Goal summary, a hot-task summary, pending interaction and message counts, requested status evidence and, with R4, policy-selected KB and memory items with selection reasons;
- bounded conversation history;
- current instruction.
The full task ledger, memory store, raw history, traces, Project catalog and peer transcripts never preload; the model reads them through bounded tools. Later context cannot grant capabilities.
Context manifest
Every activation produces a redacted maia.context-manifest.v1:
activationId,agentSnapshotDigestandtotals(bytes,estimatedTokens);- one
sourcesentry per loaded source:kind,source,reason,digest,bytes,estimatedTokens,trust,authorityClass,contentDisposition,pathScope,loaderId,causationId; warnings.
It holds digests and measurements, never secret content. Target commands: maia context inspect --json returns it; maia context lint --json reports excess size, duplicates, conflicts, undiscoverable Skills, invalid nesting and unauthorized sources.
Initial budgets
A Project may only lower these limits:
| Contribution | Warning | Hard failure |
|---|---|---|
Root AGENTS.md | 4 KiB | 8 KiB |
One nested AGENTS.md | 2 KiB | 4 KiB |
| One loaded Skill body | 6 KiB | 12 KiB |
| All loaded Skill bodies | 12 KiB | 24 KiB |
| One dynamic runtime projection | 2 KiB | 8 KiB |
| All dynamic runtime projections | 8 KiB | 16 KiB |
| All instructions before conversation history | 24 KiB | 40 KiB |
| Total initial activation before model call | 48 KiB | 64 KiB |
- Byte limits are deterministic guards, not tokenizer claims. The manifest reports exact token counts where an approved tokenizer exists and labelled estimates otherwise.
- The total activation also stays below 25% of the selected model's context window.
- Only Node operator policy may raise a hard limit, through an explicit budget-exception operation with a receipt.
- Release qualification measures baseline startup tokens and latency and lowers warning thresholds when evidence permits.
Agent activation
Managed admission freezes one activation:
interface AgentActivationV1 {
readonly schemaVersion: "maia.agent-activation.v1";
readonly activationId: string;
readonly attemptId: string;
readonly agentSessionId: string;
readonly actorId: string;
readonly projectSnapshotId: string;
readonly projectSnapshotRevision: number;
readonly policyRevision: number;
readonly expectedRevision: number;
readonly agentSnapshotDigest: string;
readonly providerConnectionId: string;
readonly providerCapabilityEvidenceDigest: string;
readonly modelId: string;
readonly workspace: {
readonly projectId: string;
readonly root: string;
readonly writableRoots: ReadonlyArray<string>;
};
readonly tools: ReadonlyArray<ResolvedToolGrant>;
readonly executionProfile: ResolvedExecutionProfile | null;
readonly peerPolicy: ResolvedPeerPolicy;
readonly contextManifest: ContextManifestV1;
readonly history: ReadonlyArray<RedactedHistoryItem>;
readonly instruction: string;
readonly wakeCause:
| { readonly type: "human"; readonly messageId: string }
| { readonly type: "peer"; readonly messageId: string }
| { readonly type: "routine"; readonly tickId: string }
| { readonly type: "recovery"; readonly priorAttemptId: string };
readonly reservationId: string;
readonly assignmentEpoch: number;
readonly workerProtocolVersion: "maia.worker/v1";
readonly idempotencyKey: string;
readonly deadline: string | null;
}
- The nested types are closed Protocol schemas, not local TypeScript types.
- The activation is canonical JSON. Its digest is recorded on the attempt, worker handshake, terminal event and receipt. A retry creates a new attempt and assignment epoch but keeps the activation and command lineage.
- Credentials travel only in a single-activation envelope over the private worker channel. They never appear in the manifest, transcript, prompt, event, log or receipt.
run_commandand the process tools are absent unless an enforceable execution profile is resolved. Pi is not a sandbox. If Node cannot enforce the profile, activation fails. Unsandboxed local execution is an operator-only mode that Project files, Skills or prompts cannot select.
Agent interfaces
Three surfaces stay separate even when they project the same operation (CLI reference):
- Agent CLI:
maia agent ...from a shell. Flags configure one invocation; they never become model tools or prompt text. Durable Sessions usemaia session ...through Node. - Interactive commands:
/commandlines typed by an attached human, parsed before chat input. They are never sent to the model as prose, and the model cannot call them. A command that projects an operation builds its own actor-bound request (command list). - Model tools: JSON Schemas registered for one activation, callable only by the LLM (catalogue).
Tool registration follows one sequence:
Agent tool grants -> Project/operator narrowing -> adapter and execution-profile availability
-> exact operation authorization -> tool schema set in the manifest digest -> Pi model request
- Project text,
AGENTS.md, Skills, prompts and tool output cannot add a tool or widen a grant. An unavailable tool is omitted, not described. - Every tool action maps to exactly one registry operation, except
maia__tool, whose admitted target risk class selects its read or mutation operation (D-172). Local mode uses an in-process implementation of the same authorization, revision, idempotency, result and receipt contracts. Consequential operations keep preview and confirmation. - Target results normalize to
maia.tool-result.v1; today's Pidetailsobjects are not stable schemas. The target replacesbashwith the bounded argvrun_command. Web, MCP and memory adapters are absent by default.
Client attachment is not a Session state (attachments):
/detach, terminal EOF or transport loss closes only that attachment. The Session continues headless; stopping work needssession.stop.- Reconnect opens a new attachment from the last acknowledged cursor; it never creates another Session.
- v1 has no
maia session detach <id>. Automation usessession show,session events listand cursors. /detachexists only in a managed attached renderer, not in localmaia agent.- Client detachment is unrelated to
detach-to-project, which changes a parent/child relation under Swarm policy.
External context and tool adapters
Web, MCP and memory adapters (R11 AG3) are absent by default. S71 owns tool-server admission, credentials and transport; these adapters project its admitted servers and never run a second MCP broker. Configuration outside the prompt resolves each into an admitted grant:
interface ExternalAdapterGrantV1 {
readonly adapterId: string;
readonly kind: "web" | "mcp" | "memory";
readonly revision: number;
readonly ownerActorId: string;
readonly projectId: string;
readonly operationIds: ReadonlyArray<string>;
readonly schemaDigest: string;
readonly riskPolicyDigest: string;
readonly dataClasses: ReadonlyArray<string>;
readonly networkAllowlist: ReadonlyArray<string>;
readonly maxRequestBytes: number;
readonly maxResponseBytes: number;
readonly timeoutMs: number;
readonly expiresAt: string | null;
}
- MCP supplies tools and context only (decision). An MCP entry also pins server identity, transport, tool-name allowlist, each tool schema digest, authentication secret reference, upstream idempotency support, mutation class and response redaction. Schema or server drift removes the tool until re-admission.
- OAuth and API secrets stay in
SecretStore. Prompts and tool arguments never contain credential locators. web_fetchrejects non-HTTP(S) URLs, credentials in URLs, and loopback, link-local, private, metadata or disallowed addresses before and after every DNS resolution and redirect. It enforces host allowlists, response type, size and time limits, and DNS-rebinding protection.- Memory reads need exact actor and owner scope, classification access, provenance, retention state and bounded content. A Project cannot discover siblings; a Workspace cannot discover other Workspaces.
- The memory adapter is a read projection only; R4 records and their write path belong to the coordinator learning contract. Its Project-only schema must be extended explicitly before Workspace reads.
- All returned material is untrusted data and cannot authorize a follow-up operation.
Services, state and source map
Kernel services are Effect services with Layer, Scope, typed errors and interruption: AgentDefinitionResolver, ProjectInstructionResolver, SkillIndex, SkillLoader, ContextCompiler, ContextAuditor, ToolRegistry, ToolAuthorization, ModelProviderAdapter, PeerAgentPort, PiSessionAdapter and AgentEventSink. Pi SDK and native APIs are wrapped at the smallest boundary.
State:
- Node's SQLite state is authoritative for managed lifecycle. Its trace is append-only, bounded and redacted; transcript content stays in the agent's own session files and is read through its reader (D-168). The trace excludes credentials, authorization headers, environment dumps, hidden reasoning and raw audio.
- Every managed Session streams through Node. The worker reports turn, tool and final-message transitions through its fenced control protocol and offers deltas, progress and debug records as bounded diagnostic batches. It never owns a client socket. Pressure may coalesce deltas with an explicit gap; final-message metadata, effect outcomes, usage and terminal state stay durable. Stream design: live Session item stream.
Source map (current folders; new code follows the source organization contract):
| Concern | Location |
|---|---|
| Local agent and Pi construction | packages/agent/src/runner/, runtime/, resources/, extensions/, auth/, login/, home/ |
| Managed worker | packages/agent/src/managed-worker/ |
| Agent definitions and grants | packages/protocol/src/agent/, services/node/src/agent/ |
| Pi Session adapters | services/node/src/harness/pi-rpc/, pi-managed/, shared scheduler in harness/conversation/ |
| CLI | apps/cli/src/ and the command tree in apps/cli/src/command-tree/ |
Each slice changes protocol, SDK, CLI, Node, worker, docs and contract tests together.
Roadmap and acceptance
| Agent work | Roadmap slice |
|---|---|
Context manifests, context inspect/lint | R1 |
| Admitted definitions, prompts, Skills, resource reload | R11 AG1 |
| Tool contract, shell/process profiles, Session work items | R2, R11 AG2 |
| Bounded recall, compaction, web/MCP/memory adapters | R11 AG3 |
| Peer Sessions, owner-aware coordinators, ordinary Workspace Sessions | R3, S17, S18 |
maia session attach renderer | S12 |
| Learned KB, memory and Skills | R4 |
| Agent-callable evaluation | R10a |
Acceptance gates:
- A useful local Agent runs with no Node and no ambient Pi files.
- The same activation runs durably through Node without changing domain semantics.
- Startup loads no Skill body and no nested instruction file unless needed.
- Context inspection accounts for every source, byte, token estimate, reason, digest and trust class.
- Context lint fails closed on hard budgets and conflicting instructions.
- Every tool and command maps to one operation owner and one JSON contract.
- Child Agents are normal Agent Sessions and cannot widen authority.
- The terminal UI owns no durable state, orchestration, authorization or telemetry truth.
- No Fleet, Workflow, Task-graph or Subagent runtime is required.
Terminal surfaces (S12)
Local maia agent keeps Pi's InteractiveMode, so extension commands, shortcuts, renderers and UI hooks work natively. Durable maia session attach is a narrower renderer over Node-owned state (decision). Neither is the product control plane.
- The durable renderer is a
PiTuiRendereradapter over@earendil-works/pi-tui, pinned to the Pi SDK version. - That dependency lives only in
apps/cli; Agent, Node, SDK and Protocol never import it. It is added only in the TUI slice. - The adapter is replaceable because the package is deprecated. A replacement changes rendering only and must pass the same renderer contract.
Screen:
Session <id> Project <id> state/turn/attempt model tokens/cost evidence
----------------------------------------------------------------------------
causal timeline: messages, assistant deltas, tools, interactions, receipts
----------------------------------------------------------------------------
current activity: queue/worker/tool/effect/waiting reason and elapsed time
----------------------------------------------------------------------------
> input or /command connection/health
- No rooms, panels, graph editor, workflow builder, terminal emulator, file browser, fleet dashboard or configuration studio.
- Tool results collapse to status, duration, bounded preview and artifact or receipt IDs. The user can expand one item without loading unbounded history.
evidence=live: timeline current through the shown watermark.evidence=lagging: shows record lag; input stays available only if Node policy permits.evidence=blocked: read-only, with the exact health diagnostic.
| Input | Behavior |
|---|---|
| text + Enter | session.send with behavior reply and current expected revision |
/detach or Ctrl-D | close this attachment and return to the shell |
/interrupt | preview and apply session.interrupt for the current activation |
/status | show the exact Session, activation, attempt and evidence snapshot |
/trace | toggle the bounded causal metadata view |
/tools | list eligible tool schemas and current grants |
/help | show only commands available in this attachment mode |
Ctrl-C | cancel input; twice within two seconds requests interrupt |
| terminal close/transport loss | expire the attachment; never stop or change the Session |
- Model or Connection changes apply to a future activation through a registered operation, never as renderer state.
- The renderer acknowledges the highest fully rendered sequence every two seconds or 64 events. On overflow or cursor reset it discards its projection and requests a fresh snapshot. Heartbeat and buffer limits are in the attachment contract.
- Output sanitation strips terminal control sequences from model, tool and provider content. Only renderer-owned ANSI sequences are emitted. Clipboard, OSC links, image protocols, mouse capture and escape passthrough are off in v1.
Acceptance:
- attach during
idle,running,waiting,blockedand terminal states; - show every turn boundary, tool and effect lifecycle, attempt change, receipt and evidence watermark without duplicates;
- send, detach, reconnect from a cursor, forced cursor reset and slow-consumer disconnect;
- lose terminal, network, worker and Node independently without stopping the Session or inventing state;
- sanitize hostile ANSI/OSC content and enforce input and output bounds;
- local
InteractiveModeandPiTuiRendererproject the same normalized events for a shared fixture corpus.
Imported from Maia OS docs at 3dc3e07