Extension guides
Host channel
The host channel lets browser UI call into the Pi extension that owns the capability. It preserves the process boundary instead of moving extension logic into the window.
Connect the Pi entry
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { connect } from "@nativepi/extension-api/host";
import { taskProtocol } from "./protocol.ts";
interface Task {
id: string;
title: string;
complete: boolean;
}
export default function taskExtension(pi: ExtensionAPI) {
let tasks: Task[] = [];
const host = connect("@acme/tasks", taskProtocol, {
list: () => tasks,
add: ({ title }) => {
const task = { id: crypto.randomUUID(), title, complete: false };
tasks = [...tasks, task];
host.emit("changed", tasks);
return task;
},
clear: () => {
tasks = [];
host.emit("changed", tasks);
return null;
},
});
}The first argument must exactly match the owning package's manifest name. The protocol determines the complete handler table, so missing, extra, or incorrectly typed handlers fail during development or registration.
Atomic registration
connect registers all methods at once. Calling it again for the same package replaces the previous table rather than merging into it. Package reloads therefore cannot leave a removed handler active.
Emit events
Use the returned host to publish state changes that renderers may be watching. Event names and payloads come from the shared protocol.
host.emit("changed", tasks);
host.emit("invalidated");Behavior outside NativePi
Pi's terminal UI does not provide the graphical host. The returned object reports connected: false, and valid emit calls become no-ops. Method handlers remain type checked and can still be used by the extension itself.
Keep a terminal-accessible command, tool, or Pi UI for any capability that needs to remain usable there. Do not import renderer components into the Pi entry.
Failure behavior
A renderer call rejects when:
- The method is not declared or registered
- Parameters or results fail their schemas
- The handler throws
- The call exceeds thirty seconds
- The active chat changes before the response returns
Catch call failures in the renderer and show an actionable state near the control that initiated them. Continue with Renderer context for the browser side of the channel.