Agent Knock Knock for Pi — POC
This Pi Extension makes Pi an Agent Knock Knock (AKK) orchestration Host. Pi
can use /akk and AKK's 16 semantic tools to control Codex and Claude Code
terminals that are already running in tmux or Herdr.
The connector does not modify Pi, launch or authenticate a coding agent, or depend on an OpenClaw Gateway. It uses AKK's public HostAdapter and returns callbacks to the exact initiating Pi session through a private local Unix socket.
Status and compatibility
This is a POC prerelease distributed on npm as
@scotthuang/agent-knock-knock-pi. Prereleases use the next dist-tag:
pi install npm:@scotthuang/agent-knock-knock-pi@next
The current compatibility contract is intentionally exact:
- Pi
0.84.4, installed from the official@earendil-works/pi-coding-agentpackage. - Node.js
22.19.0or newer. - AKK
0.12.23, pinned by this connector's package and lockfile. Runningnpm ciinconnectors/piinstalls that exact AKK runtime; a different version at the repository root is not substituted automatically. - macOS or Linux. The POC requires a POSIX Unix socket and does not support Windows named pipes.
- At least one authenticated Codex or Claude Code process already running in a supported tmux or Herdr terminal under the same OS user.
- A configured Pi model/provider. Pi model authentication is separate from AKK and is not performed by this connector.
The connector rejects a Pi runtime other than 0.84.4 before it creates a
socket or starts AKK lifecycle work. Pi's own packages remain * peer
dependencies as required by Pi's package contract; the runtime check is the
compatibility authority.
Five-minute quick start
1. Install the accepted Pi version
npm install -g @earendil-works/pi-coding-agent@0.84.4
node --version
pi --version
Configure a model using Pi's normal /login, provider environment variable,
or settings flow before continuing.
2. Start a coding agent in a shared terminal
AKK discovers an existing process; it never starts one for you. For example:
tmux new-session -s akk-pi-work -c "$(pwd -P)" codex
Wait for Codex to reach its interactive prompt, then detach with Ctrl-b
followed by d. Use claude instead of codex to test Claude Code. An
existing supported Herdr terminal works too.
3. Install the connector
pi install npm:@scotthuang/agent-knock-knock-pi@next
pi list
Using next follows compatible Pi connector prereleases. To pin this exact
build instead, install
npm:@scotthuang/agent-knock-knock-pi@0.1.0-poc.1; exact versions are pinned
and are not advanced by Pi's bulk update command.
4. Start Pi
pi
Pi should show AKK ready. The package manifest registers the Extension, so
no -e path or repository checkout is required.
5. Complete the first round trip
In Pi, list the live targets:
/akk list
If exactly one terminal is send-ready, submit a small task:
/akk reply with exactly AKK_PI_OK after inspecting the current workspace
If multiple targets are present, use the fresh selector printed by
/akk list:
/akk @a1b2c3d4: reply with exactly AKK_PI_OK after inspecting the current workspace
A managed Send returns a turn_id; when the coding agent settles, its callback
is injected into the same Pi session. Inspect it at any time with the exact
turn selector printed by AKK:
/akk status <turn-selector>
To observe work that you started manually in the terminal, copy the complete
terminal_id from a fresh list and start a read-only Watch:
/akk watch <exact-terminal-id>
/akk status <watch-id>
/akk unwatch <watch-id>
Watch does not send, adopt, approve, interrupt, or reserve the task. Do not add
a second Watch merely to make a normal managed Send callback: managed Send
already has a callback. When a user-priority Send must fall back to unmanaged
physical delivery, AKK instead tries to attach the request-bound Watch itself
and returns its watch_id.
Tool workflow
The usual product loop is:
- List to discover live terminals and their current
available_actions. - Send using the fresh action's prefilled
session_idorterminal_id. Do not invent semantic IDs or retry an uncertain terminal mutation. - Wait for the managed Callback. An unmanaged user-priority fallback may return a Terminal Watch callback instead of a managed Turn callback.
- Use Status with the exact
turn_idorwatch_idwhen the callback is delayed or the Pi route changed. - Use Respond for a question in that same Turn. Use Approve only after reviewing the live approval prompt and making an explicit decision.
- Use Cancel, Close, Renew, or Retry Callback only when the current list/status output advertises that exact action.
The /akk command is the direct human surface. The following 16 tools are also
registered for model-driven orchestration:
| Tool | Purpose |
|---|---|
agent_knock_knock_list |
List verified Codex/Claude terminals, managed work, Watches, and currently available semantic actions. |
agent_knock_knock_watch |
Start a durable, read-only Watch for one exact terminal_id. |
agent_knock_knock_unwatch |
Stop observation by exact watch_id; it does not interrupt the coding agent. |
agent_knock_knock_list_resumable_threads |
List structurally verified native threads that can be resumed in one terminal. |
agent_knock_knock_native_inspect |
Run the closed native status inspection for one exact terminal. Arbitrary slash commands are not accepted. |
agent_knock_knock_new_thread |
Start and verify a clean native coding-agent thread after explicit user intent. |
agent_knock_knock_reconcile_binding |
Detach one exact conflicting AKK Session binding after explicit confirmation, without adopting another thread. |
agent_knock_knock_resume_thread |
Resume one exact complete native_thread_id returned by the current discovery result. |
agent_knock_knock_status |
Inspect one exact managed Turn or Terminal Watch. |
agent_knock_knock_send |
Send a new task through the exact currently advertised Session or terminal action. |
agent_knock_knock_respond |
Answer a question or blocked callback in one existing Turn; it does not start a new Turn. |
agent_knock_knock_approve |
Approve one current permission request after Pi presents a native user-decision gate. |
agent_knock_knock_renew |
Renew monitoring for one stalled but still-live Turn without terminal input. |
agent_knock_knock_retry_callback |
Retry one persisted managed callback with its original message identity. |
agent_knock_knock_cancel |
Interrupt one exact task after Pi obtains native confirmation; the shared pane stays open. |
agent_knock_knock_close |
Release AKK management for one Turn without sending terminal input or stopping the coding agent. |
Except for the deliberately user-intent-first, read-only Watch path, treat the
fresh available_actions output as authority. The connector preserves AKK's
semantic-ID, idempotency, terminal identity, Store, Session, Turn, and
completion rules rather than recreating them in Pi.
Active approval, response, and cancellation
When a managed task needs permission, its callback is queued into the
originating Pi session. A model-facing agent_knock_knock_approve call does not
immediately type into the terminal. The connector first refreshes AKK Status,
shows the current prompt in Pi's native UI, and requires a selection:
- Approve once sends the current prompt-scoped AKK approval.
- Keep pending sends no terminal input.
- For a managed
turn_id, Reject and cancel task asks for a second confirmation, then invokes AKK Cancel.
A terminal-scoped approval has no terminal-scoped Cancel authority, so its dialog offers only Approve or Keep pending. A separately advertised Cancel action gets its own Pi confirmation dialog.
agent_knock_knock_respond answers an ordinary question in the exact
in-flight Turn; it is not an approval denial. AKK currently has no generic
"select the target's No option and continue this Turn" tool. Reject-and-cancel
interrupts the task instead.
The native confirmation flow requires an interactive Pi UI. In a context where
ctx.hasUI is false, the connector refuses model-facing Approve and Cancel
instead of mutating the terminal without a person. Headless/non-interactive Pi
is not a product-acceptance target for this POC.
AKK keeps the coding agent's existing permission mode. This connector does not
enable --yolo, change a target's permission settings, or expose AKK's
OpenClaw-specific autoApprove configuration.
Callback delivery and recovery
The callback path is:
AKK callback outbox
-> command_json_v1 callback helper
-> authenticated private Unix socket
-> fsync-backed Pi callback inbox
-> originating Pi session
When Pi is idle, the callback is injected with triggerTurn: true and starts a
new Pi turn. When Pi is already producing a response, the connector uses Pi's
follow-up queue so the callback is not mixed into the current model turn.
An accepted callback acknowledgement means that the connector durably
admitted the exact delivery to its local inbox and returned an acceptance ID.
It does not mean the Pi model consumed the message: Pi 0.84.4 exposes a
synchronous sendMessage() call without a model-consumption receipt. The last
hop is therefore at-least-once or uncertain if Pi crashes between
sendMessage() and recording the inbox entry as delivered. Delivery and
idempotency IDs let the connector reject collisions and suppress known exact
duplicates.
For a missing callback:
- If Pi is busy, wait for the current response to end; the callback may be a queued follow-up.
- Refresh
/akk list, then run/akk status <turn-selector-or-watch-id>. Status is the authoritative manual recovery path and does not need the callback to have reached the model. - If a still-live task has no managed callback route, start a new read-only
Watch on its exact current
terminal_idand retain the returnedwatch_id. - Use
agent_knock_knock_retry_callbackonly when the current managed Turn advertises it and the original Pi callback route is still live. Never retry an uncertain terminal Send to recover a callback.
The POC owns one live Pi runtime and one branch epoch. Explicit session-tree navigation rotates the controller route; Pi shutdown removes the socket and invalidates that runtime's route. The durable inbox does not migrate callbacks from an old random controller identity into a new Pi runtime or branch. After a restart or branch change, use fresh List/Status and, for still-running terminal work, a fresh Watch. Do not expect the old route's callback to jump to the new conversation automatically.
Configuration, security, and storage
The connector needs no project-specific configuration. These optional environment variables must be set before Pi starts and must contain absolute paths:
| Variable | Default | Purpose |
|---|---|---|
AKK_PI_STORE_DIR |
~/.agent-knock-knock/store |
Override AKK's shared Session, Turn, Watch, receipt, and callback-outbox Store. |
AKK_PI_STATE_DIR |
~/.pi/agent/akk |
Override the Pi connector's durable callback-inbox directory. |
Example with isolated development state:
AKK_PI_STORE_DIR=/absolute/private/path/akk-store \
AKK_PI_STATE_DIR=/absolute/private/path/pi-akk-state \
pi
Security and retention boundaries:
- Pi Extensions execute with the same OS privileges as Pi. Review local connector source before loading it.
- Each Pi runtime creates a random directory under the OS temporary directory
with mode
0700. Its Host Profile and authenticated Unix socket use mode0600, and the directory is removed on clean Pi shutdown. - The socket token is random and runtime-private. It is not written to the durable inbox or accepted as a model/tool argument. The callback helper is allowed only the socket and token environment variables it needs.
- The persistent state directory is forced to
0700; itscallback-inbox.jsonis written atomically with mode0600. It can retain callback bodies, which may contain task results. The inbox is bounded to 256 entries and 64 MiB, pruning older delivered entries as new callbacks arrive. - The AKK Store is separate from the Pi inbox and may contain terminal/session metadata and callback results. Use a dedicated private directory for either override; do not point it at a shared or broad filesystem root.
- The connector strips the supported GLM credential environment variables from AKK relay/callback subprocess environments. Model credentials remain Pi-owned and are never connector configuration.
Troubleshooting
| Symptom | Check and recovery |
|---|---|
requires Pi 0.84.4 |
Run pi --version, then reinstall the exact accepted release with npm install -g @earendil-works/pi-coding-agent@0.84.4. Newer Pi releases are not silently accepted by this POC. |
Pi never shows AKK ready |
Confirm Node is at least 22.19, run pi list, update or reinstall npm:@scotthuang/agent-knock-knock-pi@next, and fully restart Pi. For a source checkout, follow the local-development build commands below. |
Module or lib/index.js not found |
Remove and reinstall the npm package. For a source checkout, confirm Pi was given connectors/pi, not the repository root, and rebuild with the documented cwd-specific command. |
/akk list finds no terminal |
Start authenticated codex or claude inside supported tmux/Herdr under the same OS user and leave the process running. The connector never launches it. |
| Send says the target is ambiguous | Run a fresh /akk list and use the exact displayed selector for /akk, or the prefilled semantic ID from that row's current tool action. |
| Callback does not appear immediately | Pi may be busy, so the callback is queued as a follow-up. Wait for the current turn, then use fresh List and Status. After a Pi restart or branch change, the old callback route is intentionally not migrated. |
| Approval or cancellation says an interactive UI is required | Use Pi's interactive TUI. The POC deliberately blocks model-facing Approve/Cancel when ctx.hasUI is false. |
| Approval changed before confirmation | Refresh Status and review the newly observed prompt. Do not reuse an old approval offer or blindly retry an interrupted approval. |
| Callback socket/profile is unavailable | The owning Pi runtime may have stopped or its temporary private directory may have disappeared. Restart Pi to create a fresh route; recover existing work with List/Status rather than copying socket paths or tokens. |
| State-directory or Store permission error | Both override variables must be absolute and point to dedicated real directories. Stop Pi, inspect ownership and contents, then choose a new private directory if the existing path is unsafe or incompatible. |
| Updated connector still behaves like the old POC | Run pi update npm:@scotthuang/agent-knock-knock-pi and fully restart Pi. For a source checkout, re-run npm ci and the connector-specific build first. A running Extension is not hot-replaced. |
| Send result is uncertain | Do not automatically send the task again. Inspect Status, the exact pane, or the attached Watch; retrying terminal input could duplicate work. |
Upgrade and uninstall
Inspect and update the npm installation with Pi's package manager:
pi list
pi update npm:@scotthuang/agent-knock-knock-pi
Keep Pi at exactly 0.84.4 until this README declares another accepted
version. Do not use an unverified Pi upgrade as a connector update.
Remove the npm package by its package identity:
pi remove npm:@scotthuang/agent-knock-knock-pi
pi uninstall is an alias for pi remove. Removing the package does not stop
or delete Codex/Claude terminals, model credentials, ~/.pi/agent/akk, or the
AKK Store. Those durable directories are retained for inspection/recovery and
should be reviewed separately before any manual deletion.
Development and verification
To load a source checkout for one Pi run, build the connector explicitly:
AKK_REPO=/absolute/path/to/agent-knock-knock
cd "$AKK_REPO"
npm --prefix connectors/pi ci
npm run pi:build
pi -e "$AKK_REPO/connectors/pi"
The equivalent child-package build is:
cd "$AKK_REPO/connectors/pi"
npm ci
npm run build
Do not run a bare root npm run build and assume it built this connector. The
unambiguous root command is npm run pi:build; inside connectors/pi, use
npm run build. pi -e is temporary and changes no package settings. To
persist a local source path, use pi install "$AKK_REPO/connectors/pi"; remove
that same absolute source with pi remove when finished.
From the repository root:
npm run pi:typecheck
npm run pi:test:fast
npm run pi:pack:check
Or from connectors/pi:
npm run typecheck
npm run test:fast
npm run pack:check
The PR #266 acceptance record on 2026-08-30 included:
- root fast tests: 1,462/1,462 passed;
- connector fast tests: 23/23 passed;
- root and connector TypeScript typechecks, architecture/evidence validators, and connector package dry-run passed;
- a real Claude Code 2.1.251 flow covering Send, approval callback, Pi native approval, exact marker execution, completion callback, and delivered Status;
- a real Codex flow in a clean isolated environment covering native
agent_accepted, exact marker execution, Unix Socket callback into Pi, and durable high-confidence delivered Status.
These are POC acceptance results, not a promise of compatibility with every
future Pi, Codex, Claude Code, tmux, or Herdr release. Version
0.1.0-poc.1 is the first npm prerelease and is distributed through the
next dist-tag; it does not change the AKK main package or ClawHub artifact.
Deliberate POC limits
The POC intentionally does not provide a standalone Supervisor, multi-Host
leader election, cross-session or cross-branch callback migration, remote
terminal access, Windows named pipes, configuration-driven auto-approval, or
coding-agent --yolo adaptation. It controls only the Codex and Claude Code
terminal surfaces already supported by AKK.