# Prime Agent — full corpus # LLM Wiki An open-source template for building LLM-powered knowledge bases, following [Andrej Karpathy's "LLM Wiki" pattern](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f). You provide raw sources. The LLM reads them, writes structured wiki pages, cross-links everything, and maintains it over time. You never edit the wiki directly — you curate sources and ask questions. ## How It Works The system has three layers: ``` raw/ Sources you collect (articles, transcripts, notes, PDFs) wiki/ LLM-written & maintained pages (summaries, concepts, entities, syntheses) CLAUDE.md Schema that tells the LLM how to structure everything ``` Three operations drive the workflow: | Operation | Trigger | What happens | |-----------|---------|--------------| | **Ingest** | "ingest raw/my-source.txt" | LLM reads the source, creates a summary page, creates/updates concept and entity pages, adds cross-links, updates the index and log | | **Query** | Ask any question | LLM searches the wiki, synthesizes an answer with citations, optionally creates a synthesis page for novel insights | | **Lint** | "lint" or "health check" | LLM audits all pages for orphans, contradictions, missing links, incomplete sections, and low-confidence claims — fixes what it can, reports the rest | ## Quick Start 1. **Clone this repo** ```bash git clone https://github.com/YOUR_USERNAME/llm-wiki.git my-knowledge-base cd my-knowledge-base ``` 2. **Customize CLAUDE.md** for your domain - Update the Purpose section with your topic - Replace the placeholder tagging taxonomy with your own categories - Adjust confidence level descriptions if needed - Everything else (workflows, page formats, linking rules) works as-is 3. **Drop sources into `raw/`** - Text files, transcripts, articles, notes — any plain text - These are immutable once added; the LLM never modifies them 4. **Tell the LLM to ingest** ``` ingest raw/my-first-source.txt ``` The LLM will create summary pages, concept pages, entity pages, cross-links, and update the index. 5. **Ask questions** ``` What are the key differences between X and Y? ``` The LLM answers from the wiki, citing specific pages. 6. **Run health checks** ``` lint ``` The LLM audits the wiki and fixes issues. ## Directory Structure ``` . ├── CLAUDE.md # Schema — the LLM's instructions ├── raw/ # Your source documents (immutable) └── wiki/ ├── index.md # Master catalog of all pages ├── log.md # Append-only activity log ├── dashboard.md # Dataview dashboard (Obsidian) ├── analytics.md # Charts View analytics (Obsidian) ├── flashcards.md # Spaced repetition cards ├── summaries/ # One page per source document ├── concepts/ # Concept and framework pages ├── entities/ # People, tools, organizations, etc. ├── syntheses/ # Cross-cutting analyses and comparisons ├── journal/ # Research/session journal entries │ └── template.md # Journal entry template └── presentations/ # Marp slide decks ``` ## Enhancements This template includes several extras beyond the core wiki pattern: ### Dataview Dashboard (`wiki/dashboard.md`) Live queries that surface low-confidence pages, recent updates, concepts by tag, and pages with the most sources. Requires the [Dataview](https://github.com/blacksmithgu/obsidian-dataview) Obsidian plugin. ### Charts View Analytics (`wiki/analytics.md`) Visual analytics with pie charts, bar charts, and word clouds. Requires the [Charts View](https://github.com/caronchen/obsidian-chartsview-plugin) Obsidian plugin. ### Mermaid Diagrams Use Mermaid code blocks in any wiki page to create flowcharts, sequence diagrams, or concept maps. Native support in Obsidian and GitHub. ### Marp Slides (`wiki/presentations/`) Create slide decks from markdown using [Marp](https://marp.app/). Drop presentation files in this directory. ### Research Journal (`wiki/journal/`) Track your research sessions, experiments, or applied work with the included template. The LLM can reference journal entries when answering queries. ### Spaced Repetition (`wiki/flashcards.md`) Flashcards in the format used by the [Spaced Repetition](https://github.com/st3v3nmw/obsidian-spaced-repetition) Obsidian plugin. Ask the LLM to generate flashcards from any wiki page. ### MCP Server This repo works with Claude Code's MCP server capabilities. Point an MCP-compatible client at this repo and the LLM can read/write the wiki programmatically. ## Customizing for Your Domain The schema in `CLAUDE.md` is domain-agnostic. To adapt it: 1. **Purpose** — Describe your knowledge domain in one paragraph 2. **Tagging taxonomy** — Replace placeholder categories with your own (e.g., for a cooking KB: `cuisine`, `technique`, `ingredient`, `equipment`) 3. **Confidence levels** — Adjust the descriptions to match your domain's evidence standards 4. **Entity types** — Update the entity page description to match what entities mean in your domain (people, tools, companies, etc.) 5. **Journal template** — Customize `wiki/journal/template.md` for your workflow Everything else — page format, linking conventions, workflows, rules — is universal and works across domains. ## Example Domains This template works for any knowledge-intensive topic: - **Research notes** — papers, experiments, methodologies - **Book analysis** — themes, characters, author techniques - **Competitive analysis** — companies, products, market trends - **Course notes** — lectures, readings, key concepts - **Personal development** — frameworks, habits, book summaries - **Technical documentation** — APIs, architectures, design patterns - **Hobby deep-dives** — any subject you want to master ## License MIT # Prime Agent Knowledge Base An LLM-maintained knowledge base on **Prime Agent** (github.com/PrimeIntellect-ai/prime-agent) by Prime Intellect — a self-improving **RLM (recursive language model)** coding agent for long-running autonomous tasks: the model runs in a persistent Python control environment and composes capabilities as code. Terminal agent (TUI/SDK/daemon) with pluggable providers, MCP, ACP, skills & extensions. Pinned to v0.7.0. ## Concepts - [[concepts/prime-agent-overview|Prime Agent Overview]] - [[concepts/quickstart-and-usage|Quickstart and Usage]] - [[concepts/rlm|RLM (Recursive Language Model) Programming Model]] - [[concepts/rlm-runtime|RLM Runtime Architecture]] - [[concepts/architecture|Architecture: Packages, Agent Core, and Agent Connection]] - [[concepts/packages-overview|Packages Overview]] - [[concepts/long-running-agents|Long-Running and Background Agents]] - [[concepts/daemon|Daemon]] - [[concepts/providers-and-models|Providers and Models]] - [[concepts/custom-providers|Custom Providers]] - [[concepts/sessions-and-compaction|Sessions and Compaction]] - [[concepts/mcp-integrations|MCP Integrations]] - [[concepts/acp|ACP (Agent Client Protocol)]] - [[concepts/skills|Skills]] - [[concepts/extensions|Extensions]] - [[concepts/sdk-and-rpc|SDK and RPC]] - [[concepts/tui-and-themes|TUI and Themes]] - [[concepts/settings-and-customization|Settings and Customization]] - [[concepts/platform-setup|Platform Setup]] - [[concepts/development|Development]] ## Summaries - [[summaries/release-digest|Release Digest (v0.1.1 - v0.7.0)]] --- title: "ACP (Agent Client Protocol)" type: concept tags: [acp, area/acp, audience/developer, scope/advanced, status/well-established] created: 2026-08-06 updated: 2026-08-06 sources: ["raw/github_doc-packages-coding-agent-docs-acp-md.md"] confidence: high prime_agent_version: "v0.7.0" --- # ACP (Agent Client Protocol) ## Definition ACP mode makes Prime Agent an [Agent Client Protocol](https://agentclientprotocol.com) agent, speaking JSON-RPC 2.0 over newline-delimited JSON on stdin/stdout. Any ACP client — an editor like Zed or VS Code, or an evaluation harness — can drive it interactively without knowing anything Prime Agent-specific. Started with `prime-agent --mode acp`. ## How It Works ### Transport One JSON-RPC message per line on stdout; requests are read from stdin. stdin stays open for the connection's life; the agent exits when it closes. Diagnostics go to stderr — **stdout is reserved exclusively for the protocol**. ### Supported methods | Method | Notes | |---|---| | `initialize` | Returns protocol version, capabilities, agent info | | `session/new` | Creates the session — one session per connection | | `session/prompt` | Runs one turn, resolves with a stop reason | | `session/cancel` | Notification; aborts the addressed session's turn | | `session/close` | Releases the session, frees the connection for a new one | **One session per connection is deliberate**: Prime Agent's underlying session is fixed at process startup, so a second concurrent session would silently share conversation, working directory, and model. A second `session/new` is refused outright rather than pretending to isolate; a second concurrent session requires a second process. Similarly, `session/prompt` refuses a concurrent turn while one is running, and the working directory cannot change after startup — a client-supplied `cwd` differing from the agent's actual `cwd` is reported back in `_meta` rather than silently ignored. ### Streamed updates Session activity streams as `session/update` notifications, mapped from Prime Agent's internal activity: | Prime Agent activity | ACP update | |---|---| | assistant text | `agent_message_chunk` | | reasoning | `agent_thought_chunk` | | tool starts | `tool_call` (`in_progress`) | | tool finishes | `tool_call_update` (`completed` / `failed`) | | shell output | `tool_call` plus incremental `tool_call_update` | Since IPython is Prime Agent's model-facing tool (see [[concepts/extensions]] for the broader tool model), a cell execution is reported as a `tool_call` of kind `execute` whose `rawInput` carries the cell source. ### Prime Agent extensions via `_meta` Prime Agent has capabilities ACP has no native field for — subagents, autonomous quality gates, goals, heartbeats, continual-harness refinement, compaction, rich IPython output. These travel in a reverse-domain `_meta` envelope, for example: ```json { "sessionUpdate": "session_info_update", "_meta": { "ai.primeintellect.prime-agent": { "subagents": [{ "id": "sub-1", "sessionName": "reviewer", "status": "running" }] } } } ``` A standard ACP client ignores `_meta` and still works correctly; a Prime Agent-aware client (or a harness that tracks subagent trees and gate attempts) reads it. Nothing non-standard is ever added to an ACP object root, which the protocol reserves for future fields — extension data is confined to `_meta`. ### Stop reasons `session/prompt` resolves with one of ACP's stop reasons: `end_turn` (finished normally), `cancelled` (via `session/cancel`), `max_tokens` (autonomous token budget exhausted), `max_turn_requests` (autonomous turn/continuation/wall-clock limit stopped the run). Autonomous quality gates run **inside** a single prompt turn — a failing gate is a continuation, not a distinct stop reason, so the turn resolves only once the gate loop settles; gate attempts are visible in `_meta` in the meantime. ## Key Parameters - **One session per connection** — the hard architectural constraint driving most of ACP mode's refusal behavior. - **`_meta["ai.primeintellect.prime-agent"]`** — the namespace for all Prime Agent-specific protocol extensions. - **Stop reason** — `end_turn` / `cancelled` / `max_tokens` / `max_turn_requests`, returned once per `session/prompt` call. ## When To Use - Something external needs to **drive** a session interactively — prompt, watch tool calls stream live, cancel a turn mid-flight — from an editor or evaluation harness that already speaks ACP. - Prefer JSON event stream mode (`--mode json`, see [[concepts/sdk-and-rpc]]) instead for batch runs where you just want every event dumped with an exit code. - Prefer [[concepts/sdk-and-rpc]]'s RPC mode instead when the client needs Prime Agent's own richer command surface (session management, model switching, compaction control) beyond what ACP exposes. ## Risks & Pitfalls - A standard ACP client that doesn't read `_meta` will be blind to subagent trees, gate attempts, and other Prime Agent-specific state — it still functions, but loses that visibility. - Attempting a second `session/new` on the same connection is refused, not silently redirected — clients must open a new process/connection for concurrent sessions. - A client-supplied `cwd` on `session/new` that differs from the agent's actual working directory is not honored; it only surfaces via `_meta`, so naive clients may not notice the mismatch. - Using a generic line reader that also splits on Unicode line/paragraph separators (as Node's `readline` does) is not appropriate for the underlying stdio framing conventions Prime Agent's protocols rely on — see [[concepts/sdk-and-rpc]] for the explicit LF-only framing rule documented for RPC mode. ## Related Concepts - [[concepts/sdk-and-rpc]] — RPC mode and JSON mode are the other two headless integration surfaces; this page explains how ACP mode differs (and when to prefer it). - [[concepts/extensions]] — IPython-as-tool-call framing and the subagent/gate concepts surfaced via `_meta` originate in the extension and agent event model. - [[concepts/sessions-and-compaction]] — the compaction activity exposed through ACP's `_meta` envelope. ## Sources - raw/github_doc-packages-coding-agent-docs-acp-md.md --- title: "Architecture: Packages, Agent Core, and Agent Connection" type: concept tags: [architecture, advanced, well-established, developer] created: 2026-08-06 updated: 2026-08-06 sources: ["raw/github_doc-packages-coding-agent-docs-architecture-md.md", "raw/github_doc-packages-coding-agent-docs-packages-md.md", "raw/github_doc-packages-coding-agent-docs-agent-connection-md.md", "raw/github_doc-packages-agent-readme-md.md", "raw/github_doc-packages-coding-agent-readme-md.md", "raw/github_doc-packages-ai-readme-md.md"] confidence: high prime_agent_version: "v0.7.0" --- ## Definition Prime Agent's architecture "separates terminal presentation, process coordination, agent execution, model-facing Python, and persisted state." It is built as a monorepo of packages — a low-level stateful agent core, an LLM provider toolkit, the terminal/CLI/daemon harness, and TUI components — with normal interactive sessions running through a client-side `AgentConnection` boundary onto daemon-managed session workers. "Normal interactive sessions use the daemon-backed path... explicit SDK and fallback integrations can run the same `AgentSessionRuntime` in process." ## How It Works ### Packages / Monorepo Layout The public npm packages, per their README titles: - **`prime-agent-core`** (source dir `packages/agent`) — "Stateful agent runtime." Implements the low-level `Agent` class: `AgentMessage` vs. LLM `Message` conversion (`transformContext` → `convertToLlm`), the full event sequence (`agent_start`, `turn_start`, `message_start/update/end`, `tool_execution_start/update/end`, `turn_end`, `agent_end`), configurable tool execution (`parallel` default or `sequential`, overridable per-tool via `executionMode`), `beforeToolCall`/`afterToolCall` hooks, steering/follow-up queues (`steeringMode`, `followUpMode`, `one-at-a-time` or `all`), and the low-level `agentLoop`/`agentLoopContinue` functions for callers who want to bypass the `Agent` class. `AgentSession` (used throughout the coding-agent runtime) is built on this package. - **`prime-agent-ai`** (source dir `packages/ai`) — "LLM provider toolkit." A "unified LLM API with automatic model discovery, provider configuration, token and cost tracking, and simple context persistence and hand-off to other models mid-session," restricted to tool-calling-capable models. Exposes `stream`/`complete`/`streamSimple`/`completeSimple`, TypeBox-based `Tool` definitions, cross-provider context handoff, and a registry of API implementations (`anthropic-messages`, `google-generative-ai`, `google-vertex`, `mistral-conversations`, `openai-completions`, `openai-responses`, `openai-codex-responses`, `azure-openai-responses`, `bedrock-converse-stream`). - **`prime-agent`** / **coding-agent** (source dir `packages/coding-agent`) — "RLM-native terminal coding and research harness." This is the CLI/TUI/daemon product described throughout [[concepts/quickstart-and-usage]] and [[concepts/long-running-agents]]. "Prime Agent began as a hard fork of pi-mono... but it is now developed and distributed independently. This workspace retains inherited `@earendil-works/pi-*` source package identifiers, the `pi` package manifest key, and a source-package `pi` bin entry for internal compatibility... release packaging rewrites the application package and command to `prime-agent`." - **`prime-agent-tui`** (source dir `packages/tui`) — terminal UI components, referenced in the coding-agent README's "See Also" section as "Terminal UI components." For package authors extending Prime Agent, `AGENTS.md`-derived and `docs/packages.md` conventions apply: peer-dependency names for the inherited core packages are `@earendil-works/pi-ai`, `@earendil-works/pi-agent-core`, `@earendil-works/pi-coding-agent`, `@earendil-works/pi-tui`, and `typebox` — list them with a `"*"` range and do not bundle them. A Prime Agent *package* (distinct from the npm workspace packages above) bundles extensions, skills, prompt templates, and themes for distribution via npm, git, or a local path, declared either under a `pi` key in `package.json` or via convention directories (`extensions/`, `skills/`, `prompts/`, `themes/`): ```json { "name": "my-package", "keywords": ["pi-package"], "pi": { "extensions": ["./extensions"], "skills": ["./skills"], "prompts": ["./prompts"], "themes": ["./themes"] } } ``` Install/manage commands: `prime-agent package install npm:@foo/bar@1.0.0`, `git:github.com/user/repo@v1`, or a local path; `prime-agent package remove`, `list`, `update`; `--local` writes to project settings (`.prime/agent/settings.json`) instead of global (`~/.prime/agent/settings.json`). "Prime Agent packages run with full system access. Extensions execute arbitrary code, and skills can instruct the model to perform any action including running executables. Review source code before installing third-party packages." If the same package identity (npm name, git URL without ref, or resolved local path) appears in both global and project settings, "the project entry wins." ### System Topology The system-at-a-glance flow: an **Interactive TUI** or **headless (print/JSON/RPC) client** talks to an `AgentConnection` (the client-side execution boundary), which for normal sessions talks over the **local daemon protocol** to a **daemon supervisor** (routing, attachments, recovery) and a separate **catalog process** (saved-session scans). The supervisor routes into a **session worker**, which owns one root session tree: an `AgentSessionRuntime`, a root `AgentSession`, a `Scheduler`, a root IPython kernel, and any RLM child runtimes below that root. Root and child sessions stream to/from **model providers** and persist to **session JSONL + artifacts**. Ownership rules, stated directly: "The client owns rendering, keyboard input, and local UI preferences; it does not own execution." "The supervisor owns discovery, routing, attachments, worker health, and cross-agent message delivery." "Each worker owns one root runtime, its scheduler, kernels, and all descendants below that root." "`AgentSession` owns provider calls, queues, tools, compaction, goals, child lifecycles, and transcript writes." "IPython is the model-facing control environment. Typed host requests return authoritative operations to the TypeScript session." "Workers and kernels are separate processes for lifecycle and failure containment, not security sandboxes. They normally run with the same operating-system permissions as the client." ### Prompt Execution Flow A user's prompt, steer, or follow-up goes: UI → `AgentConnection` (versioned command) → Supervisor (routes to the active session) → Session worker → `AgentSession` (enqueues the prompt) → model provider (streams a request). If the provider returns text it flows straight back; if it returns an IPython tool call, `AgentSession` executes Python in the kernel — a *typed host request* returns through `AgentSession` and back to the kernel, while *ordinary execution* returns a result/stdout/error directly to `AgentSession`. `AgentSession` appends to session storage and emits session events up through the worker and supervisor as a live stream or recovery snapshot, which the client renders. "From the session queue onward, the same execution and persistence path is used when a prompt comes from a heartbeat, cron schedule, goal continuation, autonomous mode, or another agent instead of an attached user." ### Agent Connection `AgentConnection` is "the client-side boundary between an interactive user interface and the process that owns agent execution. It lets the terminal UI remain transport-agnostic while normal local sessions run in daemon workers." The normal interactive path is `InteractiveMode` (terminal UI) → `AgentConnection` (client interface) → `DaemonAgentConnection` (transport adapter) → local daemon protocol (commands, snapshots, events) → session worker → `AgentSessionRuntime` → `AgentSession`. "`AgentConnection` is not the daemon wire protocol and is not a hosted gateway protocol. It expresses client intent in TypeScript. Each transport adapter is responsible for framing, versioning, recovery, and translation at its own boundary." Responsibilities exposed through the connection: prompting/steering/follow-up/abort/idle-waiting; model/tier/thinking/transport/queue settings; compaction/retry/refinement/navigation; session state/transcript/tree/context/statistics/queues; model and resource catalogs; saved-session and import/export operations; serializable extension UI requests; and RLM child snapshots, agent messaging, schedules, and heartbeats. "The execution owner remains responsible for provider calls, tools, kernels, queues, compaction, scheduling, persistence, and RLM descendants." Two implementations: - **`DaemonAgentConnection`** — "the standard local interactive adapter." Owns a `DaemonClient`, active-session ID, latest snapshot, last event cursor, streamed snapshot assembly, and reconnect behavior. Large transcripts transfer as begin/chunk/end records; live events carry generation-aware cursors `{ generation, sequence }`; the adapter "rejects duplicate or retired-generation events." After a transient socket loss it "reconnects with the same client identity and last cursor, reattaches, and emits a resynchronized snapshot." Key files: `src/modes/agent-connection/daemon-agent-connection.ts`, `src/modes/daemon/daemon-client.ts`, `src/modes/daemon/daemon-protocol.ts`. - **`InProcessAgentConnection`** — wraps an `AgentSessionRuntime` "for SDK compatibility and explicit local fallbacks." It "may access runtime and session objects because it is an adapter; the UI may not." Key files: `src/modes/agent-connection/in-process-agent-connection.ts`, `src/modes/interactive/interactive-mode-services.ts`. `AgentConnectionState` is "the UI's cached view of execution state" — active session, model/thinking config, stream/compaction status, queue modes, session identity, goals, tools, context usage. A snapshot bundles connection state, transcript messages, session context, the last event cursor, active RLM child snapshots, and any in-progress assistant message. **Reconnect and replay**: stable client ID + command ID; mutations journaled by `clientId + commandId`; events carry a `{ generation, sequence }` cursor; attach accepts a resume cursor; reconnect retries supervisor recovery for a bounded interval; attach returns replay status plus a coherent (possibly chunked) snapshot; the UI receives `session_resynced` after recovery. "A client must not compare bare sequence values across worker generations." "The protocol does not promise that every historical event remains replayable. Durable session state and a fresh snapshot are the recovery baseline." **Command lifecycle**: "The public daemon protocol is JSONL-framed and currently at protocol v4." Mutating commands are recorded before dispatch; a repeated completed command returns its recorded result; an uncertain (received-but-no-durable-result) command is reported as uncertain rather than replayed blindly. "The `AgentConnection` method promise is a client convenience. It should not be treated as a general accepted/running/completed remote workflow API." **Boundary invariants** — `InteractiveMode` must not depend on `AgentSessionRuntime`/`AgentSession`, `SessionManager`, daemon socket paths/clients/command types, in-process execution event emitters, or executable runtime callbacks delivered through `AgentConnection`. "Startup code is the composition root and may know about concrete adapters, daemon startup, local settings, and fallback runtime construction." Executable callbacks (tool `execute`, argument preparation, custom renderer functions, extension runner callbacks, local completion functions, session-manager/runtime objects) are deliberately excluded from the connection surface and stay inside the process that loaded them. ## Key Parameters - Public daemon protocol version: **v4** (JSONL-framed). - Package identity for dedup across global/project settings: npm → package name; git → repository URL without ref; local → resolved absolute path. - Peer-dependency names package authors must not bundle: `@earendil-works/pi-ai`, `@earendil-works/pi-agent-core`, `@earendil-works/pi-coding-agent`, `@earendil-works/pi-tui`, `typebox`. - `AgentTool` execution modes: `parallel` (default) or `sequential`, settable globally (`toolExecution`) or per-tool (`executionMode`); a `sequential` tool in a batch forces the whole batch sequential. - Steering/follow-up modes: `one-at-a-time` (default) or `all`. ## When To Use Consult this page when deciding where a new capability belongs: agent execution/session state changes go through `AgentConnection`/`AgentSession`; terminal rendering, keybindings, themes, clipboard, and local UI preference changes stay client-side in `InteractiveModeUiServices`. Also consult it when building an SDK integration (choose `InProcessAgentConnection` vs. the daemon path) or a Prime Agent package (extensions/skills/prompts/themes bundling). ## Risks & Pitfalls - Process isolation is for **lifecycle and failure containment, not security**: workers and kernels "normally run with the same operating-system permissions as the client." - "Several operations intentionally preserve local filesystem semantics, including saved-session paths and import/export paths. Do not extend these shapes into a remote API. A hosted transport should use opaque session and artifact IDs, string timestamps, and explicit upload/download handles." - Wire/schema changes to the connection or protocol must be classified as backward-compatible, capability-gated, or incompatible, with matching updates to both old-client/new-daemon and new-client/old-daemon test coverage — skipping this classification risks breaking mixed-version deployments. - "The durable architectural rule is narrower and already enforced: the UI can be rich and client-specific, but it cannot own agent execution" — a hosted control plane still needs its own authentication, authorization, sandbox identity, artifact transfer, stable public DTOs, multi-client ownership, and compatibility policy; the local `AgentConnection` boundary does not provide these by itself. ## Related Concepts - [[concepts/rlm-runtime]] — the kernel/child-execution machinery that `AgentSession` drives via IPython. - [[concepts/long-running-agents]] — how detached sessions, scheduling, and goals share the same worker runtime described here. - [[concepts/prime-agent-overview]] — the product-level framing of RLM and the Continual Harness that this architecture implements. - [[concepts/quickstart-and-usage]] — the CLI/TUI client surface that sits on top of this architecture. ## Sources - raw/github_doc-packages-coding-agent-docs-architecture-md.md - raw/github_doc-packages-coding-agent-docs-packages-md.md - raw/github_doc-packages-coding-agent-docs-agent-connection-md.md - raw/github_doc-packages-agent-readme-md.md - raw/github_doc-packages-coding-agent-readme-md.md - raw/github_doc-packages-ai-readme-md.md --- title: "Custom Providers" type: concept tags: [providers, extensions, area/providers, audience/developer, scope/advanced, status/well-established] created: 2026-08-06 updated: 2026-08-06 sources: ["raw/github_doc-packages-coding-agent-docs-custom-provider-md.md"] confidence: high prime_agent_version: "v0.7.0" --- # Custom Providers ## Definition A custom provider is a model provider that an extension registers at runtime via `pi.registerProvider()`, going beyond what declarative `~/.prime/agent/models.json` config (see [[concepts/providers-and-models]]) can express: corporate proxies, self-hosted/private deployments, OAuth/SSO login flows, and entirely non-standard streaming APIs. Extensions can also remove a previously registered provider with `pi.unregisterProvider()`. ## How It Works ### Overriding an existing provider The simplest case redirects an existing built-in provider through a proxy or adds headers, without touching its model list: ```typescript pi.registerProvider("anthropic", { baseUrl: "https://proxy.example.com" }); pi.registerProvider("openai", { headers: { "X-Custom-Header": "value" } }); ``` When only `baseUrl` and/or `headers` are given (no `models`), all existing models for that provider are preserved with the new endpoint. ### Registering a brand-new provider Supplying `models` along with `baseUrl`, `apiKey`, and `api` registers a new provider. If the model list comes from a remote endpoint, use an **async extension factory** rather than deferring to `session_start` — Prime Agent awaits the factory before startup continues, so the provider (and its dynamically discovered models) is available during interactive startup and to `prime-agent model list`: ```typescript export default async function (pi: ExtensionAPI) { const response = await fetch("http://localhost:1234/v1/models"); const payload = await response.json(); pi.registerProvider("local-openai", { baseUrl: "http://localhost:1234/v1", apiKey: "LOCAL_OPENAI_API_KEY", api: "openai-completions", models: payload.data.map((model) => ({ id: model.id, name: model.name ?? model.id, reasoning: false, input: ["text"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: model.context_window ?? 128000, maxTokens: model.max_tokens ?? 4096, })), }); } ``` When `models` is provided, it **replaces** all existing models for that provider name. Calls to `pi.registerProvider()` made during the extension factory are queued and applied once the runner initializes. Calls made afterward — e.g. from a command handler after a setup flow — take effect immediately, with no `/reload` required. ### Unregistering `pi.unregisterProvider(name)` removes a provider that was registered via `pi.registerProvider()`. It removes the provider's dynamic models, API key fallback, OAuth registration, and custom stream handler registration, and restores any built-in models/behavior that had been overridden. This also applies immediately without `/reload`. ### API types The `api` field selects the streaming implementation: | API | Use for | |-----|---------| | `anthropic-messages` | Anthropic Claude API and compatibles | | `openai-completions` | OpenAI Chat Completions API and compatibles | | `openai-responses` | OpenAI Responses API | | `azure-openai-responses` | Azure OpenAI Responses API | | `openai-codex-responses` | OpenAI Codex Responses API | | `mistral-conversations` | Mistral SDK Conversations/Chat streaming | | `google-generative-ai` | Google Generative AI API | | `google-vertex` | Google Vertex AI API | | `bedrock-converse-stream` | Amazon Bedrock Converse API | Most OpenAI-compatible providers work with `openai-completions` plus model-level `thinkingLevelMap` and `compat` flags (same mechanism as [[concepts/providers-and-models]]). If a provider expects `Authorization: Bearer ` but doesn't use a standard API, set `authHeader: true`. ### OAuth support `oauth` on the provider config integrates with `/login`, offering three callback-driven login mechanisms via `OAuthLoginCallbacks`: - `onAuth({ url })` — browser-based OAuth redirect - `onDeviceCode({ userCode, verificationUri })` — device code flow - `onPrompt({ message })` — manual token/code entry, returns a string The `login()` implementation exchanges the result for `OAuthCredentials { refresh, access, expires }`, which persist in `~/.prime/agent/auth.json`. `refreshToken(credentials)` re-derives fresh credentials; `getApiKey(credentials)` extracts the usable API key; an optional `modifyModels(models, credentials)` can rewrite model definitions based on decoded subscription/region info (e.g. changing `baseUrl` per region). After registration, users authenticate via `/login corporate-ai`. ### Custom streaming API For genuinely non-standard APIs, implement `streamSimple(model, context, options)` returning an `AssistantMessageEventStream`, following the same event pattern as built-in providers (reference implementations: `anthropic.ts`, `mistral.ts`, `openai-completions.ts`, `openai-responses.ts`, `google.ts`, `amazon-bedrock.ts`). Push events in order: 1. `{ type: "start", partial: output }` 2. Content events per block, tracked by `contentIndex`: `text_start`/`text_delta`/`text_end`, `thinking_start`/`thinking_delta`/`thinking_end`, `toolcall_start`/`toolcall_delta`/`toolcall_end` 3. `{ type: "done", reason, message }` or `{ type: "error", reason, error }` Update `output.usage` from the API response and call `calculateCost(model, output.usage)` before emitting `done`. Register the custom stream function via the `streamSimple` field on `registerProvider()`. ### Testing Copy and adapt the built-in provider test suites from `packages/ai/test/` against your provider/model pairs: `stream.test.ts`, `tokens.test.ts`, `abort.test.ts`, `empty.test.ts`, `context-overflow.test.ts`, `image-limits.test.ts`, `unicode-surrogate.test.ts`, `tool-call-without-result.test.ts`, `image-tool-result.test.ts`, `total-tokens.test.ts`, `cross-provider-handoff.test.ts`. ## Key Parameters - **`ProviderConfig`** fields: `name`, `baseUrl`, `apiKey`, `api`, `streamSimple`, `headers`, `authHeader`, `models`, `oauth`. - **`ProviderModelConfig`** fields: `id`, `name`, `api`, `baseUrl` (per-model override), `reasoning`, `thinkingLevelMap`, `input`, `cost`, `contextWindow`, `maxTokens`, `headers`, `compat`. - **Timing** — async factories block startup completion; post-load `registerProvider`/`unregisterProvider` calls apply immediately. ## When To Use - A team needs all Anthropic (or any built-in provider) traffic routed through a corporate proxy or API gateway. - A private/self-hosted model deployment needs to appear in the model picker with proper capability metadata. - A provider requires an OAuth/SSO login flow that `/login` doesn't already support out of the box. - A provider's wire format doesn't match any of the built-in `api` types, requiring a fully custom `streamSimple` implementation. - Model list must be discovered dynamically at startup from a remote endpoint (async factory + `registerProvider`). ## Risks & Pitfalls - If you don't use an async factory for remote model discovery, and instead register from `session_start`, the provider's models won't be available during interactive startup or to `prime-agent model list` at the same reliability. - `models` on `registerProvider()` **replaces** the provider's entire model list — there's no per-model merge semantics like `modelOverrides` provides for `models.json` built-in overrides. - Implementing a custom `streamSimple` requires manually managing `contentIndex` bookkeeping, partial JSON tool-call accumulation, and usage/cost calculation correctly — study a reference provider implementation first. - OAuth `modifyModels` runs against decoded credential data (e.g. region) — a broken decode can silently point all models at a bad `baseUrl`. ## Related Concepts - [[concepts/providers-and-models]] — the declarative `models.json` approach and the shared model/provider config vocabulary (`compat`, `thinkingLevelMap`, API types) that custom providers build on. - [[concepts/extensions]] — `pi.registerProvider()` and `pi.unregisterProvider()` are `ExtensionAPI` methods; this page is a deep dive on that one capability. - [[concepts/sdk-and-rpc]] — `ModelRegistry`/`AuthStorage` in the SDK for resolving models and keys outside the extension system. ## Sources - raw/github_doc-packages-coding-agent-docs-custom-provider-md.md --- title: "Daemon" type: concept tags: [platform, architecture, developer, well-established] created: 2026-08-05 updated: 2026-08-05 sources: ["raw/github_doc-packages-coding-agent-docs-daemon-md.md"] confidence: high prime_agent_version: "v0.7.0" --- ## Definition The daemon is Prime Agent's internal background infrastructure that isolates each active root session tree in its own process. It is not a user-facing surface — interactive, print, JSON, RPC, piped-stdin, and `--no-session` client modes all describe client behavior and keep their existing public I/O contracts regardless of the daemon underneath. The daemon exists so that long-running or many-session work (including [[concepts/long-running-agents]] and RLM descendants) survives client disconnects, recovers from crashes, and does not block unrelated sessions on one another. ## How It Works **Process topology.** A detached supervisor owns the public local socket(s), client attachments, routing, global agent-message delivery, worker health, command journals, and coordinated updates — it does not itself execute providers, tools, compaction, bash, kernels, schedules, or transcript scans. A separate catalog subprocess owns saved-session scans and inactive-session file operations, so a catalog failure fails only a catalog request without interrupting active workers. Each worker owns exactly one root `AgentSessionRuntime`, its root `AgentSession`, scheduler, kernels, and every RLM descendant below that root; new/switch/fork/import operations replace the root runtime inside a worker while preserving the public active-session ID. **Resident workers** back normal interactive sessions. The supervisor starts one detached process group per active root tree; closing the TUI detaches the client without stopping the worker. Worker descriptors, auth tokens, active-session IDs, session paths, and recovery journals are written with owner-only permissions under the agent directory. Workers monitor the public supervisor socket and one worker acquires an atomic launch lease to start a replacement supervisor if it disappears; the replacement adopts live workers and their active-session IDs. A worker crash affects only its own root tree — recovery retries after 250ms, 1s, and 5s, and three failures mark that root failed. `prime-agent shutdown` stops the supervisor and all workers; `--force` also terminates unresponsive worker process groups and tracked children. There is no fixed session, worker, client, or workload cap at this layer. **Client-owned workers** back headless/ephemeral clients using the same worker runtime but a client-owned lifecycle: print, piped-stdin, and JSON mode stay one-shot; RPC keeps LF-delimited JSONL framing and accepts prompts until EOF; interactive `--no-session` uses an in-memory session. Normal completion explicitly removes the worker without archiving it; unexpected client loss starts a bounded cleanup grace period that reconnecting with the same stable client identity cancels. Default lists, global schedules, and peer routing omit client-owned workers unless the owner explicitly addresses them. The full launch environment stays in supervisor memory (never written to the worker descriptor); direct SDK calls to print/RPC modes remain in-process so embedders can pass non-serializable extension factories. **Session ownership and leases.** Every persisted session is protected by a process-safe lease keyed by canonical JSONL path. A worker acquires the target lease before opening a session; runtime replacement acquires the new lease before releasing the old one. Concurrent opens of the same session return `session_already_active` with the owning active-session ID; concurrent creates for the same path converge on one worker launch. This prevents two processes from writing the same transcript concurrently. **Scheduling.** Each worker runs one scheduler for its root and descendants; jobs persist per-session in `session-artifacts//scheduled-jobs.json` rather than a shared global cron file. Due ticks are claimed and advanced before prompt delivery, so a crash never replays an uncertain prompt, and a still-active claim coalesces missed ticks instead of building an unbounded backlog. Resident workers keep scheduling across supervisor replacement; worker recovery marks uncertain claims interrupted but keeps the advanced schedule and resumes only future ticks. The supervisor routes schedule commands and merges worker summaries for global listing. **Public Daemon Protocol v4** runs over a JSONL-framed local socket, providing: versioned command envelopes with stable client/command IDs; capability negotiation with per-command compatibility metadata; generation-aware event cursors `{generation, sequence}`; reconnect with a stable identity and resume cursor; attach acknowledgment plus coherent snapshots; begin/chunk/end snapshot streaming (512 KiB target chunk size); file-backed transcript caches above 4 MiB; resident and client-owned worker lifecycle commands; daemon-side headless completion, session-header, bash, and retry operations; and structured errors for recoverable cases (already-active session, uncertain mutation result). Protocol version and schema revision are tracked independently — a compatible addition can be capability-gated or need a schema bump, while an incompatible wire change needs a protocol bump. Protocol v1 is retained only for the one-release update handoff that prepares/stops an older daemon; a busy older daemon unable to produce a recovery manifest is left running. JSON and RPC client modes never expose daemon greetings, envelopes, snapshot records, lifecycle events, or connection metadata. **Reconnect, replay, and snapshots.** Every sequenced event belongs to a worker generation; clients retain the last `{generation, sequence}` cursor and present it on attach, and the server reports whether the requested interval is complete, partial, or unavailable. A generation change invalidates comparison with the old sequence, but missing replay is not fatal — the attach snapshot is the durable recovery baseline. `DaemonAgentConnection` applies the snapshot, ignores duplicate/retired-generation events, and reports a resynchronized session to the UI. Large snapshots are encoded in the worker and streamed as opaque chunks through a bounded supervisor cache; the supervisor never constructs a history-sized object in memory. **Private worker transport** between supervisor and worker uses a binary frame (4-byte JSON header length, 4-byte payload length, small JSON routing header, opaque payload bytes). Workers serialize a public event once; the supervisor reads only the routing header and forwards the same payload buffer to eligible clients. Assistant streaming uses compact start/delta/end payloads privately, and the supervisor reconstructs the public `message_update` once per delta rather than repeatedly re-transferring the growing assistant message. Private connections authenticate with per-worker tokens fenced to the current supervisor generation — this is process coordination against an obsolete replacement supervisor, not a sandbox boundary (all processes still run as the same OS user). **Backpressure** is attachment-local: a blocked client simply stops receiving incremental events while other clients and workers continue, the supervisor retains no unbounded per-client queue, and after drain the attachment either catches up from its cursor or receives a fresh snapshot. Final transcript caching is kept separate from live partial-message reconstruction. **Idempotency and crash recovery.** Mutating commands are keyed by `clientId + commandId` and recorded in an append-only journal before dispatch. Repeating a completed command returns the stored result; a received command without a durable result is reported uncertain and not replayed; reconnect retains the same command ID; clients acknowledge completed mutations so journal entries can be compacted. Workers journal operation transitions and detached subprocess identities, so after a worker crash, recovery reaps the old process group and tracked detached bash trees, appends a visible recovery marker to the transcript, restores the root under the same active-session ID, and does not replay uncertain side effects. **Coordinated updates** (e.g., self-update) are two-phase: resident workers create non-destructive checkpoints in parallel, the supervisor validates and atomically persists the aggregate manifest, and only after every prepare succeeds does it commit and stop workers. If preparation or manifest validation fails, prepared workers are released and every root keeps running. ## Key Parameters - **Recovery backoff**: 250ms, 1s, 5s retries; three failures marks a root failed. - **Snapshot chunking**: 512 KiB target chunk size; file-backed transcript caches kick in above 4 MiB. - **Per-worker scheduling state**: `session-artifacts//scheduled-jobs.json`. - **`prime-agent shutdown [--force]`**: graceful vs. forced termination of the supervisor and all workers. - **Idle eviction**: `idleEvictionMinutes` setting (see [[concepts/settings-and-customization]]) governs whole-tree worker eviction and idle-child passivation and is read only from global settings. - **Benchmark commands** (from `packages/coding-agent`): `npx tsx test/daemon-multiclient-bench.ts [--generated-session-mib N] [--session-file path]`, and a stress test via `PRIME_AGENT_STRESS_WORKERS=50 npx tsx ../../node_modules/vitest/dist/cli.js --run test/daemon-supervisor-process.test.ts -t "hosts resident roots"`. ## When To Use The daemon operates transparently underneath every Prime Agent client mode, so there's no direct "opt in" — it activates whenever a session is created. Understanding its architecture matters when: debugging session recovery after a crash (worker journals and the recovery marker in the transcript), diagnosing why a session reports `session_already_active` (lease contention), reasoning about resource limits for many concurrent [[concepts/long-running-agents]] sessions (idle eviction, no hard worker cap), or building daemon protocol changes (each command/event/response-shape change must be classified backward-compatible, capability-gated, or incompatible — see [[concepts/development]]). ## Risks & Pitfalls - The private worker-supervisor transport authenticates connections but is explicitly **not a sandbox boundary** — all processes run as the same OS user, so it does not protect against malicious code within a worker. - A worker crash is isolated to its root tree, but three recovery failures in the 250ms/1s/5s backoff window permanently mark that root failed rather than retrying indefinitely. - Protocol v1 compatibility is retained for exactly one release's update handoff — old daemons that can't produce a recovery manifest and are still busy are left running rather than forcibly stopped. - Client-owned (headless/ephemeral) workers are excluded from default lists, global schedules, and peer routing by design — they must be explicitly addressed, which can make headless RPC/JSON sessions "invisible" to schedule or agent-messaging tooling unless the caller knows to target them. ## Related Concepts - [[concepts/long-running-agents]] — the daemon's resident-worker model, per-worker scheduling, and idle eviction are the infrastructure that makes multi-hour/multi-day agent sessions and heartbeats durable - [[concepts/sessions-and-compaction]] — session leases, JSONL transcript paths, and snapshot streaming described here underpin how sessions persist and resume - [[concepts/settings-and-customization]] — `idleEvictionMinutes` is the one daemon-level setting exposed to users, and only from global `settings.json` - [[concepts/development]] — daemon protocol changes require classifying compatibility and following the protocol-version/schema-revision rules in the root `AGENTS.md` - [[concepts/sdk-and-rpc]] — RPC and SDK client modes connect through the same daemon protocol described here while keeping mode-specific framing (LF-delimited JSONL for RPC) ## Sources - raw/github_doc-packages-coding-agent-docs-daemon-md.md --- title: "Development" type: concept tags: [developer, platform, advanced, well-established] created: 2026-08-05 updated: 2026-08-05 sources: ["raw/github_doc-packages-coding-agent-docs-development-md.md"] confidence: high prime_agent_version: "v0.7.0" --- ## Definition Development covers building and running Prime Agent from source, the naming/packaging split between the public "Prime Agent" product and its inherited `pi-mono`/`@earendil-works/pi-*` source-package identifiers, local configuration for isolated dev sessions, the rules for changing the daemon wire protocol, and the validation commands contributors run before submitting changes. ## How It Works **Setup.** Prime Agent requires Node.js 22.8.0 or newer. Standard clone-and-install: ```bash git clone https://github.com/PrimeIntellect-ai/prime-agent cd prime-agent npm ci ``` Run from source with `/path/to/prime-agent/prime-agent.sh`. The script can be invoked from any directory and preserves the caller's working directory, which lets a contributor run a source checkout against a separate test project without `cd`-ing into the checkout first. **Product and source naming.** "Prime Agent" is the product, public CLI, release artifact, and repository name, but the monorepo still carries inherited `@earendil-works/pi-*` npm workspace names, a source-package `pi` bin entry, the `pi` package manifest key, and some `PI_*`-prefixed compatibility environment variables — these are source/compatibility details from the project's fork lineage (Prime Agent began as a hard fork of [pi-mono](https://github.com/badlogic/pi-mono) by Mario Zechner and still keeps MIT attribution), not a signal to install or develop against pi-mono directly. Public releases are versioned tarball artifacts produced by `scripts/pack-prime-agent-release.mjs`, which rewrites the coding-agent package name, executable, config metadata, and internal dependency URLs for distribution — contributors should never document the inherited npm workspace package as the public install path. **Local configuration for development.** User configuration lives under `~/.prime/agent/`; project-local settings, prompts, themes, extensions, skills, and system-prompt files live under `.prime/agent/` in the project root. `PRIME_AGENT_CODING_AGENT_DIR` overrides the user config directory and `PRIME_AGENT_SESSION_DIR` overrides the session directory. When manually exercising daemon behavior, use an isolated config directory so dev sessions don't collide with normal ones: ```bash PRIME_AGENT_CODING_AGENT_DIR=/tmp/prime-agent-dev /path/to/prime-agent/prime-agent.sh ``` **Daemon protocol changes.** Every daemon command, event, or response-shape change must be classified as backward-compatible, capability-gated, or incompatible; optional behavior must be negotiated and degrade locally. Contributors must follow the protocol-version, schema-revision, compatibility-map, and cross-version test requirements in the root `AGENTS.md` before changing the wire contract — see [[concepts/daemon]] for the protocol mechanics this governs (capability negotiation, generation-aware cursors, protocol vs. schema-revision independence). **Package asset resolution.** Because Prime Agent runs from source, Node package output, and standalone release artifacts, packaged assets (like theme files) must always be resolved through `src/config.ts` helpers (`getPackageDir`, `getThemeDir`) rather than directly from `__dirname`, since `__dirname`-relative resolution breaks across those three deployment shapes. **Debugging.** The hidden `/debug` command writes `~/.prime/agent/prime-agent-debug.log` with rendered TUI lines, their visible widths, and current agent messages — useful for diagnosing [[concepts/tui-and-themes]] line-width violations. Daemon, worker, client, and provider diagnostic logs live under `~/.prime/agent/logs/`. Useful service commands: `prime-agent status`, `prime-agent doctor`, `prime-agent doctor --fix`, `prime-agent shutdown`. **Validation.** After code changes, run `npm run check` from the repository root — this performs formatting, linting, type checking, installer rendering checks, and a browser smoke check, but does **not** run the test suite. Focused tests run from the package root, e.g.: ```bash cd packages/coding-agent npx tsx ../../node_modules/vitest/dist/cli.js --run test/specific.test.ts ``` Any test file a contributor creates or modifies must be run and iterated on until it passes. Coding-agent suite regressions belong under `test/suite/regressions/` and must use the suite harness and faux provider (see [[concepts/prime-agent-overview]] / the `packages/ai` faux provider) rather than live provider credentials. ## Key Parameters - **Node.js floor**: 22.8.0 or newer, enforced at startup (unsupported versions fail before loading the CLI, per the v0.3.2 release note). - **`PRIME_AGENT_CODING_AGENT_DIR`**: overrides the user config directory — the standard way to sandbox a dev daemon from a real one. - **`npm run check`**: the required pre-submission validation command; explicitly does not include the test suite. - **`scripts/pack-prime-agent-release.mjs`**: the release-packaging script that rewrites source-package identifiers into the public `prime-agent` distribution. - **`src/config.ts`**: the required indirection point (`getPackageDir`, `getThemeDir`) for resolving packaged assets across source/npm/standalone deployment shapes. ## When To Use Follow this workflow when contributing to Prime Agent itself: cloning and building from source, running an isolated dev daemon alongside a normal installed one, changing anything touching the daemon wire protocol (always classify compatibility first), or debugging TUI rendering/session issues via `/debug` and `~/.prime/agent/logs/`. See [[concepts/platform-setup]] for Termux, which also builds from source via this same `npm ci` path since no packaged installer exists for Android. ## Risks & Pitfalls - Assuming the inherited `@earendil-works/pi-*` npm workspace name is installable as the public product — it is not; only the release tarballs produced by the packaging script are the supported distribution. - Resolving packaged assets via `__dirname` instead of the `src/config.ts` helpers works when running from source but breaks under the Node-package or standalone-release deployment shapes. - Treating `npm run check` as sufficient validation — it deliberately excludes the test suite, so modified or new test files must be run explicitly and iterated on separately. - Making a daemon protocol change without first classifying it as backward-compatible / capability-gated / incompatible violates the root `AGENTS.md` contract and risks breaking older clients or daemons during the update handoff window (see [[concepts/daemon]]'s protocol v1 retention note). - Running a dev checkout without `PRIME_AGENT_CODING_AGENT_DIR` isolation risks colliding with a real, already-running daemon and its sessions. ## Related Concepts - [[concepts/daemon]] — the protocol-versioning and schema-revision discipline referenced here governs daemon wire changes - [[concepts/platform-setup]] — Termux setup uses the same from-source build path described here - [[concepts/tui-and-themes]] — `/debug` output (rendered lines and visible widths) is the primary tool for diagnosing TUI issues during development - [[concepts/packages-overview]] — the monorepo package layout (`agent`, `ai`, `coding-agent`, `tui`) that this development workflow builds against ## Sources - raw/github_doc-packages-coding-agent-docs-development-md.md --- title: "Extensions" type: concept tags: [extensions, area/extensions, audience/developer, scope/advanced, status/well-established] created: 2026-08-06 updated: 2026-08-06 sources: ["raw/github_doc-packages-coding-agent-docs-extensions-md.md"] confidence: high prime_agent_version: "v0.7.0" --- # Extensions ## Definition Extensions are TypeScript modules that extend Prime Agent's behavior: they subscribe to lifecycle events, register custom tools the LLM can call, add slash commands and keyboard shortcuts, drive custom TUI components, and persist state across restarts. An extension exports a default factory function that receives an `ExtensionAPI` object (`pi`); the factory can be synchronous or `async`, and is loaded via [jiti](https://github.com/unjs/jiti) so raw TypeScript works without a build step. ## How It Works ### Minimal shape ```typescript import type { ExtensionAPI } from "@earendil-works/pi-coding-agent"; import { Type } from "typebox"; export default function (pi: ExtensionAPI) { pi.on("session_start", async (_event, ctx) => { ctx.ui.notify("Extension loaded!", "info"); }); pi.on("tool_call", async (event, ctx) => { if (event.toolName === "bash" && event.input.command?.includes("rm -rf")) { const ok = await ctx.ui.confirm("Dangerous!", "Allow rm -rf?"); if (!ok) return { block: true, reason: "Blocked by user" }; } }); pi.registerTool({ name: "greet", label: "Greet", description: "Greet someone by name", parameters: Type.Object({ name: Type.String({ description: "Name to greet" }) }), async execute(toolCallId, params, signal, onUpdate, ctx) { return { content: [{ type: "text", text: `Hello, ${params.name}!` }], details: {} }; }, }); pi.registerCommand("hello", { description: "Say hello", handler: async (args, ctx) => { ctx.ui.notify(`Hello ${args || "world"}!`, "info"); }, }); } ``` Test quickly with `prime-agent -e ./my-extension.ts` (or `--extension`); for permanent, hot-reloadable use, place the file where auto-discovery picks it up. ### Locations and styles **Discovery locations** (each hot-reloadable via `/reload`): | Location | Scope | |----------|-------| | `~/.prime/agent/extensions/*.ts` | Global | | `~/.prime/agent/extensions/*/index.ts` | Global (subdirectory) | | `.prime/agent/extensions/*.ts` | Project-local | | `.prime/agent/extensions/*/index.ts` | Project-local (subdirectory) | Additional paths and shareable packages come from `settings.json` (`packages: ["npm:@foo/bar@1.0.0", "git:github.com/user/repo@v1"]`, `extensions: ["/path/to/local/extension.ts"]`). **Security note**: extensions run with full system permissions and can execute arbitrary code — only install from trusted sources. Three structural styles: a **single file** for small extensions; a **directory with `index.ts`** plus helper modules for multi-file extensions; and a **package with `package.json`** declaring `dependencies` and a `pi.extensions` entry array, for extensions needing npm packages (`npm install` in the directory makes `node_modules/` imports resolve automatically). Node built-ins (`node:fs`, `node:path`, etc.) are always available. For npm/git-distributed Prime Agent packages, runtime dependencies must live in `dependencies` (not `devDependencies`) because package installs use `npm install --omit=dev` by default. **Available imports**: `@earendil-works/pi-coding-agent` (extension types), `typebox` (tool parameter schemas), `@earendil-works/pi-ai` (AI utilities, notably `StringEnum`), `@earendil-works/pi-tui` (custom rendering components). ### Async factories If the factory returns a `Promise`, Prime Agent awaits it before continuing startup — so async initialization completes before `session_start`, `resources_discover`, and any queued `pi.registerProvider()` calls are flushed. This is the correct place for one-time startup work like fetching remote model lists (see [[concepts/custom-providers]]) or remote configuration, rather than deferring to `session_start`. ### The event lifecycle The full sequence, in order: ``` Prime Agent starts ├─► session_start { reason: "startup" } └─► resources_discover { reason: "startup" } user sends prompt ├─► (extension commands checked first, bypass if found) ├─► input (can intercept, transform, or handle) ├─► (skill/template expansion if not handled) ├─► before_agent_start (can inject message, modify system prompt) ├─► agent_start ├─► message_start / message_update / message_end │ ┌─── turn (repeats while LLM calls tools) ───┐ │ ├─► turn_start │ ├─► context (can modify messages) │ ├─► before_provider_request (can inspect or replace payload) │ ├─► after_provider_response (status + headers, before stream consume) │ │ tool_execution_start → tool_call (can block) → tool_execution_update → tool_result (can modify) → tool_execution_end │ └─► turn_end └─► agent_end /new or /resume: session_before_switch (can cancel) → session_shutdown → session_start{reason:"new"|"resume"} → resources_discover /fork or /clone: session_before_fork (can cancel) → session_shutdown → session_start{reason:"fork"} → resources_discover /compact or auto-compaction: session_before_compact (can cancel/customize) → session_compact /tree navigation: session_before_tree (can cancel/customize) → session_tree /model or Ctrl+P: thinking_level_select (if clamped) → model_select thinking level change: thinking_level_select exit: session_shutdown ``` ### Resource events `resources_discover` fires after `session_start`, letting an extension contribute extra skill/prompt/theme paths; `reason` is `"startup"` or `"reload"`: ```typescript pi.on("resources_discover", async (event, _ctx) => ({ skillPaths: ["/path/to/skills"], promptPaths: ["/path/to/prompts"], themePaths: ["/path/to/themes"], })); ``` ### Session events See [[concepts/sessions-and-compaction]] for session storage internals; the relevant events: - **`session_start`** — fires on start/load/reload; `event.reason` is `"startup" | "reload" | "new" | "resume" | "fork"`, with `event.previousSessionFile` present for the latter three. - **`session_before_switch`** — fires before `/new` or `/resume`; `event.reason` is `"new"` or `"resume"`; return `{ cancel: true }` to block. On success, Prime Agent emits `session_shutdown` for the old extension instance, rebinds extensions for the new session, then `session_start`. - **`session_before_fork`** — fires on `/fork` (`event.position: "before"`) or `/clone` (`"at"`); can `{ cancel: true }` or return `{ skipConversationRestore: true }` (reserved for future use). Same shutdown/rebind/start sequence as above follows a successful fork/clone. - **`session_before_compact` / `session_compact`** and **`session_before_tree` / `session_tree`** — detailed in [[concepts/sessions-and-compaction]]. - **`session_shutdown`** — fires before an extension runtime is torn down; `event.reason` is `"quit" | "reload" | "new" | "resume" | "fork"`, plus `event.targetSessionFile` for replacement flows. Do cleanup here; reestablish in-memory state in the following `session_start`. ### Agent, turn, and message events - **`before_agent_start`** — fires after the user submits a prompt, before the agent loop starts. Can inject a persistent custom message and/or replace the system prompt for the turn (chained across extensions — `event.systemPrompt` reflects earlier handlers' changes). `event.systemPromptOptions` exposes the same structured data Prime Agent uses internally to build the prompt (`customPrompt`, `selectedTools`, `toolSnippets`, `promptGuidelines`, `appendSystemPrompt`, `cwd`, `contextFiles`, `skills`) — useful for making informed changes without re-discovering resources. - **`agent_start` / `agent_end`** — once per user prompt; `agent_end.messages` holds messages generated during that run. - **`turn_start` / `turn_end`** — once per LLM-response-plus-tool-calls cycle; `turn_end` carries `message` and `toolResults`. - **`message_start` / `message_update` / `message_end`** — message lifecycle for user/assistant/toolResult messages (`message_update` only for assistant streaming). `message_end` handlers may `return { message }` to replace the finalized message, provided the replacement keeps the same `role`. - **`tool_execution_start` / `tool_execution_update` / `tool_execution_end`** — tool execution lifecycle. In the default **parallel tool mode**, `tool_execution_start` fires in assistant source order during preflight, `tool_execution_update` events may interleave across tools, and `tool_execution_end` fires in completion order — while the final `toolResult` message events still emit later in source order. - **`context`** — fires before each LLM call; handlers get a deep copy of `event.messages`, safe to filter/modify, returned as `{ messages }`. - **`before_provider_request`** — fires after the provider-specific payload is built, right before sending; handlers run in extension load order; returning a value replaces the payload for later handlers and the actual request. Can rewrite or strip provider-level system instructions — a payload-level change `ctx.getSystemPrompt()` does **not** reflect, since that method reports Prime Agent's system-prompt string, not the final serialized payload. Mainly useful for debugging provider serialization/caching. - **`after_provider_response`** — fires after the HTTP response arrives, before the stream body is consumed; exposes `event.status` and `event.headers` (availability depends on provider/transport). ### Model events - **`model_select`** — fires on `/model`, `Ctrl+P` cycling, or session restore; carries `event.model`, `event.previousModel`, `event.source` (`"set" | "cycle" | "restore"`). - **`thinking_level_select`** — notification-only (return values ignored); fires whenever `pi.setThinkingLevel()`, a model change, or built-in controls change the level. ### Tool events - **`tool_call`** — fires after `tool_execution_start`, before execution; **can block** via `{ block: true, reason? }`. `event.input` is mutable — mutations affect actual execution, are visible to later handlers in the same event, and are **not re-validated**. `isToolCallEventType("bash", event)` (or with explicit generics for custom tools) narrows the type. Before `tool_call` runs, Prime Agent waits for previously emitted agent events to drain, so `ctx.sessionManager` is current through the assistant tool-calling message — but in parallel mode it's not guaranteed to include sibling tool results from that same message. - **`tool_result`** — fires after execution, before `tool_execution_end` and the final message events; **can modify** the result. Handlers chain like middleware (extension load order, each sees the prior handler's changes) and may return partial patches (`content`/`details`/`isError`; omitted fields keep current values). Use `ctx.signal` for nested abort-aware work (fetch, model calls) inside the handler. ### User bash and input events - **`user_bash`** — fires on `!`/`!!` commands; **can intercept** by returning custom `operations` (e.g. SSH), by wrapping the built-in local backend via `createLocalBashOperations()`, or by fully replacing with `{ result: {...} }`. - **`input`** — fires on raw user input, after extension-command checks but before skill/template expansion (so `/skill:foo` and `/template` are not yet expanded). Processing order: (1) extension commands checked first — if matched, input event is skipped; (2) `input` fires; (3) if unhandled, skill commands expand; (4) if still unhandled, prompt templates expand; (5) agent processing begins. Return `{ action: "transform", text, images? }` to rewrite before expansion (transforms chain across handlers), `{ action: "handled" }` to bypass the agent entirely (first such return wins), or `{ action: "continue" }` (default) to pass through. `event.source` is `"interactive" | "rpc" | "extension"`. ### ExtensionContext (`ctx`) — available to every handler - **`ctx.ui`** — see [Custom UI](#custom-ui). - **`ctx.hasUI`** — `false` in print mode (`-p`) and JSON mode; `true` in interactive and RPC mode (in RPC mode dialog methods work via the extension UI sub-protocol; some TUI-only methods are no-ops or return defaults — see [[concepts/sdk-and-rpc]]). - **`ctx.cwd`** — current working directory. - **`ctx.sessionManager`** — read-only session access (`getEntries()`, `getBranch()`, `getLeafId()`, etc.); see [[concepts/sessions-and-compaction]] for the full API and entry types. - **`ctx.modelRegistry` / `ctx.model`** — model and API-key access. - **`ctx.signal`** — the current agent abort signal, or `undefined` outside an active turn (typically defined during `tool_call`, `tool_result`, `message_update`, `turn_end`; usually `undefined` in idle/session/command/shortcut contexts). Pass to `fetch`, model calls, or abort-aware helpers for Esc-cancellation. - **`ctx.isIdle()` / `ctx.abort()` / `ctx.hasPendingMessages()`** — control-flow helpers. - **`ctx.shutdown()`** — requests graceful shutdown; deferred until idle in interactive mode, deferred to next idle in RPC mode, a no-op in print mode (process exits automatically there). Emits `session_shutdown` first. Available from any handler, tool, command, or shortcut. - **`ctx.getContextUsage()`** — current context usage for the active model (last assistant usage when available, else estimated). - **`ctx.compact()`** — triggers compaction without awaiting; takes `customInstructions`, `onComplete`, `onError`. - **`ctx.getSystemPrompt()`** — the current system-prompt string. During `before_agent_start` it reflects chained changes made so far this turn; it does **not** include later `context` mutations or `before_provider_request` payload rewrites, and later-loaded extensions can still change what's ultimately sent. ### ExtensionCommandContext — command handlers only Extends `ExtensionContext` with session-control methods unavailable to event handlers (to avoid deadlocks): - **`ctx.waitForIdle()`** — wait for the agent to finish streaming before touching session state. - **`ctx.newSession(options?)`** — `{ parentSession?, setup?, withSession? }`; `setup` mutates the new `SessionManager` before `withSession` runs; `withSession` runs post-switch work against a **fresh** replacement-session context. - **`ctx.fork(entryId, options?)`** — `{ position: "before" | "at", withSession? }`; `"before"` (default) forks before the selected user message and restores its text to the editor, `"at"` duplicates the active path without restoring editor text. - **`ctx.navigateTree(targetId, options?)`** — `{ summarize?, customInstructions?, replaceInstructions?, label? }`. - **`ctx.switchSession(sessionPath, options?)`** — `{ withSession? }`; discover sessions via static `SessionManager.list()`/`listAll()`. - **`ctx.reload()`** — runs the same flow as `/reload`: emits `session_shutdown` for the current runtime, reloads resources, emits `session_start{reason:"reload"}` and `resources_discover{reason:"reload"}`. The **currently running handler continues in the old call frame** — code after `await ctx.reload()` still runs the pre-reload version and must not assume old in-memory extension state remains valid. Treat it as terminal: `await ctx.reload(); return;`. Tools run with plain `ExtensionContext` and cannot call `ctx.reload()` directly — expose a command as the reload entrypoint and have a tool queue it via `pi.sendUserMessage("/reload-runtime", { deliverAs: "followUp" })`. **Session replacement lifecycle and footguns**: `withSession` receives a fresh `ReplacedSessionContext` (adds async `sendMessage()`/`sendUserMessage()`) that only runs after the old session's `session_shutdown` has fired, the old runtime is torn down, the replacement is rebound, and the new extension instance has already received `session_start`. The callback body still executes in the **original closure**, not the new extension instance — so your old instance's shutdown cleanup may have already run. Captured old `pi`/old command `ctx` objects are stale and throw if used; only the `ctx` passed into `withSession` is safe for session-bound work. Raw objects captured before replacement (e.g. `const sm = ctx.sessionManager`) remain the *old* object and must not be reused. Safe pattern: capture only plain data (strings, ids) that survives shutdown, and do all session-bound work through the `withSession` callback's own `ctx`. ### ExtensionAPI (`pi`) methods - **`pi.on(event, handler)`** — subscribe (see [Events](#how-it-works) above). - **`pi.registerTool(definition)`** — register an LLM-callable tool (see [Custom Tools](#custom-tools)). Works both during load and after startup — new tools appear immediately in `pi.getAllTools()` without `/reload`. `promptGuidelines` appends tool-specific bullets to the system prompt while the tool is active; each bullet must name the tool explicitly (no "Use this tool..." — the model can't resolve "this"). - **`pi.sendMessage(message, options?)`** — inject a custom message. `deliverAs`: `"steer"` (default; delivered after the current turn's tool calls finish, before the next LLM call), `"followUp"` (only once the agent has no more tool calls), `"nextTurn"` (queued for the next user prompt, non-interrupting). `triggerTurn: true` immediately triggers an LLM response if idle (ignored for `"nextTurn"`). - **`pi.sendUserMessage(content, options?)`** — sends an actual user message (as if typed); always triggers a turn. Requires `deliverAs` (`"steer"` or `"followUp"`) while streaming; throws if streaming without one. - **`pi.appendEntry(customType, data?)`** — persists extension state that does **not** enter LLM context; reconstruct on `session_start` by scanning `ctx.sessionManager.getEntries()` for matching `customType`. - **`pi.setSessionName(name)` / `pi.getSessionName()`** — session display name shown in `/resume`. - **`pi.setLabel(entryId, label)`** — set/clear a bookmark label (`undefined` clears); read via `ctx.sessionManager.getLabel(entryId)`. Persists and survives restarts. - **`pi.registerCommand(name, options)`** — registers `/name`. Colliding names across extensions are all kept, suffixed numerically in load order (`/review:1`, `/review:2`). Supports `getArgumentCompletions(prefix)` for `/command ...` autocompletion. - **`pi.getCommands()`** — lists invocable commands (extension, prompt-template, skill), matching RPC `get_commands` ordering (extensions, then templates, then skills). Each entry has `name`, `description?`, `source`, `sourceInfo: { path, source, scope, origin, baseDir? }` — use `sourceInfo` as the canonical provenance signal, not name/path parsing. Built-in interactive-only commands (`/model`, `/settings`) are excluded. - **`pi.registerMessageRenderer(customType, renderer)`** — custom TUI renderer for a `customType`. - **`pi.registerShortcut(shortcut, options)`** — keyboard shortcut registration. - **`pi.registerFlag(name, options)`** — CLI flag registration; read back with `pi.getFlag(name)`. - **`pi.exec(command, args, options?)`** — run a shell command; returns `{ stdout, stderr, code, killed }`. - **`pi.getActiveTools()` / `pi.getAllTools()` / `pi.setActiveTools(names)`** — manage which tools (built-in or extension-registered) are active. `getAllTools()` returns `name`, `description`, `parameters`, `sourceInfo` (`source` is `"builtin"`, `"sdk"` for SDK `customTools`, or an extension source). - **`pi.setModel(model)`** — sets the current model; returns `false` if no API key is configured. - **`pi.getThinkingLevel()` / `pi.setThinkingLevel(level)`** — reasoning-level control; changes are clamped to model capability and emit `thinking_level_select`. - **`pi.events`** — a shared event bus (`on`/`emit`) for inter-extension communication. - **`pi.registerProvider(name, config)` / `pi.unregisterProvider(name)`** — model provider registration; see [[concepts/custom-providers]] for the full config surface and OAuth details. Calls during the factory are queued until the runner initializes; calls afterward (e.g. from a command handler) apply immediately without `/reload`. ### State management pattern Extensions with state should reconstruct it from session history on `session_start` by scanning tool-result `details` for branching-safe replay, rather than relying purely on an in-memory variable that a branch/fork could invalidate: ```typescript export default function (pi: ExtensionAPI) { let items: string[] = []; pi.on("session_start", async (_event, ctx) => { items = []; for (const entry of ctx.sessionManager.getBranch()) { if (entry.type === "message" && entry.message.role === "toolResult" && entry.message.toolName === "my_tool") { items = entry.message.details?.items ?? []; } } }); pi.registerTool({ name: "my_tool", async execute(toolCallId, params, signal, onUpdate, ctx) { items.push("new item"); return { content: [{ type: "text", text: "Added" }], details: { items: [...items] } }; }, }); } ``` ### Custom Tools Tools register via `pi.registerTool()` and surface through provider tool schemas (no separate rendered tool list in the default prompt). `promptSnippet` is short metadata for extensions composing their own prompts; `promptGuidelines` adds active-tool-only bullets to the default prompt (each bullet must name the tool explicitly). **File mutation safety**: tool calls run in parallel by default, so a custom tool that mutates files must join the same per-file queue as the built-in `edit` tool via `withFileMutationQueue()` — otherwise two tools (or your tool and `edit`) can read stale contents and one write silently clobbers the other. Pass the **resolved absolute path** (via `realpath()` for existing files, so symlink aliases share a queue; the resolved path itself for new files), and wrap the entire read-modify-write window, not just the final write: ```typescript import { withFileMutationQueue } from "@earendil-works/pi-coding-agent"; import { mkdir, readFile, writeFile } from "node:fs/promises"; import { dirname, resolve } from "node:path"; async execute(_toolCallId, params, _signal, _onUpdate, ctx) { const absolutePath = resolve(ctx.cwd, params.path); return withFileMutationQueue(absolutePath, async () => { await mkdir(dirname(absolutePath), { recursive: true }); const current = await readFile(absolutePath, "utf8"); const next = current.replace(params.oldText, params.newText); await writeFile(absolutePath, next, "utf8"); return { content: [{ type: "text", text: `Updated ${params.path}` }], details: {} }; }); } ``` Tool definition fields: `name`, `label`, `description`, `promptSnippet`, `promptGuidelines`, `parameters` (TypeBox schema — **use `StringEnum` from `@earendil-works/pi-ai`**, not `Type.Union`/`Type.Literal`, for Google API compatibility), an optional `prepareArguments(args)` compatibility shim (runs before schema validation, useful for accepting an older resumed-session argument shape without loosening the current public schema), `execute(toolCallId, params, signal, onUpdate, ctx)`, and optional `renderCall`/`renderResult`. **Signaling errors**: throw from `execute()` — this sets `isError: true` and reports the error to the LLM. Returning a value never sets the error flag regardless of its contents. **Early termination**: return `terminate: true` from `execute()` to hint that the automatic follow-up LLM call should be skipped after the current tool batch — but only takes effect when **every** finalized tool result in that batch also terminates. **Overriding built-in tools** (`ipython`, `bash`, `edit`): register a tool with the same name; interactive mode warns when this happens. `--no-builtin-tools` starts with zero built-in tools while keeping extension tools. Rendering inherits per slot independently of execution — omitting `renderCall` or `renderResult` falls back to the built-in renderer for that slot (syntax highlighting, diffs, etc.), so you can wrap a built-in tool for logging/access-control without reimplementing its UI. `promptSnippet`/`promptGuidelines` are **not** inherited from the built-in — redefine them explicitly if wanted. The override's result shape (including `details`) must match exactly, since UI and session logic depend on it. **Remote execution**: `bash` and `edit` support pluggable `operations` for delegating to SSH/containers via `createBashTool(cwd, { operations })`; `createLocalBashOperations()` reuses Prime Agent's local shell backend for `user_bash` without reimplementing process spawning. A `spawnHook` on `createBashTool` can rewrite command/cwd/env before execution (e.g. sourcing a profile, remapping into a sandbox path, injecting env vars). **Output truncation is mandatory**: the built-in limit is 50KB (~10k tokens) or 2000 lines, whichever hits first. Use `truncateHead` (keep-first, good for file reads/search results) or `truncateTail` (keep-last, good for logs/command output), plus `formatSize`, `DEFAULT_MAX_BYTES`, `DEFAULT_MAX_LINES` from `@earendil-works/pi-coding-agent`. Always tell the LLM when output was truncated and where the full version lives (e.g. a temp file path). Unbounded tool output risks context overflow, compaction failures, and degraded model performance. ### Custom UI Available via `ctx.ui`, with different behavior per mode (see [Mode Behavior](#mode-behavior)): - **Dialogs**: `select(title, options)`, `confirm(title, message)`, `input(title, placeholder)`, `editor(title, prefill)`, `notify(message, "info"|"warning"|"error")`. Dialogs accept a `timeout` (ms) for an auto-dismissing countdown (`select`/`input` return `undefined`, `confirm` returns `false` on timeout), or an `AbortSignal` for manual dismissal distinguishable from user-cancel. - **Widgets/status/footer**: `setStatus(key, text)` (footer entry; `undefined` clears), `setWorkingMessage(text)` / `setWorkingVisible(bool)` / `setWorkingIndicator({frames, intervalMs})` (streaming loader customization), `setWidget(key, lines|componentFactory, {placement})` (above/below editor), `setFooter(componentFactory|undefined)` (replaces built-in footer entirely), `setTitle(text)` (terminal title), `setEditorText(text)` / `getEditorText()`, `pasteToEditor(text)` (triggers paste handling incl. large-content collapse), `addAutocompleteProvider(factory)` (stacks on top of built-in slash/path completion — inspect text before cursor, return custom suggestions on match, else delegate to `current`), `getToolsExpanded()`/`setToolsExpanded(bool)`, `setEditorComponent(factory|undefined)`/`getEditorComponent()` (swap the input editor, e.g. for vim/emacs modes — extend `CustomEditor`, not base `Editor`, to retain app keybindings; call `super.handleInput(data)` for unhandled keys), and theme management (`getAllThemes()`, `getTheme(name)`, `setTheme(nameOrTheme)`, `ctx.ui.theme.fg(...)`). - **`ctx.ui.custom()`** — for complex interactions, temporarily replaces the editor with a full custom component until `done(value)` is called. The factory receives `(tui, theme, keybindings, done)`. Supports an **experimental overlay mode** (`{ overlay: true, overlayOptions: {...}, onHandle }`) to render as a floating modal without clearing the screen, with anchor/width/margin positioning and programmatic `handle.setHidden()` visibility control. - **Message rendering**: `pi.registerMessageRenderer(customType, (message, options, theme) => Component)` pairs with `pi.sendMessage({ customType, content, display, details })` to control how custom messages appear in the TUI. - **Theme colors**: `theme.fg("toolTitle"|"accent"|"success"|"error"|"warning"|"muted"|"dim", text)`, `theme.bold/italic/strikethrough(text)`; `highlightCode(code, language, theme)` and `getLanguageFromPath(path)` for syntax highlighting in custom renderers. - **Tool call/result rendering**: `renderCall`/`renderResult` on a tool definition return a `Component`; by default output sits inside a bordered tool panel (`label · status` header, indented body). `renderShell: "self"` opts a tool out of that shell for full control over framing. Both slot renderers receive a `context` with `args`, `state` (shared across call/result slots), `lastComponent`, `invalidate()`, plus `toolCallId`, `cwd`, `executionStarted`, `argsComplete`, `isPartial`, `expanded`, `showImages`, `isError`. `keyHint(keybindingId, description)` / `keyText(id)` / `rawKeyHint(key, description)` format keybinding hints consistent with the user's active keybinding config. ### Error handling Extension errors are logged and the agent continues running. `tool_call` handler errors block the tool (fail-safe). Tool `execute()` errors must be **thrown**, not returned — the framework catches them, sets `isError: true`, reports to the LLM, and execution continues. ### Mode behavior | Mode | UI Methods | Notes | |------|-----------|-------| | Interactive | Full TUI | Normal operation | | RPC (`--mode rpc`) | JSON protocol | Host handles UI; see [[concepts/sdk-and-rpc]] | | JSON (`--mode json`) | No-op | Event stream to stdout | | Print (`-p`) | No-op | Extensions run but can't prompt | Check `ctx.hasUI` before calling UI methods in non-interactive modes. ## Key Parameters - **Event handler return value semantics** vary per event — some block (`tool_call`), some replace/modify (`tool_result`, `message_end`, `before_provider_request`), some only cancel-or-customize (`session_before_compact`, `session_before_tree`, `session_before_switch`, `session_before_fork`), and some are pure notifications (`thinking_level_select`). - **`deliverAs`** (`"steer"` / `"followUp"` / `"nextTurn"`) — controls when an injected or user message reaches the LLM relative to the current turn. - **Load order** — determines both command-suffix numbering on name collisions and the sequencing of chained `tool_result`/`before_provider_request` handlers. - **`renderShell: "self"`** vs. the default tool panel — the escape hatch for tools needing full control over their TUI framing. - **Output truncation limits** — 50KB / 2000 lines, whichever hits first, as the hard ceiling for tool output. ## When To Use - Enforce policy before risky actions: permission gates confirming `rm -rf`/`sudo`, path protection blocking writes to `.env`/`node_modules/`. - Add project-specific automation: git checkpointing (stash per turn, restore on branch), auto-commit on shutdown, file-watcher-triggered messages. - Extend the model's capability surface: stateful tools (todo lists, connection pools), external integrations (webhooks, CI triggers), custom compaction summarization (see [[concepts/sessions-and-compaction]]). - Reshape the interaction surface itself: custom system-prompt injection per turn, interactive wizards, custom editors, custom footers/widgets. - Route model traffic through a custom or proxied provider — see [[concepts/custom-providers]] for the dedicated deep dive on `pi.registerProvider()`. ## Risks & Pitfalls - Extensions run with **full system permissions** — only install extensions from trusted sources; this is not a sandboxed plugin model. - Custom file-mutating tools that skip `withFileMutationQueue()` can silently lose data under Prime Agent's default parallel tool execution, because concurrent writers can each read stale content. - Code after `await ctx.reload()` in a command handler still runs in the **pre-reload** closure — assuming fresh extension state there is a common bug; treat reload as terminal for that handler. - The `withSession` callback for session-replacement APIs (`newSession`, `fork`, `switchSession`) executes in the **original closure**, not the new extension instance — captured old `pi`/`ctx`/`sessionManager` objects are stale and will throw or silently misbehave if reused; only the `ctx` passed into `withSession` is safe. - `promptGuidelines` bullets are appended flat with **no automatic tool-name prefix** — a guideline written as "Use this tool when..." is ambiguous to the model when multiple tools are active; always name the tool explicitly. - Unbounded tool output (skipping truncation) risks context overflow and compaction failures — the 50KB/2000-line ceiling exists for a reason. - In parallel tool execution mode, `tool_call` is not guaranteed to see sibling tool results from the same assistant message, and `tool_execution_update`/`tool_result` ordering across tools may interleave — code that assumes strict sequential ordering across sibling tool calls will misbehave. - `ctx.getSystemPrompt()` does not reflect `context`-event message mutations or `before_provider_request` payload rewrites — debugging "what actually got sent" requires checking `before_provider_request`, not `getSystemPrompt()`. ## Related Concepts - [[concepts/sessions-and-compaction]] — the session tree, compaction, and branch-summary events (`session_before_compact`, `session_before_tree`, and the underlying `SessionManager` API) that extensions hook into. - [[concepts/custom-providers]] — a full deep dive on `pi.registerProvider()`/`pi.unregisterProvider()`, OAuth flows, and custom streaming APIs, one specific extension capability covered only briefly here. - [[concepts/skills]] — the complementary, more lightweight capability-packaging mechanism (markdown/Python skill packages) that extensions coexist with. - [[concepts/sdk-and-rpc]] — RPC mode's extension UI sub-protocol (how `ctx.ui` dialog/fire-and-forget methods map onto `extension_ui_request`/`extension_ui_response` over JSON-RPC) and the SDK's `DefaultResourceLoader` for loading extensions programmatically. ## Sources - raw/github_doc-packages-coding-agent-docs-extensions-md.md --- title: "Long-Running and Background Agents" type: concept tags: [sessions, advanced, well-established, user] created: 2026-08-06 updated: 2026-08-06 sources: ["raw/github_doc-packages-coding-agent-docs-long-running-agents-md.md", "raw/github_doc-packages-coding-agent-docs-daemon-md.md"] confidence: high prime_agent_version: "v0.7.0" --- ## Definition Long-running and background agents is Prime Agent's model for unattended and multi-turn work: "Prime Agent combines daemon-backed session workers with persistent state, scheduled prompts, direct agent messaging, goals, and bounded autonomous continuations. These features serve different purposes but share the same session and worker runtime." This page focuses on that use case — detach/reattach, messaging, scheduling, goals, and autonomous mode — and defers the daemon's internal process/protocol mechanics to [[concepts/daemon]]. ## How It Works ### Runtime Flow A resident session worker holds: user + RLM heartbeats and one-time/cron schedules (both feeding a continuation policy alongside a persistent goal and autonomous mode), a session prompt queue, the `AgentSession`, its persistent IPython kernel, and RLM child sessions. A TUI/CLI client or a peer agent can attach/detach/send messages through the daemon supervisor, which routes into that queue. The session writes a JSONL transcript plus session artifacts, which can restore the session after a restart. "The client can detach at any point. The resident worker continues to own the queue, schedules, session, kernel, descendants, and persisted state." ### Daemon-Backed Sessions "Normal interactive sessions run in resident worker processes managed by a local supervisor. The worker owns the root session, its IPython kernel, scheduled jobs, and RLM descendants." Closing the terminal UI detaches the client — it does not stop the worker: ```bash prime-agent list prime-agent attach ``` Other lifecycle commands: ```bash prime-agent agents # Open the agents view prime-agent rename # Give an agent a stable readable name prime-agent stop # Stop one agent prime-agent status # Inspect background services prime-agent doctor [--fix] # Diagnose or repair service state prime-agent shutdown [--force] # Stop all agents and services ``` "Workers persist transcripts as JSONL and store feature-specific state under the session artifact directory. A worker or supervisor restart can recover session state and schedules and rehydrate retained completed RLM children without treating a terminal client as the owner of the work." Daemon workers "are process-isolated for lifecycle and failure containment, not security-sandboxed. They normally run with the same operating-system permissions as the client." ### Agent-to-Agent Communication The daemon routes direct messages between active sessions and retained daemon-backed subagents. From a shell: ```bash prime-agent send "Please verify the latest migration" ``` From the IPython kernel, via the preloaded `agent_message` Python skill: ```python roster = await agent_message.list_agents() receipt = await agent_message.send( "Recheck the endpoint after the latest edit", receiver_role="sibling", receiver_name="api-reviewer", mode="auto", ) print(receipt["deliveryStatus"]) ``` For the current parent's direct RLM children, prefer the parent-scoped registry (see [[concepts/rlm]] / [[concepts/rlm-runtime]]): ```python children = await rlm.list_subagents() child = next(item for item in children if item.session_name == "api-reviewer") await agent_message.send( "Continue with the updated diff", receiver_role="child", receiver_name=child.session_name, ) ``` Delivery modes: `auto` ("steer a busy target and deliver immediately to an idle target"), `steer` ("intentionally inject the message into active work"), and `follow_up` ("wait until the target's current work finishes"). "A receipt is `delivered` when it reached an idle target's context or `queued` when accepted for later delivery." `agent_message.send("all", message)` "broadcasts only within the family roster." The daemon derives sender identity and enforces message-size, rate, and pending-queue limits. ### Heartbeats and Scheduled Prompts Three related surfaces: | Surface | Owner | Purpose | |---|---|---| | `/heartbeat` | User | One visible recurring instruction for the current session. | | `rlm_heartbeat` | Agent | Multiple programmatically managed recurring instructions internal to the current session. | | `prime-agent schedule` | User or automation | General one-time or cron prompts targeted at an agent. | **User heartbeat**: ```text /heartbeat every 10m Check the deployment and report meaningful changes /heartbeat status /heartbeat pause /heartbeat resume /heartbeat clear ``` "Heartbeat delivery defaults to steering active work. Add `--follow-up` when the recurring prompt should wait until the current turn finishes." `/heartbeats` inspects and manages both user and agent-created heartbeats. **Agent-created RLM heartbeats**: ```python first = await rlm_heartbeat.create( "check whether the test run finished", interval="5m", label="tests", ) second = await rlm_heartbeat.create( "inspect the deployment status", interval="10m", label="deploy", delivery_mode="follow_up", ) await rlm_heartbeat.list() await rlm_heartbeat.update(first["heartbeat"]["id"], status="pause") ``` "RLM heartbeats are distinct from the user's `/heartbeat`; the Python skill cannot replace or clear the user-owned heartbeat." **General schedules**: ```bash prime-agent schedule add worker "in 30m" -- "Check the benchmark result" prime-agent schedule add worker "0 9 * * 1-5" -- "Review open work" prime-agent schedule list --all prime-agent schedule cancel ``` "Scheduled jobs are persisted per session and continue while the UI is detached. Due ticks are claimed before delivery so a crash does not replay an uncertain prompt, and missed ticks are coalesced rather than accumulated into an unbounded backlog." (Persistence path: `session-artifacts//scheduled-jobs.json`, per [[concepts/daemon]].) ### Persistent Goals "A goal is a durable objective that the harness continues to present across turns until it is complete, paused, budget-limited, errored, or cleared." ```text /goal Ship the release and verify every published artifact /goal --budget 200000 Complete the repository migration ``` ```text /goal status /goal pause /goal resume /goal clear ``` The model uses the kernel-side `goal` skill to inspect or finish the objective: ```python state = await goal.get() await goal.complete() ``` "Goal state records token usage, elapsed time, continuation count, and an optional explicit token budget. The harness keeps prompting an active goal after ordinary assistant turns; only `goal.complete()` marks successful completion. Creating a persistent goal is an explicit user or host action, not something the agent should infer from every task." ### Autonomous Mode "Autonomous mode is a bounded host policy for runs where no human input is expected. Prime Agent adds follow-up continuations until configured quality gates pass or a continuation, turn, token, or wall-clock limit is reached." ```text /autonomous on /autonomous status /autonomous off ``` ```bash prime-agent \ --autonomous \ --autonomous-gate "npm run check" \ --autonomous-max-turns 20 \ "Implement and verify the requested change" ``` "Gate commands run before the session may finish; a failed gate returns its bounded output to the agent for another attempt. Prime Agent avoids rerunning the same failed gate when the workspace has not changed." Goals and autonomous mode are complementary but different: "a **goal** stores the objective and its progress state across turns" while "**autonomous mode** decides whether to inject another continuation based on evidence, gates, and limits." ### Compaction and Continuity "Automatic compaction handles context growth during long tasks. On overflow or near the configured threshold, Prime Agent summarizes older messages, retains recent context, and continues. The IPython kernel persists through compaction, so variables, imports, helper functions, and task state remain available." Programmatic access: ```python await compact.status() await compact.run("Preserve the failing tests and remaining migration steps") ``` "Compaction is not a completion signal. It does not stop goals, autonomous continuations, heartbeats, or existing child sessions; later parent turns continue from the compacted context." ## Key Parameters - Autonomous-mode defaults (documented in [[concepts/quickstart-and-usage]]'s CLI reference): `--autonomous-gate-retries` 3, `--autonomous-gate-timeout-ms` 300000 (5 min), `--autonomous-max-continuations` 3, `--autonomous-max-turns` 12, `--autonomous-max-tokens` 80000, `--autonomous-timeout-ms` 1800000 (30 min). - Heartbeat delivery modes: steering (default) or `--follow-up` / `delivery_mode="follow_up"`. - Agent-message delivery modes: `auto`, `steer`, `follow_up`; receipt states `delivered` or `queued`. - Schedule expressions: one-time (e.g., `in 30m`) or standard cron (e.g., `0 9 * * 1-5`). - Worker crash recovery timing (from `docs/daemon.md`): "Recovery retries after 250 ms, 1 second, and 5 seconds; three failures mark that root failed." ## When To Use - Unattended evaluations or CI-style "fix and verify" runs, using `--autonomous` with a gate command such as `npm run check`. - Multi-day or multi-session research/coding tasks where the terminal will be closed and reattached later (`prime-agent list` / `attach`). - Coordinating multiple cooperating agents via `agent_message`, either from the shell (`prime-agent send`) or from inside a session's kernel. - Recurring checks against a moving target (deployments, test runs) via `/heartbeat` or `rlm_heartbeat`, or scheduled one-off/cron prompts via `prime-agent schedule`. - Tracking a durable objective across many turns with `/goal`, independent of whether autonomous mode is also enabled. ## Risks & Pitfalls - "Limits are checked in this order: continuations, turns, tokens, then elapsed time. Reaching one prevents another automatic continuation; it does not imply task success." (from the CLI usage docs, reinforced here: gates, not limits, are the completion signal.) - Goals and autonomous mode are easy to conflate: a goal only tracks/re-presents an objective; only autonomous mode decides whether to inject another continuation, and only `goal.complete()` — not reaching a limit — marks a goal done. - Compaction is lossy for the live context (though full history remains in the JSONL file, revisitable via `/tree`) and explicitly does **not** stop goals, autonomous continuations, heartbeats, or child sessions — code that assumes compaction implies a pause point will be wrong. - `rlm_heartbeat` cannot replace or clear the user's `/heartbeat`; the two are intentionally separate owners. - Daemon/worker process isolation is for lifecycle and failure containment only — "not security-sandboxed. They normally run with the same operating-system permissions as the client," which matters for anything left running unattended for long periods. - Scheduled jobs guard against duplicate delivery ("due ticks are claimed before delivery so a crash does not replay an uncertain prompt") but also coalesce missed ticks rather than replaying every one — a long-detached schedule will not "catch up" tick-by-tick. ## Related Concepts - [[concepts/rlm]] and [[concepts/rlm-runtime]] — the subagent/child mechanics that `agent_message` and the parent-scoped registry build on. - [[concepts/daemon]] — the supervisor/worker process topology, protocol, and crash-recovery internals underlying daemon-backed sessions (not duplicated here). - [[concepts/architecture]] — how the worker/session/kernel pieces referenced here fit the overall system. - [[concepts/prime-agent-overview]] — "Built for Long-Running Work" as one of Prime Agent's headline capabilities. ## Sources - raw/github_doc-packages-coding-agent-docs-long-running-agents-md.md - raw/github_doc-packages-coding-agent-docs-daemon-md.md --- title: "MCP Integrations" type: concept tags: [mcp, area/mcp, audience/developer, scope/advanced, status/well-established] created: 2026-08-06 updated: 2026-08-06 sources: ["raw/github_doc-packages-coding-agent-docs-mcp-integrations-md.md"] confidence: high prime_agent_version: "v0.7.0" --- # MCP Integrations ## Definition An MCP integration connects an external service (e.g. Linear, Notion) to Prime Agent over the [Model Context Protocol](https://modelcontextprotocol.io). Distinctively, Prime Agent does **not** expose MCP servers as new agent tools — consistent with its single-tool design, each integration is instead a [Python-backed skill](#related-concepts) (see [[concepts/skills]]) that the model imports and calls directly from the persistent IPython kernel, e.g. `import linear; issues = await linear.list_issues(team="Engineering")`. ## How It Works ### Architecture The MCP connection runs **inside the IPython kernel** via the official `mcp` Python SDK. The host process's only responsibilities are interactive login (browser OAuth) and minting/refreshing credentials into `auth.json`. This means the tool surface the LLM sees is whatever Python functions the skill package exposes, not a fixed MCP-shaped tool schema. ### Using a built-in integration Built-in integrations (Linear, Notion) ship **disabled**. Logging in enables them: open `/login`, switch to **MCP Connections**, pick the integration, and complete OAuth in the browser (`/mcp login ` does the same from the CLI). Once connected, the integration's skill becomes visible to the model and is auto-imported into the kernel. `/mcp` lists integrations and connection status; `/mcp logout ` disconnects. Credentials are stored once in `auth.json` under `mcp:`; enablement is derived purely from whether valid credentials exist (no separate on/off switch). If you log in mid-turn, the reload is deferred — run `/reload` after the turn to activate the integration. ### How a call works The tool set is defined by the **server**, not the skill — the model must discover before calling, never assume names or schemas: ```python import linear for tool in await linear.list_tools(): print(tool["name"], "-", tool["description"]) help(linear.list_issues) # populated once list_tools() has run result = await linear.list_issues(team="Engineering") ``` Every tool method is `async`. Results are already Python-native (dict/string/content-block list) — no manual `json.loads`. A tool whose name isn't a valid Python identifier (e.g. `notion-search`) is invoked via the escape hatch `await notion.call_tool("notion-search", {...})`. Calling an integration with no credentials raises `NotEnabled`; a tool call that returns an error result raises `McpToolError`. ### Authoring a custom integration An integration is a Python skill package whose module subclasses `McpIntegration` (imported from `rlm`). Two steps: **1. Declare the server** under `mcpServers` in `settings.json`: ```jsonc { "mcpServers": { "acme": { "type": "http", "url": "https://mcp.acme.com/mcp", "oauth": true } } } ``` Only remote `"http"` servers are currently supported — `stdio` (local-subprocess) entries are dropped by the host. HTTP fields: `type` (must be `"http"`), `url`, `oauth` (browser OAuth, requires dynamic client registration support), `bearerTokenEnvVar` (static token instead of OAuth), `headers` (extra static HTTP headers), `enabled` (force-disable even with valid credentials). **2. Ship the skill package** — a normal Python-backed skill directory (`SKILL.md`, `pyproject.toml` depending on `mcp`/`httpx`/`prime-agent-runtime`, `src/acme/__init__.py`). Minimal implementation: ```python from rlm import McpIntegration class Acme(McpIntegration): server = "acme" # matches mcpServers key / auth.json `mcp:acme` url = "https://mcp.acme.com/mcp" acme = Acme() _RESERVED = {"run", "__wrapped__", "__call__"} def __getattr__(name): if name.startswith("_") or name in _RESERVED: raise AttributeError(name) return getattr(acme, name) ``` The base class handles: connecting via the `mcp` SDK, resolving URL/headers from `mcpServers` config, injecting and refreshing the bearer token from `auth.json`, and binding the server's tools as async methods automatically. The `_RESERVED`/`__getattr__` pattern forwards bare module access (`import acme; await acme.(...)`) to the instance without accidentally making the module itself look like a callable skill (which would break kernel bootstrap tool dispatch). **Authentication modes**: OAuth (`"oauth": true`) — user runs `/login` → MCP Connections, or `/mcp login acme`; requires OAuth 2.1 dynamic client registration (RFC 7591) support server-side; servers needing a pre-registered client ID aren't supported this way. Static bearer token (`bearerTokenEnvVar`) — no login step; "connected" whenever the env var is set; the subclass sets the matching `bearer_token_env`. ### The `McpIntegration` API Class attributes: `server: str` (required — the `mcpServers` key / `auth.json` credential id), `url: str | None` (required unless overriding `_open_session`), `bearer_token_env: str | None`. Methods: `await list_tools()` (also populates `help()` docstrings), `await call_tool(name, arguments={})` (escape hatch for non-identifier tool names), and auto-bound `integration.(**kwargs)`. Exceptions (both importable from `rlm`): `NotEnabled`, `McpToolError`. ### Enable-by-login lifecycle (built-in integrations only) 1. Skill ships installed but disabled (excluded from prompt, not imported) — no credentials exist. 2. User logs in; credentials land in `auth.json` under `mcp:`. 3. A resource reload (automatic after `/login`/`/mcp login`, or manual `/reload`) detects credentials, enables the skill, kernel installs + imports it. 4. Logout (or losing credentials) disables it again. **User-authored integrations are not auth-gated this way** — a skill dropped into a skills directory loads immediately regardless of `auth.json`, and simply raises `NotEnabled` at call time until credentials exist. Its `SKILL.md` should tell the model how to connect on `NotEnabled`, matching the configured auth mode: for OAuth, point to `/mcp login `; for bearer token, point to setting the env var (never to `/mcp login`, which has no provider for bearer-only servers and reports "Unknown MCP integration"). ## Key Parameters - **`mcpServers..type`** — must be `"http"`; other transports are dropped. - **`mcpServers..oauth` vs `bearerTokenEnvVar`** — mutually exclusive auth strategies, each with different `NotEnabled` recovery instructions. - **`server` class attribute** — must match both the `mcpServers` key and the `auth.json` credential id (`mcp:`). - **Kernel import name** — equals the `server` value; collides with any unrelated same-named PyPI package on a custom `PRIME_AGENT_KERNEL_PYTHON`. ## When To Use - Connecting a SaaS product (issue tracker, docs tool, CRM) that already exposes a remote MCP server, without inventing a bespoke tool schema. - Wrapping the same MCP server used by other clients so Prime Agent and, say, an editor's MCP client share one backend implementation. - Overriding a built-in integration's endpoint (e.g. testing against a staging Linear/Notion-compatible MCP server) while keeping the official skill's UX. ## Risks & Pitfalls - Overriding a built-in name (e.g. declaring your own `linear` entry in `mcpServers` with a custom `url`) does **not** reuse the previously stored official OAuth credential — for security, only `bearerTokenEnvVar` authenticates such an override; OAuth credentials are never honored for a catalog-name override. - On a custom `PRIME_AGENT_KERNEL_PYTHON`, `import ` can silently resolve to an unrelated PyPI package of the same name instead of your integration; use the default managed kernel venv to avoid this. - OAuth provider registration is process-global; in a multi-session daemon, a user-declared server unique to one daemon session re-registers on that session's next reload. - Tool names and argument schemas come from the server and can change — hardcoding them instead of calling `list_tools()`/`help()` will silently break when the server updates. - Logging in mid-turn does not immediately activate the integration; forgetting the follow-up `/reload` leaves the model unable to see the newly enabled skill. ## Related Concepts - [[concepts/skills]] — MCP integrations are implemented as Python-backed skills; this page assumes that skill packaging model. - [[concepts/extensions]] — the broader extensibility system that skills and integrations sit alongside. ## Sources - raw/github_doc-packages-coding-agent-docs-mcp-integrations-md.md --- title: "Packages Overview" type: concept tags: [architecture, developer, foundational, well-established] created: 2026-08-05 updated: 2026-08-05 sources: ["raw/github_doc-packages-coding-agent-docs-packages-md.md", "raw/github_doc-packages-agent-readme-md.md", "raw/github_doc-packages-ai-readme-md.md", "raw/github_doc-packages-coding-agent-readme-md.md", "raw/github_doc-packages-tui-readme-md.md"] confidence: high prime_agent_version: "v0.7.0" --- ## Definition Prime Agent's monorepo layers four core npm workspace packages — `agent` (stateful agent runtime), `ai` (LLM provider toolkit), `coding-agent` (the CLI/product itself), and `tui` (terminal UI primitives) — plus a separate, unrelated concept also called "packages": user-installable **Prime Agent packages**, which bundle extensions, skills, prompt templates, and themes for distribution via npm or git. This page covers both: the internal package architecture and the external package-installation system. ## How It Works **`packages/agent` (published as `prime-agent-core`, source name inherited from `pi-mono`)** is the stateful agent runtime. Its `Agent` class wraps a message loop around `AgentMessage[]` state (`systemPrompt`, `model`, `thinkingLevel`, `tools`, `messages`), converting to LLM-native messages via a required `convertToLlm` function and optionally pruning/injecting context via `transformContext`. It emits a structured event sequence per prompt (`agent_start` → `turn_start` → `message_start`/`message_update`/`message_end` → `tool_execution_start`/`update`/`end` → `turn_end` → `agent_end`), supports `parallel` (default) or `sequential` tool execution (overridable per-tool via `executionMode`), `beforeToolCall`/`afterToolCall` hooks, steering and follow-up message queues (`steeringMode`/`followUpMode`, "one-at-a-time" or "all"), custom message types via TypeScript declaration merging, and a low-level `agentLoop`/`agentLoopContinue` API for callers who don't need the `Agent` class's barrier semantics around tool preflight. **`packages/ai` (published as `prime-agent-ai`)** is the unified LLM provider toolkit — "only includes models that support tool calling," since that's essential for agentic workflows. It exposes `stream`/`complete` (full event/provider control) and `streamSimple`/`completeSimple` (unified reasoning interface) over roughly two dozen providers (OpenAI, Anthropic, Google/Vertex, Mistral, Groq, Cerebras, Cloudflare, xAI, OpenRouter, Bedrock, GitHub Copilot, DeepSeek, and more — see [[concepts/providers-and-models]]), TypeBox-schema tool definitions with `validateToolCall`, streaming partial tool-call JSON, image input for vision models, thinking/reasoning content across providers, cross-provider handoff (thinking blocks from a different provider get converted to ``-tagged text), and OAuth flows for Anthropic/OpenAI Codex/GitHub Copilot via the `prime-agent-ai/oauth` entry point. A `registerFauxProvider()` helper registers a scripted in-memory provider for tests, used by `coding-agent`'s regression suite (see [[concepts/development]]). **`packages/coding-agent`** is the CLI product itself — the "RLM-native terminal coding and research harness." It composes `agent` and `ai` into the interactive TUI, the daemon (see [[concepts/daemon]]), sessions ([[concepts/sessions-and-compaction]]), settings ([[concepts/settings-and-customization]]), skills/extensions/MCP integrations ([[concepts/skills]], [[concepts/extensions]], [[concepts/mcp-integrations]]), and every CLI mode (interactive, `-p`/print, `--mode json`, `--mode rpc`, `--mode acp`). It exposes a programmatic SDK (`createAgentSession`, `SessionManager`, `ModelRegistry`, `AuthStorage`) for embedding — see [[concepts/sdk-and-rpc]]. **`packages/tui` (published as `prime-agent-tui`)** is the standalone terminal UI framework `coding-agent` builds its interactive mode on — differential rendering, synchronized output, bracketed paste, and the component/overlay primitives detailed in [[concepts/tui-and-themes]]. It is usable independently of Prime Agent for building other flicker-free terminal apps. All four packages currently retain inherited `@earendil-works/pi-*` source workspace names from the `pi-mono` fork lineage — release docs and public documentation use the Prime Agent package names (`prime-agent-core`, `prime-agent-ai`, `prime-agent-tui`) throughout, and the source names are called out explicitly as an in-progress namespace migration, not the documented public interface. **Prime Agent packages (the installable-bundle system)** are a separate concept: a package declares `extensions`, `skills`, `prompts`, and `themes` resource arrays either under a `pi` key in `package.json` (for compatibility with the inherited extension ecosystem) or via convention directories (`extensions/`, `skills/`, `prompts/`, `themes/`) when no manifest is present. Three source types are accepted: - **npm**: `npm:@scope/pkg@1.2.3` or `npm:pkg`; versioned specs are pinned (skipped by `package update`); global installs use `npm install -g`, project installs go under `.prime/agent/npm/`. - **git**: `git:github.com/user/repo@v1`, `git:git@github.com:user/repo@v1`, or raw `https://`/`ssh://` URLs; refs pin the package; cloned to `~/.prime/agent/git//` (global) or `.prime/agent/git//` (project); runs `npm install` after clone/pull if a `package.json` exists. - **Local paths**: absolute or relative filesystem paths, added to settings without copying; a file path loads as a single extension, a directory loads via package rules. Management commands: `prime-agent package install [--local]`, `package remove`, `package list`, `package update [source]`. `-e`/`--extension ` loads a package temporarily (current run only, to a temp directory) without installing it. Package filtering in settings (object form with `extensions`/`skills`/`prompts`/`themes` glob arrays, `!exclude`, `+forceInclude`, `-forceExclude`) narrows what an installed package actually loads. Third-party runtime dependencies belong in `package.json` `dependencies` (installed automatically); a package that imports Prime Agent's own core libraries (`@earendil-works/pi-ai`, `pi-agent-core`, `pi-coding-agent`, `pi-tui`, `typebox`) must list them as `peerDependencies` with a `"*"` range rather than bundling them, since Prime Agent already provides them at runtime. Packages appearing in both global and project settings dedupe by identity (npm package name, git repo URL sans ref, or resolved local path); on conflict, the project entry wins. ## Key Parameters - **Four core packages**: `agent` (runtime), `ai` (providers), `coding-agent` (product/CLI), `tui` (UI) — each independently publishable, `coding-agent` depending on the other three. - **`Agent` tool execution modes**: `parallel` (default, global or per-tool via `executionMode`) vs. `sequential`; any `sequential` tool in a batch forces the whole batch sequential. - **`ai` faux provider**: `registerFauxProvider({ tokensPerSecond? })` — deterministic scripted responses for tests, not part of the built-in provider set. - **Package source identity for dedup**: npm → package name; git → repo URL without ref; local → resolved absolute path. - **`peerDependencies` requirement**: Prime Agent's own core libraries (`pi-ai`, `pi-agent-core`, `pi-coding-agent`, `pi-tui`, `typebox`) must never be bundled by a third-party package. ## When To Use Consult the internal package breakdown when deciding where a change belongs (agent-loop/event semantics → `agent`; provider/model/streaming behavior → `ai`; CLI/TUI/daemon/session product behavior → `coding-agent`; terminal-rendering primitives → `tui`) or when embedding Prime Agent programmatically via the `agent`/`ai` SDKs directly rather than the CLI. Consult the installable-packages system when distributing a bundle of extensions/skills/prompts/themes to a team (via git or npm, project-local with `--local` for team-shared settings) or when trying a package once without committing to an install (`-e`/`--extension`). ## Risks & Pitfalls - Confusing the two "package" concepts described here — internal monorepo workspace packages (`agent`, `ai`, `coding-agent`, `tui`) versus user-installable Prime Agent packages (npm/git/local bundles of extensions/skills/prompts/themes) — is an easy documentation trap since both use the word "package." - Bundling Prime Agent's own core libraries as regular `dependencies` in a third-party package (instead of `peerDependencies`) risks shipping a duplicate, possibly incompatible copy alongside the host's own runtime instance. - Pinned npm/git package specs (with an explicit version or ref) are silently skipped by `prime-agent package update` — a common source of "why isn't this getting the latest version" confusion. - Package filtering syntax mixes glob exclusion (`!pattern`) with exact-path force-include/exclude (`+path`/`-path`); these operate differently and are easy to conflate. ## Related Concepts - [[concepts/architecture]] — how `agent`, `ai`, `coding-agent`, and `tui` fit into Prime Agent's overall runtime architecture - [[concepts/extensions]] and [[concepts/skills]] — the resource types that Prime Agent packages bundle and distribute - [[concepts/providers-and-models]] — the provider catalog implemented in `packages/ai` - [[concepts/tui-and-themes]] — built on `packages/tui` - [[concepts/daemon]] and [[concepts/sessions-and-compaction]] — core `coding-agent` subsystems - [[concepts/sdk-and-rpc]] — the programmatic SDK surface `coding-agent` exposes over `agent`/`ai` - [[concepts/development]] — building and validating changes across these packages from source ## Sources - raw/github_doc-packages-coding-agent-docs-packages-md.md - raw/github_doc-packages-agent-readme-md.md - raw/github_doc-packages-ai-readme-md.md - raw/github_doc-packages-coding-agent-readme-md.md - raw/github_doc-packages-tui-readme-md.md --- title: "Platform Setup" type: concept tags: [platform, user, foundational, well-established] created: 2026-08-05 updated: 2026-08-05 sources: ["raw/github_doc-packages-coding-agent-docs-terminal-setup-md.md", "raw/github_doc-packages-coding-agent-docs-windows-md.md", "raw/github_doc-packages-coding-agent-docs-termux-md.md", "raw/github_doc-packages-coding-agent-docs-tmux-md.md"] confidence: high prime_agent_version: "v0.7.0" --- ## Definition Prime Agent runs across a range of terminal emulators, operating systems, and multiplexers, but reliable modifier-key handling (`Shift+Enter` for newline, `Ctrl+Enter`, etc.) depends on the terminal supporting either the Kitty keyboard protocol or, failing that, correctly configured extended key reporting. Platform setup covers general terminal compatibility, Windows-specific shell requirements, running under Termux on Android, and tmux configuration — each with its own gap between "works out of the box" and "needs one extra config line." ## How It Works **General terminal compatibility.** Prime Agent uses the [Kitty keyboard protocol](https://sw.kovidgoyal.net/kitty/keyboard-protocol/) for reliable modifier-key detection. Kitty and iTerm2 work out of the box. Ghostty needs `keybind = alt+backspace=text:\x1b\x7f` added to its config; an older `keybind = shift+enter=text:\n` mapping some users added for Claude Code sends a raw linefeed indistinguishable from `Ctrl+J` inside Prime Agent, breaking real `Shift+Enter` detection in both tmux and Prime Agent — remove it unless still needed for Claude Code in tmux, in which case add `ctrl+j` to the `newLine` keybinding in `~/.prime/agent/keybindings.json` (`{"newLine": ["shift+enter", "ctrl+j"]}`) to keep both working. WezTerm needs `config.enable_kitty_keyboard = true` in `~/.wezterm.lua`. VS Code's integrated terminal needs a `keybindings.json` entry sending `\u001b[13;2u` for `Shift+Enter` when `terminalFocus`. Windows Terminal needs `sendInput` actions remapping `Shift+Enter` (`\u001b[13;2u`) and `Alt+Enter` (`\u001b[13;3u`) — the latter is necessary because Windows Terminal binds `Alt+Enter` to fullscreen by default, which otherwise prevents Prime Agent from ever seeing that chord for follow-up message queueing (see [[concepts/tui-and-themes]] for the message-queue Alt+Enter binding). xfce4-terminal, terminator, and IntelliJ IDEA's built-in terminal have limited escape-sequence support and cannot distinguish modified Enter from plain Enter at all — a dedicated terminal (Kitty, Ghostty, WezTerm, iTerm2, or Alacritty compiled with Kitty protocol support) is recommended instead. In IntelliJ specifically, set `PI_HARDWARE_CURSOR=1` if a visible hardware cursor is wanted (disabled by default for compatibility). **Windows.** Prime Agent requires a bash shell on Windows and checks, in order: a custom path from `~/.prime/agent/settings.json`, Git Bash at `C:\Program Files\Git\bin\bash.exe`, then any `bash.exe` on `PATH` (Cygwin, MSYS2, WSL). For most users, installing [Git for Windows](https://git-scm.com/download/win) is sufficient. A non-default shell (e.g., Cygwin) is configured via the `shellPath` setting: `{"shellPath": "C:\\cygwin64\\bin\\bash.exe"}` (see [[concepts/settings-and-customization]]). **Termux (Android).** Prime Agent runs on Android through [Termux](https://termux.dev/). Prerequisites are Termux itself (from GitHub or F-Droid — not the deprecated Google Play build) and Termux:API (for clipboard and device integrations). Installation is standard Node tooling inside Termux: ```bash pkg update && pkg upgrade pkg install nodejs termux-api git ripgrep git clone https://github.com/PrimeIntellect-ai/prime-agent.git cd prime-agent npm ci ./prime-agent.sh ``` Clipboard operations use `termux-clipboard-set`/`termux-clipboard-get` (text only — image clipboard, and thus the `Ctrl+V` image-paste feature, is unsupported on Termux). Some optional native dependencies (like the clipboard module) are skipped on Android ARM64 during install. Accessing shared storage (`/storage/emulated/0`) requires running `termux-setup-storage` once. A project `~/.prime/agent/AGENTS.md` can describe the Termux environment to the agent (home path, prefix, URL-opening via `termux-open-url`, notifications via `termux-notification`, etc.) so it reasons correctly about the sandboxed filesystem layout. **tmux.** tmux strips modifier information from certain keys by default, making `Shift+Enter`/`Ctrl+Enter` indistinguishable from plain `Enter` without configuration. The recommended `~/.tmux.conf` addition is: ```tmux set -g extended-keys on set -g extended-keys-format csi-u ``` followed by a full tmux restart (`tmux kill-server` then `tmux`). Prime Agent requests extended key reporting automatically when the Kitty keyboard protocol isn't available. With only `extended-keys on` (no format specified), tmux defaults to `extended-keys-format xterm`, forwarding modified keys in xterm `modifyOtherKeys` format (e.g., `Ctrl+Enter` → `\x1b[27;5;13~`); with `csi-u`, the same keys forward as CSI-u sequences (e.g., `Ctrl+Enter` → `\x1b[13;5u`). Prime Agent supports both formats but recommends `csi-u`. Without extended keys at all, modified Enter variants collapse to legacy sequences indistinguishable from each other (`Enter`, `Shift+Enter`, and `Ctrl+Enter` all send `\r`; only `Alt+Enter` differs, as `\x1b\r`). Requirements: tmux 3.2+ (`tmux -V` to check) and a terminal emulator supporting extended keys (Ghostty, Kitty, iTerm2, WezTerm, Windows Terminal). ## Key Parameters - **Kitty keyboard protocol**: the primary mechanism Prime Agent relies on for modifier-key detection; supported natively by Kitty, iTerm2, Ghostty, and WezTerm (with config). - **tmux `extended-keys-format`**: `xterm` (tmux default when only `extended-keys on` is set) vs. `csi-u` (recommended) — determines the escape-sequence dialect forwarded to Prime Agent. - **`shellPath`** setting: overrides Windows bash discovery order. - **`PI_HARDWARE_CURSOR=1`**: enables the hardware cursor in terminals (like IntelliJ's) with limited escape support; disabled by default. - **tmux version floor**: 3.2 or later required for `extended-keys` support. ## When To Use Consult platform setup whenever `Shift+Enter` doesn't insert a newline, `Alt+Enter` doesn't queue a follow-up message, or any modifier-augmented keybinding behaves like plain `Enter` — the fix is almost always a terminal- or multiplexer-level configuration change, not a Prime Agent keybinding change (see [[concepts/tui-and-themes]] for the keybinding layer itself). Consult the Windows section specifically when Prime Agent reports it cannot find a bash shell. Consult Termux setup when running Prime Agent on an Android device rather than a desktop OS — note it requires building from source via `npm ci`, not the standard install script. ## Risks & Pitfalls - A Ghostty config carried over from Claude Code setup (`shift+enter=text:\n`) actively breaks Prime Agent's and tmux's ability to distinguish `Shift+Enter` from `Ctrl+J` — this is a cross-tool config collision, not a Prime Agent bug, and needs either removal or a compensating keybinding. - Windows Terminal's default `Alt+Enter` → fullscreen binding silently swallows the follow-up-message keybinding until remapped; the fix requires editing Windows Terminal's own `settings.json`, not Prime Agent's. - xfce4-terminal, terminator, and IntelliJ's integrated terminal have a hard compatibility ceiling — no Prime Agent-side configuration can restore modified-Enter detection there; only switching terminal emulators fixes it. - tmux configured with only `extended-keys on` (omitting `extended-keys-format csi-u`) still works, but uses the less-recommended `xterm` format — a subtly incomplete fix that may not be obvious from behavior alone. - Termux lacks image-clipboard support entirely; `Ctrl+V` image paste is a no-op there regardless of configuration. ## Related Concepts - [[concepts/tui-and-themes]] — the keybinding system that platform terminal configuration exists to make reliable (message-queue Enter/Alt+Enter, editor newline, etc.) - [[concepts/settings-and-customization]] — `shellPath` is set through the standard settings file mechanism - [[concepts/development]] — running Prime Agent from source (as Termux setup requires) is covered in more detail there - [[concepts/daemon]] — daemon behavior is platform-independent, but native Windows specifically lacks a default `app.suspend` binding because Windows terminals don't support Unix job control (WSL retains normal Linux `Ctrl+Z`/`fg` behavior) ## Sources - raw/github_doc-packages-coding-agent-docs-terminal-setup-md.md - raw/github_doc-packages-coding-agent-docs-windows-md.md - raw/github_doc-packages-coding-agent-docs-termux-md.md - raw/github_doc-packages-coding-agent-docs-tmux-md.md --- title: "Prime Agent Overview" type: concept tags: [overview, rlm, foundational, well-established, user] created: 2026-08-06 updated: 2026-08-06 sources: ["raw/github_doc-readme-md.md", "raw/github_doc-packages-coding-agent-docs-index-md.md", "raw/github_doc-agents-md.md"] confidence: high prime_agent_version: "v0.7.0" --- ## Definition Prime Agent is Prime Intellect's open-source coding and research agent, subtitled in its own README "A Self-Improving RLM Agent." It is "an open-source coding and research agent for general and long-running work," distributed as a terminal coding agent with a TUI, an embeddable SDK, and a daemon-backed background-worker model. The project began as a hard fork of [pi-mono](https://github.com/badlogic/pi-mono) but, per its documentation index, "Prime Agent is now the product, CLI, install source, and development repository," and it sits alongside Prime Intellect's other RL-research projects — Verifiers, PRIME-RL, and pi-mono — as part of the same ecosystem. ## How It Works The README states Prime Agent "is designed around two core abstractions": - The **Recursive Language Model (RLM)** — "treats context as variables (*prompt-as-a-variable*) and tools like recursive subagents as function calls (*programmatic tool /sub-agent calling*) inside a persistent REPL." See [[concepts/rlm]]. - The **Continual Harness** (arXiv:2605.09998) — "stores supplemental prompts, memories, skill descriptions, and reusable subagent specifications as durable state that Prime Agent can refine through small, evidence-backed updates, local to the session by default." "Prime Agent combines a persistent Python control environment with durable harness state, so useful working context and reusable operating patterns can outlive a single chat window." The "self-improving" framing comes from the harness side of this pair: `/refine` "reviews the current trajectory and can apply small, evidence-backed updates to supplemental harness state. It never rewrites the immutable base system prompt, and recorded snapshots support rollback." This is refinement of durable *operating state* (prompts, memories, skill descriptions, subagent specs), not retraining of the underlying model. The README's condensed summary of the design: - "Everything is programmatic:" persistent IPython is the built-in model tool; file operations, shell commands, tool use, subagents, and context management happen through code. - "Subagents are built in:" `rlm(...)` spawns real child agents for parallel or background work and returns their results programmatically. - "The harness can improve:" `/refine` applies small, evidence-backed updates to supplemental harness state. - "Skills are executable:" skills are importable Python packages, and a built-in skill creator can turn recurring workflows into skills. - "Sessions run in the background:" daemon-backed agents keep running when the terminal disconnects and can be reattached later. - "Agents communicate directly:" running agents can exchange messages and orchestrate one another. - "Long tasks keep moving:" automatic compaction, persistent goals, heartbeats, schedules, autonomous mode, and retained subagents preserve progress across turns and terminal sessions. The documentation index describes Prime Agent as "an RLM-native coding and research harness built around a persistent IPython kernel, recursive subagents, durable sessions, and a multi-process local runtime." ## Key Parameters - Documented current stable release: `v0.7.0` (this wiki's `prime_agent_version`). - Single built-in model tool: `ipython`. - License: MIT (`LICENSE`, README "License" section). - Built on top of `pi` (earendil-works/pi); the README's Acknowledgements section states "Our agent and TUI is built on top of [`pi`]... We thank the authors of `pi` for their valuable work." - Ecosystem links given directly in the README header: [Verifiers](https://github.com/PrimeIntellect-ai/verifiers), [PRIME-RL](https://github.com/PrimeIntellect-ai/prime-rl), [pi-mono](https://github.com/badlogic/pi-mono). - `AGENTS.md` (development rules) organizes issues with `pkg:*` labels for the monorepo's packages: `pkg:agent`, `pkg:ai`, `pkg:coding-agent`, `pkg:tui` — corresponding to the four core packages covered in [[concepts/architecture]]. ## When To Use Per the README's "Built for Long-Running Work" section, Prime Agent "is built for long-running work, especially for evaluations in research." It is intended for both interactive, everyday coding assistance (terminal TUI) and for unattended or long-horizon work via its daemon-backed sessions, goals, heartbeats, schedules, and bounded autonomous mode. See [[concepts/long-running-agents]] and [[concepts/quickstart-and-usage]]. ## Risks & Pitfalls The README carries an explicit warning: "Prime Agent executes model-generated Python and project commands with your user permissions. Its worker and kernel processes improve lifecycle isolation and recovery; they are **not** a security sandbox. Review changes and use trusted repositories, instructions, skills, and extensions only. Run untrusted code or instructions in an external sandbox or restricted environment." The README also recommends using "a disposable clone, clean worktree, or another checkpoint you can inspect and restore" before letting Prime Agent modify a working directory. ## Related Concepts - [[concepts/rlm]] — the Recursive Language Model programming model that Prime Agent is built around. - [[concepts/rlm-runtime]] — the concrete runtime that executes the RLM loop. - [[concepts/architecture]] — the packages/monorepo layout and system topology. - [[concepts/quickstart-and-usage]] — install, first run, and the day-to-day usage loop. - [[concepts/long-running-agents]] — the daemon-backed model for long/autonomous tasks. ## Sources - raw/github_doc-readme-md.md - raw/github_doc-packages-coding-agent-docs-index-md.md - raw/github_doc-agents-md.md --- title: "Providers and Models" type: concept tags: [providers, area/providers, scope/foundational, status/well-established] created: 2026-08-06 updated: 2026-08-06 sources: ["raw/github_doc-packages-coding-agent-docs-providers-md.md", "raw/github_doc-packages-coding-agent-docs-models-md.md"] confidence: high prime_agent_version: "v0.7.0" --- # Providers and Models ## Definition A **provider** in Prime Agent is a named source of models that speaks one of a small set of supported streaming APIs (`anthropic-messages`, `openai-completions`, `openai-responses`, `google-generative-ai`, and others). A **model** is a specific model ID exposed by a provider, with metadata describing its capabilities (reasoning, image input, context window, cost). Prime Agent ships a built-in catalog of providers and models, updated with each release, and lets users add or override providers and models through `~/.prime/agent/models.json` without writing code. ## How It Works ### Authentication paths Prime Agent resolves credentials for a provider through one of three mechanisms: 1. **Subscriptions (OAuth)** — `/login` in interactive mode, selecting ChatGPT Plus/Pro (Codex), Claude Pro/Max, or GitHub Copilot. Tokens are stored in `~/.prime/agent/auth.json` and auto-refresh when expired. `/logout` clears credentials. 2. **API keys** — set via environment variable (e.g. `ANTHROPIC_API_KEY`) or stored in `auth.json` via `/login`. Each built-in provider has a documented env var and an `auth.json` key, for example Anthropic (`ANTHROPIC_API_KEY` / `anthropic`), OpenAI (`OPENAI_API_KEY` / `openai`), Prime Inference (`PRIME_API_KEY` / `prime-inference`), OpenRouter (`OPENROUTER_API_KEY` / `openrouter`), and many more (DeepSeek, Google Gemini, Mistral, Groq, Cerebras, Cloudflare, xAI, Vercel AI Gateway, ZAI, OpenCode, Hugging Face, Fireworks, Kimi For Coding, MiniMax, Xiaomi MiMo variants). 3. **Cloud providers with structured config** — Azure OpenAI, Amazon Bedrock, Cloudflare AI Gateway, Cloudflare Workers AI, and Google Vertex AI each use their own environment-variable set (e.g. `AZURE_OPENAI_API_KEY` + `AZURE_OPENAI_BASE_URL`, or `AWS_PROFILE`/`AWS_ACCESS_KEY_ID`/`AWS_BEARER_TOKEN_BEDROCK` for Bedrock). The `auth.json` `key` field for API-key entries supports three resolution formats: a **shell command** prefixed with `!` (executed and cached for the process lifetime, e.g. `"!op read 'op://vault/item/credential'"`), an **environment variable name**, or a **literal value**. Auth-file credentials take priority over environment variables. **Credential resolution order** when Prime Agent needs a key for a provider: 1. CLI `--api-key` flag 2. `auth.json` entry (API key or OAuth token) 3. Environment variable 4. Custom provider keys from `models.json` ### Custom and local models via `models.json` `~/.prime/agent/models.json` adds providers and models without code. For local model servers (Ollama, LM Studio, vLLM), only an `id` is required per model: ```json { "providers": { "ollama": { "baseUrl": "http://localhost:11434/v1", "api": "openai-completions", "apiKey": "ollama", "models": [ { "id": "llama3.1:8b" }, { "id": "qwen2.5-coder:7b" } ] } } } ``` The file **reloads every time `/model` is opened** — edits apply mid-session with no restart needed. Supported `api` values: `openai-completions` (most compatible), `openai-responses`, `anthropic-messages`, `google-generative-ai` (the last requires `baseUrl` even for Google AI Studio models). `api` can be set at the provider level (default) or overridden per model. **Provider config fields:** `baseUrl`, `api`, `apiKey`, `headers`, `authHeader` (adds `Authorization: Bearer ` automatically), `models`, `modelOverrides`. **Model config fields:** `id` (required), `name` (defaults to `id`; used for `--model` pattern matching and status text), `api` override, `reasoning` (default `false`), `thinkingLevelMap`, `input` (`["text"]` or `["text","image"]`), `contextWindow` (default 128000), `maxTokens` (default 16384), `cost` (per-million-token `{input, output, cacheRead, cacheWrite}`, default all zero), `compat`. ### Overriding built-in providers vs. registering new ones Setting only `baseUrl`/`headers` on a built-in provider name (e.g. `anthropic`) routes existing OAuth/API-key auth and all built-in models through a proxy, keeping the full built-in model list. Adding a `models` array to that same provider **merges**: built-in models are kept, and models are upserted by `id` (a custom model with a matching `id` replaces the built-in one; a new `id` is added alongside). `modelOverrides` customizes specific built-in models (name, reasoning, input, partial cost, contextWindow, maxTokens, headers, compat) **without replacing the provider's full model list** — unknown model IDs in `modelOverrides` are silently ignored. Registering a provider name that is genuinely new, with a `models` array, **replaces** all existing models for that provider name (this matters more for extension-registered providers; see [[concepts/custom-providers]]). ### Thinking level mapping `thinkingLevelMap` translates Prime Agent's six thinking levels (`off`, `minimal`, `low`, `medium`, `high`, `xhigh`) to provider-specific values. Each key is tristate: omitted uses the provider default mapping, a string value is sent verbatim, and `null` marks the level unsupported (hidden/clamped in the UI). Example — a model that only supports off/high/max: ```json { "id": "deepseek-v4-pro", "reasoning": true, "thinkingLevelMap": { "minimal": null, "low": null, "medium": null, "high": "high", "xhigh": "max" } } ``` ### OpenAI-compatibility (`compat`) flags Because many servers implement `openai-completions` slightly differently, per-provider or per-model `compat` flags patch the gaps: `supportsDeveloperRole` (use `system` instead of `developer` role), `supportsReasoningEffort`, `supportsUsageInStreaming`, `maxTokensField` (`max_completion_tokens` vs `max_tokens`), `requiresToolResultName`, `requiresAssistantAfterToolResult`, `requiresThinkingAsText`, `requiresReasoningContentOnAssistantMessages`, `thinkingFormat` (`reasoning_effort` | `deepseek` | `zai` | `qwen` | `qwen-chat-template`), `cacheControlFormat: "anthropic"` (Anthropic-style `cache_control` markers on system prompt/tools/last text), `supportsStrictMode`, `supportsLongCacheRetention`, `openRouterRouting`, `vercelGatewayRouting`. Model-level `compat` overrides provider-level `compat` for that model. For `anthropic-messages` proxies, `supportsEagerToolInputStreaming` (default `true`) controls whether Prime Agent sends per-tool `eager_input_streaming` or falls back to the legacy fine-grained-tool-streaming beta header. ## Key Parameters - **`api`** — which streaming implementation is used (`anthropic-messages`, `openai-completions`, `openai-responses`, `google-generative-ai`, plus provider-specific ones registered via extensions). - **`reasoning`** — whether a model supports extended thinking; gates whether `thinkingLevelMap` applies. - **`contextWindow` / `maxTokens`** — sizing defaults (128000 / 16384) used when not specified. - **`cost`** — `{input, output, cacheRead, cacheWrite}` per million tokens, used for usage/cost tracking; defaults to all zeros for custom models. - **`compat`** — the escape hatch for OpenAI-compatible servers that deviate from the reference implementation. - **Auth resolution order** — CLI flag > `auth.json` > env var > `models.json` custom keys. ## When To Use - Point Prime Agent at a self-hosted or local inference server (Ollama, vLLM, LM Studio) by adding a minimal `models.json` entry. - Route a built-in provider (e.g. Anthropic) through a corporate proxy or gateway while keeping all built-in models and existing auth. - Add pricing/capability metadata for a niche or newly released model not yet in the built-in catalog. - Tune OpenAI-compatible server quirks (role names, token field names, thinking parameter formats) via `compat` instead of writing code. - When the need goes beyond declarative config — OAuth flows, non-standard streaming, or dynamic model discovery from a remote endpoint at startup — use an extension instead; see [[concepts/custom-providers]]. ## Risks & Pitfalls - Declaring a `models` array on an existing provider **replaces** the model list for a genuinely new provider name (not for built-in overrides, where it merges) — the merge-vs-replace distinction depends on whether the provider name is built-in. - Shell-command (`"!command"`) key resolution has **no built-in TTL, stale-value reuse, or recovery logic** — a slow, rate-limited, or flaky command needs its own caching wrapper. - `/model` availability checks use configured auth presence only and do not execute shell commands, so a broken shell command may not surface until an actual request is made. - Forgetting `baseUrl` when adding custom models to `google-generative-ai` will fail — it's required for that API type even for Google AI Studio. - Mismatched `compat` flags (e.g. wrong `thinkingFormat` or missing `supportsDeveloperRole: false`) are a common source of confusing 400 errors from OpenAI-compatible local servers. ## Related Concepts - [[concepts/custom-providers]] — registering providers programmatically via extensions, including OAuth and custom streaming APIs, when `models.json` isn't expressive enough. - [[concepts/sdk-and-rpc]] — the `ModelRegistry` and `AuthStorage` classes used to resolve models and credentials programmatically. - [[concepts/extensions]] — the general extension mechanism that `pi.registerProvider()` is part of. ## Sources - raw/github_doc-packages-coding-agent-docs-providers-md.md - raw/github_doc-packages-coding-agent-docs-models-md.md --- title: "Quickstart and Usage" type: concept tags: [overview, platform, foundational, well-established, user] created: 2026-08-06 updated: 2026-08-06 sources: ["raw/github_doc-packages-coding-agent-docs-quickstart-md.md", "raw/github_doc-packages-coding-agent-docs-usage-md.md", "raw/github_doc-packages-coding-agent-docs-terminal-setup-md.md"] confidence: high prime_agent_version: "v0.7.0" --- ## Definition Quickstart and Usage cover the path from installing Prime Agent to a working first session, plus the recurring day-to-day interaction loop: the terminal UI, its editor and slash commands, session management, and the `prime-agent` CLI (flags, modes, and environment variables). ## How It Works ### Install ```bash curl -fsSL https://app.primeintellect.ai/prime-agent/install.sh | sh ``` For the latest beta built from `main`: ```bash curl -fsSL https://app.primeintellect.ai/prime-agent/install.sh | sh -s -- beta ``` "Both commands fetch versioned Prime Agent release artifacts and install the `prime-agent` command. The inherited npm workspace identifiers in the source tree are not the public install path." To run from a source checkout (requires Node.js 22.8.0 or newer): ```bash git clone https://github.com/PrimeIntellect-ai/prime-agent cd prime-agent npm ci ./prime-agent.sh ``` Then start it in the target project directory: ```bash cd /path/to/project prime-agent ``` ### Authenticate Two paths, both reachable via `/login`: - **Subscription login** — run `/login` inside Prime Agent and pick a provider. "Built-in subscription logins include Claude Pro/Max, ChatGPT Plus/Pro (Codex), and GitHub Copilot." - **API key** — set an environment variable before launch, e.g. `export ANTHROPIC_API_KEY=sk-ant-...`, or run `/login` and choose an API-key provider to store the key in `~/.prime/agent/auth.json`. ### First Session and the IPython Loop "Prime Agent gives the model one built-in tool, `ipython`. The long-lived kernel is a control environment for reading and editing files, running project commands, inspecting data, retaining Python state, and invoking installed skills." The kernel bootstraps automatically on first use; set `PRIME_AGENT_KERNEL_PYTHON` to reuse an existing Python environment with `ipykernel`. Recursive subagents are reachable directly from a prompt, e.g.: "Review authentication and test coverage as independent subtasks. Run them in parallel, then synthesize the findings." See [[concepts/rlm]] for the mechanics of `rlm(...)`. ### Project Instructions Prime Agent loads context files at startup: `~/.prime/agent/AGENTS.md` for global instructions, and `AGENTS.md` or `CLAUDE.md` walking up from parent directories to the current directory. Restart Prime Agent, or run `/reload`, after changing context files. ### Interactive Mode The interface has four areas: **Startup header** (compact brand/runtime summary; `--verbose` lists loaded context files, prompt templates, skills, extensions), **Messages**, **Editor**, and **Footer** (empty by default; `/usage` shows token/cost/context details). | Feature | How | |---------|-----| | File reference | Type `@` to fuzzy-search project files | | Path completion | Tab | | Multi-line input | Shift+Enter, or Ctrl+Enter on Windows Terminal | | Images | Paste with Ctrl+V (Alt+V on Windows), or drag into the terminal | | Shell command | `!command` runs and sends output to the model | | Hidden shell command | `!!command` runs without sending output to the model | | External editor | Ctrl+G opens `$VISUAL` or `$EDITOR` | ### Slash Commands (selected) `/login`, `/logout`, `/model`, `/effort`, `/scoped-models`, `/settings`, `/resume`, `/new`, `/name `, `/session`, `/traces [...]`, `/usage`, `/context`, `/tree`, `/fork`, `/clone`, `/compact [prompt]`, `/refine [instructions]`, `/copy`, `/btw `, `/side `, `/export [file]`, `/share`, `/reload`, `/hotkeys`, `/changelog`, `/quit`. ### Message Queue - **Enter** queues a steering message, delivered after the current assistant turn finishes its tool calls. - **Alt+Enter** queues a follow-up message, delivered after the agent finishes all work. - **Ctrl+C** interrupts; pressing it again while the exit hint is visible exits. - **Escape** clears the input bar without interrupting the agent. - **Alt+Up** retrieves queued messages back to the editor. ### Sessions and Non-Interactive Modes ```bash prime-agent -c # Continue the most recent session prime-agent -r [path|id] # Browse sessions or open a specific session prime-agent --no-session # Ephemeral mode; do not save prime-agent --fork # Fork a session into a new session file ``` Inside Prime Agent: `/resume`, `/new`, `/tree`, `/fork`, `/clone`. Sessions run in worker processes, so closing the TUI detaches rather than stops the agent; use `prime-agent agents` to inspect or reattach. For one-shot prompts: ```bash prime-agent -p "Summarize this codebase" cat README.md | prime-agent -p "Summarize this text" prime-agent -p @screenshot.png "What's in this image?" ``` `--mode json` gives JSON event output; `--mode rpc` gives stdin/stdout process integration. ### CLI Reference (usage.md) ```bash prime-agent agents prime-agent list [--all] prime-agent attach prime-agent stop prime-agent rename prime-agent send prime-agent schedule prime-agent status prime-agent doctor [--fix] prime-agent shutdown [--force] prime-agent package install [--local] prime-agent package remove [--local] prime-agent package list prime-agent package update [source] prime-agent update [--force] prime-agent config ``` Built-in tools: `ipython` (the only one). Model options include `--provider`, `--model`, `--api-key`, `--thinking `, `--models `. ## Key Parameters - Autonomous defaults (usage.md): `--autonomous-gate-retries` 3, `--autonomous-gate-timeout-ms` 300000 (5 min), `--autonomous-max-continuations` 3, `--autonomous-max-turns` 12, `--autonomous-max-tokens` 80000, `--autonomous-timeout-ms` 1800000 (30 min). See [[concepts/long-running-agents]] for the full autonomous-mode discussion. - Environment variables of note: `PRIME_AGENT_CODING_AGENT_DIR` (default `~/.prime/agent`), `PRIME_AGENT_SESSION_DIR`, `PI_OFFLINE`, `PI_SKIP_VERSION_CHECK`, `PRIME_AGENT_DOWNLOAD_BASE_URL`, `PI_CACHE_RETENTION`, `PRIME_API_KEY`, `PRIME_AGENT_KERNEL_PYTHON`, `VISUAL`/`EDITOR`. - Resource discovery flags: `--extension`, `--skill`, `--prompt-template`, `--theme`, and their `--no-*` counterparts, plus `--no-context-files` / `-nc`. - Terminal requirement: Prime Agent "uses the Kitty keyboard protocol for reliable modifier key detection." Kitty and iTerm2 work out of the box; Ghostty, WezTerm, VS Code's integrated terminal, and Windows Terminal need explicit config (see terminal-setup.md) to forward `Shift+Enter`/`Alt+Enter` correctly. ## When To Use - First-time install/auth and running a first prompt in a project directory. - Day-to-day interactive coding sessions using `@file` references, `!shell` commands, and slash commands. - Scripting or CI integration via `-p` (print mode), `--mode json`, or `--mode rpc`. - Fixing terminal-specific key handling (e.g., Windows Terminal's default `Alt+Enter` fullscreen binding, or Ghostty/tmux `Shift+Enter` conflicts) before relying on message-queue shortcuts. ## Risks & Pitfalls - Prime Agent "runs in your current working directory and can modify files there. Use git or another checkpointing workflow if you want easy rollback." - Some terminals cannot distinguish modified Enter keys at all: "xfce4-terminal, terminator... have limited escape sequence support. Modified Enter keys like `Ctrl+Enter` and `Shift+Enter` cannot be distinguished from plain `Enter`," breaking custom keybindings such as `submit: ["ctrl+enter"]`. IntelliJ IDEA's integrated terminal has the same limitation for `Shift+Enter`. - On Windows Terminal, `Alt+Enter` is bound to fullscreen by default, which silently prevents Prime Agent from receiving the follow-up-queue shortcut until remapped. - An old Ghostty `shift+enter=text:\n` mapping (added for older Claude Code versions) sends a raw linefeed indistinguishable from `Ctrl+J`, so "tmux and Prime Agent no longer see a real `shift+enter` key event" — remove it unless you still need it for Claude Code in tmux. - Source checkouts require Node.js 22.8.0+; older Node is not supported for `npm ci` / `./prime-agent.sh`. ## Related Concepts - [[concepts/prime-agent-overview]] — what Prime Agent is and its place in the Prime Intellect ecosystem. - [[concepts/rlm]] — the `rlm(...)` subagent call introduced during quickstart. - [[concepts/long-running-agents]] — session continuation, autonomous mode, and scheduling referenced from the CLI reference. - [[concepts/architecture]] — how the CLI/TUI client relates to the daemon-backed worker. ## Sources - raw/github_doc-packages-coding-agent-docs-quickstart-md.md - raw/github_doc-packages-coding-agent-docs-usage-md.md - raw/github_doc-packages-coding-agent-docs-terminal-setup-md.md --- title: "RLM Runtime Architecture" type: concept tags: [rlm, architecture, advanced, well-established, developer] created: 2026-08-06 updated: 2026-08-06 sources: ["raw/github_doc-packages-coding-agent-docs-rlm-runtime-md.md"] confidence: high prime_agent_version: "v0.7.0" --- ## Definition The RLM runtime is the concrete execution layer that runs the [[concepts/rlm]] programming model. Per the source doc: "Prime Agent gives each agent session a persistent IPython kernel and a native recursive sub-agent interface. The Python `rlm` package is a model-facing shim; the TypeScript host owns child execution, persistence, usage accounting, and lifecycle." The Python side is deliberately thin: "The Python side does not call providers or implement an agent loop." ## How It Works ### Architecture The chain is: `AgentSession` (TypeScript — owns the IPython tool and host-request handlers) → `KernelManager` (TypeScript — execution + comm dispatch) ↔ IPython kernel process (Python) → `prime-agent-runtime` (the `rlm` module + Python skills) → model-executed Python code. Model code calls back into the runtime (`rlm.run`, `goal.*`, `agent_message.*`), which talks to `KernelManager` over a Jupyter comm target named `host.request`, which dispatches typed requests back to the owning `AgentSession`. When the model delegates work: ```python handle = await rlm("inspect the API", name="api-reviewer") print(handle.rlm_child_id, handle.name, handle.session_dir, handle.model) ``` the call travels through `host.request`; `KernelManager` dispatches request type `rlm.run` to the parent `AgentSession`, which starts a child through the same TypeScript agent machinery as the parent. "The call returns over the comm immediately after task admission with a child handle; it never waits for or returns the child's answer." The same bridge supports other typed host requests — e.g., the bundled `goal` skill calls `rlm.host_request("goal.get", ...)`. ### Delegation Flow Sequence: parent model issues an IPython tool call → parent `AgentSession` executes `await rlm("inspect the API")` in the kernel → kernel sends `host.request` / `rlm.run` → the session checks depth and resolves the model, admits the child task, updates the registry, and returns an `RLMSpawnHandle` over the comm → the kernel returns that as the tool's IPython result → the host creates the child runtime and prompt → the child agent loop streams to/from the model provider in its own loop → the child eventually replies with an explicit `agent_message` → the parent receives this as an ordinary agent message → the host updates the registry and attributes usage. ### Component Ownership | Component | Responsibility | |---|---| | `src/core/kernel/index.ts` | ZeroMQ sockets, Jupyter framing, execution, comm dispatch, interrupt, and shutdown. | | `src/core/tools/ipython.ts` | Agent tool wrapper, lazy kernel provisioning, namespace bootstrap, and output shaping. | | `src/core/agent-session.ts` | RLM policy, child creation, registry, usage attribution, cancellation, and goal handlers. | | `src/core/rlm-runtime.ts` | Typed request/spawn-handle validation for `rlm.run`, model discovery, list, and delete. | | `prime-agent-runtime/src/rlm/` | Python shim, handle types, callable `rlm`, and session-backed harness state. | ### Kernel Lifecycle The kernel is created lazily on first IPython use. Python resolution order: (1) `PRIME_AGENT_KERNEL_PYTHON`, when it can import `ipykernel`; (2) `~/.prime/agent/kernel-venv/bin/python`, bootstrapped with `uv`; or (3) the XDG data location when `~/.prime` is not writable. "The managed environment includes Python 3.11, `ipykernel`, and `prime-agent-runtime`. A bootstrap marker detects stale environments." Startup creates a temporary Jupyter connection file with loopback TCP ports and an HMAC key, starts `python -m ipykernel_launcher`, connects shell/IOPub/control sockets, waits for subscription propagation, and probes readiness with `kernel_info_request`. Shutdown sends `shutdown_request`, closes sockets, terminates the process as a fallback, and removes temporary connection data. Persistent sessions may snapshot the kernel namespace into their session artifact directory for revival. ### Jupyter Transport Three channels: `shell` (`execute_request`, `execute_reply`, `kernel_info_request`), `iopub` (stdout, stderr, results, errors, status, `comm_open`), and `control` (interrupt, shutdown, host-request replies during execution). Messages use normal Jupyter multipart framing (``, signature, header, parent_header, metadata, content), signed with HMAC-SHA256. "Ordinary output is accepted only when `parent_header.msg_id` matches the active execution. Comm messages are handled before that filter because asynchronous Python tasks can open comms after their scheduling cell returns to idle." Calls to `KernelManager.execute()` are serialized — one kernel has one shared namespace and does not run two ordinary IPython cells concurrently — but "RLM child agents can still run concurrently because each delegation uses a distinct comm and child runtime." ### Why Host-Request Responses Use the Control Channel A running cell can await task admission (`handle = await rlm("subtask")`). IPython processes shell messages serially, so sending the admission response on the shell channel would deadlock — "the active `execute_request` cannot finish until the response arrives, while the kernel will not process that shell response until the request finishes." The Python shim therefore registers comm handlers on the *control* channel, and the host sends admission responses there, scheduling future completion with `loop.call_soon_threadsafe()` since the control handler may run on another thread. Child *answers* do not use this path; they arrive later via explicit `agent_message` replies or files. ### Python API `prime-agent-runtime` exports: ```python rlm run(prompt: str, **kwargs) find_models(query: str = "", limit: int = 8) list_subagents() delete_subagent(selector) host_request(request_type: str, payload: dict | None = None) RLMSpawnHandle RLMModel RLMSubagent TokenUsage ``` The bootstrap places the callable `rlm` object in the namespace so these are equivalent: `await rlm("subtask")` and `await rlm.run("subtask")`. `RLMSpawnHandle` contains `rlm_child_id`, `name`, `session_dir`, and `model`, and "confirms admission only and never contains the child's answer." Supported `rlm.run` options: `name` (unique readable child session name) and `model` (an exact `provider/model` selector from `rlm.find_models()`). "Unknown options fail instead of being ignored." Model search is bounded to active, non-expired credentials; "If an exact selection is unavailable or fails auth preflight, spawn fails instead of silently falling back to another model." ### Child Execution `AgentSession.runRlmChild()`: (1) check `RLM_DEPTH < RLM_MAX_DEPTH`; (2) resolve the requested model or inherit the parent model; (3) create a `sub-xxxxxxxx` child directory under the parent artifact directory; (4) admit the task into the parent registry and return its `RLMSpawnHandle`; (5) in detached work, create a child `SessionManager`, `Agent`, and `AgentSession`; (6) reuse provider hooks, resource loader, model registry, tools, transport, retry settings, and thinking configuration; (7) run the child prompt, retain its session, and update lifecycle state independently of the admission call; (8) attribute child usage to the parent assistant turn and persist the attribution. "Children receive incremented `RLM_DEPTH`, the inherited maximum depth, and their own `RLM_SESSION_DIR`. The default maximum depth is 1, so root sessions may create children and those children may not create grandchildren unless the limit is configured higher." ### Independent Delegation and the Parent-Scoped Registry Each direct call admits an independent child and returns its handle immediately (see the three-call `api_review`/`test_review`/`audit` example in [[concepts/rlm]]). "The TypeScript parent maintains the authoritative direct-child registry." `await rlm.list_subagents()` returns stable child IDs, active-session IDs when daemon-backed, session IDs, names, directories, and running/completed status. "This registry survives kernel restart, compaction, and parent restore." `rlm.delete_subagent()` accepts an exact child ID, active-session ID, session ID, or unique name; deletion "cancels or closes the runtime, writes a durable tombstone, and removes the child from messaging and observation," but "does not erase the transcript or artifacts on disk." Registry scope follows the parent transcript — "an unrelated new parent session does not inherit children." ### Usage and Cost Attribution "The admission handle does not contain usage or completion data." Prime Agent asynchronously folds the child's assistant usage/cost into the parent assistant turn that launched it, persisting a `child_usage_attributed` transcript entry with the target parent message ID, the child usage, and the resulting aggregate. On reload the aggregate is reapplied. "Context-tree reporting subtracts attributed child usage when showing each node's own usage, so tree-wide own usage and root aggregate totals remain reconcilable. Child work increases billable session totals but does not inflate the parent model's context-window measurement." ### Continual Harness State `rlm.harness` is "a persisted state ledger for prompt notes, memories, reusable skill descriptions, sub-agent specifications, and refinement events. It is not a second execution engine." Session-local state lives at `harness/harness_state.json` under the session artifact directory; explicitly global entries live under `~/.prime/agent/harness/`. "The Python store reloads after external modification so host-side `/refine` writes and kernel writes do not overwrite each other." `/refine` "runs a dedicated review over the current trajectory and applies small create/update/delete edits," with rollback via recorded before/after snapshots; "the base system prompt remains immutable." ### Goal Requests `goal` is a thin host-bridge client: `await goal.get()`, `await goal.create("ship the release", token_budget=200000)`, `await goal.complete()`. "Goal state, persistence, token and wall-clock accounting, and continuation prompting live in `AgentSession`." When goals are disabled, the skill and `goal.*` host handlers are not registered. See [[concepts/long-running-agents]]. ### Session Artifacts For a persisted root session: ```text ~/.prime/agent/ sessions/ .jsonl session-artifacts/ / kernel-state.dill kernel-state.json scheduled-jobs.json harness/ harness_state.json sub-xxxxxxxx/ .jsonl sub-yyyyyyyy/ ``` "Exact artifact files are created only when their features are used. Non-persistent sessions place RLM directories under the OS temporary directory and do not gain revivable session artifacts." ## Key Parameters - Default max recursion depth: **1** (`RLM_DEPTH < RLM_MAX_DEPTH`) — root sessions may create children, but those children cannot recurse further unless the limit is raised. - `rlm.run` accepts exactly `name` and `model`; unknown options fail the call. - Kernel Python resolution order: `PRIME_AGENT_KERNEL_PYTHON` → `~/.prime/agent/kernel-venv/bin/python` (via `uv`) → XDG fallback. - Transport: three Jupyter channels (`shell`, `iopub`, `control`); host-request admission replies specifically use `control` to avoid a shell-channel deadlock. - Session artifact layout under `~/.prime/agent/sessions/` and `~/.prime/agent/session-artifacts//`. ## When To Use Consult this page when debugging or extending recursion/child behavior: changing child creation or usage accounting should include `agent-session-recursion.test.ts`; changing comm transport should include the kernel comm tests; changing daemon retention should include the daemon RLM lifecycle tests (per the doc's "Focused Validation" section). ## Risks & Pitfalls Documented failure modes: | Failure | Behavior | |---|---| | Managed runtime is missing | Kernel bootstrap rebuilds it; a custom Python without `rlm` fails clearly when recursion is called. | | Depth limit reached | Python raises before opening a comm; the host checks again. | | Unsupported options | Host rejects the request. | | Requested model unavailable | Spawn fails instead of substituting another model. | | Shell-channel comm reply | Deadlock risk; current replies use control. | | Child cancellation | Host aborts the child and removes failed/cancelled registry entries. | | Parent teardown | Active descendants are cancelled and their runtimes are closed. | **Trust boundary**: "IPython executes model-generated Python and shell-magics with the worker's OS permissions. The kernel boundary isolates protocol and lifecycle concerns; it is not a security sandbox. Installed Python packages, skills, and extensions are trusted code. Use an external sandbox or restricted execution environment when the workspace or generated code is untrusted." Provider credentials are resolved by the TypeScript host; only the bounded model catalog crosses into Python as metadata — the full auth store does not. ## Related Concepts - [[concepts/rlm]] — the programming model this runtime implements (single `ipython` tool, `rlm(...)` calls, skills, durable state). - [[concepts/architecture]] — where `AgentSession`, workers, and kernels sit in the overall system topology. - [[concepts/long-running-agents]] — goals, heartbeats, and compaction that rely on this runtime's persistence guarantees. ## Sources - raw/github_doc-packages-coding-agent-docs-rlm-runtime-md.md --- title: "RLM (Recursive Language Model) Programming Model" type: concept tags: [rlm, foundational, well-established, developer] created: 2026-08-06 updated: 2026-08-06 sources: ["raw/github_doc-packages-coding-agent-docs-rlm-md.md", "raw/github_doc-readme-md.md"] confidence: high prime_agent_version: "v0.7.0" --- ## Definition The source document (`docs/rlm.md`) defines it directly: "Prime Agent is built around a recursive language model (RLM) runtime: the model works inside a persistent Python control environment and composes capabilities as code." That is the exact expansion given by the docs — **recursive language model** — and the doc does not offer a different or fuller acronym gloss beyond this sentence. "Provider calls, session persistence, child lifecycles, scheduling, and safety policy remain in the TypeScript host; IPython is the model-facing programming surface." The README's complementary framing (used in [[concepts/prime-agent-overview]]) describes the RLM as something that "treats context as variables (*prompt-as-a-variable*) and tools like recursive subagents as function calls (*programmatic tool /sub-agent calling*) inside a persistent REPL." Both descriptions point at the same mechanism: a durable, code-executing REPL is the model's interface, and recursion (spawning child agents) is a first-class, in-language operation rather than a bolted-on feature. ## How It Works ### RLM Loop `docs/rlm.md` gives this flow: task + working context go to the **parent model**, which issues an **IPython call** into a **persistent IPython kernel**. The kernel inspects/searches/transforms **files, data, and shell commands**, calls **Python-backed skills**, and can **spawn child agents** via `rlm(...)`. Children return results to the parent via **agent messages or files**; the kernel also hands the parent an **admission handle**; the parent then produces an **answer or next turn**. "The parent keeps its own context focused while Python holds working state and child agents receive only the context needed for their subtasks." ### Core Invariant 1 — Execution Is Programmatic "The default RLM runtime exposes one built-in model tool: `ipython`." Reading/editing files, running project commands, transforming results, invoking skills, and delegating work all start from this one persistent kernel rather than from separate built-in tool calls. Python state survives across tool calls *and compaction* — variables, imports, functions, parsed results, and task handles remain available on later turns. Example from the doc: ```python from pathlib import Path config_files = list(Path(".").rglob("*.toml")) large_files = [path for path in config_files if path.stat().st_size > 10_000] ``` Shell commands run via `%%bash` cells, each "a temporary subshell," while Python state and `%cd` changes persist in the kernel: ```bash %%bash npm run check ``` ### Core Invariant 2 — Subagents Are Native RLM Calls The callable `rlm` object is preloaded in the kernel: ```python handle = await rlm("Review the authentication flow for security issues", name="auth-reviewer") print(handle.rlm_child_id, handle.name, handle.session_dir, handle.model) ``` "The call returns immediately after task admission with a child handle; it never waits for or returns the child's answer." The TypeScript host creates a normal child `AgentSession` with an independent context and session directory. "The child inherits the parent model, provider configuration, skills, tools, retry policy, and resource loader unless the call requests another configured model." Independent children can be spawned in separate calls without awaiting completion: ```python api_review = await rlm("Review the public API", name="api-reviewer") test_review = await rlm("Review the test coverage", name="test-reviewer") integration_audit = await rlm("Run the slow integration audit", name="integration-audit") ``` "Results arrive only through explicit `agent_message` replies or files, never as an `rlm()` return value." A child replies with: ```python await agent_message.send(message, receiver_role="parent") ``` and the parent can follow up with a retained child: ```python await agent_message.send( "Check the newly added regression test.", receiver_role="child", receiver_name=api_review.name, ) ``` An admission handle contains `rlm_child_id`, `name`, `session_dir`, and `model`. "The parent-scoped child registry survives compaction, kernel restart, and parent restoration": ```python children = await rlm.list_subagents() for child in children: print(child.session_name, child.status, child.active_session_id) ``` Delete a child only when its context is no longer needed: ```python await rlm.delete_subagent(children[0]) ``` "The default recursion depth allows a root agent to create children. Raising the configured depth allows descendants to recurse further." (Exact numeric default and depth-check mechanics live in [[concepts/rlm-runtime]].) ### Core Invariant 3 — Skills Add Programmatic Capability Prime Agent supports the Agent Skills markdown format and extends it with Python-backed skills; both use `SKILL.md` for discovery, routing, and instructions. A Python-backed skill also contains a Python package that Prime Agent installs into the kernel environment and exposes by import name — for example, a skill named `release-audit` can be called as: ```python report = await release_audit(repository=".", target_version="0.4.0") ``` "This makes Python-backed skills a superset of instruction-only skills: they can provide guidance, scripts, references, dependencies, typed callables, and optional shell commands. They may also call `rlm(...)` themselves when a capability needs recursive delegation." Only skill metadata is placed in the startup prompt; the full `SKILL.md` loads only when the task matches or the model/user invokes it explicitly. ### Core Invariant 4 — State Is Designed to Outlive One Turn The RLM programming model assumes work may span many turns or continue after the terminal UI closes: - automatic compaction summarizes older context while preserving recent messages and kernel state; - daemon-backed workers keep active sessions running after clients detach; - child registries and session artifacts make subagents recoverable; - heartbeats and scheduled prompts re-enter a session later; - persistent goals continue until the objective is complete or the user changes state; and - autonomous mode adds bounded continuations and optional quality gates. (Details in [[concepts/long-running-agents]].) ### Host Bridge "Python skills use typed host requests for capabilities whose authoritative state belongs outside the kernel." For example, the `goal`, `agent_message`, `rlm_heartbeat`, and `compact` skills call `rlm.host_request(...)`; the TypeScript host validates the request and owns the state transition. This "keeps credentials, provider execution, transcript writes, worker routing, and scheduling out of Python while retaining a programmatic model interface." Implementation detail lives in [[concepts/rlm-runtime]]. ## Key Parameters - One built-in model tool: `ipython`. - The preloaded `rlm` callable, with an admission-only return (`RLMSpawnHandle`). - Recursion depth: configurable; default allows a root agent to create children (not further, unless raised). - Skill discovery surface: `SKILL.md` (metadata only at startup; full content and Python package loaded on demand). - Result channel for children: `agent_message.send(..., receiver_role=...)` or files — never the `rlm()` return value. ## When To Use - Any task where the model needs durable, inspectable working state across many turns (parsed data, imports, helper functions) rather than one-shot tool calls. - Parallel or background delegation: spawning independent reviewers/auditors (e.g., "Review authentication and test coverage as independent subtasks. Run them in parallel, then synthesize the findings" — the quickstart's own example). - Wrapping recurring workflows as Python-backed skills so they become directly callable, typed functions instead of re-explained instructions each time. ## Risks & Pitfalls - **Trust model, not a sandbox**: "The IPython kernel runs model-generated Python and project commands with the worker's operating-system permissions. It is a durable control environment, not a security sandbox. Review third-party Python skills and use an external sandbox or restricted environment for untrusted repositories and instructions." - **`rlm()` never returns the answer.** A common misunderstanding is expecting `await rlm(...)` to yield the child's result synchronously — it only confirms admission. Results require an explicit `agent_message` reply or a file the parent later reads. - Recursion depth is bounded by design; deeper descendant recursion requires explicitly raising the configured depth. ## Related Concepts - [[concepts/rlm-runtime]] — the concrete execution machinery (ZeroMQ/Jupyter transport, child lifecycle, usage attribution) behind this programming model. - [[concepts/architecture]] — where the kernel and `AgentSession` sit in the overall system. - [[concepts/prime-agent-overview]] — RLM as one of Prime Agent's two core abstractions, alongside the Continual Harness. - [[concepts/long-running-agents]] — compaction, heartbeats, goals, and autonomous mode that let RLM state outlive a single turn. - [[concepts/skills]] — the Agent Skills / Python-backed skill format referenced under Core Invariant 3. ## Sources - raw/github_doc-packages-coding-agent-docs-rlm-md.md - raw/github_doc-readme-md.md (for the complementary "prompt-as-a-variable" framing and the Continual Harness / self-improving context) --- title: "SDK and RPC" type: concept tags: [sdk, area/sdk, audience/developer, scope/advanced, status/well-established] created: 2026-08-06 updated: 2026-08-06 sources: ["raw/github_doc-packages-coding-agent-docs-sdk-md.md", "raw/github_doc-packages-coding-agent-docs-rpc-md.md", "raw/github_doc-packages-coding-agent-docs-json-md.md", "raw/github_doc-packages-ai-readme-md.md"] confidence: high prime_agent_version: "v0.7.0" --- # SDK and RPC ## Definition Prime Agent exposes three ways to control it programmatically. The **SDK** (`@earendil-works/pi-coding-agent`, npm package `prime-agent-ai` at the lower `packages/ai` layer) embeds the agent directly in a Node.js process via `createAgentSession()`, giving full type-safe access to agent state. **RPC mode** (`prime-agent --mode rpc`) runs the agent as a subprocess speaking a JSON command/event protocol over stdin/stdout, for cross-language or process-isolated integration. **JSON event stream mode** (`prime-agent --mode json`) is a simpler one-shot variant: run one prompt, dump every event as JSON lines, exit — good for `jq`-style pipelines. A fourth mode, [[concepts/acp]], speaks the standardized Agent Client Protocol instead of Prime Agent's own richer command surface. ## How It Works ### SDK quick start ```typescript import { AuthStorage, createAgentSession, ModelRegistry, SessionManager } from "@earendil-works/pi-coding-agent"; const authStorage = AuthStorage.create(); const modelRegistry = ModelRegistry.create(authStorage); const { session } = await createAgentSession({ sessionManager: SessionManager.inMemory(), authStorage, modelRegistry, }); session.subscribe((event) => { if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") { process.stdout.write(event.assistantMessageEvent.delta); } }); await session.prompt("What files are in the current directory?"); ``` Install with `npm install @earendil-works/pi-coding-agent` (the SDK ships in the main package; no separate install for basic use). ### `createAgentSession()` and `AgentSession` `createAgentSession()` is the main factory for a single `AgentSession`; without an explicit `resourceLoader` it uses `DefaultResourceLoader` with standard discovery (extensions, skills, prompts, context files — see [[concepts/extensions]] and [[concepts/skills]]). `AgentSession` exposes: `prompt(text, options?)` (send and await completion), `steer(text)` / `followUp(text)` (queue during streaming), `subscribe(listener)` (returns an unsubscribe function), `sessionFile`/`sessionId`, model control (`setModel`, `setThinkingLevel`, `cycleModel`, `cycleThinkingLevel`), state access (`agent`, `model`, `thinkingLevel`, `messages`, `isStreaming`), `navigateTree(targetId, options?)` (in-place tree navigation within the current file), `compact(customInstructions?)`/`abortCompaction()`, `abort()`, and `dispose()`. **Session-replacement operations** (new session, resume, fork, import) live on a separate `AgentSessionRuntime`, not on `AgentSession` itself — `createAgentSessionRuntime()` takes a factory that recreates cwd-bound services for a given cwd/session target and returns the full runtime. `AgentSessionRuntime` owns `newSession()`, `switchSession()`, `fork()`, clone (via `fork(entryId, { position: "at" })`), and `importFromJsonl()`. After any of these, `runtime.session` changes — because event subscriptions attach to a specific `AgentSession`, callers must **re-subscribe** and, if using extensions, call `runtime.session.bindExtensions(...)` again for the new session. Runtime creation/replacement failures throw and the caller decides how to handle them; diagnostics are on `runtime.diagnostics`. ### Prompting and queueing semantics `PromptOptions`: `expandPromptTemplates?`, `images?`, `streamingBehavior?: "steer" | "followUp"`, `source?`, `preflightResult?: (success: boolean) => void`. `preflightResult` fires once per `prompt()` call, before `prompt()` resolves: `true` means accepted/queued/handled, `false` means rejected before acceptance — `prompt()` itself still only resolves after the full accepted run (including retries) finishes; post-acceptance failures surface through the normal event/message stream, not through `preflightResult(false)`. Behavior notes: **extension commands** (`/mycommand`) execute immediately even while streaming, managing their own LLM interaction via `pi.sendMessage()`; **file-based prompt templates** expand to their content before sending/queueing; calling `prompt()` while streaming **without** `streamingBehavior` throws — use `session.steer("...")` / `session.followUp("...")` directly, or pass the option explicitly. Both `steer()` and `followUp()` expand file-based templates but error on extension commands (which can't be queued). ### Agent and AgentState `session.agent` (an `Agent` from `@earendil-works/pi-agent-core`) exposes `state.messages`, `state.model`, `state.thinkingLevel`, `state.systemPrompt`, `state.tools`, `state.streamingMessage?`, `state.errorMessage?`. Assigning `session.agent.state.messages = messages` or `.tools = tools` copies the top-level array. `await session.agent.waitForIdle()` blocks until processing completes. ### Events `session.subscribe((event) => {...})` delivers the same event taxonomy documented for extensions and RPC: `message_update` (including `text_delta`/`thinking_delta` on `assistantMessageEvent`), `tool_execution_start/update/end`, `message_start/end`, `agent_start/end`, `turn_start/end`, plus SDK-level `session_action_update`, `compaction_start/end`, `auto_retry_start/end`. ### Options reference (selected) - **Directories**: `cwd` (default `process.cwd()`) drives `DefaultResourceLoader` discovery of project extensions/skills/prompts, `AGENTS.md` context files, and session storage resolution. `agentDir` (default `~/.prime/agent`) drives global extensions/skills/prompts, the global `AGENTS.md`, `settings.json`, `models.json`, `auth.json`, and `sessions/`. Supplying a custom `resourceLoader` makes `cwd`/`agentDir` stop controlling discovery (they still affect session naming and tool path resolution). - **Model**: `getModel(provider, id)` finds a built-in model (no API-key check); `modelRegistry.find(provider, id)` also finds custom `models.json` models; `modelRegistry.getAvailable()` filters to models with valid keys configured. `scopedModels` provides the model+thinkingLevel list for `Ctrl+P` cycling. If no model is given: restore from session (if continuing) → settings default → first available model. - **API keys/OAuth**: resolution priority is (1) runtime overrides via `authStorage.setRuntimeApiKey(provider, key)` (not persisted), (2) stored `auth.json` credentials, (3) environment variables, (4) a fallback resolver for `models.json` custom-provider keys — mirroring the provider resolution order in [[concepts/providers-and-models]]. `AuthStorage.create(path?)` and `ModelRegistry.create(authStorage, modelsJsonPath?)` accept custom locations; `ModelRegistry.inMemory(authStorage)` skips `models.json` entirely. - **System prompt**: override via `new DefaultResourceLoader({ systemPromptOverride: () => "..." })`, then `await loader.reload()` before passing `resourceLoader: loader` to `createAgentSession()`. - **Tools**: omitting `tools` auto-creates built-ins bound to the session `cwd`. Tool **factory functions** (`createIpythonToolDefinition(cwd)`, `createBashToolDefinition(cwd)`, `createEditToolDefinition(cwd)`) are needed only when specifying a **custom** `cwd` different from `process.cwd()` together with an explicit `tools`/`customTools` list. `defineTool({...})` builds standalone custom tool definitions passed via `customTools`, combined with any extension-registered tools. - **Extensions**: `DefaultResourceLoader` discovers from `~/.prime/agent/extensions/`, `.prime/agent/extensions/`, and `settings.json` sources; `additionalExtensionPaths` and inline `extensionFactories` add more. A shared `eventBus` (via `createEventBus()`) passed to the loader lets code outside the extension system emit/listen on `pi.events`. - **Skills / context files / slash commands**: `skillsOverride`, `agentsFilesOverride`, `promptsOverride` on `DefaultResourceLoader` let SDK callers inject custom skills, `AGENTS.md`-equivalent content, or `PromptTemplate` slash commands programmatically, merging with `current.skills`/`current.agentsFiles`/`current.prompts`. - **Session management**: `SessionManager.inMemory()`, `.create(cwd)`, `.continueRecent(cwd)` (returns `modelFallbackMessage` if the session's model couldn't be restored), `.open(path)`, `.list(cwd)`, `.listAll()`. Full tree API: `getEntries()`, `getTree()`, `getPath()`, `getLeafEntry()`, `getEntry(id)`, `getChildren(id)`, `getLabel(id)`/`appendLabelChange(id, label)`, `branch(entryId)`, `branchWithSummary(id, summary)`, `createBranchedSession(leafId)` — see [[concepts/sessions-and-compaction]] for entry-type semantics. - **Settings**: `SettingsManager.create(cwd?, agentDir?)` loads and merges global (`~/.prime/agent/settings.json`) and project (`/.prime/agent/settings.json`) settings, project overriding global with nested-object key merging; `SettingsManager.inMemory(settings?)` skips file I/O (useful for tests). Getters/setters are synchronous for in-memory state, but setters enqueue **asynchronous** persistence writes — call `await settingsManager.flush()` for a durability boundary (e.g. before process exit or before asserting file contents in tests). `SettingsManager` does not print I/O errors itself; call `drainErrors()` to surface them. ### Return value ```typescript interface CreateAgentSessionResult { session: AgentSession; extensionsResult: LoadExtensionsResult; // { extensions, errors, runtime } modelFallbackMessage?: string; } ``` ### Run modes exported by the SDK `InteractiveMode` (full TUI), `runPrintMode` (single-shot: send prompts, print result, exit), and `runRpcMode` (drives the JSON-RPC protocol described below) are all built from the same `AgentSessionRuntime`, letting SDK consumers reuse Prime Agent's own CLI mode implementations rather than reimplementing them. ### Choosing SDK vs. RPC vs. ACP vs. JSON mode The SDK is preferred when: you want type safety, you're already in the same Node.js process, you need direct access to agent state, or you want to customize tools/extensions programmatically. **RPC mode** is preferred when: integrating from another language, wanting process isolation, or building a language-agnostic client — start it directly with `prime-agent --mode rpc --no-session` without building against the SDK at all. Prefer [[concepts/acp]] instead when an existing ACP-speaking client (editor, harness) should drive the session and doesn't need Prime Agent's fuller command surface. Prefer **JSON mode** for simple batch/pipeline use where you just want one prompt's full event stream with an exit code, not bidirectional command/response interaction. --- ### RPC mode protocol Started with `prime-agent --mode rpc [options]` (`--provider`, `--model`, `--no-session`, `--session-dir`). **Commands** are JSON objects on stdin, one per line; **responses** (`type: "response"`) indicate success/failure and echo any request `id`; **events** stream to stdout as JSON lines with no `id`. Framing is strict JSONL with **LF only** as the record delimiter — clients must split on `\n` only, may strip a trailing `\r`, and must not use a generic line reader (like Node's `readline`) that also splits on `U+2028`/`U+2029`, which are valid inside JSON strings. **Key commands** (selected — see raw source for the complete list): `prompt` (with optional `images`, requires `streamingBehavior: "steer"|"followUp"` if already streaming), `steer`, `follow_up`, `abort`, `new_session`, `get_state`, `get_messages`, `set_model`, `cycle_model`, `get_available_models`, `set_thinking_level`, `cycle_thinking_level`, `set_steering_mode`/`set_follow_up_mode` (`"all"` vs `"one-at-a-time"`, the latter default), `compact`/`set_auto_compaction`, `set_auto_retry`/`abort_retry`, `bash`/`abort_bash`, `get_session_stats`, `export_html`, `switch_session`, `fork`/`clone`/`get_fork_messages`, `get_last_assistant_text`, `set_session_name`, `get_commands`. **Daemon coordination commands** (additive, shared with the interactive client): `send_message` (to another active session), `agent_messages_status/pause/resume/clear`, `list_schedules`/`add_schedule`/`cancel_schedule`, `list_heartbeats`/`get_heartbeat`/`set_heartbeat`/`update_heartbeat`/`manage_heartbeat`, and `observe`/`unobserve` for watching another root or subagent session's event stream (wrapped as `observed_session_event`/`observed_session_closed` so they can't be confused with the client's own events). Adding a schedule or heartbeat **promotes** an invocation-local RPC session into a resident daemon session so the scheduled work survives after RPC stdin closes. **How bash results reach the LLM**: the `bash` RPC command executes immediately and returns a `BashResult`, storing a `BashExecutionMessage` in agent state **without emitting an event**. That message is transformed into a `UserMessage` (formatted as `` Ran `cmd` `` plus a fenced code block of output) only when the **next** `prompt` command is sent — so multiple bash commands can run before a prompt, and all their outputs get included together, but none of it reaches the LLM context until that next prompt fires. **Events**: `agent_start`, `agent_end` (with all generated `messages`), `turn_start`/`turn_end`, `message_start`/`message_update`/`message_end`, `tool_execution_start/update/end`, `session_action_update` (fires whenever queued or active scheduler actions change), `compaction_start`/`compaction_end` (`reason`: `"manual"|"threshold"|"overflow"`; on `"overflow"` success, `willRetry: true` and the agent automatically retries the prompt), `auto_retry_start`/`auto_retry_end`, `extension_error`. **`message_update` delta types** (on `assistantMessageEvent`): `start`, `text_start/delta/end`, `thinking_start/delta/end`, `toolcall_start/delta/end`, `done` (`reason`: `"stop"|"length"|"toolUse"`), `error` (`reason`: `"aborted"|"error"`). ### Extension UI protocol (RPC mode) Extension `ctx.ui` calls (see [[concepts/extensions]]) map onto a request/response sub-protocol layered on the base command/event flow. **Dialog methods** (`select`, `confirm`, `input`, `editor`) emit `extension_ui_request` on stdout and block until a matching `extension_ui_response` arrives on stdin (or a request `timeout` auto-resolves with a default: `undefined` for select/input/editor, `false` for confirm — the client need not track timeouts itself). **Fire-and-forget methods** (`notify`, `setStatus`, `setWidget`, `setTitle`, `set_editor_text`) emit a request but expect no response. Several TUI-only `ExtensionUIContext` methods degrade in RPC mode: `custom()` returns `undefined`; `setWorkingMessage/setWorkingIndicator/setFooter/setHeader/setEditorComponent/setToolsExpanded` are no-ops; `getEditorText()` returns `""`; `getToolsExpanded()` returns `false`; `pasteToEditor()` delegates to `setEditorText()` with no paste/collapse handling; `getAllThemes()` returns `[]`; `getTheme()` returns `undefined`; `setTheme()` returns `{ success: false, error }`. `ctx.hasUI` is still `true` in RPC mode because dialog/fire-and-forget methods do function via this sub-protocol. Response shapes: value response (`select`/`input`/`editor`) — `{ type: "extension_ui_response", id, value }`; confirmation — `{ ..., confirmed: true|false }`; cancellation (any dialog) — `{ ..., cancelled: true }` (extension receives `undefined` or `false` accordingly). ### Error handling and types Failed commands return `{ type: "response", command, success: false, error }`; unparseable input returns `{ type: "response", command: "parse", success: false, error }`. Core wire types: `Model` (id, name, api, provider, baseUrl, reasoning, input, contextWindow, maxTokens, cost), `UserMessage`, `AssistantMessage` (with `stopReason: "stop"|"length"|"toolUse"|"error"|"aborted"`), `ToolResultMessage`, `BashExecutionMessage` (created only by the RPC `bash` command, not by LLM tool calls), `Attachment`. --- ### JSON event stream mode `prime-agent --mode json "Your prompt"` runs one prompt and dumps every session event to stdout as JSON lines — no bidirectional command protocol, just output for downstream tools (e.g. `| jq -c 'select(.type == "message_end")'`). The first line is always the session header (`{"type":"session","version":3,...}`), followed by the same `AgentEvent` taxonomy as RPC/SDK events (`agent_start/end`, `turn_start/end`, `message_start/update/end`, `tool_execution_start/update/end`) plus `session_action_update`, `compaction_start/end`, `auto_retry_start/end`. This is the simplest of the four programmatic surfaces — no session control, just "run and observe." --- ### The underlying AI package (`prime-agent-ai`) `packages/ai` is the lower-level LLM provider toolkit that both the coding agent and SDK build on — a unified API across all supported providers (Anthropic, OpenAI, Google, Mistral, Bedrock, and every OpenAI-compatible endpoint) with automatic model discovery, cost tracking, and context serialization/hand-off between models. Core primitives: `getModel(provider, id)`, `getModels(provider)`, `getProviders()`, a `Context` object (`{ systemPrompt?, messages, tools }`) that serializes to plain JSON via `JSON.stringify`/`JSON.parse` for persistence or transfer, and `stream()`/`complete()` (full event control) vs. `streamSimple()`/`completeSimple()` (a unified `reasoning: "minimal"|"low"|"medium"|"high"|"xhigh"` interface layered over provider-specific thinking options). Tool arguments during `toolcall_delta` streaming are a **best-effort partial JSON parse** — fields may be missing, strings truncated mid-word, arrays incomplete; `arguments` is never `undefined`, at minimum `{}`. `validateToolCall(tools, toolCall)` validates a completed call's arguments against its TypeBox schema before execution (used automatically inside `agentLoop`; needed manually when hand-rolling a tool loop over `stream()`/`complete()`). **Cross-provider handoff**: messages from one provider are automatically transformed for a different provider mid-conversation — user/tool-result messages pass through unchanged; same-provider assistant messages are preserved as-is; different-provider assistant messages have thinking blocks converted to ``-tagged text, while tool calls and regular text are preserved. This is what lets a session (see [[concepts/sessions-and-compaction]]) survive a `/model` switch across providers mid-conversation. **Browser usage**: the AI package runs in browsers, but API keys must be passed explicitly (no environment variables in-browser) — a stated security warning against exposing keys in frontend code outside of internal tools/demos. Amazon Bedrock and OAuth login flows are not supported in browser environments (Bedrock can still appear in model lists there, but calls fail at runtime). **OAuth entry point**: `prime-agent-ai/oauth` exports `loginAnthropic`, `loginOpenAICodex`, `loginGitHubCopilot`, `loginGeminiCli`, `refreshOAuthToken`, and `getOAuthApiKey(provider, credentialsMap)` — credential storage is explicitly the caller's responsibility (the library returns credentials, doesn't persist them). `npx prime-agent-ai login [provider]` is the fastest way to authenticate outside the full coding agent, saving to a local `auth.json`. **Faux provider for tests**: `registerFauxProvider()` (opt-in, not part of the built-in provider set) registers a temporary in-memory provider with a scripted response queue (`setResponses`/`appendResponses`) — useful for deterministic single-flow SDK/extension tests without hitting a real API. Usage is estimated at ~1 token per 4 characters, and prompt-cache read/write simulate automatically when `sessionId` is set with `cacheRetention !== "none"`. ## Key Parameters - **`streamingBehavior` / `deliveryMode`** (`"steer"` vs `"followUp"`) — governs whether an SDK/RPC message interrupts the current turn's tool-call batch or waits for full idle, mirroring the extension `deliverAs` semantics. - **RPC framing** — strict LF-delimited JSONL; this single detail breaks naive `readline`-based clients. - **`preflightResult` callback** — the SDK's signal for "accepted vs. rejected before acceptance," distinct from post-acceptance failures reported via the event stream. - **`agentDir` vs. `cwd`** — split responsibility for global vs. project-scoped resource discovery; only meaningful when no custom `resourceLoader` is supplied. - **`Context` object shape** (`systemPrompt?`, `messages`, `tools`) — the serializable unit at the `prime-agent-ai` layer that both extensions and the SDK build on top of. ## When To Use - Embed Prime Agent inside another Node.js application, custom UI, or automated pipeline with full type-safe state access — use the **SDK**. - Build a language-agnostic client, or need process isolation from the host application — use **RPC mode**. - Need only a one-shot prompt-and-dump for a shell pipeline — use **JSON mode**. - Integrate with an editor or harness that already speaks the standard Agent Client Protocol — use [[concepts/acp]] instead. - Need the raw LLM provider layer without any agent/tool/session scaffolding (e.g. building a different kind of app on the same provider abstraction) — use `prime-agent-ai` (`packages/ai`) directly. ## Risks & Pitfalls - Using Node's `readline` (or any Unicode-line-separator-aware reader) to parse RPC stdout is **not protocol-compliant** — it can split mid-JSON-string on `U+2028`/`U+2029`. - Forgetting to re-subscribe to `runtime.session` (and re-bind extensions) after `newSession()`/`switchSession()`/`fork()` leaves a caller silently listening to a disposed session. - Calling `session.prompt()` while streaming without `streamingBehavior` throws — a common integration bug when reusing the same call site for both idle and mid-stream sends. - RPC's `bash` command results only reach the LLM on the **next** `prompt` call, not immediately — code that expects synchronous inclusion in context will be surprised. - Several `ctx.ui` methods silently no-op or return defaults in RPC mode (`custom()`, `setWorkingMessage`, theme getters/setters, etc.) — an extension written and tested only in interactive mode may misbehave when driven over RPC. - `SettingsManager` setters return synchronously but persist asynchronously — code that writes a setting and immediately asserts the on-disk file without `await flush()` will see stale content. - Streaming tool-call arguments during `toolcall_delta` are a best-effort partial parse; code that doesn't defensively check for missing/incomplete fields before `toolcall_end` can crash on legitimate mid-stream state. ## Related Concepts - [[concepts/extensions]] — the extension event/API surface that the SDK's `DefaultResourceLoader` loads and that RPC's extension UI sub-protocol drives remotely. - [[concepts/sessions-and-compaction]] — `SessionManager`/`AgentSessionRuntime` session-tree operations exposed identically through the SDK and RPC's session commands. - [[concepts/providers-and-models]] — `ModelRegistry`/`AuthStorage` and the credential-resolution order shared between the coding-agent SDK and the underlying `prime-agent-ai` package. - [[concepts/acp]] — the standards-based alternative to RPC mode for editor/harness integration. ## Sources - raw/github_doc-packages-coding-agent-docs-sdk-md.md - raw/github_doc-packages-coding-agent-docs-rpc-md.md - raw/github_doc-packages-coding-agent-docs-json-md.md - raw/github_doc-packages-ai-readme-md.md --- title: "Sessions and Compaction" type: concept tags: [sessions, area/sessions, scope/foundational, status/well-established] created: 2026-08-06 updated: 2026-08-06 sources: ["raw/github_doc-packages-coding-agent-docs-sessions-md.md", "raw/github_doc-packages-coding-agent-docs-session-format-md.md", "raw/github_doc-packages-coding-agent-docs-compaction-md.md"] confidence: high prime_agent_version: "v0.7.0" --- # Sessions and Compaction ## Definition A **session** is Prime Agent's persistent record of a conversation, stored as a JSONL (JSON Lines) file where entries form a **tree** via `id`/`parentId` links rather than a flat list — enabling in-place branching without new files. **Compaction** and **branch summarization** are the two mechanisms that keep a long-running session's context within the model's context window by replacing older messages with LLM-generated structured summaries. ## How It Works ### Session storage and lifecycle Sessions auto-save to `~/.prime/agent/sessions/.jsonl`. CLI flags control session behavior: `--continue` (most recent), `--resume [path|id]` (browse or resume directly), `--no-session` (ephemeral, nothing saved), `--fork ` (fork into a new session). In interactive mode, `/session` shows the current file/ID/message count, `/usage` shows token/cost/context usage, `/name ` sets a display name, and `/resume` opens an interactive picker (search by typing, Ctrl+P toggles path display, Ctrl+S sort mode, Ctrl+N filter to named sessions, Ctrl+R rename, Ctrl+D delete-with-confirm). Deletion prefers the `trash` CLI over permanent removal when available. ### The tree structure and navigation Every entry has `id` and `parentId` (`null` for the first entry); the **leaf** is the current position. `/tree` lets you jump to any earlier point and continue without creating a new file — selecting a **user/custom message** moves the leaf to that message's parent and places its text back in the editor for resubmission (creating a new branch); selecting an **assistant/tool/compaction/other** entry moves the leaf there directly with an empty editor. `/fork` creates a new session file from a selected earlier user message; `/clone` duplicates the current active branch into a new session file at the current position. `/tree`, unlike `/fork`/`/clone`, keeps everything in one file and offers an in-place branch summary. | Feature | `/tree` | `/fork` | `/clone` | |---|---|---|---| | Output | Same session file | New session file | New session file | | View | Full tree | User-message selector | Current active branch | | Typical use | Explore alternatives in place | Start new session from earlier prompt | Duplicate current work | ### Session file format and versioning The header (first line, no `id`/`parentId`) records version, session `id`, timestamp, `cwd`, and — for forked/cloned sessions — `parentSession`. Version 1 was a linear sequence (legacy, auto-migrated); version 2 introduced the tree structure; **version 3** renamed the `hookMessage` role to `custom` as part of extensions unification. Old sessions auto-migrate to v3 on load. Entry types beyond ordinary messages: `ModelChangeEntry`, `ThinkingLevelChangeEntry`, `ServiceTierChangeEntry`, `CompactionEntry`, `BranchSummaryEntry`, `CustomEntry` (extension state, **not** sent to the LLM), `CustomMessageEntry` (extension-injected message that **does** enter LLM context), `LabelEntry` (user bookmark), `SessionInfoEntry` (display name), `SessionStateEntry` (daemon lifecycle: `active`/`archived`/legacy `crash`; old `sleep` normalizes to `archived`), `AgentStatusEntry`, `GitStateEntry`, and `ChildUsageAttributionEntry` (folds RLM child-agent usage into a parent assistant message; daemon bookkeeping only). Bookkeeping entries (child usage, session lifecycle, agent status, git state) are excluded when `buildSessionContext()` constructs the LLM-facing message list. `AgentMessage` is a union of `UserMessage`, `AssistantMessage`, `ToolResultMessage`, `BashExecutionMessage`, `CustomMessage`, `BranchSummaryMessage`, `CompactionSummaryMessage`. Content blocks within messages are `TextContent`, `ImageContent` (base64 + mimeType), `ThinkingContent`, and `ToolCall`. ### Compaction: when and how Auto-compaction triggers when `contextTokens > contextWindow - reserveTokens` (default `reserveTokens` 16384, configurable in `settings.json`). It can also be triggered manually with `/compact [instructions]`, where instructions get high-priority weight in the summarization prompt and are persisted on the `CompactionEntry`. The algorithm: 1. **Find cut point** — walk backward from the newest message, accumulating token estimates, until `keepRecentTokens` (default 20000) is reached. 2. **Extract messages** to summarize — from the previous kept boundary (or session start) up to the cut point. 3. **Generate summary** via LLM call, passing the previous summary as iterative context if one exists. 4. **Append** a `CompactionEntry` with the summary and `firstKeptEntryId`. 5. **Reload** — the session now presents summary + messages from `firstKeptEntryId` onward to the LLM. On repeated compactions, the next summarization span starts at the *previous* compaction's `firstKeptEntryId` (not the compaction entry itself), so messages that survived one compaction get folded into the next pass too. `tokensBefore` is recalculated from the rebuilt session context immediately before writing the new entry. Valid cut points are user messages, assistant messages, `BashExecution` messages, and custom messages — **never** at a tool result, which must stay paired with its tool call. When a single turn is larger than `keepRecentTokens`, the cut lands mid-turn (a **split turn**): Prime Agent generates and merges two summaries — a history summary and a turn-prefix summary for the early part of the oversized turn. ### Branch summarization Triggered by `/tree` navigation away from a branch. Steps: find the deepest common ancestor of the old and new leaf, collect entries from the old leaf back to that ancestor, prepare them within a token budget (newest first), generate an LLM summary, and append a `BranchSummaryEntry` at the navigation point. The user is offered: no summary, default-prompt summary, or custom-focus-instructions summary. Both mechanisms track file operations (`readFiles`, `modifiedFiles`) **cumulatively** — extracted from tool calls in the summarized span plus any prior compaction/branch-summary `details` — so file history survives across nested summarizations. ### Message serialization for summarization Before either summarization runs, messages are serialized to plain text via `serializeConversation()` (from `convertToLlm(...)` output) in a format like: ``` [User]: What they said [Assistant thinking]: Internal reasoning [Assistant]: Response text [Assistant tool calls]: ipython(code="..."); bash(command="...") [Tool result]: Output from tool ``` This deliberately prevents the summarizer model from treating the log as a conversation to continue. Tool results are truncated to 2000 characters during serialization (with a marker noting how much was cut), since `ipython`/`bash` output is typically the largest context consumer. ### Extension hooks `session_before_compact` fires before auto-compaction or `/compact`; it can `return { cancel: true }` or supply a fully custom `{ compaction: {...} }` object (see [[concepts/extensions]] for the general event model). `session_before_tree` fires before every `/tree` navigation (even if the user declined to summarize) and can similarly cancel or supply a custom summary. ### Summary format Both mechanisms produce the same structured Markdown: `## Goal`, `## Constraints & Preferences`, `## Progress` (Done/In Progress/Blocked), `## Key Decisions`, `## Next Steps`, `## Critical Context`, plus ``/`` blocks. ### SessionManager API (selected) Static: `create(cwd)`, `open(path)`, `continueRecent(cwd)`, `inMemory(cwd?)`, `forkFrom(sourcePath, targetCwd)`, `list(cwd)`, `listAll()`. Instance — appending: `appendMessage`, `appendCompaction`, `appendCustomEntry`, `appendCustomMessageEntry`, `appendLabelChange`, `appendSessionInfo`, `appendChildUsageAttribution`. Tree navigation: `getLeafId`, `getEntry`, `getBranch`, `getTree`, `getChildren`, `branch(entryId)`, `branchWithSummary`, `resetLeaf`. Context: `buildSessionContext()` — walks leaf to root, applies compaction summary + `firstKeptEntryId` window, converts branch-summary/custom-message entries, and skips bookkeeping entries. ## Key Parameters - **`reserveTokens`** (default 16384) — headroom reserved for the LLM's response before auto-compaction triggers. - **`keepRecentTokens`** (default 20000) — how much recent context survives a compaction pass uncompressed. - **`enabled`** (compaction settings, default `true`) — disables auto-compaction while leaving `/compact` available. - **`firstKeptEntryId`** — the pivot ID separating summarized history from literal kept messages; also the anchor for the *next* compaction's summarization span. - **Session version** — currently 3; determines migration behavior on load. ## When To Use - Continuing multi-day or multi-session work: `--continue`/`--resume` plus named sessions (`/name`) for discoverability. - Exploring multiple solution approaches from the same point without duplicating files: `/tree`. - Starting a genuinely separate line of work from an earlier prompt while preserving the original: `/fork`. - Long-running agent tasks that will exceed the context window: rely on auto-compaction, or force early compaction with `/compact focus on X` before a context-sensitive operation. - Building tooling that inspects or replays sessions: parse the JSONL directly, or use `SessionManager` from the SDK (see [[concepts/sdk-and-rpc]]). ## Risks & Pitfalls - Tool results are truncated to 2000 characters during summarization serialization — very large tool outputs lose detail in the summary even though the original entry is retained in the raw JSONL. - A single oversized turn (many large tool calls before the next user message) triggers a "split turn," which is handled but produces a merged two-part summary that may be less coherent than a normal cut. - Compaction never cuts at a tool result, so the actual "kept" boundary can land later than `keepRecentTokens` alone would suggest. - Custom `session_before_compact`/`session_before_tree` extension handlers can silently change what "compaction" means for a project — check for these before assuming default behavior when debugging. - Session version migrations are automatic and largely invisible; code that parses `.jsonl` files directly should check the header version rather than assume v3 shapes everywhere. ## Related Concepts - [[concepts/extensions]] — `session_before_compact`, `session_before_tree`, `session_start`, `session_shutdown`, and the full session lifecycle event sequence. - [[concepts/sdk-and-rpc]] — programmatic `SessionManager`/`AgentSessionRuntime` APIs for creating, listing, forking, and switching sessions from code, and the `compact`/`get_session_stats`/`fork`/`clone` RPC commands. - [[concepts/acp]] — ACP mode surfaces compaction and subagent activity through a reverse-domain `_meta` envelope rather than native protocol fields. ## Sources - raw/github_doc-packages-coding-agent-docs-sessions-md.md - raw/github_doc-packages-coding-agent-docs-session-format-md.md - raw/github_doc-packages-coding-agent-docs-compaction-md.md --- title: "Settings and Customization" type: concept tags: [platform, user, foundational, well-established] created: 2026-08-05 updated: 2026-08-05 sources: ["raw/github_doc-packages-coding-agent-docs-settings-md.md", "raw/github_doc-packages-coding-agent-docs-shell-aliases-md.md", "raw/github_doc-packages-coding-agent-docs-prompt-templates-md.md"] confidence: high prime_agent_version: "v0.7.0" --- ## Definition Prime Agent is configured through layered JSON settings files, plus two smaller customization surfaces built on top of settings: shell alias forwarding for the non-interactive bash tool, and Markdown-based prompt templates that expand into slash commands. Together these are the main levers a user has over model defaults, UI behavior, retries, daemon policy, and reusable prompt snippets, without writing an extension. ## How It Works **Settings files and precedence.** Prime Agent reads JSON settings from `~/.prime/agent/settings.json` (global, all projects) and `.prime/agent/settings.json` (project, current directory); project settings override global settings, and nested objects are merged key-by-key rather than replaced wholesale (e.g., a project can override just `compaction.reserveTokens` while inheriting the global `compaction.enabled`). Edit the files directly or use `/settings` for common options. **Settings coverage** spans several areas: - *Model & Thinking*: `defaultProvider`, `defaultModel`, `defaultThinkingLevel` (default `"xhigh"`), `hideThinkingBlock`, and per-level `thinkingBudgets` token overrides. - *UI & Display*: `theme` (default `"dark"`; see [[concepts/tui-and-themes]]), `quietStartup`, `collapseChangelog`, `treeFilterMode` (default `"user-only"`), `editorPaddingX` (0-3), `autocompleteMaxVisible` (3-20), `showHardwareCursor`. - *Update checks*: stable builds poll a release manifest URL, beta builds poll a separate `beta.json`; `PI_SKIP_VERSION_CHECK=1` disables the check, `--offline`/`PI_OFFLINE=1` disables all startup network operations including package update checks. `PRIME_AGENT_DOWNLOAD_BASE_URL` overrides the manifest/tarball base URL. - *Warnings*: `warnings.anthropicExtraUsage` (default `true`) toggles the paid-extra-usage warning for Anthropic subscription auth. - *Compaction*: `compaction.enabled` (default `true`), `compaction.reserveTokens` (default `16384`), `compaction.keepRecentTokens` (default `20000`) — see [[concepts/sessions-and-compaction]]. - *Branch Summary*: `branchSummary.reserveTokens`, `branchSummary.skipPrompt`. - *Retry*: agent-level `retry.enabled`/`maxRetries`/`baseDelayMs` (2s/4s/8s exponential backoff by default) plus provider-level `retry.provider.timeoutMs`/`maxRetries`/`maxRetryDelayMs` (default 60000ms cap on a provider-requested retry delay — set to `0` to disable the cap so, e.g., Google's "quota resets in 5h" delay is honored in full instead of failing fast). - *Message Delivery*: `steeringMode`/`followUpMode` (`"all"` or `"one-at-a-time"`, default the latter) and `transport` (`"sse"`, `"websocket"`, or `"auto"`). - *Terminal & Images*: `terminal.showImages`, `terminal.clearOnShrink`, `images.autoResize` (default `true`, resizes to 2000x2000 max), `images.blockImages`. - *Shell*: `shellPath` (custom shell binary, e.g. Cygwin on Windows — see [[concepts/platform-setup]]), `shellCommandPrefix` (prefix injected before every bash command), `npmCommand` (argv override for npm-package-manager operations, e.g. routing through `mise` or `bun`). - *Daemon*: `idleEvictionMinutes` (default `90`, or `"off"`) — global-only, read exclusively from `~/.prime/agent/settings.json` (see [[concepts/daemon]]). - *Sessions*: `sessionDir`, with precedence `--session-dir` > `PRIME_AGENT_SESSION_DIR` > legacy `PRIME_AGENT_CODING_AGENT_SESSION_DIR` > `sessionDir` in settings. - *Model Cycling*: `enabledModels` (glob-style patterns for Ctrl+P cycling, same format as `--models`). - *Markdown*: `markdown.codeBlockIndent` (default two spaces). - *Resources*: `packages`, `extensions`, `skills`, `prompts`, `themes` arrays (globs with `!exclude`, `+forceInclude`, `-forceExclude`), plus `enableSkillCommands`, `enableBuiltinSkills`, and `bundledSkills.websearch` (default `true`) toggles — see [[concepts/skills]] and [[concepts/extensions]]. Paths in global settings resolve relative to `~/.prime/agent`; paths in project settings resolve relative to `.prime/agent`. **Shell aliases.** Prime Agent runs bash non-interactively (`bash -c`), which does not expand shell aliases by default. To make personal aliases available to bash-tool commands, set `shellCommandPrefix` to source them explicitly, e.g.: ```json { "shellCommandPrefix": "shopt -s expand_aliases\neval \"$(grep '^alias ' ~/.zshrc)\"" } ``` Adjust the sourced file (`~/.zshrc`, `~/.bashrc`, etc.) to match the user's shell. **Prompt templates.** A prompt template is a Markdown file whose filename (minus `.md`) becomes a slash command — `review.md` becomes `/review`. Prime Agent discovers templates from `~/.prime/agent/prompts/*.md` (global, non-recursive), `.prime/agent/prompts/*.md` (project, non-recursive), package `prompts/` directories or `pi.prompts` manifest entries, the `prompts` settings array, and repeatable `--prompt-template ` CLI flags; `--no-prompt-templates` disables discovery. Subdirectory templates require explicit inclusion via settings or a package manifest since directory discovery is non-recursive. Template frontmatter supports an optional `description` (falls back to the first non-empty line if omitted) and an optional `argument-hint`, shown before the description in autocomplete using `` and `[optional]` bracket conventions: ```markdown --- description: Review PRs from URLs with structured issue and code analysis argument-hint: "" --- ``` Template bodies support positional arguments and slicing: `$1`, `$2`, ... for positional args; `$@` or `$ARGUMENTS` for all args joined; `${@:N}` for args from the Nth position (1-indexed); `${@:N:L}` for `L` args starting at N. Example: ```markdown --- description: Create a component --- Create a React component named $1 with features: $@ ``` invoked as `/component Button "onClick handler" "disabled support"`. ## Key Parameters - **Settings precedence**: project `.prime/agent/settings.json` overrides global `~/.prime/agent/settings.json`, merged per-key for nested objects. - **`retry.provider.maxRetryDelayMs`** (default `60000`): the ceiling on how long Prime Agent will honor a provider-requested retry delay before failing with an informative error; `0` disables the cap entirely. - **`compaction.reserveTokens` / `keepRecentTokens`** (defaults `16384`/`20000`): control how much of the context window compaction reserves for the response versus preserves verbatim. - **Prompt template argument syntax**: `$1`..`$N`, `$@`/`$ARGUMENTS`, `${@:N}`, `${@:N:L}`. - **`shellCommandPrefix`**: raw shell text prepended to every bash-tool invocation — the mechanism for alias expansion, environment setup, or any per-command shell customization. ## When To Use Edit global settings for defaults that should apply everywhere (default model, theme, retry policy, idle eviction); edit project settings to override those defaults per-repository (e.g., a tighter `compaction.reserveTokens` for a small-context model used only on one project) or to share team-wide extension/skill/prompt package lists via version control. Use `shellCommandPrefix` whenever bash-tool commands need shell features (aliases, functions, `nvm`/`asdf`/`mise` activation) that non-interactive `bash -c` doesn't provide by default. Use a prompt template for any repeatable, parameterized instruction (code review checklist, PR analysis, component scaffolding) that would otherwise be retyped every session. ## Risks & Pitfalls - `idleEvictionMinutes` is silently ignored if set in project settings — it is read only from the global settings file. - Because nested settings objects merge per-key rather than replace, a project override of `{"compaction": {"reserveTokens": 8192}}` keeps the global `compaction.enabled` value rather than resetting it — an easy source of "why didn't my override fully apply" confusion. - Prompt template discovery in `prompts/` directories is explicitly non-recursive; templates placed in subdirectories are silently invisible unless added explicitly through settings or a package manifest. - `retry.provider.maxRetryDelayMs`'s default 60s cap means a provider's legitimate long backoff request (e.g., a multi-hour quota reset) fails fast by default rather than waiting — this is deliberate, but can surprise users expecting silent waiting. - `shellCommandPrefix` content is prepended verbatim to every bash invocation; a broken or slow prefix (e.g., a `.zshrc` with expensive plugin loading) taxes every single tool call. ## Related Concepts - [[concepts/daemon]] — `idleEvictionMinutes` is the one daemon-level setting exposed here - [[concepts/sessions-and-compaction]] — compaction, branch-summary, and session-directory settings covered here configure that subsystem - [[concepts/tui-and-themes]] — the `theme` setting and UI-display options connect settings to the rendered TUI and theme system - [[concepts/platform-setup]] — `shellPath` and `shellCommandPrefix` interact directly with platform-specific shell setup (Windows Cygwin, alias expansion) - [[concepts/skills]] and [[concepts/extensions]] — the `skills`/`extensions`/`prompts`/`themes`/`packages` resource arrays documented here are how those systems are wired into a given project or globally ## Sources - raw/github_doc-packages-coding-agent-docs-settings-md.md - raw/github_doc-packages-coding-agent-docs-shell-aliases-md.md - raw/github_doc-packages-coding-agent-docs-prompt-templates-md.md --- title: "Skills" type: concept tags: [skills, area/skills, audience/user, audience/developer, scope/foundational, status/well-established] created: 2026-08-06 updated: 2026-08-06 sources: ["raw/github_doc-packages-coding-agent-docs-skills-md.md"] confidence: high prime_agent_version: "v0.7.0" --- # Skills ## Definition A skill is a self-contained capability package that Prime Agent loads on demand, providing specialized workflows, setup instructions, helper scripts, and reference documentation for a specific task. Prime Agent implements the [Agent Skills standard](https://agentskills.io/specification) (warning on violations but staying lenient), and additionally supports **Python-backed skills** — a superset that installs a real Python package into the persistent IPython kernel, giving the model an importable callable rather than just instructions. ## How It Works ### Progressive disclosure At startup, Prime Agent scans all skill locations and extracts name, description, type, and file location for each skill. Only these lightweight descriptions are included in the system prompt (in XML format per the Agent Skills spec). When a task matches, the model uses `ipython` to load the full `SKILL.md` on demand — though models don't always do this reliably, so prompting or forcing via `/skill:name` helps — then follows the instructions, using relative paths to reference the skill's scripts/assets. Only descriptions sit in context permanently; full instructions load lazily. ### Discovery locations (in order, later overrides same-named earlier) - Global: `~/.prime/agent/skills/`, `~/.agents/skills/` - Project: `.prime/agent/skills/`, `.agents/skills/` (searched in `cwd` and ancestor directories, up to the git repo root or filesystem root) - Packages: `skills/` directories or `pi.skills` entries in `package.json` - Settings: a `skills` array of files/directories in `settings.json` - CLI: repeatable `--skill ` (additive even with `--no-skills`) - Built-in: shipped with the prime-agent package (**lowest** precedence — any user/project/package/CLI skill with the same name overrides it) Discovery rule nuance: in `~/.prime/agent/skills/` and `.prime/agent/skills/`, root `.md` files are discovered as individual skills directly; in `~/.agents/skills/` and project `.agents/skills/`, root `.md` files are **ignored** — only `SKILL.md`-containing directories count there (and recursively in all locations). `--no-skills` disables discovery entirely, though explicit `--skill` paths still load. ### Built-in skills `prime-intellect` (Prime Intellect product workflows via the `prime` CLI — environments, evaluations, hosted training, sandboxes, tunnels, inference, GPU compute, storage, with reference docs loading on demand), `skill-creator` (teaches the agent to build new skills, both markdown and Python-backed), and `websearch` (a Python-backed Serper-API search skill). Built-ins have the lowest precedence of any location. `websearch` setup: get a free key at serper.dev, then `/login` → MCP Connections → "Serper (web search)" to store it in `auth.json` (no env var required; works mid-session); `SERPER_API_KEY` in the environment takes precedence over the stored key if set. Disable one built-in via `{"bundledSkills": {"websearch": false}}`, or all of them via `{"enableBuiltinSkills": false}`; a single built-in without a dedicated toggle can be force-excluded via `{"skills": ["-prime-intellect/SKILL.md"]}` (patterns resolve against the built-in skills directory). Skills from other harnesses (Claude Code, OpenAI Codex) can be reused by adding their directories to the `skills` array in `settings.json`, e.g. `["~/.claude/skills", "~/.codex/skills"]`, or `["../.claude/skills"]` for a project-level Claude Code skill directory. ### Python-backed skills Layout adds a `pyproject.toml` and `src//__init__.py` (import name = skill name with hyphens converted to underscores) alongside `SKILL.md`: ``` web-search/ ├── SKILL.md ├── pyproject.toml └── src/ └── web_search/ └── __init__.py ``` Detection requires `SKILL.md` (always), `pyproject.toml` (marks it Python-backed), and the matching `src//__init__.py`. If the module defines `run()`, Prime Agent wraps the module as an async callable: `await web_search("query")` and `await web_search.run("query")` are equivalent, and `help(web_search)` works. Python skills install **editable** into the kernel venv during kernel setup — by default `~/.prime/agent/kernel-venv`, overridable via `PRIME_AGENT_KERNEL_VENV`. Changing `pyproject.toml` triggers a kernel venv rebuild so dependency changes are picked up. If `PRIME_AGENT_KERNEL_PYTHON` is set instead, Prime Agent does **not** install packages into that environment — it must already have `ipykernel`, `prime-agent-runtime`, and default runtime packages; missing imports there are disabled with a warning and calling the skill raises `RuntimeError`. A Python skill can optionally expose a **shell command** via a `[project.scripts]` console script whose name exactly matches the Python import name (including underscores): ```toml [project.scripts] web_search = "rlm.skill:cli" ``` The `rlm.skill:cli` helper imports `web_search.run`, parses CLI args with `tyro`, awaits async results, and prints non-`None` returns. The model can then call it from Python (`await web_search(...)`) or from shell mode (`!web_search "query" --limit 3`). ### Creating skills with Prime Agent The built-in `skill-creator` skill teaches both the markdown-skill format and the Python-backed package contract; ask in natural language, or force it explicitly with `/skill:skill-creator `. Tell it three things: **scope** (`.prime/agent/skills//` for project-committed, `~/.prime/agent/skills//` for personal), **kind** (markdown for pure instructions, Python-backed for reusable callable functionality), and **contract** (intended call signature, inputs/output, dependencies, credentials, verification behavior). After adding a Python-backed skill, start a fresh session so kernel setup can install and import the package; use `/reload` to rediscover new/edited metadata for markdown skills. An **installed Python-backed skill** (real package on disk, importable in the kernel) is distinct from a **continual harness skill entry** (a persisted description of a reusable Python call, managed by `/refine` after a repeated procedure emerges) — the latter does not replace packaging real functionality with `skill-creator`. ### Skill commands Skills register as `/skill:name` slash commands (`/skill:brave-search`, or `/skill:pdf-tools extract` with arguments appended as `User: `). Toggle globally via `enableSkillCommands` in settings or `/settings`. ### SKILL.md structure and frontmatter A skill is a directory containing `SKILL.md`; everything else (`scripts/`, `references/`, `assets/`) is freeform, referenced with relative paths. Frontmatter fields per the Agent Skills spec: | Field | Required | Description | |-------|----------|-------------| | `name` | Yes | Max 64 chars; lowercase a-z, 0-9, hyphens; must match parent directory name | | `description` | Yes | Max 1024 chars; what it does and when to use it | | `license` | No | License name or bundled-file reference | | `compatibility` | No | Max 500 chars; environment requirements | | `metadata` | No | Arbitrary key-value map | | `allowed-tools` | No | Space-delimited pre-approved tools (experimental) | | `disable-model-invocation` | No | `true` hides it from the startup skill list; still invokable via `/skill:name` | Name rules: 1–64 chars, lowercase letters/numbers/hyphens only, no leading/trailing or consecutive hyphens (valid: `pdf-processing`; invalid: `PDF-Processing`, `-pdf`, `pdf--processing`). The description is what determines whether the model loads the skill for a given task — vague descriptions ("Helps with PDFs") load unreliably; specific ones ("Extracts text and tables from PDF files, fills PDF forms, and merges multiple PDFs. Use when working with PDF documents.") load reliably. ### Validation Most violations (name/directory mismatch, name length/character violations, hyphen placement, description over 1024 chars) produce warnings but still load the skill. Unknown frontmatter fields are ignored. The one hard failure: **a missing description prevents loading entirely.** Name collisions across locations warn and keep the first skill found (i.e. discovery-order precedence applies). ## Key Parameters - **Discovery precedence** — CLI `--skill` and settings/project/global locations override same-named built-in skills; built-ins are always lowest priority. - **`disable-model-invocation`** — controls whether a skill is proactively suggested vs. explicit-only. - **`pyproject.toml` presence** — the sole signal that flips a skill from markdown-only to Python-backed. - **`PRIME_AGENT_KERNEL_PYTHON`** — opts out of Prime Agent managing the kernel venv, shifting dependency responsibility to the user. ## When To Use - Package a repeatable, documented procedure (setup steps + scripts + reference docs) that the model should discover and follow on demand, without bloating every system prompt. - Wrap reusable Python functionality (an API client, a data-processing routine) that the model should be able to call directly from IPython rather than re-deriving each time — a Python-backed skill. - Bring an MCP-integrated service into the model's tool surface (see [[concepts/mcp-integrations]], which is itself implemented as a Python-backed skill). - Reuse an existing Claude Code or Codex skill library rather than duplicating instructions. - For richer runtime hooks, custom tools with typed schemas, or TUI integration beyond what a skill package offers, use an extension instead — see [[concepts/extensions]]. ## Risks & Pitfalls - **Security**: skill content can instruct the model to perform any action and may include executable code the model invokes — review skill content before trusting it, especially from third-party sources. - Models don't always proactively load a skill's full `SKILL.md` even when its description matches — explicit prompting or `/skill:name` may be needed to force it. - Root `.md` skill files are only auto-discovered in `~/.prime/agent/skills/`/`.prime/agent/skills/`, **not** in the `~/.agents/skills/` / project `.agents/skills/` locations, a discovery-rule asymmetry that's easy to overlook when placing a quick markdown skill. - Changing `pyproject.toml` triggers a full kernel venv rebuild; on `PRIME_AGENT_KERNEL_PYTHON`, no rebuild happens at all and a missing dependency silently disables the skill with only a warning. - Name collisions across skill locations resolve by "first found" rather than any explicit precedence indicator visible to the user in normal operation — a shadowed skill can be surprising to debug. ## Related Concepts - [[concepts/extensions]] — the broader TypeScript extension system; skills are markdown/Python capability packages loaded declaratively, while extensions are executable modules with full lifecycle-event access. - [[concepts/mcp-integrations]] — MCP servers are wired into Prime Agent specifically as Python-backed skills, reusing this skill infrastructure rather than a separate tool-registration path. ## Sources - raw/github_doc-packages-coding-agent-docs-skills-md.md --- title: "TUI and Themes" type: concept tags: [tui, ui, foundational, user, well-established] created: 2026-08-05 updated: 2026-08-05 sources: ["raw/github_doc-packages-coding-agent-docs-tui-md.md", "raw/github_doc-packages-coding-agent-docs-keybindings-md.md", "raw/github_doc-packages-coding-agent-docs-themes-md.md", "raw/github_doc-packages-tui-readme-md.md"] confidence: high prime_agent_version: "v0.7.0" --- ## Definition Prime Agent's terminal user interface (TUI) is built on `packages/tui` (published as `prime-agent-tui`, source name `@earendil-works/pi-tui`), a minimal terminal UI framework with differential rendering and synchronized output for flicker-free interactive CLI applications. The interactive-mode screen it renders is composed, top to bottom, of a startup header, the message transcript, an input editor, and a footer. Themes are JSON files that supply the 51 color tokens the TUI's components use to style everything from borders to syntax highlighting, and keybindings are a namespaced, user-remappable id-to-key mapping that drives every keyboard interaction in that screen. ## How It Works **Rendering.** The TUI uses three rendering strategies: first render (output all lines without clearing scrollback), width-changed-or-change-above-viewport (clear screen, full re-render), and normal update (move cursor to the first changed line, clear to end, render only changed lines). All updates are wrapped in synchronized output (`\x1b[?2026h` ... `\x1b[?2026l`) for atomic, flicker-free updates. The TUI works with any object implementing a `Terminal` interface (`ProcessTerminal` for real terminals, `VirtualTerminal` for tests using `@xterm/headless`). **Components.** Every component implements `render(width): string[]`, optional `handleInput(data)`, optional `wantsKeyRelease`, and `invalidate()`. Each returned line must not exceed the given `width` or the TUI errors; helpers `visibleWidth()`, `truncateToWidth()`, and `wrapTextWithAnsi()` handle ANSI-aware sizing. Built-ins include `Text`, `TruncatedText`, `Box`, `Container`, `Spacer`, `Input`, `Editor`, `Markdown`, `Loader`/`CancellableLoader`, `SelectList`, `SettingsList`, and `Image` (Prime Agent renders compact image metadata rather than terminal graphics). Components needing a text cursor (for CJK IME support) implement the `Focusable` interface; the TUI scans rendered output for a zero-width `CURSOR_MARKER` and positions the hardware cursor there. Container components with embedded `Input`/`Editor` children must propagate `focused` down to the child or IME candidate windows appear in the wrong place. **Overlays.** Overlays render on top of existing content without clearing the screen (`tui.showOverlay()` at the TUI-primitives layer, or `{ overlay: true }` passed to `ctx.ui.custom()` from an extension). Overlay placement supports anchor-based positioning (9 anchors: `center`, `top-left`, ..., `right-center`), percentage or absolute row/col, size as fixed or percentage with `minWidth`/`maxHeight` floors, margins, and a `visible(termWidth, termHeight)` callback for responsive hiding. Resolution order: `minWidth` floors width; absolute row/col beats percentage beats anchor; margin clamps the final position; `visible` is re-evaluated every frame. Overlay components are disposed on close — extensions must create fresh instances rather than reusing a stale reference to re-show one. **Theming inside components.** Components accept `theme.fg(color, text)` and `theme.bg(color, text)` callbacks rather than importing a theme module directly. When the active theme changes, the TUI calls `invalidate()` on every component to clear render caches. A component that pre-bakes theme colors into cached strings (e.g., via `theme.fg()` stored in a child `Text`) must rebuild that content inside its own `invalidate()` override, or the old theme's ANSI codes remain baked in after a theme switch. **Themes as data.** A theme is a JSON file with `name` (required, unique), optional `vars` (reusable named colors), and `colors` (must define all 51 required tokens across Core UI, Backgrounds & Content, Markdown, Tool Diffs, Syntax Highlighting, Thinking Level Borders, and Bash Mode categories — there are no optional colors). Color values are hex (`"#ff0000"`), a 256-color palette index (`0-255`), a `vars` reference, or `""` for the terminal's default color. An optional `export` section customizes `/export` HTML colors; if omitted, they derive from `userMessageBg`. Prime Agent uses 24-bit RGB color and falls back to nearest approximation on 256-color terminals (check with `echo $COLORTERM`). **Theme discovery and hot reload.** Prime Agent loads themes from built-ins (`dark`, `light`), `~/.prime/agent/themes/*.json` (global), `.prime/agent/themes/*.json` (project), package `themes/` directories or `pi.themes` manifest entries, the `themes` array in settings, and repeatable `--theme ` CLI flags; `--no-themes` disables discovery. Select via `/settings` or `{"theme": "my-theme"}` in `settings.json`. On first run, Prime Agent detects the terminal background and defaults to `dark` or `light`. Editing the currently active custom theme file triggers an automatic hot reload for immediate visual feedback. **Keybindings.** All shortcuts are customizable via `~/.prime/agent/keybindings.json`, keyed by namespaced ids (e.g., `tui.editor.cursorUp`, `app.model.select`) that are the same ids extension authors use in `keyHint()` and the injected `keybindings` manager. Older pre-namespaced ids (like `cursorUp`) are migrated automatically on startup. Each action can bind to one key or an array of keys; user config overrides (not merges into) the default list per-action. Key format is `modifier+key` with combinable modifiers `ctrl`, `shift`, `alt` and keys spanning letters, digits, special keys (`escape`, `enter`, `tab`, arrows, `home`/`end`, `pageUp`/`pageDown`, etc.), function keys `f1`-`f12`, and symbols. After editing `keybindings.json`, run `/reload` to apply changes without restarting the session. `app.suspend` (Ctrl+Z) has no default binding on native Windows because Windows terminals lack Unix job control; binding it manually there just shows a status message instead of suspending (WSL keeps normal Linux behavior). ## Key Parameters - **51 required color tokens**, grouped as: Core UI (11: `accent`, `border`, `borderAccent`, `borderMuted`, `success`, `error`, `warning`, `muted`, `dim`, `text`, `thinkingText`), Backgrounds & Content (12), Markdown (10), Tool Diffs (3: `toolDiffAdded`/`Removed`/`Context`), Syntax Highlighting (9), Thinking Level Borders (6: `thinkingOff` through `thinkingXhigh`), and Bash Mode (1: `bashMode`, the editor border color when a `!`-prefixed bash command is being entered). - **Component interface contract**: `render(width): string[]` (line length must never exceed `width`), `handleInput?(data)`, `wantsKeyRelease?` (Kitty protocol key-release events, default `false`), `invalidate()`. - **Overlay sizing/position keys**: `width`/`minWidth`/`maxHeight` (number or `%` string), `anchor`, `offsetX`/`offsetY`, `row`/`col` (percent or absolute), `margin`, `visible`, `nonCapturing`. - **`PI_TUI_WRITE_LOG`**: env var that captures the raw ANSI stream written to stdout, for debugging renders. - **Debug key**: Shift+Ctrl+D triggers `tui.onDebug`. ## When To Use Reach for the TUI component/overlay system when building an extension that needs custom interactive UI — selection dialogs (`SelectList` + `DynamicBorder`), cancellable async operations (`BorderedLoader`), settings toggles (`SettingsList`), persistent status indicators (`ctx.ui.setStatus`), widgets above/below the editor (`ctx.ui.setWidget`), a custom footer (`ctx.ui.setFooter`), or a fully custom editor such as a vim-mode input (`CustomEditor` subclass via `ctx.ui.setEditorComponent`). Reach for the theming system when Prime Agent's default `dark`/`light` themes don't match a terminal or personal palette preference, or when shipping a themed extension/package. Reach for keybindings customization when the defaults conflict with terminal-level bindings (see [[concepts/platform-setup]] for terminal-specific Enter-key caveats) or to emulate emacs/vim editing conventions. ## Risks & Pitfalls - Emitting multi-line styled text without reapplying ANSI codes per line: the TUI appends a full SGR/OSC-8 reset at the end of every rendered line, so styles never carry across lines — use `wrapTextWithAnsi()` for correctly-styled wrapped output. - Forgetting the `Focusable` propagation pattern in container components (dialogs, selectors) with embedded `Input`/`Editor` children breaks IME candidate-window positioning for CJK input. - Pre-baking theme colors into cached component state without overriding `invalidate()` to rebuild that content means a theme switch leaves stale ANSI codes on screen. - Reusing a disposed overlay component reference (e.g., holding onto a `MenuComponent` instance after `close()`) is a dangling reference — always re-invoke the factory to show an overlay again. - A theme file that omits any of the 51 required tokens is invalid — there is no partial/optional-token mode. - On xfce4-terminal, terminator, and IntelliJ IDEA's integrated terminal, modifier-augmented Enter (`Ctrl+Enter`, `Shift+Enter`) can't be distinguished from plain `Enter`, which silently breaks any keybinding relying on that distinction (see [[concepts/platform-setup]]). ## Related Concepts - [[concepts/settings-and-customization]] — where the active theme name, `editorPaddingX`, `autocompleteMaxVisible`, and other UI settings are configured - [[concepts/platform-setup]] — terminal-specific configuration (Ghostty, WezTerm, Windows Terminal, tmux) required for reliable modifier-key detection that the keybinding system depends on - [[concepts/extensions]] — extensions are the primary consumer of the TUI component, overlay, and custom-editor APIs described here - [[concepts/daemon]] — the daemon delivers session/transcript state that the TUI renders; TUI invalidation and re-render is triggered by daemon-sourced events ## Sources - raw/github_doc-packages-coding-agent-docs-tui-md.md - raw/github_doc-packages-coding-agent-docs-keybindings-md.md - raw/github_doc-packages-coding-agent-docs-themes-md.md - raw/github_doc-packages-tui-readme-md.md # Change Log ## 2026-08-06 — Initial build Built from the PrimeIntellect-ai/prime-agent repo docs (34 pages under packages/coding-agent/docs + package READMEs) and 30 release mirrors. Prime Agent is a self-improving **RLM (recursive language model)** coding agent by Prime Intellect — the model runs in a persistent Python control environment and composes capabilities (tools, subagents) as code; part of the Prime Intellect RL ecosystem (verifiers, PRIME-RL, pi-mono). **Pages (21):** 20 concepts + 1 summary (release digest). **Sourcing notes:** - "RLM" = **recursive language model** (grounded verbatim in docs/rlm.md), NOT reinforcement-learned — corrected during the build. "Self-improving" refers to the harness/refine mechanism, not model retraining (synthesized from README, flagged in the rlm page). - Newest stable release is **v0.7.0**; the 0.x line has four breaking-change releases (v0.4/0.5/0.6/0.7). Release digest covers v0.1.1→v0.7.0 by theme. - Excluded CHANGELOG files (releases cover version history) and node_modules. - Naming lineage note (from docs/development): packages are also published as `prime-agent-core`/`-ai`/`-tui`; shares the `pi-mono` (badlogic) lineage. - Potential XL seed later: the extensions API surface, the SDK/RPC protocol, and a per-provider matrix are deep enough to expand into a Pro reference as the project matures past 0.x. --- title: "Release Digest (v0.1.1 - v0.7.0)" type: summary tags: [overview, platform, architecture, well-established] created: 2026-08-05 updated: 2026-08-05 sources: ["raw/github_release-v0-1-1.md", "raw/github_release-v0-1-2.md", "raw/github_release-v0-1-3.md", "raw/github_release-v0-1-4.md", "raw/github_release-v0-1-5.md", "raw/github_release-v0-1-6.md", "raw/github_release-v0-1-7.md", "raw/github_release-v0-1-8.md", "raw/github_release-v0-1-9.md", "raw/github_release-v0-2-0.md", "raw/github_release-v0-2-1.md", "raw/github_release-v0-2-2.md", "raw/github_release-v0-2-3.md", "raw/github_release-v0-2-4.md", "raw/github_release-v0-2-5.md", "raw/github_release-v0-2-6.md", "raw/github_release-v0-2-7.md", "raw/github_release-v0-2-8.md", "raw/github_release-v0-2-9.md", "raw/github_release-v0-3-0.md", "raw/github_release-v0-3-1.md", "raw/github_release-v0-3-2.md", "raw/github_release-v0-3-3.md", "raw/github_release-v0-4-0.md", "raw/github_release-v0-5-0.md", "raw/github_release-v0-5-1.md", "raw/github_release-v0-6-0.md", "raw/github_release-v0-6-1.md", "raw/github_release-v0-7-0.md", "raw/github_release-beta-v0-7-0-beta-454-1-be9e2fa.md"] confidence: high prime_agent_version: "v0.7.0" --- ## Key Points - **Release cadence is very rapid.** The mirrored history runs from v0.1.1 (published 2026-06-12) to v0.7.0 (published 2026-08-05) — 29 stable releases across roughly 8 weeks, averaging better than one release every two days. Several days shipped multiple releases (v0.1.1 → v0.1.2 about 18 hours apart; v0.6.0, v0.6.1, and v0.7.0 all published on 2026-08-05 alone). A parallel beta channel (`v0.7.0-beta.454.1.be9e2fa`, tagged `beta`) auto-builds from every commit to `main`, ahead of stable tags. This is consistent with a project still in active 0.x development rather than a mature, slow-cadence product. - **Versioning is still pre-1.0 and the wire/data-model contracts have broken repeatedly.** Four releases in the mirrored window carry explicit "Breaking Changes" sections: v0.4.0 (flat `get_session_tree` response, protocol 6; removed `/resume`/bare `--resume`), v0.5.0 (reworked session-action lifecycle, protocol 7, schema revision 8), v0.6.0 (`rlm(...)` becomes async/non-blocking with a spawn handle instead of a blocking result, role-addressed `agent_message.send`, nuclear-family-only agent reach, schema revision 13), and v0.7.0 (agent messages always use steering delivery, delivery-mode options removed from Python/CLI/RPC APIs). Each bump is paired with "older clients and daemons are rejected cleanly at connect" rather than silent incompatibility — see [[concepts/daemon]] for the protocol/schema-revision mechanism this relies on. - **Daemon and process-architecture hardening is the dominant thread across the whole line.** Early releases fix daemon OOM crashes and slim attach snapshots (v0.1.9), speed up session loading (v0.1.5, v0.2.0, v0.2.4), and add `daemon ps`/crash-log capture (v0.1.6). v0.3.0 is the architectural pivot: daemon and headless execution move to per-root-session-tree isolated recoverable worker processes with protocol-v2 chunked snapshots and session leases (see [[concepts/daemon]]). v0.3.1-v0.3.2 continue hardening (serialized worker recovery, convergent shutdown-all, idempotent snapshot transfers, capability negotiation for incompatible daemon builds). v0.5.0 reworks session input into a single action lifecycle/store. v0.6.0 adds idle eviction/passivation (`idleEvictionMinutes`) so finished subagents stay on disk until touched rather than consuming memory indefinitely. - **Subagent/RLM orchestration matured from an ad hoc feature into a first-class, schema-versioned model.** v0.1.4 introduces `/refine` and persistent harness state; v0.1.7 adds session/RLM heartbeats; v0.2.5 adds agent-to-agent messaging and orchestration heartbeats; v0.2.7-v0.2.9 add non-blocking subagent delegation guidance and steer/follow-up delivery modes; v0.3.0 fixes heartbeat starvation by dispatching schedules per isolated session worker; v0.3.2 adds parent-scoped subagent lifecycle APIs (`rlm.list_subagents()`, `rlm.delete_subagent()`) and per-subagent model selection. v0.6.0 is the big rework: `rlm(...)` returns immediately with a spawn handle instead of blocking for a result, `agent_message.send` becomes role-addressed (parent/sibling/child) via `receiver_role`, and agent reach is narrowed to the "nuclear family" (parent, siblings, direct children only — grandchildren/cousins require relaying). v0.7.0 simplifies again by making all agent messages use steering delivery unconditionally, removing the delivery-mode option added in v0.2.9. See [[concepts/long-running-agents]] and [[concepts/rlm]]. - **Session, tree, and compaction features grew steadily.** v0.1.3 adds `/context` (tree overview with per-agent tokens/cost) and `/usage`; v0.2.3 keeps the IPython kernel alive across compaction instead of wiping variables; v0.2.9 simplifies the session tree to show only user messages by default; v0.3.3 renders a bounded recent-transcript tail for long sessions while preserving full history; v0.4.0 replaces `/resume` with left-arrow tree browsing from a daemon chat plus direct `--resume `; v0.5.0 streams JSONL history for large loads and reworks session-action state reporting; v0.5.1 fixes `/refine` failing on models with small fixed output caps by deriving the budget from the selected model. See [[concepts/sessions-and-compaction]]. - **UI/UX iteration is continuous and detail-oriented**, spanning diff rendering (v0.1.5, v0.3.1), a redesigned prompt bar and subagent tree (v0.2.2), full-screen mode becoming default (v0.2.5/v0.2.6), a Claude-Code-flow shortcut rewire (Escape/`?`, v0.2.8), a unified tabbed provider/model/MCP configuration menu (v0.3.1-v0.3.2), and numerous small icon/connector consistency passes (v0.3.3). See [[concepts/tui-and-themes]]. - **Provider and integration surface expanded incrementally**: new Prime Inference models (GLM-5.2, MiniMax M3, Kimi K2.7 — v0.1.7; OpenAI Fast mode — v0.3.1), image/vision support for Prime Inference models (v0.2.2), a bundled `websearch` skill via Serper (v0.2.2), built-in Linear/Notion MCP integrations driven from the Python kernel rather than as new agent tools (v0.2.3), a built-in Herdr pane-status integration (v0.2.8), and — the largest single addition — `--mode acp` running Prime Agent as an Agent Client Protocol agent over NDJSON/stdio, with Prime-Agent-specific capabilities (subagents, autonomous gates, compaction, goals, heartbeats, refinement) carried in a namespaced `_meta` envelope for ACP clients that don't understand them (v0.6.0). See [[concepts/mcp-integrations]] and [[concepts/acp]]. - **Autonomous/unattended-run capability was added and then documented more prominently**: v0.3.0 introduces autonomous mode with host-side continuations and quality gates; v0.4.0 adds session-owned `/autonomous` (and `/compact`, `/refine`, `/goal`) commands in the Agents View reply composer; v0.5.0 exposes autonomous mode, quality gates, and their limits more visibly in top-level CLI help and docs. - **Overall maturity read**: this is an actively developed 0.x product moving fast on both features and breaking internal contracts (daemon protocol, RLM messaging model), with release notes showing a tight feedback loop of user-reported issue numbers (`#NNN`) and internal tracker tickets (`ENG-NNNN`) being fixed within days. v0.7.0 is the newest stable release at the time of this digest. ## Relevant Concepts - [[concepts/daemon]] — process topology, protocol versioning, worker recovery, snapshot streaming - [[concepts/long-running-agents]] and [[concepts/rlm]] — subagent spawning, heartbeats, and the v0.6.0 messaging-model rework - [[concepts/sessions-and-compaction]] — tree navigation, `/context`/`/usage`, compaction-safe kernel state - [[concepts/tui-and-themes]] — fullscreen mode, configuration menu, prompt bar, diff rendering - [[concepts/mcp-integrations]] — Linear/Notion, Herdr, websearch skill - [[concepts/acp]] — the `--mode acp` addition in v0.6.0 - [[concepts/providers-and-models]] — Prime Inference model additions and vision/image support - [[concepts/settings-and-customization]] — `idleEvictionMinutes` (v0.6.0), autonomous-mode settings ## Source Metadata - **Type**: GitHub release notes (mirrored) - **Repository**: github.com/PrimeIntellect-ai/prime-agent - **Range covered**: v0.1.1 (published 2026-06-12) through v0.7.0 (published 2026-08-05), plus one beta channel tag (`v0.7.0-beta.454.1.be9e2fa`, published 2026-07-17, built from commit `be9e2fa`) - **Count**: 30 release mirrors (29 stable tags v0.1.1-v0.7.0, 1 beta tag) - **Fetched**: 2026-08-05 - **Identifiers**: raw/github_release-v0-1-1.md through raw/github_release-v0-7-0.md, raw/github_release-beta-v0-7-0-beta-454-1-be9e2fa.md