pi-herdr-chat-relay

A `Pi Agent` extension using `Herdr` CLI that enables two-way chat between two running Pi Agent instances.

Packages

Package details

extension

Install pi-herdr-chat-relay from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:pi-herdr-chat-relay
Package
pi-herdr-chat-relay
Version
1.0.0
Published
Sep 9, 2026
Downloads
119/mo · 119/wk
Author
ashlatham
License
MIT
Types
extension
Size
15.7 KB
Dependencies
0 dependencies · 0 peers
Pi manifest JSON
{
  "extensions": [
    "./chat-relay.ts"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

pi-herdr-chat-relay

A Pi Agent extension using Herdr CLI that enables two-way chat between two running Pi Agent instances. Each agent runs the extension independently; one starts a conversation and the other auto-detects and joins. Messages are relayed back and forth — the AI equivalent of passing the ball.

How it works

Each extension instance registers an /chat slash command and listens for incoming messages via the input event hook. When Agent A starts a chat with Agent B:

  1. Agent A finds Agent B's herdr pane via herdr agent list
  2. Sends the topic as a JSON payload: { DELEGATE: { ORIGIN: "<name>", MESSAGE: "<topic>" } }
  3. Agent B's input hook intercepts the text, parses the JSON, and transforms it to From-AgentsName: <message> so the LLM treats it as a user message
  4. When Agent B finishes a turn (agent_end fires), its extension extracts the last assistant message and sends it back to Agent A wrapped as { FROM_PARTNER: { sender: "<name>", message: "<text>" } }
  5. Agent A's input hook transforms it the same way, LLM sees it as a user message
  6. Repeat — agent_end triggers each direction

No polling, no ACKs, no handshakes. The conversation loop is driven entirely by agent_end events firing after each LLM turn.

Installation

Each agent needs a copy of the chat-relay.ts file in their .pi/extensions folder (unless it is placed in a global extensions folder for use by all Pi Agents - I don't do this)

pi install git:github.com/ashLatham/pi-herdr-chat-relay

Or install into the current project only:

pi install git:github.com/ashLatham/pi-herdr-chat-relay -l

For development (without permanent installation):

pi -e git:github.com/ashLatham/pi-herdr-chat-relay

Usage

Starting a chat

/chat <agent>: <topic>

Example:

/chat kat: "Let's debate pizza toppings"

The other agent must already be running in herdr. The extension resolves the target agent by matching workspace name against herdr agent list output.

Ending a chat

No explicit end command — conversations continue indefinitely until both agents naturally fall silent or the user simply hits esc in the currently responding agent to cancel.

Requirements

  • herdr installed — the extension shells out to herdr for all inter-pane communication
  • Both agents must have the extension loaded
  • Agents should be distinguishable by workspace/cwd name (used for pane lookup)

Limitations

  • Two-agent only — designed for pairwise relay. Multi-agent fan-out would require fundamental restructuring (each agent would need to track multiple partners and route responses correctly).
  • Terminal-as-pipe — messages are typed into the terminal via herdr pane send-text + send-keys enter. Special characters may need escaping.
  • Fire-and-forget — no delivery guarantees. If agent_end fires but the response extraction fails, the ball drops silently.
  • No structured protocol — message framing relies on JSON payloads that look like { DELEGATE: {...} } or { FROM_PARTNER: {...} }. Custom formatting could collide with normal input.

Architecture

Agent A (Pi)                          Agent B (Pi)
┌─────────────┐                      ┌─────────────┐
│ /chat cmd   │                      │ input hook  │
│ agent_end   │                      │ agent_end   │
└──────┬──────┘                      └──────┬──────┘
       │                                    │
       │  JSON: { DELEGATE: {...} }         │
       │  execSync('herdr pane send-text')  │
       │ ─────────────────────────────────▶ │
       │                                    │
       │  Transform: From-A: <msg>          │
       │ ◀── input hook                     │
       │                                    │
       │                                    │  LLM generates response
       │                                    │  agent_end fires
       │                                    │
       │  JSON: { FROM_PARTNER: {...} }     │
       │  execSync('herdr pane send-text')  │
       │ ◀──────────────────────────────────│
       │                                    │
       │  Transform: From-B: <msg>          │
       │ ◀── input hook                     │
       │                                    │
       │  (repeat cycle...)                 │
       │                                    │

Each agent owns one half of the loop. The agent_end event is the handoff signal — when one agent finishes thinking, its extension blindly passes the LLM's latest response back to the other agent via execSync('herdr pane send-text').

Links

License

MIT