### Quick start example for @earendil-works/chord Source: https://github.com/earendil-works/pi/blob/main/packages/chord/README.md A complete example showing how to define a remote contract, create a host, serve the contract, and use it from a root. The contract is shared between provider and consumers. The host serves the Counter contract, and the root gets an instance, subscribes to its state, and calls a method. ```ts import { Type } from "typebox"; import { createHost, hostNamed, method, remote } from "@earendil-works/chord"; // contract.ts: shared by provider and consumers export const Counter = remote("demo.counter", { version: 1, input: Type.Object({ name: Type.String() }), host: hostNamed("server"), // where its objects live; callers never name a host variants: { default: { state: { count: Type.Number() }, methods: { increment: method(Type.Object({ by: Type.Number() })) }, }, }, }); const host = createHost({ name: "server", self: { kind: "server" } }); host.serve(Counter, ({ name }, _principal, self) => { const count = self.state("count", Type.Number(), 0); return { variant: "default", count, increment: async ({ by }, ctx) => { count.change(ctx, (n) => n + by); }, }; }); await host.root(async (ctx) => { const clicks = await ctx.get(Counter, { name: "clicks" }); // ready, with its state; released when this root ends clicks.count.subscribe((n) => console.log("count", n)); await clicks.increment({ by: 2 }, ctx); // logs 0, then 2 }); ``` -------------------------------- ### Install an extension with registry.install Source: https://github.com/earendil-works/pi/blob/main/packages/durable/README.md Installing an extension with an installed name replaces it in place, in one step. ```typescript registry.install(await loadCodingExtension()); // same name "coding": replaces the installed one ``` -------------------------------- ### Run an SDK example Source: https://github.com/earendil-works/pi/blob/main/packages/coding-agent/examples/sdk/README.md Execute an SDK example script using Node.js from the coding-agent package directory. ```bash cd packages/coding-agent node examples/sdk/01-minimal.ts ``` -------------------------------- ### registry.install(extension) Source: https://github.com/earendil-works/pi/blob/main/packages/durable/README.md Installs an extension, replacing any existing extension with the same installed name in one step. After a restart, extensions must be installed again, and pending tasks resume once installed. ```APIDOC ## registry.install(extension) ### Description Installs an extension. If an extension with the same installed name already exists, it is replaced in place in one step. After a restart, the same extensions must be installed again; pending tasks of an extension's `tasks` resume once it is installed. ### Method SDK method ### Endpoint registry.install(extension) ### Parameters - **extension** (Extension) - Required - The extension object to install. ### Request Example ```typescript registry.install(await loadCodingExtension()); // same name "coding": replaces the installed one ``` ### Response No return value is documented. ``` -------------------------------- ### Run the chat-simple.ts chat interface example Source: https://github.com/earendil-works/pi/blob/main/packages/tui/README.md Run the complete chat interface example located at test/chat-simple.ts. ```bash node test/chat-simple.ts ``` -------------------------------- ### Add local stdio MCP server and start Pi Source: https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/mcp.md Add a local stdio server, check the connection, then start Pi. ```bash pi mcp add filesystem -- npx -y @modelcontextprotocol/server-filesystem . pi mcp list pi ``` -------------------------------- ### Install Node.js and Git Source: https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/termux.md Installs the required runtime and version control tools in Termux. ```bash pkg install nodejs git ``` -------------------------------- ### Start llama-server with preset Source: https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/nvidia-rtx-llama-cpp.md Start the llama.cpp router with the preset. Run from the llama.cpp folder; set $env:HF_TOKEN first if the recipe requires a Hugging Face token. ```powershell .\llama-server.exe --models-preset qwen3.8-27b.ini --host 127.0.0.1 --port 8080 ``` -------------------------------- ### Run a TypeScript example with node Source: https://github.com/earendil-works/pi/blob/main/packages/durable/README.md Run a runnable example from the test/examples directory. Use this command from the package directory to execute a TypeScript example with source conditions and experimental type stripping. ```bash node --conditions=source --experimental-strip-types test/examples/14-chat.ts ``` -------------------------------- ### Run rpc-client.ts example with node Source: https://github.com/earendil-works/pi/blob/main/packages/coding-agent/examples/README.md Build the coding-agent package before running this command from a repository checkout. It runs the rpc-client.ts example to explain a repository. ```bash node examples/rpc-client.ts "Explain this repository" ``` -------------------------------- ### Install Pi with Nix Source: https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/quickstart.md Installs the latest release from the Pi flake and builds Pi from source on macOS or Linux. ```bash nix profile add github:earendil-works/pi/stable ``` -------------------------------- ### Install @earendil-works/pi-durable and dependencies Source: https://github.com/earendil-works/pi/blob/main/packages/durable/README.md Install the durable agent harness along with its required peer dependencies @earendil-works/pi-ai and @earendil-works/chord. ```bash npm install @earendil-works/pi-durable @earendil-works/pi-ai @earendil-works/chord ``` -------------------------------- ### Install the Gondolin extension Source: https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/containerization.md Copies the Gondolin extension into the Pi extensions directory and installs dependencies without running scripts. Requires Node.js 23.6 or newer and system QEMU. ```bash mkdir -p ~/.pi/agent/extensions cp -R packages/coding-agent/examples/extensions/gondolin ~/.pi/agent/extensions/gondolin cd ~/.pi/agent/extensions/gondolin npm install --ignore-scripts ``` -------------------------------- ### Install dependencies, run type checking, and run the demo Source: https://github.com/earendil-works/pi/blob/main/packages/tui/README.md Development commands for the monorepo: install dependencies from the monorepo root, run type checking, and run the demo. ```bash # Install dependencies (from monorepo root) npm install # Run type checking npm run check # Run the demo node test/chat-simple.ts ``` -------------------------------- ### Launch and run DOOM overlay extension Source: https://github.com/earendil-works/pi/blob/main/packages/coding-agent/examples/extensions/doom-overlay/README.md Start pi loading the DOOM extension and invoke the overlay command. The required ~4MB shareware WAD file is downloaded automatically on first run. ```bash pi --extension ./examples/extensions/doom-overlay ``` ```text /doom-overlay ``` -------------------------------- ### streamSimple() Source: https://github.com/earendil-works/pi/blob/main/packages/ai/README.md Direct API call that initiates a streaming assistant message generation. Throws synchronously when request authentication is missing. The stream follows `start -> updates* -> done` on success, `start -> updates* -> error` on failure after generation starts, or contains only `error` if request setup fails before generation starts. ```APIDOC ## streamSimple() ### Description Direct API call that initiates a streaming assistant message generation. Throws synchronously when request authentication is missing. The stream follows `start -> updates* -> done` on success, `start -> updates* -> error` on failure after generation starts, or contains only `error` if request setup fails before generation starts. ### Method SDK function call ### Endpoint streamSimple() ### Parameters No parameters are explicitly documented in the source. ### Response Returns a stream of events emitted during assistant message generation. #### Event Sequence - Success: `start -> updates* -> done` - Failure after generation starts: `start -> updates* -> error` - Request setup failure before generation starts: only `error` - `done` and update events are invalid before `start` #### Event Types | Event Type | Description | Key Properties | |------------|-------------|----------------| | `start` | Stream begins | `partial`: Initial assistant message structure | | `text_start` | Text block starts | `contentIndex`: Position in content array | | `text_delta` | Text chunk received | `delta`: New text, `contentIndex`: Position | | `text_end` | Text block complete | `content`: Full text, `contentIndex`: Position | | `thinking_start` | Thinking block starts | `contentIndex`: Position in content array | | `thinking_delta` | Thinking chunk received | `delta`: New text, `contentIndex`: Position | | `thinking_end` | Thinking block complete | `content`: Full thinking, `contentIndex`: Position | | `toolcall_start` | Tool call begins | `contentIndex`: Position in content array | | `toolcall_delta` | Tool arguments streaming | `delta`: JSON chunk, `partial.content[contentIndex].arguments`: Partial parsed args | | `toolcall_end` | Tool call complete | `toolCall`: Complete, but not schema-validated, tool call with `id`, `name`, `arguments` | | `done` | Stream complete | `reason`: Stop reason ("stop", "length", "toolUse"), `message`: Final assistant message | | `error` | Error occurred | `reason`: Error type ("error" or "aborted"), `error`: AssistantMessage with partial content | #### Event Properties - Every non-terminal event's `partial` is the shared live response-so-far helper. It is intentionally not an event-time snapshot: providers may mutate the same message and content blocks as generation advances, including while older events wait in the stream queue. Inspect it when handling an event instead of retaining it as historical state. - Text and ordinary thinking blocks are empty when their `*_start` event is emitted and grow only through matching `*_delta` events until the authoritative `*_end`; redacted thinking may be complete at start and emit no deltas. - Tool-call arguments at `toolcall_start` are provider-specific; `toolcall_delta` carries subsequent JSON updates. - Streaming events for different content blocks are not guaranteed to be contiguous. Providers may emit deltas for text, thinking, and tool calls in the same upstream chunk, and pi may surface corresponding events interleaved, for example `text_start`, `text_delta`, `toolcall_start`, `text_delta`, `toolcall_delta`. Consumers must use `contentIndex` to associate each delta/end event with its block and must not assume that a block's `*_start`/`*_delta`/`*_end` sequence is uninterrupted by events for other blocks. ``` -------------------------------- ### qwen3.8-27b.ini preset Source: https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/nvidia-rtx-llama-cpp.md Router preset converted from the example recipe command. Save next to llama-server or pass its full path when starting the router. ```ini version = 1 [qwen3.8-27b] load-on-startup = true hf-repo = unsloth/Qwen3.8-27B-GGUF hf-file = Qwen3.8-27B-UD-Q4_K_M.gguf hf-repo-draft = z-lab/Qwen3.8-27B-DFlash2-GGUF spec-draft-model = Qwen3.8-27B-DFlash2-Q4_K_M.gguf no-mmproj = true batch-size = 4096 ubatch-size = 1024 ctx-size = 65536 parallel = 1 ngl = 999 jinja = true chat-template-kwargs = {"preserve_thinking":true} spec-type = draft-dflash spec-draft-n-max = 7 spec-draft-backend-sampling = true ``` -------------------------------- ### Define and install multiple extensions with Harness.open Source: https://github.com/earendil-works/pi/blob/main/packages/durable/docs/spec.md Defines several extensions (ContextFiles, Skills, Coding, Permissions, Reviewer) and installs them into a registry. Opens a harness with settings that select all except Reviewer, and creates a root conversation with a specified agent model and cwd. ```ts export const ContextFiles = defineExtension({ name: "context-files", sections: [section("agents-md", renderAgentsMd)] }); export const Skills = defineExtension({ name: "skills", sections: [section("skills", renderSkills)] }); export const Coding = defineExtension({ name: "coding", sections: [ section("preamble", () => "You are an expert coding assistant.", { tag: false }), // The environment the host built for this conversation, in the conversation's directory. section("cwd", (input) => input.env && `Working directory: ${input.env.cwd}`), ], }); export const Permissions = defineExtension({ name: "permissions", hooks: [hook(ToolTask, { beforeTool: async (call) => (isDangerous(call) ? { block: "Needs approval" } : undefined) })], }); // A role and a review loop, for conversations that select it. export const Reviewer = defineExtension({ name: "reviewer", sections: [section("role", () => "You review diffs. Report problems as a list. Never edit files.")], hooks: [hook(GenerationTask, { onYield: requestSecondPass })], }); const registry = createRegistry(); for (const extension of [CodingTools, Coding, ContextFiles, Skills, Permissions, Reviewer]) registry.install(extension); const harness = await Harness.open(storage, { models, registry, // Reviewer is installed but not selected by default: only conversations that select it get its role and hooks. settings: { extensions: [CodingTools, Coding, ContextFiles, Skills, Permissions] }, env: ({ cwd }) => localEnv(cwd ?? process.cwd()), // cached NodeExecutionEnv per directory }, context); // The conversation remembers its model and directory; a restart elsewhere keeps both. const root = await harness.root(context, { agent: { model: sonnet, cwd: process.cwd() } }); ``` -------------------------------- ### stream(model, context, options) Source: https://github.com/earendil-works/pi/blob/main/packages/ai/README.md Starts a streaming request to a model. Returns an async iterable of events and a result promise. Request failures after a stream is returned never throw; instead an error event is emitted and the final message carries the details. Setup failures may emit error without start; failures after generation begins emit start, any observed updates, then error. ```APIDOC ## stream(model, context, options) ### Description Starts a streaming request to a model. Returns an async iterable of events and a result promise. Request failures after a stream is returned never throw; instead an error event is emitted and the final message carries the details. Setup failures may emit error without start; failures after generation begins emit start, any observed updates, then error. ### Method stream ### Endpoint models.stream(model, context, options) ### Parameters #### Request Body - **model** (Model) - Required - The model to use for the request. - **context** (Context) - Required - The conversation context containing messages. - **options** (StreamOptions) - Optional - Additional options such as signal, onPayload, onProviderStreamEvent, headers. #### Options - **signal** (AbortSignal) - Optional - Allows canceling in-progress requests. Aborted requests have stopReason === 'aborted'. - **onPayload** (function) - Optional - Callback to inspect the request payload sent to the provider. Supported by stream, complete, streamSimple, and completeSimple. - **onProviderStreamEvent** (function) - Optional - Callback to inspect provider-specific fields before normalization. Callbacks are awaited in stream order; slow callbacks delay stream consumption and thrown errors fail the request. - **headers** (object) - Optional - Additional headers to send with the request. ### Response #### Success Response - **events** (AsyncIterable) - Stream of events including text_delta, error, etc. - **result()** (Promise) - Final message with stopReason, errorMessage, content, usage. #### Error Events - **event.type** (string) - 'error' - **event.reason** (string) - Either 'error' or 'aborted' - **event.error** (AssistantMessage) - The AssistantMessage with partial content and error details. ### Request Example const s = models.stream(model, { messages: [{ role: 'user', content: 'Write a long story', timestamp: Date.now() }] }, { signal: controller.signal }); ### Response Example for await (const event of s) { if (event.type === 'text_delta') { process.stdout.write(event.delta); } else if (event.type === 'error') { console.log(`${event.reason === 'aborted' ? 'Aborted' : 'Error'}:`, event.error.errorMessage); } } const response = await s.result(); if (response.stopReason === 'aborted') { console.log('Request was aborted:', response.errorMessage); console.log('Partial content received:', response.content); console.log('Tokens used:', response.usage); } ``` -------------------------------- ### Quick Start with Harness.open, MemoryStorage, and OpenAI Source: https://github.com/earendil-works/pi/blob/main/packages/durable/README.md Opens a Harness over MemoryStorage, creates a root conversation with an OpenAI model, submits an input, waits for the answer, commits the assistant entry, and closes the harness. Requires OPENAI_API_KEY for the OpenAI provider. Every async call takes a Chord Context; BACKGROUND_CONTEXT never cancels. ```typescript import { BACKGROUND_CONTEXT } from "@earendil-works/chord/context"; import { createModels } from "@earendil-works/pi-ai/models"; import { openaiProvider } from "@earendil-works/pi-ai/providers/openai"; import { AssistantEntry, createRegistry, Harness, MemoryStorage } from "@earendil-works/pi-durable"; const context = BACKGROUND_CONTEXT; const models = createModels(); models.setProvider(openaiProvider()); // reads OPENAI_API_KEY const harness = await Harness.open(new MemoryStorage(), { models, registry: createRegistry() }, context); const root = await harness.root(context, { agent: { model: { provider: "openai", modelId: "gpt-6-sol" } } }); const submission = await root.submit({ type: "input", content: "What is the capital of France?" }, context); const settled = await submission.wait(context); if (settled.status === "done" && settled.type === "input") { const answer = await root.commit((tx) => tx.entry(AssistantEntry, settled.answer), context); console.log(answer?.model?.[0]); } await harness.close(context); ``` -------------------------------- ### Run both Workers locally with wrangler dev and test with curl Source: https://github.com/earendil-works/pi/blob/main/packages/codemode/examples/cloudflare/README.md Install @earendil-works/pi-codemode and wrangler in each directory, then start both Workers in one process. The curl command sends a script to the local endpoint. ```sh npx wrangler dev -c agent/wrangler.jsonc -c sandbox/wrangler.jsonc curl -X POST http://localhost:8787 --data 'const n = await tools.count({ add: 2 }); text("n=" + n); return n' ``` -------------------------------- ### Run storage conformance suite with registerStorageConformance Source: https://github.com/earendil-works/pi/blob/main/packages/durable/README.md Use to run the shared conformance suite for a custom storage backend with any Vitest- or Jest-compatible runner. The example uses Vitest and provides a setup function that opens and closes the storage. ```typescript import { registerStorageConformance } from "@earendil-works/pi-durable/testing"; import { describe, expect, it } from "vitest"; registerStorageConformance({ describe, expect, it }, "My Storage", async (use) => { const storage = await openMyStorage(); try { await use(storage); } finally { await closeMyStorage(storage); } }); ``` -------------------------------- ### sandbox.start(code, options) Source: https://github.com/earendil-works/pi/blob/main/packages/codemode/README.md Starts a deterministic script run in the sandbox VM. The host supplies the initial time, seed, tools, and callbacks to handle calls and results. The run is deterministic given the same inputs and result order. ```APIDOC ## sandbox.start(code, options) ### Description Starts a deterministic script run in the sandbox VM. The host supplies the initial time, seed, tools, and callbacks to handle calls and results. The run is deterministic given the same inputs and result order. ### Method sandbox.start ### Endpoint sandbox.start(code, options) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **code** (string) - Required - The script code to run. - **options** (object) - Required - Configuration for the run. - **startedAt** (number) - Required - The initial timestamp for Date.now() and performance.now(). - **seed** (number) - Required - Seed for randomness (Math.random() and other randomness). - **tools** (array) - Required - List of tool definitions available to the script. Each tool has a name and description. - **onStarted** (function) - Optional - Callback invoked with a fingerprint (engine versions, prelude hash, limits) when the run starts. - **onCall** (function) - Required - Callback invoked when the script makes a call. Receives a call object with id and args. The host must eventually deliver a result using run.deliver. - **onIdle** (function) - Optional - Callback invoked after a result is processed. Receives seq (result number, 0 for first run) and issued (total calls issued so far). - **timeoutMs** (number) - Optional - Deadline for the run in milliseconds. If not provided, no deadline. ### Request Example { "code": "const text = await read({ path: 'file.txt' }); return text;", "options": { "startedAt": 1620000000000, "seed": 7, "tools": [ { "name": "read", "description": "Read a file" } ], "onStarted": "(fingerprint) => {}", "onCall": "(call) => { void readFile(call.args).then((text) => run.deliver(nextResult++, Date.now(), call.id, { ok: true, value: text })); }", "onIdle": "(seq, issued) => {}", "timeoutMs": 5000 } } ### Response #### Success Response - **run** (object) - The run object with methods and properties: - **result** (Promise) - Resolves to the final result of the script. - **deliver** (function) - Method to deliver a result for a call. Signature: deliver(resultNumber, timestamp, callId, resultObject). resultNumber must be sequential starting from 1. resultObject has ok (boolean) and value or error. - **signal** (AbortSignal) - Signal to abort the run with an error the script cannot catch. #### Response Example { "run": { "result": "Promise { }", "deliver": "function deliver(resultNumber, timestamp, callId, resultObject) { ... }", "signal": "AbortSignal { ... }" } } ### Error Handling - If timeoutMs is provided and exceeded, the run may be aborted. - Aborting the signal ends the run with an error the script cannot catch. - Result numbers must be sequential without gaps; otherwise behavior is undefined. ``` -------------------------------- ### Install a package with pi install Source: https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/cli.md Installs a package from a source such as npm. Use --local or -l to install to project settings instead of global settings. ```sh pi install npm:@scope/package ``` -------------------------------- ### Prompt example: Summarize and save action items Source: https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/quickstart.md Demonstrates referencing a file with `@` and instructing Pi to output results to a new file. ```text Summarize @meeting-notes.md and save the action items to action-items.md. ``` -------------------------------- ### Install Pi CLI with the shell installer Source: https://github.com/earendil-works/pi/blob/main/README.md Installs the Pi command-line interface on macOS and Linux. The installer pins all dependencies, and Pi is later updated with `pi update`. ```bash curl -fsSL https://pi.dev/install.sh | sh ``` -------------------------------- ### Prompt example: Explain repository structure Source: https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/quickstart.md Prompts Pi to inspect the working directory and explain the project structure and testing commands. ```text Explain how this repository is structured and how to run its checks. ``` -------------------------------- ### Install @earendil-works/pi-agent-core Source: https://github.com/earendil-works/pi/blob/main/packages/agent/README.md Install the package via npm. ```bash npm install @earendil-works/pi-agent-core ``` -------------------------------- ### Install Pi CLI on Windows with PowerShell Source: https://github.com/earendil-works/pi/blob/main/README.md Installs the Pi command-line interface on Windows. The installer pins all dependencies, and Pi is later updated with `pi update`. ```shell powershell -c "irm https://pi.dev/install.ps1 | iex" ``` -------------------------------- ### Choose initial theme with --use-theme Source: https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/themes.md Choose the initial theme for one invocation without changing the saved setting. ```bash pi --use-theme light pi --use-theme light/dark ``` -------------------------------- ### Clean install with npm ci --ignore-scripts Source: https://github.com/earendil-works/pi/blob/main/AGENTS.md Clean or CI-style install without running lifecycle scripts. Use in CI or when you need a clean install. ```bash npm ci --ignore-scripts ``` -------------------------------- ### Start a deterministic sandbox run with sandbox.start Source: https://github.com/earendil-works/pi/blob/main/packages/codemode/README.md Use sandbox.start to run a script deterministically, providing startedAt, seed, tools, and callbacks. The host must answer each call with a result number in order. The run has no deadline unless timeoutMs is given. ```ts const run = sandbox.start(code, { startedAt: Date.now(), seed: 7, tools: [{ name: "read", description: "Read a file" }], onStarted: (fingerprint) => {}, // what the VM is: engine versions, prelude hash, limits onCall: (call) => { // call.id is the VM's own number for the call, in the order the script made them. void readFile(call.args).then((text) => run.deliver(nextResult++, Date.now(), call.id, { ok: true, value: text })); }, onIdle: (seq, issued) => {}, // after result `seq` (0: the first run), `issued` calls in total }); const result = await run.result; ``` -------------------------------- ### Install @earendil-works/pi-telemetry via npm Source: https://github.com/earendil-works/pi/blob/main/packages/telemetry/README.md Installs the package dependency into your project. ```bash npm install @earendil-works/pi-telemetry ``` -------------------------------- ### Start Pi in a working directory Source: https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/termux.md Navigates to the designated project folder and launches the Pi coding agent. ```bash cd /path/to/working-folder pi ``` -------------------------------- ### Install @earendil-works/pi-ai with npm Source: https://github.com/earendil-works/pi/blob/main/packages/ai/README.md Installs the @earendil-works/pi-ai package using npm. ```bash npm install @earendil-works/pi-ai ``` -------------------------------- ### Configure Pi with /login llama.cpp Source: https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/llama-cpp.md Use this command to start Pi and configure the llama.cpp provider. Enter the router URL and optional API key; the default URL is http://127.0.0.1:8080. ```text /login llama.cpp ``` -------------------------------- ### Verify Pi installation Source: https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/quickstart.md Checks the installed version of the Pi CLI. ```bash pi --version ```