@sage-protocol/pi-adapter0.5.1
Sage Protocol MCP integration for pi coding agent
Untested on omp
This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.
Reports 0
No reports yet.
Readme
@sage-protocol/pi-adapter
Sage integration for the Pi coding agent runtime.
- Pi agent: earendil-works/pi — extensible terminal coding harness
- Compatibility: declared peer range
>=0.64.0 <0.87.0; local typecheck, tests, and synthetic SDK tool execution verified with Pi0.86.1. Targeted Pi1.3.0native codemode checks pass; packaged-extension compatibility with 1.x is not yet declared. - Sage Protocol: sage-protocol/sage — decentralized capability/library layer for AI agents
What It Does
- Exposes Sage MCP tools (
hub_list_servers,hub_status,hub_session_list,hub_start_server,hub_stop_server,sage_search,sage_execute,sage_status, andsage_behavior) - Lets Pi own skill discovery and loading through native
<available_skills>,/skill:<name>, and fullSKILL.mdreads - Injects SessionStart Sage context and shows the loaded library/skill inventory
- Captures prompts and responses for RLM feedback
- Observes truthful full native skill loads and writes source- and session-qualified load receipts
- Exposes
sage_mark_guided_usein the packaged Pi extension so an agent can bind actually loaded, actually applied skills to the exact prompt capture through Sage's native-use daemon path - Optionally exposes one status-only
sage_wallet_statustool when Glove supplies either a strict inherited connected descriptor declaration or the complete legacy endpoint/root/owner tuple - Preserves optional security hooks and explicit subagent skill resolution
- Keeps Sage-owned skills under
packages/sage/skills/and the curated Pi export surface rather than bundling copies in this adapter
The adapter does not call sage suggest hook skill for each prompt, inject
sage-suggested-skills, or render a suggestion-quality widget. It has no
suggestion auto-skip or auto-reject lifecycle. Manual sage suggest skill "<task>" remains available when a person or agent explicitly wants CLI
ranking, but it is not automatic Pi injection.
Tool and CLI routing
Prefer Sage tools. When an operation is unavailable through them, use the
installed Sage CLI with the same approval and credential safeguards. A security
or approval denial is not tool unavailability: switching surfaces must not
bypass it. Keep the same profile, required approvals, dry runs, and credential
protections. Explicit CLI restrictions such as SAGE_ALLOW_BASH_CLI=0 remain
in effect.
The local extension imports dist/index.js. After changing its source, run
npm run build and start a fresh Pi session to load the revised guidance.
Install
# Pi CLI extension (no source changes)
pi install npm:@sage-protocol/pi-adapter
# SDK embedding
npm install @sage-protocol/pi-adapter
Quick Start
import {
createAgentSession,
createCodingTools,
type ToolDefinition as PiToolDefinition,
} from '@earendil-works/pi-coding-agent';
import {
createSageSessionConfig,
type ToolDefinition as SageToolDefinition,
} from '@sage-protocol/pi-adapter';
function asPiCustomTools(tools: SageToolDefinition[]): PiToolDefinition[] {
// Type-shape compatibility across supported Pi minors; no runtime conversion.
return tools as unknown as PiToolDefinition[];
}
const sage = await createSageSessionConfig({ source: 'pi-agent-core' });
const cwd = process.cwd();
const securedTools = sage.wrapToolsWithSecurity(createCodingTools(cwd));
const { session } = await createAgentSession({
cwd,
noTools: 'builtin',
customTools: asPiCustomTools([...securedTools, ...sage.customTools]),
});
const disposeSageHooks = sage.setupHooks(session);
In current Pi, tools is a string allowlist. Tool definitions belong in
customTools; noTools: 'builtin' prevents duplicate unwrapped built-ins. The
single helper cast is only the TypeScript peer-version boundary between the
adapter's cross-minor tool shape and Pi's generic ToolDefinition—it does not
convert anything at runtime.
Pi presents its native skill catalog separately. When a skill applies, load it
with /skill:<name> or read its complete SKILL.md, follow the procedure, then
call sage_mark_guided_use only if the loaded procedure actually guided the
current turn. Loading alone is not use.
API
createSageSessionConfig(config) returns:
{
customTools: ToolDefinition[]; // Sage hub and code-mode bridge tools
mcpBridge: SageMcpBridge; // MCP process lifecycle
setupHooks: (session: AgentSession) => () => void; // SessionStart + capture hooks
wrapToolsWithSecurity: (tools: ToolDefinition[]) => ToolDefinition[];
}
Recommended configuration:
interface SageP2Config {
sageBin?: string; // default: "sage"
sageProfile?: string; // Sage config profile
timeoutMs?: number; // default: 20_000
enableRlmFeedback?: boolean;
enableSecurityHooks?: boolean;
securityFailurePolicy?: "warn" | "block"; // default: "warn"; what to do when a scan cannot decide
source?: string; // default: "pi"
// Inherited mode: both exact Glove values are required, with no legacy fields.
gloveLocalServiceFdsV1?: string; // exact JSON alias-to-FD map
gloveGuestChannelServiceAlias?: string; // exact wallet service alias
// Legacy mode: all three are required, with no inherited fields.
gloveGuestChannelEndpoint?: string; // canonical absolute Unix socket path
gloveGuestChannelRoot?: string; // canonical absolute trusted root
gloveGuestChannelOwnerUid?: number; // isolated socket-owner UID (not Pi's UID)
env?: Record<string, string>;
/** @deprecated Low-level legacy suggestion compatibility; ignored by the default Pi path. */
suggestLimit?: number;
/** @deprecated Low-level legacy suggestion compatibility; ignored by the default Pi path. */
suggestDebounceMs?: number;
/** @deprecated Low-level legacy suggestion compatibility; ignored by the default Pi path. */
enableProvision?: boolean;
}
Migrating to 0.4
Version 0.4 moves Pi skill discovery and loading to Pi's native skill surface.
The legacy sageInjectSuggestion(...) method is retained as a no-op for
compatibility, and default setup no longer performs automatic suggestions. Do
not call sageInjectSuggestion; use Pi's native skill load flow and call
sage_mark_guided_use after an actually loaded skill guides the current prompt.
The guided-use write requires both the Sage CLI command
sage suggest feedback native-use and daemon capability native_skill_use_v1.
Version 0.4.2 reports which runtime half is stale instead of collapsing either
case into a generic write failure. It never falls back to weaker suggestion
feedback. Update the CLI when it lacks the command; update and restart saged
when the daemon lacks the capability. Then retry the same declaration.
Docs
- Usage Guide — native skill flow, integration modes, env vars
- Setup — install and verify
- Developer Guide — build, test, CI contract
- SKILL.md — agent-driven integration skill
Validate
npm test
npm run typecheck
npm run build
git diff --check
License
MIT
Session inbox discovery
sage_inbox({ action: "list" }) returns at most 20 live peers and 8 KiB of
JSON text. Each row keeps its canonical session UUID. Labels remain untrusted;
compact project labels show the last two path segments.
List-only options:
includeOffline: true: include historical peers.limit: 1..200: change the row ceiling; the byte ceiling still applies.detail: "full": include bounded full project labels, generation, and lease.project,harness: exact label filters, applied before the row ceiling.
All options apply only to the received broker page, currently at most 200
peers. hasMore retains the broker's meaning. view reports source, matched,
returned, and omitted counts, label truncation, and source incompleteness.
An empty filtered view does not prove no matching peer exists. There is no
server cursor or stable pagination; reaching peers beyond the first broker
page still requires Sage transport/broker changes (#18).
/inbox selects a live peer; /inbox all includes offline peers. Use
/inbox ask [all] for a correlated request. Explicit sends to canonical UUIDs
still support offline delivery. ACK, fencing, and ask timeout rules are unchanged.
Inbox discovery, search/execute, hub tools, and sage_status retain legacy text
for older Pi hosts and also provide outputSchema / structuredContent for
native codemode. Status keeps its CLI reference in text and in cliReference;
its version and MCP client version come from package metadata. A security block
withholds text, structured data, and details; a warning removes structured data
so codemode callers must see the warning text.
Session inbox liveness (shared with hook-driven harnesses)
The adapter currently renews the daemon lease from its own 2 s poll in
src/intercom.ts. The Sage CLI now ships a harness-agnostic keepalive,
sage inbox keepalive --auth-file <capability> --watch-pid <pid>, which is what
hook-driven harnesses (Claude Code, Codex) use. A follow-up can have the adapter
spawn it detached after saveAuth with process.pid as the watched host, send
heartbeat only on idle/busy transitions, and replace the receive poll with
sage inbox receive --auth-file <capability> --wait <secs>, so both harness
families share one liveness mechanism. Fencing (session_inbox_fenced) stops
both the adapter timer and the keepalive.