Pi is the default daily-task agent reached through its native stdin/stdout JSONL RPC.
It is not an ACP bridge and does not replace the Python Host. The runtime is
pinned to @earendil-works/pi-coding-agent@1.2.0.
Use Node 22.19 or newer. The normal desktop installation (npm ci in
electron/) installs the pinned Pi runtime automatically alongside Electron.
An existing desktop checkout can rerun that command to install Pi or restore
the locked version. Pi installation errors fail the desktop installation;
they are not silently ignored. Runtime startup does not install packages.
For a headless deployment or a standalone Pi runtime repair, run this from the repository root:
npm ci --ignore-scripts --prefix agent_host/pi_runtimePi is enabled by default. The runtime install uses its existing lockfile and
--ignore-scripts; if you skip the desktop postinstall with --ignore-scripts,
install Pi separately with the command above (and provision Electron separately
for desktop use). Model credentials are still required. For the default
DeepSeek connection, the same DEEPSEEK_API_KEY configured for Amadeus under
Settings -> Models or in .env is passed to the trusted Pi child process; no
second agent login is required.
Settings → Work Provider connections and .env expose these defaults:
PI_PROVIDER_ENABLED=true
PI_NODE_PATH=node
PI_AGENT_DIR=runtime/pi
PI_MODEL_PROVIDER=deepseek
PI_MODEL=deepseek-v4-flashAt backend startup Amadeus runs Pi's non-refreshing native authentication check
for the selected provider/model. A missing credential keeps Pi unregistered and
Settings reports the actionable reason instead of allowing the first Work to
fail. This check does not make a billed inference request, so account access and
remote model availability are still established by the first real Work. For
custom API endpoints or local models, configure runtime/pi/models.json using
Pi's native model schema. Existing Amadeus Models UI endpoint settings are not
automatically translated into Pi configuration. Do not put credentials in
command-line args.
The managed Pi extension retains the official legacy DeepSeek wire IDs
deepseek-v4-flash and deepseek-v4-flash-vision-exp. At session_start and
before each agent turn, only an unregistered current selection of either alias
can copy the effective canonical deepseek-flash metadata through public
pi.setModel. This happens before Pi converts images. No Provider is replaced,
so native catalog caches and later native refreshes remain intact; configured
endpoints, authentication and session defaults remain owned by Pi. Registered
aliases and explicit native/extension Provider registrations take precedence.
At the first eligible selection in a new Work, the extension reads only alias
declaration presence from native models.json: an alias in models or
modelOverrides disables automatic compatibility. The declaration snapshot is
reused for that Work. If declarations cannot be read or parsed reliably, the
registry reports an error (including an unrelated Provider), or the repair is
unavailable or rejected, compatibility is skipped for that Work and Pi's native
model selection is retained. A fixed warning is shown once without configuration
contents; this optional repair does not emit a fatal extension error. No file is
rewritten. Canonical models, Pro and other unknown IDs are unchanged. See DeepSeek's
alias compatibility and
image input contract.
The initial native unknown-model warning may still appear because CLI selection
precedes session_start. Changes to declarations or compatibility code require
a new Pi Work/process; hot editing declarations and manual native /reload
of an already corrected unregistered alias are not supported by this Host path.
The extension does not trigger catalog or authentication refreshes. A successful
MCP image tool result alone does not prove the model received or understood it.
中文:维护的 Pi 扩展在 session_start 和每轮开始前,仅为当前选中且未注册的上述
两个精确旧别名,经公开 pi.setModel 复用有效 canonical metadata,保留 wire ID,
并在 Pi 转换图片之前生效。不替换 Provider,原生目录缓存和后续原生 refresh 不变,
endpoint、认证、默认型号仍由 Pi 管理;已注册别名、显式 native/extension Provider
优先。新 Work 首次符合条件时,仅读原生 models.json 中别名是否出现在 models
或 modelOverrides,有声明便不自动兼容;本 Work 复用该声明快照。若声明无法可靠
读取或解析、注册表报错(包括无关 Provider),或修补不可用、被拒绝,本 Work 跳过
兼容修补并保留 Pi 原生选择,只提示一次不含配置内容的固定警告;这项可选修补不产生
致命扩展错误。不改写文件。canonical、Pro 和其他未知型号不受影响。
初始 CLI 选择早于 session_start,因此原生未知型号警告仍可能出现。配置声明或兼容
代码变更须新建 Pi Work/进程;不支持热改声明,也不承诺手工 /reload 已修补未注册
别名的语义。扩展不主动刷新目录或认证;工具返回图片成功不等于模型已接收或理解。
For interactive Pi login against the same isolated configuration directory:
$env:PI_CODING_AGENT_DIR = (Join-Path (Get-Location) 'runtime/pi')
node agent_host/pi_runtime/node_modules/@earendil-works/pi-coding-agent/dist/cli.jsSettings → Models → Roles → Work role assignments has two independent dropdowns: Coding defaults to Codex, everyday execution defaults to Pi. Candidates come from registered compatible manifests, including custom ACP agents. Equivalent startup settings are:
WORK_CODING_PROVIDER=codex
WORK_EXECUTION_PROVIDER=piRestart the backend after startup configuration changes. Work Page also exposes Pi through the existing dynamic provider list. Missing optional runtimes are reported as unavailable and do not prevent role-only Chat startup. This branch adds no complexity classifier or automatic failover. Provider selection and explicit task addressing use the existing planner.
OpenClaw remains registerable through its existing Gateway adapter and keeps its native session support. It no longer owns the default everyday execution role by default. It can be assigned the execution role in the GUI, explicitly selected for an individual task, or used to continue its existing Work.
Role changes update the existing planner's routing instructions and new-task
examples; they do not alter registration, manifests, or existing Work ownership.
Registered general agents remain addressable regardless of role assignment.
No extra requirements JSON is needed to enable an assigned agent: the Host
derives its baseline context requirements from registered capabilities.
COOPERATIVE_CHAT_REQUIREMENTS_JSON and
COOPERATIVE_CHAT_ADDITIONAL_REQUIREMENTS_JSON remain optional Host policy
overrides, defaulting to {}. Remove stale overrides if switching providers
with different workspace capabilities. Legacy COOPERATIVE_CHAT_PROVIDER and
PROVIDER_DELEGATE_DEFAULT_PROVIDER are read as execution-role migration
aliases only when WORK_EXECUTION_PROVIDER is absent.
Builtin adapters are composed by provider_bootstrap.py; their capability
manifests are code-owned in provider_catalog.py. Settings choose connections,
enablement and defaults, not whether an implementation can actually restore,
cancel, access a workspace or accept an MCP projection. The GUI displays runtime
availability; it does not let users grant an adapter unsupported capabilities.
Role dropdowns live under Models → Roles; connection/registration cards live under Providers, with a link back to the role settings. Changes persist in Desktop settings and apply at backend restart. Coding and daily execution route independently; there is no universal Pi role. The Work page is an explicit per-task provider selector. It initially selects the execution-role provider and preserves manual choices. An unavailable default requires a selection rather than silently choosing by manifest priority.
The existing ACP editor adds installed external agents without Python code
changes. Registered compatible ACP agents appear in the role dropdowns too.
Advanced cooperative policy overrides and trusted Pi extension paths remain
startup configuration, with no dedicated GUI editor.
MCP connections are configurable in the GUI only for adapters advertising the
mcp_connection projection (Codex, Pi and compatible ACP agents). Enable a
connection, bind it to Pi, then save and restart the backend. Pi projects the
same Host registry, including bound extension-package MCP contributions.
OpenClaw does not advertise this projection. Pi's bundled anonymous web search
continues to use its existing Host MCP bridge independently of these bindings.
ProviderRuntime, Work Ledger, control admission and task/session identities remain unchanged. Bootstrap registers one ordinarypiprovider.- The adapter reuses
ProviderSessionHandle,ProviderInputDelivery, activity evidence, parent-context/progress helpers and the Host permission flow. pi_rpc.pyimplements only Pi's distincttype-based JSONL transport. Codex and ACP SDKs own incompatible transports; OpenClaw uses WebSocket RPC. There is no second task store or new Host-level agent framework.- Each run owns one subprocess; the saved native session file is its opaque continuation handle. Reattachment requires that exact file and identity. Sessions are not reused by guessing the latest transcript.
- Startup update/telemetry requests are disabled for the managed runtime; model inference and explicitly invoked network tools still use the network.
- The adapter waits for
agent_settled, not intermediateagent_endevents which can precede retries, compaction or queued inputs. - Additional input uses native
steeracknowledgement at a tool boundary. This is append delivery, not the Host's latest-revision-wins plan replacement; the manifest deliberately does not advertise immediate replacement steering. - Cancellation clears queued input and awaits native
abortacknowledgement. Process loss or a missing prompt acknowledgement yields an unknown/orphaned execution, never an automatic retry or a claimed successful cancellation.
The bundled amadeus.ts extension uses anonymous Exa MCP for search through
Amadeus's existing MCP client, and pi-simple-web-tools@0.1.0 inside the Pi
process for article extraction only. Its keyed search module is not used.
There is no dependency on Amadeus's Browser provider, planner, browser sessions
or Playwright installation. The extraction package is pinned because the adapter
uses its module API; upgrade it with the integration tests.
| User goal | Tools / existing owner |
|---|---|
| Find an article by title, author or topic | web_search uses anonymous Exa MCP; no API key or registration |
| Read and summarize an article | web_read extracts markdown/HTML/PDF with HTTP and Readability; web_fetch reads simple text/feeds |
| Open a supplied or discovered URL visibly | open_url reuses the system-browser opener also used by Canvas URL actions |
| Find, read and open a particular article | Pi can compose search → select source → read → open in one Work and continue the same native session |
| Read current news | news_search reads Google News RSS; source articles should be read before making detailed claims |
Search connects to https://mcp.exa.ai/mcp?tools=web_search_exa only when called.
It requires no API key, browser, local MCP server, or new npm dependency. The
short-lived Python bridge uses the existing open_mcp_connection implementation;
it never creates a nested Provider or Work and never reads/sends an Exa key.
There is no paid fallback. The public service has rate limits and may become
unavailable; these produce ordinary tool failures for Pi to handle without
failing the RPC conversation. Queries are sent to Exa as an external search
service. Search relevance and publication dates still need model evaluation.
Live anonymous smoke checks found the original Transformer paper, Chinese weekly article sources and dated New Zealand news results. Three search calls took about 0.9–1.1 seconds each, excluding initial connection/process startup. This is a small sample, not a service guarantee or proof of same-day coverage.
web_read returns bounded slices with next_offset, so long articles remain
readable without writing outside the Host workspace or granting access to a
global temporary directory. The source URL is the requested URL, not a verified
redirect destination. Content extraction does not prove completeness or bypass
paywalls. Neither search snippets nor news feeds prove the full article was read.
JavaScript rendering is optional. If needed, install Playwright in
agent_host/pi_runtime and its Chromium binary; the component loads it lazily.
The default install does not include a browser. This experiment does not provide
general click/type control or access to a user's logged-in tabs.
pi_web_tools.py also bridges the shared OS URL opener. A visible open reports
OS acceptance, not verified page load. Opening the system browser does not
create another Provider or Work.
Pi retains its native file/command tools. File tools are confined to the Host-assigned workspace and access level; command execution and unknown extension tools require write access and a Host approval. Launching an app uses an executable plus argv without a shell, always requires approval and reports process-start evidence only. It does not claim control over an existing app or reuse Browser login state; those remain with Amadeus's existing domain owners.
Set PI_EXTENSIONS_JSON to an array of explicit trusted extension paths to use
the native plugin API. Ambient extension discovery and project trust approval
are disabled; Pi's native skills are retained. Confirmation requests are mapped
to existing Host allow/deny requests. Native select/input/editor dialogs are
cancelled because this provider contract has no general form response; TUI-only
extensions are not supported by RPC.
The extension gate is not an operating-system sandbox: native extensions are arbitrary code, and approved shell commands have process-user access. Do not load untrusted extensions or treat the path checks as isolation from hostile code. No Pi process runs in the Electron UI process.
The managed runtime retains the existing file/web tools and adds direct tools
and resources only from enabled MCP connections bound to Pi. The Host supplies
the configuration in the trusted child environment, never command-line arguments
or a second persisted registry. Pi's public createMcpExtension and MCP client
own discovery, schema/result handling and connection shutdown.
Ambient extensions and Pi's built-in discovery remain disabled by
--no-extensions; project-local files remain disabled by --no-approve.
Neither global/project mcp.json nor native extension server registrations can
override or add to the Host snapshot. Explicit trusted native extension code
still loads under PI_EXTENSIONS_JSON, with the same arbitrary-code trust
boundary as before. Codemode and tool search are not part of the managed
default tool set. No connection binding means the original tool set.
Every projected MCP tool or resource call uses the existing Host allow-once/deny
card, including tools annotated read-only. A server's annotation does not grant
permission. This approval is independent of local workspace write access: a
workspace-less or read-only Work or cooperative chat can use an approved connector without acquiring
file or shell rights. File/path checks and the write-access-plus-approval gate
for shell and other extension tools are unchanged. Denial and cancellation do
not authorize a later call.
The trusted MCP gate uses the existing mcp.tool.call capability and call_tool
action, shared with the standard MCP Provider. The Host applies the same
workspace-independent approval policy to that capability; generic tool
permissions remain denied in read-only cooperative contexts. Codex's
mcp.elicitation remains a distinct server input/confirmation request and does
not receive this tool-call exception. The earlier pre-release
mcp.tool.execute spelling is superseded, without an alias; restart the backend
when updating this integration so active permission owners use the same contract.
Direct-tool approval cards show the Host connection display name and original
MCP tool name, even when Pi hashes its model-facing identifier. The three resource
operations resolve their server argument against the same Host snapshot and
show its display name and ID. An unfiltered list identifies all bound connections
as its scope with a bounded name preview; an unknown ID is not attributed to a
known connection. Approval labels replace control/format characters and line
breaks with spaces, and are capped at 320 Unicode code points (plus the fixed
title prefix), with an ellipsis when shortened. Execution names and arguments
are never rewritten by this display formatting.
Enabling and binding a stdio connection authorizes starting its configured
executable when the Work connects. Per-call approval does not sandbox that
server's startup code; only bind trusted services.
Stdio servers receive the platform allowlist from isolated_child_environment
plus only their own explicit environment bindings. Values remain literal;
${...} and !command are not expanded by Pi. HTTP connections use anonymous
access or the configured bearer token (the explicit connection value takes
precedence over its named Host environment variable). Pi model credentials,
other connections' values and native Pi OAuth accounts are not implicitly
forwarded. Interactive MCP OAuth and native /mcp configuration are not exposed
through this adapter; configure authentication through Host connection settings.
Missing bearer tokens skip the affected connection; native namespace collisions
skip all ambiguous connections. Other connections and Pi remain available. These
errors and connection failures appear as redacted runtime.notice status entries
in provider activity, with Host Settings guidance. They neither count as task
progress nor claim tool execution or a diagnosed task failure.
Notices are retained in the bounded Provider activity journal so session reloads
and backend restarts can restore the same activity entries.
Each run (including each cooperative turn) starts a fresh Pi process and the bound services. This incurs service startup/discovery cost on every run; connections are not pooled across turns. The first prompt waits at most 3 seconds for direct tools, down from Pi's 10-second default. Connected services contribute tools to the first model request; slower services can become available on later model turns within the same run, and a runtime notice reports that they are still connecting. A short run may finish before a slow service becomes usable. This budget does not change the native timeout for an actual MCP request.
Connections reload from the current Host snapshot on a new run, including when restoring an existing native session. Disabling or unbinding a connection takes effect after the backend restart required by Host settings.
Normal completion/cancellation closes Pi's stdin and waits for native session disposal before force termination is considered. Tests verify direct server exit and sequential-session cleanup. This is not an OS sandbox or a guarantee that arbitrary descendants survive neither an abrupt Host/Pi crash nor forced termination; the native transport owns its process handling.
An acknowledged native abort is the business cancellation result, not proof that the Pi/MCP transport has closed. PiAdapter completes and awaits its owned transport teardown even if permission-expiration publication fails or the Host cancels the producer task again. The original publication error or cancellation still propagates; successful disposal also releases the active-run/session registrations and signals the run's completion. EOF and the existing close deadline remain unchanged; this does not authorize replay or automatic approval.
原生 abort 回执只证明业务取消,不等于 Pi/MCP 连接已经关闭。权限过期事件发布失败, 或 Host 再次取消 producer 时,PiAdapter 仍等待本轮原连接完成收尾,再释放运行及会话 登记并标记完成;原发布错误或取消继续向上传播。EOF 和原有关闭时限不变,不重派任务, 不自动批准权限。真实进程与连接清理应与业务终态分别核验。
Keep package.json, package-lock.json and the adapter's startup version check
in sync. Install with npm ci --ignore-scripts in agent_host/pi_runtime (or the
normal desktop installation), then restart the backend. Pi 1.2.0 no longer ships
an npm shrinkwrap; the repository lockfile pins the complete tested tree. The
Node requirement remains 22.19 or newer. Preserve a copy of the isolated Pi
session/configuration directory before upgrading a deployment; restoring a
1.2.0-written session with 0.86.1 is not a supported rollback guarantee.
The scope and acceptance boundary are recorded in issue #222. Codemode/tool search and interactive OAuth require separate integration and acceptance work; MCP schemas remain on the bound Work Provider and are not published to Main Chat. Pi may truncate large direct results or return temporary paths for binary resources. Those paths do not grant extra filesystem access; this integration does not open a global temporary directory to the file tools.
npm ci --ignore-scripts --prefix agent_host/pi_runtime
npm --prefix agent_host/pi_runtime run typecheck
.venv/Scripts/python.exe -m pytest tests/test_pi_provider.py tests/test_pi_runtime.py tests/test_pi_mcp.py tests/test_pi_web_tools.py tests/test_skill_pi_runtime.pyThe native extension has its own pinned TypeScript compiler and strict, no-emit
configuration (tsconfig.typecheck.json). It checks every first-party .ts
entry and imported TypeScript source, including the web component. As in the
Electron configuration, third-party declaration files use skipLibCheck; no
source checks are suppressed. Electron's normal npm run build invokes this
check through check:pi, so Windows and Linux build CI cover the native extension.
The web component's optional playwright import needs declarations even when
the runtime package is absent. Only the type-check configuration maps that name
to the pinned development dependency playwright-core, whose declarations are
re-exported by Playwright itself.
This does not change runtime module resolution, install playwright, download
browser binaries, or enable browser rendering. @types/turndown supplies the
web parser's missing declarations and @types/node matches the supported Node
22 line. The real Pi regression includes a client-rendered page that must still
report the missing optional browser fallback, while ordinary HTTP article reads
remain supported. Production runtime installs can omit development dependencies;
type checking and source builds require them.
The first suite checks acknowledgement uncertainty, correlation, permissions, cancellation and session identity using deterministic protocol peers. The second starts the real pinned Pi CLI against a local mock model endpoint to test file tools, explicit versus ambient extensions, disabled ambient MCP discovery, Host approval/denial, workspace boundaries and on-disk session restoration. The Skill suite covers native instruction/resource reads, continuation and stale bindings. It skips when the optional npm runtime is absent; it uses no paid model calls. The MCP suite uses synthetic stdio and loopback HTTP services to check connection binding, literal credentials, independent approvals, denial/cancellation, resources, connection errors and restored-session cleanup. Windows Python CI installs the pinned runtime before running these suites. Cooperative ingress tests cover exact approval ownership, read-only MCP approval, local shell denial and unchanged workspace access. The MCP suite also checks per-connection configuration failures, original tool labels after native hashing, single-server and unfiltered resource approval scopes, label normalization without rewriting execution identifiers, and a hanging server's bounded first-prompt delay. Standard MCP Provider and Pi tests assert the shared permission capability/action; cooperative tests reject shell, generic, obsolete and elicitation capabilities under the read-only tool-call policy.
Synthetic captures using the real Electron activity-card component show the notice and approval text before and after the audit fixes. They use fixture events and no real credentials or sessions. Resource cards have separate before and after captures showing selected connections and unfiltered list scope.
For an opt-in real-model run that creates files and opens real browser/Notepad windows on Windows:
.venv/Scripts/python.exe scripts/pi_daily_acceptance.py --provider pi --label trial-1
.venv/Scripts/python.exe scripts/pi_daily_acceptance.py --provider openclaw --label trial-1The harness approves only Notepad opening the exact generated summary file;
it denies additional shell commands. Reports and native sessions stay under
ignored runtime/pi-acceptance/. See live comparison
for the observed results and verification limits.
References: anonymous search, web extraction component, native RPC, native extensions. The installed version's bundled documentation is the protocol baseline.