# 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 capability-handshake-verified 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: ```sh 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-agent` package. - Node.js `22.19.0` or newer. - AKK `0.13.3`, pinned by this connector's package and lockfile. Running `npm ci` in `connectors/pi` installs 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 ```sh 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: ```sh 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 ```sh 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.2`; exact versions are pinned and are not advanced by Pi's bulk update command. ### 4. Start Pi ```sh pi ``` Pi should show `AKK ready`. The package manifest registers both the Extension and its bundled `agent-knock-knock` skill, so no separate skill copy, `-e` path, or repository checkout is required. The structured List result stays small by returning current action names and dynamic inputs; Pi loads the skill when it needs the static action meanings and safety rules. ### 5. Complete the first round trip In Pi, list the live targets: ```text /akk list ``` If exactly one terminal is send-ready, submit a small task: ```text /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`: ```text /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: ```text /akk status ``` 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: ```text /akk watch /akk status /akk unwatch ``` 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: 1. **List** to discover live terminals and their current `available_actions`. 2. **Send** using the fresh action's prefilled `session_id` or `terminal_id`. Do not invent semantic IDs or retry an uncertain terminal mutation. 3. Wait for the managed **Callback**. An unmanaged user-priority fallback may return a Terminal Watch callback instead of a managed Turn callback. 4. Use **Status** with the exact `turn_id` or `watch_id` when the callback is delayed or the Pi route changed. 5. Use **Respond** for a question in that same Turn. Use **Approve** only after reviewing the live approval prompt and making an explicit decision. 6. 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 complete semantic catalog is 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_model_options` | Read one exact idle terminal's native model and reasoning catalog and create a single-use typed offer. | | `agent_knock_knock_repair_model_control` | Dismiss only an exactly recognized stale model-control surface; it never selects a model or submits a task. | | `agent_knock_knock_set_model` | Consume the current catalog offer to select one advertised semantic model and reasoning effort. | | `agent_knock_knock_identify_foreground` | Run a bounded diagnostic native identity probe without creating durable model-control authority. | | `agent_knock_knock_identify_and_send` | Keep one terminal lock across identity observation and one explicit Send when the normal foreground identity is ambiguous. | | `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_respond_interaction` | Answer the current typed native questionnaire step for one exact response-capable Turn or Watch. | | `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: ```text 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: 1. If Pi is busy, wait for the current response to end; the callback may be a queued follow-up. 2. Refresh `/akk list`, then run `/akk status `. Status is the authoritative manual recovery path and does not need the callback to have reached the model. 3. If a still-live task has no managed callback route, start a new read-only Watch on its exact current `terminal_id` and retain the returned `watch_id`. 4. Use `agent_knock_knock_retry_callback` only 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: ```sh 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 mode `0600`, 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`; its `callback-inbox.json` is written atomically with mode `0600`. 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: ```sh 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: ```sh 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: ```sh 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: ```sh 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: ```sh npm run pi:typecheck npm run pi:test:fast npm run pi:pack:check ``` Or from `connectors/pi`: ```sh npm run typecheck npm run test:fast npm run pack:check ``` ## Release safety `npm run release:check` is check-only. The shared connector gate proves the generated Skill hash, package manifest/constants/lock/dependency parity, then runs typecheck, fast tests, and inspection of the real package tarball. In release mode it also requires a clean synchronized `main`, verifies that the exact npm version and `pi-v` repository tag are unused, and rejects non-publishable runtime dependency specifiers. Activation also performs a runtime compatibility gate. The pinned AKK HostAdapter must expose capability handshake v1, whose catalog digest, ordered tool names and derived count, and canonical Skill digest must match both this package's generated Skill and the tools Pi just registered. Missing or forged metadata, an unknown handshake version, or partial registration prevents the connector from reporting `AKK ready`; no connector-local tool-count literal is used. The deterministic local form performs the same package checks without reading registry or git-remote release state: ```sh npm run release:check -- --offline ``` From the repository root, `npm run connectors:verify` checks Pi and DeepSeek Harness independently; it does not require their package versions to match. Publishing Pi additionally requires explicit version confirmation: ```sh npm run release:check -- --publish --confirm-version 0.1.0-poc.2 ``` Prereleases use npm tag `next`; stable versions use `latest`. Tags and GitHub Releases use `pi-v` and are created separately after npm verification. The [PR #266](https://github.com/scotthuang/agent-knock-knock/pull/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.2` is an 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.