19. Add Pi and an explicit single-port localhost relay#
Status#
Proposed. Superseded in part by 20. Relay a set of loopback ports to every agent (ADR 20): the relay is no longer Pi-only or single-port, though its mechanism and the discovery step are unchanged.
Context#
Pi supports cloud providers and local OpenAI-compatible servers. lllm2 starts
a single-model llama.cpp server bound to 127.0.0.1:1920. The agent’s network
namespace has its own loopback, so allowing an RFC1918 address does not make
that server reachable. Mapping the entire host loopback would grant access to
unrelated services.
Pi has a standalone Linux release and its own ~/.pi/agent store, but no
equivalent to the managed prompt-hook policies used by Claude and Codex.
Decision#
Extend ADR 0018’s shared shadow with a Pi profile. Install the current,
checksum-verified standalone release under the read-only /usr/libexec tree;
keep the wrapper on PATH even when its optional download is skipped or fails.
Resolve the latest release once on a fresh installation, then fetch its archive
and checksums from that same tag. Existing installations are kept on an
installer re-run, as with Claude and Codex. PI_VERSION optionally pins a
release. Devcontainers install during postCreate; the separate published
image installs at image build time.
Bind and persist only Pi’s store for Pi sessions. Use Pi’s own authentication
and model picker. At Pi startup, query lllm2’s /v1/models and /props through
the relay to refresh the model ID and actual per-slot context window in Pi’s
local provider. Failed discovery preserves existing configuration and does not
prevent cloud sessions. Keep a manual helper for other compatible servers.
A fixed Bash launcher checks the sandbox markers
before starting Pi; it is a launch guard, not a managed per-prompt hook.
Add local-model-port in the operator-controlled sandbox configuration,
set to 1920 in the shipped file and used only for Pi; 0 disables the relay
and discovery. A host-side socat forwards a private
Unix socket to the configured port on 127.0.0.1. A second socat in the
holder’s network namespace forwards a loopback listener to that socket. bwrap
masks the host socket under /tmp; both relays remain outside the agent’s PID
namespace. Each relay owns a process
group so cleanup also terminates forked streaming connections. No additional
IP route, firewall capability, GPU mount or model installation is needed.
Make pasta’s port forwarding explicit for all agents: -t none -u none -T none -U none --no-map-gw. In the tested Ubuntu 24.04 pasta package, default
automatic forwarding exposed other host-loopback listeners and occupied the
intended relay port. Gateway mapping also bypasses the intent of the pinned
gateway route. Disabling those shortcuts preserves ordinary outbound traffic
and the existing dedicated DNS forwarder. This supplements ADR 0015’s routing
policy; routes alone do not restrict socket forwarding performed by pasta.
Consequences#
The outer container must share the server’s network namespace for an external localhost server; the existing devcontainer uses host networking, and the published-image launcher supports
--host-net.The selected TCP port exposes the entire service, including any management endpoints it serves. It is not an HTTP path filter.
The port stays available throughout a Pi session to support
/modelswitching. It does not depend on which provider is currently selected.Automatic forwarding of agent listeners back onto the outer host is also disabled. Workflows that depended on pasta discovering listening ports need an explicit exposure mechanism outside this feature.
All providers authenticated in Pi share Pi’s credential store. Stores from other coding agents remain hidden.
A separate, deliberately unwrapped Pi installation is not protected by a vendor-managed guard. Document this difference instead of claiming parity.
Namespace tests cover streaming, other localhost ports, gateway mapping, routing, normal exit and signal cleanup. The image tests exercise a real Pi release making a streamed tool call against a deterministic local server.