@dougbots/avenor-pi

中文文档
0.26.0发布于 2026/11/13TypeScriptES Module构建来源已验证近 30 天下载 2719

Pi extension that registers avenor agent runs as tools in your Pi session. When you need a sub-agent to handle a well-defined task — write code, run tests, search a codebase — avenor operates in the background while you keep your session focused.

原始使用文档
文档目录17 节
  1. Prerequisites
  2. Installation
  3. From npm (once published)
  4. From a git repo
  5. Local development
  6. Manual settings.json
  7. Package Structure
  8. Features
  9. Top-level peers on a central broker
  10. Tools
  11. Direct and roster modes
  12. Pi-specific features
  13. Completion notices
  14. Tool-result channels
  15. Agent profiles
  16. Typical workflows
  17. Dependencies

@dougbots/avenor-pi

Pi extension that registers avenor agent runs as tools in your Pi session. When you need a sub-agent to handle a well-defined task — write code, run tests, search a codebase — avenor operates in the background while you keep your session focused.

Prerequisites

You need the avenor binary available. It is installed to ~/.botfiles/bin/avenor by default.

# Check it's on PATH
which avenor

# Or set explicitly
export AVENOR_BIN=~/.botfiles/bin/avenor

You also need Pi 1.4.0 or newer (pi --version). Busy-session delivery depends on the agent_before_settle hook, so a notice raised while you were busy needs that version to reach you. A missing notification is not a lost run.

Installation

From npm (once published)

pi install npm:@dougbots/avenor-pi

This writes to your global settings (~/.pi/agent/settings.json). Use -l for project-local installation (.pi/settings.json).

From a git repo

pi install git:github.com/sdougbrown/[email protected]

Pi will clone the repo and load the extension from packages/pi.

Local development

Quick test — run pi with the extension directly:

cd packages/pi
pi -e ./src/index.ts

Symlink for auto-discovery — link into your global extensions directory:

mkdir -p ~/.pi/agent/extensions/avenor
ln -sf $(pwd)/packages/pi/src/index.ts ~/.pi/agent/extensions/avenor/index.ts

Pi auto-discovers ~/.pi/agent/extensions/*/index.ts. Changes are hot-reloadable with /reload.

Local path in settings — add the built dist directly:

# Build first
cd packages/pi && bun run build

# Add to settings
pi install /path/to/avenor/packages/pi

Manual settings.json

If you prefer to edit settings directly:

// ~/.pi/agent/settings.json
{
  "packages": ["npm:@dougbots/avenor-pi"]
}

Or for a local path:

{
  "packages": ["/path/to/avenor/packages/pi"]
}

Package Structure

packages/pi/
├── package.json
├── tsdown.config.ts
├── src/
│   ├── index.ts          # main extension, tool registration, commands, and hooks
│   ├── render.ts         # host-only tool-call and result presentation
│   ├── types.ts          # shared types and status emoji mapping
│   └── watch.ts          # EventFeedOverlay TUI component
└── dist/
    └── index.js          # built output (loaded by pi)

The pi key in package.json declares the extension entry point:

{
  "pi": {
    "extensions": ["./dist/index.js"]
  }
}

Features

Top-level peers on a central broker

Two independently started sessions need separate inboxes to message each other. Set AVENOR_BROKER_URL before starting Pi to register this session on a central broker. Pi polls that broker over outbound HTTP(S); it needs no inbound port.

AVENOR_BROKER_URL=https://avenor-broker.home.douggo.com pi --name scout

The broker must support leased peer registrations. Pi refuses a broker that does not acknowledge that capability. Leave AVENOR_RUN_ID and AVENOR_BROKER_TOKEN unset for a top-level session; together, those variables select the existing provisioned child mode. An incomplete pair is refused.

Pi publishes its session name so other sessions can address scout. Without a Pi name, AVENOR_SESSION_NAME or AVENOR_LABEL supplies the display name. With none of those, a top-level session takes pi-<repo> from its git top-level (the directory name outside a repository). The machine's short name leads (<hostname>-pi-<repo>) only when the broker is on another machine. A six character run-id tail is added when another session already holds the label, when the broker's session list cannot be read in full, or when there is no repository. The label is posted as Pi's own default, so a broker that checks names follows a taken one with the tail instead of refusing the rename. A Pi session name set later replaces the default. Use the existing tools:

{"action":"ask","target":"scout","message":"Ready?","timeout_ms":30000}

An inbound ask includes the arguments for avenor_message action reply. Tells arrive as messages without reply instructions. The Claude peer layer can join the same broker.

The local supervisor remains available for spawning, status, results, and local child messages. Central peer tools alone do not start it. Once it exists, avenor_peers combines its peers with the central peers. avenor_message prefers an exact ID, then a unique label. Duplicate labels return ambiguous_name; duplicate IDs across independent brokers are also ambiguous. Matching IDs alone do not establish that two records are the same peer. An incomplete listing or transport failure refuses resolution across the combined view, including a local match, because an unseen record could shadow it. Replies and withdrawals retain the provider that owns their message.

Identity and delivery lifetime

Pi keeps a generated ID and credential in memory for one session. Registration retries use that same pair. After registration, a temporary transport failure retries polling without registering another identity. Successful polling renews the broker's 60-second lease. Session shutdown aborts the poll and pending asks, then requests retirement; if retirement cannot be confirmed, the lease expires.

An expired or retired peer disappears from listings and cannot receive messages. Authentication, concurrent-poll, or expired-identity refusals stop participation; start a new session to obtain a new identity. A broker restart also requires a new session. Pi does not silently replace an inbox that may have held messages. The broker retains expired and retired identity records until shutdown to fence delayed registration retries, so those records consume memory for its lifetime.

Polling removes messages from the broker queue before Pi injects them. Pi retries an injection failure from its in-memory batch, but a process crash or interrupted poll response can lose delivery. This is not an exactly-once delivery guarantee. The broker excludes overlapping polls for a leased peer; bearer credentials do not establish that only one physical process holds them.

The registration route remains open to clients that can reach the broker. Restrict access to the intended tailnet or equivalent trusted network, and use HTTPS when the network does not encrypt transport. Credentials travel in request bodies or headers, never in broker URLs. Do not put them in logs, command arguments, or committed configuration. Leases apply to opt-in Pi peers; existing Claude self-registrations retain their existing lifetime behavior.

See the top-level peer verification map for the independent session proof. This Pi–Claude integration covers part of #434; other harnesses and plain MCP client identities remain separate work.

Tools

Available tools for LLM sub-agent management:

ToolDescription
avenor_spawnDispatch an agent run (blocking or fire-and-forget). Uses the pi backend by default in direct mode; accepts optional agent, model, prompt, dir, roster_file, and roster_entry. In host mode, spawns to this process's singleton supervisor (the default) receive a parent broker note for avenor_message. Non-local and nested spawns need an address supplied in the brief; their asks are not forwarded to the parent.
avenor_statusGet status of a run or all runs; use view="lifecycle" for compact progress and permission checks
avenor_resultWait for a run and return its complete final output without transcript details
avenor_inspectReview a bounded transcript, tool activity, permissions, and final output
avenor_answer_permissionAnswer a pending permission request
avenor_messageOne messaging tool with an explicit action: tell, ask, reply, resume, withdraw or control_reply. Every result states the outcome and, for a failed ask, whether it can still be withdrawn.
avenor_peersOne peers tool with an explicit action: list (the default), rename or last. last returns the target's last agent message with its stop reason, or the empty result when the target has no completed turn yet.
avenor_eventsRead events from a run
avenor_killKill a run
avenor_workflowOne workflow tool with an explicit action: status, inspect, events, wait, ready, controller_status, gate, complete or cancel. Read-only actions need no permission; gate, complete and cancel keep their authority checks.
avenor_shutdownShut down the avenor supervisor

Direct and roster modes

Direct mode permits agent, model, and backend to be omitted independently, including a backend-only request; omitted values use runtime defaults. Pi supplies backend: "pi" in direct mode when no backend is given. Roster mode uses both roster_file and roster_entry, and leaves backend selection to the roster entry instead of applying Pi's direct default:

{
  "prompt": "Review the repository",
  "roster_file": "/repo/roster.json",
  "roster_entry": "reviewer"
}

Each roster entry must contain backend and at least one of agent or model. Do not combine roster mode with direct agent, model, or backend overrides. Roster entries reject system; an entry's thinking is only a default, so a run-level thinking still wins and is validated against the effective backend. A resumed session must stay on its original backend. Use an absolute roster_file path when the Pi process and target project have different working directories.

Pi-specific features

Beyond the tools, the extension integrates with Pi's TUI and event system:

  • Status widget — persistent widget showing all active runs with status, phase, and permission state
  • Footer status — the avenor status key carries active runs, the live agent-tree total, the unread notice count, and the current poll-failure count (see Completion notices)
  • Completion notices — one notice per finished run, delivered immediately when your session is idle and batched into a single continuation when it was busy
  • Polling diagnostics — bounded polling errors are emitted on avenor:poll:error for companion extensions; a completion-notice delivery that exhausts its retries is emitted separately on avenor:delivery:error; a failed last-turn record (session_last_set) is emitted per failure on avenor:last-turn:error
  • Central-peer diagnostics — in a top-level session, every central-broker failure (session name, poll, registration, turn publication, retirement) is emitted on avenor:peer:error with the operation, the broker's refusal code, and whether the identity is terminal. The first failure per operation raises one warning notice; a child session keeps reporting to stderr, which is its supervisor's record
  • Live progress — blocking avenor_spawn calls stream progress updates via onUpdate
  • Context enrichment — active sub-agents are automatically surfaced in the system prompt via before_agent_start
  • Custom rendering — The Pi extension renders all Avenor tool calls and results as themed, bounded summaries. Results have collapsed and expanded views.
  • Commands — interactive commands for run management:
    • /avenor-status — show status of all runs
    • /avenor-errors — show and clear recent polling errors
    • /avenor-watch <run_id> — open a live event feed overlay
    • /avenor-cancel <run_id> — cancel a running sub-agent

Completion notices

A fire-and-forget spawn (wait: false) promises one thing: you hear about the run when it ends. Each finished run produces one notice — label, terminal status, bounded output preview — and where it lands depends on your session at that moment.

  • Idle. The notice is sent as a user message and starts its own turn. It counts as unread until Pi confirms the message landed, and while compaction is running the send waits for it to finish. A send that is accepted but never confirmed is sent at most three times; once that budget is spent the notice stays unread for the next settlement and the failure is emitted on avenor:delivery:error.
  • Busy. The notice is queued and the footer shows unread:N. The next settlement that completes normally appends each queued notice as an avenor-completion custom message under a single continuation, so three runs finishing while you work mean three messages and one wake-up. A settlement that ends in abort or error delivers nothing; the notices wait.

Every terminal status queues a notice — done, failed, timeout, killed.

avenor_result and a blocking avenor_spawn (wait: true) own delivery while they run; avenor_result takes the label you spawned with, so you need not keep the id. A ready result consumes the run: the queued notice is dropped, unread:N falls by one, and nothing arrives for it later. A result that is not ready — interrupted by a sibling's stopping point, timed out, or reporting a pending permission — consumes nothing, and its notice arrives on the normal schedule. A blocking spawn that reaches completion returns the result inline and removes the notice; the footer can show a transient unread:N for that run while the wait is in flight.

One string under the status key avenor, in this order:

TokenMeaning
🟢 label — running [phase] 🔒 +2one per non-terminal run: status emoji, label, status, phase label, 🔒 for a pending permission, +N for that run's active descendants
total:Ndirect active runs plus discovered active descendants; present only when active descendants exist
unread:Nnotices not yet delivered: queued for a settlement, or in flight for an idle session
errors:Nrecent poll failures; cleared by a cycle that adds no new error

Missing unread:N or errors:N means zero. Without total:N, count the active run lines. unread:N counts notices, not runs, and can stay set after the last run exits — an otherwise idle session can still advertise unread:1 until you consume or receive that notice. total:N tracks live runs and disappears with them. errors:N outlives them too: it clears when a later poll cycle adds no new error, so it counts recent failures rather than a consecutive streak. The bounded history behind /avenor-errors is longer than errors:N; running that command clears both.

Tool-result channels

Pi returns JSON model content in content[0].text and structured details for all tools except avenor_spawn. The renderer creates themed, bounded summaries for display. It does not modify the underlying model content or the details object.

Pi's rendered summaries sanitize and bound the output, events, and snapshot rows they display. Use avenor_result, avenor_inspect, or avenor_events for the corresponding data.

MCP clients render their own results.

Agent profiles

The avenor_spawn tool accepts an optional agent parameter that maps to a named profile in pi's agents.json:

{
  "jockey": {
    "model": "anthropic/claude-sonnet-4",
    "systemPrompt": "You are a PR reviewer..."
  }
}

When agent is set, avenor passes PI_AGENT=<name> to the pi subprocess. The @dougbots/pi-agents extension reads this to load the corresponding profile (model, system prompt, tools, permissions) from agents.json (located at PI_CODING_AGENT_DIR or ~/.pi/agent/).

If you don't need a named profile, model alone is sufficient — no agent config or extension setup required.

When pi-agents has selected a session-scoped /agent-profile, this extension also forwards that optional session metadata to Pi automatically. Avenor does not depend on pi-agents; absent or malformed metadata is ignored. The setting is not an avenor_spawn parameter and applies only to Pi-backed child runs.

Typical workflows

Blocking (default):

1. avenor_spawn            →  tool call shows live progress, blocks until done
2. tool call returns       →  completion preview with status + session_id
3. avenor_result           →  retrieve the complete final output when needed
4. avenor_inspect          →  inspect transcript and tool details when needed
5. avenor_message           →  action "resume" to optionally iterate
6. avenor_shutdown         →  clean up when finished

Parallel / fire-and-forget (wait=false):

1. avenor_spawn × N        →  each returns run_id immediately
2. (status widget updates) →  persistent widget shows all active runs
3. avenor_status           →  optional compact lifecycle/permission check
4. avenor_result           →  wait for and retrieve each final output
5. /avenor-watch <id>      →  open live diagnostics for a specific run

Dependencies

  • Peer: @earendil-works/pi-coding-agent (Pi runtime, provided by pi)
  • Peer: @earendil-works/pi-tui (TUI components, provided by pi)
  • Dependency: @dougbots/avenor-core (supervisor, client, tool primitives)
  • Binary: avenor must be available on PATH or at AVENOR_BIN

版本与发布记录

@dougbots/avenor-pi 共发布 44 个版本,首次发布于 2026/06/20;过去 12 个月发布了 44 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.26.0latest2026/11/13今天
0.25.02026/11/13今天
0.24.02026/11/093 天前
0.23.02026/11/057 天前
0.22.02026/11/0310 天前
0.21.02026/11/0112 天前

关于 @dougbots/avenor-pi 的常见问题

@dougbots/avenor-pi 是什么?

Pi extension that registers avenor agent runs as tools in your Pi session. When you need a sub-agent to handle a well-defined task — write code, run tests, search a codebase — avenor operates in the background while you keep your session focused.

如何安装 @dougbots/avenor-pi?

在项目目录运行 npm install @dougbots/avenor-pi,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@earendil-works/pi-tui(*)、@earendil-works/pi-coding-agent(>=1.4.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@dougbots/avenor-pi 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@dougbots/avenor-pi 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@dougbots/avenor-pi 可以商用吗?

@dougbots/avenor-pi 使用 未声明 许可。package.json 没有声明许可证。没有许可证的代码默认保留全部权利,商用前请联系作者或查看仓库中的 LICENSE 文件。以上为概括,不构成法律意见,请以许可原文为准。

@dougbots/avenor-pi 的下载量有多少?

根据 npm 官方下载统计,@dougbots/avenor-pi 在 2026/10/13 – 2026/11/11 这 30 天内被下载 2,719 次,日均约 91 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@dougbots/avenor-pi 还在维护吗?

最新版本 0.26.0 发布于 2026/11/13(今天);至今共发布 44 个版本,其中过去 12 个月发布了 44 个;首次发布于 2026/06/20。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。