Use when designing, reviewing, or refactoring a CLI that must serve AI agents alongside humans, or when converting an API or SDK into an agent-usable CLI interface.
日本語の概要は準備中です。原文の説明を表示しています。
Developer reference for building applications, tools, and agents on the Pi Durable agent harness (@earendil-works/pi-durable) and the pi-ai model layer. Use when writing or debugging code that imports @earendil-works/pi-durable or pi-ai: assembling a Harness over memory/SQLite/JSONL/Durable Object storage, submitting input and waiting for answers, defining tools with TypeBox schemas and structured output, calling tools from tools, hooks and guards, durable tasks with checkpoints and ownership, subagents and child tasks, documents and migrations, code mode, tool search, per-conversation environments, compaction, recovery after a crash, storage and environment conformance tests, or choosing models and providers. Also use when a durable/agent-runtime behavior question comes up: what survives a restart, why an input stayed queued, why a task is blocked or orphaned, how abort cascades, or what the Pico5 specification requires.
インストールする前に、エージェントに与えられる指示の中身を確認できます。
@earendil-works/pi-durable is a durable agent harness: conversations, model turns, tool calls,
tasks, and your own documents are committed to storage before anything is shown, so a process that dies
mid-turn is picked up where it stopped. It ships in the pi monorepo next to @earendil-works/pi-ai
(model access, tools, messages) and @earendil-works/chord (tracked JSON state).
Two things about it decide most design choices:
pi-dev-rules.@earendil-works/pi-durable or @earendil-works/pi-ai.HarnessOptions, settings, the registry, and an
execution environment.executeTool(), callers,
deferred tools and tool search, replay safety, output limits, image handling.failFast, abort, recovery, migration.| File | Covers |
|---|---|
references/durable-guide.md | The package's own guide, bundled verbatim: quick start, concepts, persist and resume, extensions, tools (including nested calls and callers), code mode, system prompt, per-conversation agent, settings, environment, reload, watching, busy conversations, reset and handoff, compaction, agent events, hooks, more conversations and forks, abort and subagents, child tasks, the task graph, your own state, usage and cost, storage, errors, and the runnable examples. Start here. |
references/durable-api.md | The exact public surface: entry-point map, Context, Harness/Session/Conversation/ConversationHandle, submissions, the Tx transaction surface, documents, entries, extensions and sections, hooks, tools and ToolExecutionApi, tasks and TaskRuntime, environment, storage, testing, observation, error classes, and the export inventory per subpath |
references/durable-runtime.md | How work actually executes: the commit line and its rules, one input end to end, task checkpoints, the ownership tree, recovery by case, compaction, the inbox boundaries, live state and progress cadence, the failure model, the knobs that change behavior, and the deliberate non-goals |
references/durable-recipes.md | Project setup, the catalogue of all 32 runnable examples, and 19 recipes with code: minimal chat, persistence and exactly-once input, live UI, agent events, structured-output tools, tool-calling tools, foreground and background subagents, child tasks with durable waits, coding agent, plan mode, per-conversation sandbox, tool override and wrappers, extension state and migration, hooks, compaction, code mode, tool search, conformance testing, plus the pitfall checklist |
references/durable-spec.md | The normative Pico5 specification bundled verbatim (5340 lines): records and lifetimes, documents and mutation ownership, transactions and storage ownership, tasks and the effect sandwich, structured concurrency, submissions and the inbox, extensions/hooks/tools, the built-in tasks, document observation, the storage contract and failure model, the backends, API footguns, and non-goals. Read section 12 before shipping |
references/pi-ai-models.md | The model layer bundled verbatim: createModels()/builtinModels(), provider factories and auth, querying the model catalog, environment variables, defining tools with TypeBox, constrained sampling, the event reference, image input, usage and cost, retries, and the message types that end up in entries |
references/codemode-sandbox.md | @earendil-works/pi-codemode bundled verbatim: what a script may call, the injected globals, the sandbox module surface, determinism and memory limits, and local versus remote sandboxes |
npm install @earendil-works/pi-durable @earendil-works/pi-ai @earendil-works/chord
node --conditions=source --experimental-strip-types app.ts # run TS directly against the source
import { BACKGROUND_CONTEXT } from "@earendil-works/chord/context";
import { builtinModels } from "@earendil-works/pi-ai/providers/all";
import { createRegistry, Harness, AssistantEntry } from "@earendil-works/pi-durable";
import { openNodeSqliteStorage } from "@earendil-works/pi-durable/storage/sqlite/node";
const context = BACKGROUND_CONTEXT;
const harness = await Harness.open(await openNodeSqliteStorage("./session.sqlite"), {
models: builtinModels(), registry: createRegistry(), env: (target) => new NodeExecutionEnv({ cwd: target.cwd ?? process.cwd() }),
}, context);
const root = await harness.root(context, { agent: { model: { provider: "openai", modelId: "gpt-6-sol" } } });
harness.resume(); // continue unfinished work from a previous process
const submission = await root.submit({ type: "input", content: "Hello", requestId: "greeting-1" }, context);
const settled = await submission.wait(context); // "done" | "unanswered"
if (settled.status === "done" && settled.type === "input") {
const answer = await root.commit((tx) => tx.entry(AssistantEntry, settled.answer), context);
}
await harness.close(context);
Storage: MemoryStorage (nothing persisted), openNodeSqliteStorage(path) (the default for anything
long-running; WAL, commits survive process crashes), openNodeJsonlStorage(directory, context)
(append-only, keeps the whole history in memory), openDurableObjectSqliteStorage(ctx.storage).
One process owns a storage at a time.
tx; read every table row you need before the first table write
(ReadAfterWrite), and never await slow work there: no models, tools, processes, network, humans,
nested commits, or session waiters.Context. Cancelling it cancels only that call or wait, never the
durable work. Use BACKGROUND_CONTEXT where nothing should cancel, and withCancel() at a host
boundary. withoutAbortSignal() is for mandatory cleanup such as close().runtime.memo() for first-writer-wins decisions, and set
replay: "safe" on a tool only when a rerun is genuinely safe. An unsafe tool that is interrupted
gives the model an interrupted error result with the output committed so far.output is what the model reads, structuredOutput is what
programs calling the tool read (validated against structuredOutputSchema, required unless the result
is an error), details is for the host UI. Only output and details enter the transcript.api.executeTool() return their result to the caller instead of the transcript and reuse a key on
rerun; cancelling the context stops only the wait. A nested result's usage is already counted under
its own tool, so forwarding it double-counts it.completing until then); a background: true task is a boundary that ordinary
aborts and idle waits skip. Never create owned work from an abort handler (the task is abort-marked):
compensate inline, or use background conversation-owned tasks with runtime.waitForTask().tx.appendEntry() cannot replace and which runs the stale check.pi.-prefixed names belong to the built-ins for task names, document kinds, and entry kinds
(pi.user, pi.assistant, pi.system, pi.tool-result, pi.reset, pi.compaction, pi.agent,
pi.provider, pi.live, pi.inbox, pi.usage, pi.generation, pi.tool). Nothing enforces this
and reusing one collides with harness behavior.SessionFailed, watches end with session_failed, and onReport gets the error once.
Nothing is retried; reopen to recover and resubmit with the same requestId. An invalid request
fails only that call (StorageRequestError), and your own code fails only its own unit.migrate, fails access. Only a typed tx.doc() creates an absent document.snapshot(), document states, and watches are tracked containers. Never mutate them;
copy first. A watch keeps at most 100 undelivered frames before collapsing into one full-value
replacement, so a consumer that must see every transition has to journal it itself.pi.system entry on every request and defeats provider prompt
caching. Settings can be getters: they are read at every use and never stored.references/durable-guide.md for behavior, references/durable-spec.md when a rule matters, and
section 12 (API footguns) of the spec before shipping.まだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
Use when designing, reviewing, or refactoring a CLI that must serve AI agents alongside humans, or when converting an API or SDK into an agent-usable CLI interface.
日本語の概要は準備中です。原文の説明を表示しています。
Search free commercial-use creative assets across multiple online sources — photos, illustrations, icons, video footage, music, sound effects, and fonts. Use when the user needs to find assets for videos, PPTs, articles, or any content creation. Trigger on phrases like "find me a photo of", "search for icons", "I need background music", "find video footage", "search fonts", "找一张图片", "搜素材", "帮我找图标/视频/音乐/字体". Covers Pexels, Unsplash, Pixabay, Iconify, Freesound, Google Fonts and more — with API-backed search where available.
日本語の概要は準備中です。原文の説明を表示しています。
Query the Semantic Scholar academic corpus through AI2's Asta MCP server: keyword or title search with venue and date filters, who-cited-a-paper traversal, author profiles and publications, DOI/arXiv/PMID lookup, and ~500-word full-text snippets for evidence, with citation counts and h-index. Use when the user asks for papers on a topic, who cited a paper, an author's work, recent literature since a date, or a venue-scoped paper list. Requires the Asta MCP server.
日本語の概要は準備中です。原文の説明を表示しています。
Extract and organize frames from a Bilibili video (bangumi episode, UP upload, or a local file) into scenery shots and per-character image groups, using anime-specific person detection + CCIP character-identity embeddings. Two modes — cluster everyone, or pull out one (or several) named characters via reference folders. Use when the user wants to collect, extract, or organize anime frames/screenshots by character or by scenery from a Bilibili video. Read-only download for personal viewing/analysis; uploads nothing.
日本語の概要は準備中です。原文の説明を表示しています。
Fetch Bilibili (哔哩哔哩) video comments for UP主 self-analysis. Use when the user asks to collect, download, export, or analyze comments on a Bilibili video (BV号 / URL / UID). Produces JSONL + summary.json suitable for further Claude Code analysis (sentiment, keywords, audience trends). Read-only; does not post/edit/delete.
日本語の概要は準備中です。原文の説明を表示しています。
Use when user requests diagrams, flowcharts, architecture charts, or visualizations. Also use proactively when explaining systems with 3+ components, complex data flows, or relationships that benefit from visual representation. Generates .excalidraw files and exports to PNG/SVG via Kroki API or locally using excalidraw-brute-export-cli.
日本語の概要は準備中です。原文の説明を表示しています。