Session multiplexer for pi-coding-agent. Exposes N independent AgentSession instances through WebSocket and stdio transports.
- Dual transport: WebSocket (port 3141) + stdio (JSON lines)
- Session lifecycle: Create, delete, list, switch sessions
- Command execution: Deterministic lane serialization per session
- Idempotent replay: Atomic outcome storage with free replay lookups
- Optimistic concurrency: Session versioning for conflict detection
- Extension UI: Full round-trip support for
select,confirm,input,editor,interview - Resource governance: Rate limiting, session limits, message size limits
- Graceful shutdown: Drain in-flight commands, notify clients
- Protocol versioning:
serverVersion+protocolVersionfor compatibility checks
npm install pi-app-server# Start server
npx pi-server
# Connect with wscat
wscat -c ws://localhost:3141// Create and use a session
ws> {"type":"create_session","sessionId":"my-session"}
ws> {"type":"switch_session","sessionId":"my-session"}
ws> {"id":"cmd-1","type":"prompt","sessionId":"my-session","message":"Hello!"}echo '{"type":"create_session","sessionId":"test"}
{"type":"switch_session","sessionId":"test"}
{"id":"cmd-1","type":"prompt","sessionId":"test","message":"Hello!"}' | npx pi-serversrc/
├── server.ts # transports, connection lifecycle, routing glue
├── session-manager.ts # orchestration: coordinates stores, engines, sessions
├── command-router.ts # session command handlers, routing
├── command-classification.ts # pure command classification (timeout, mutation)
├── command-replay-store.ts # idempotency, duplicate detection, outcome history
├── session-version-store.ts # monotonic version counters per session
├── command-execution-engine.ts # lane serialization, dependency waits, timeouts
├── resource-governor.ts # limits, rate controls, health/metrics
├── extension-ui.ts # pending UI request tracking
├── server-ui-context.ts # ExtensionUIContext for remote clients
├── validation.ts # command validation
└── types.ts # wire protocol types + SessionResolver interface
- For each admitted command, there is exactly one terminal response.
- For each session ID, there is at most one live
AgentSession. - Subscriber session sets are always a subset of active sessions.
- Session version is monotonic and mutation-sensitive.
- Fingerprint excludes retry identity (
id,idempotencyKey) for semantic equivalence.
SessionResolver— Interface for session access (enables test doubles, future clustering)CommandReplayStore— Idempotency and duplicate detectionSessionVersionStore— Optimistic concurrency via version countersCommandExecutionEngine— Deterministic lane serialization and timeout management
See PROTOCOL.md for the normative wire contract.
Every command receives exactly one response:
{"id": "cmd-1", "type": "prompt", "sessionId": "s1", "message": "hello"}
{"id": "cmd-1", "type": "response", "command": "prompt", "success": true}Events flow session → subscribers:
{"type": "event", "sessionId": "s1", "event": {"type": "agent_start", ...}}- Extension calls
ui.select()→ server creates pending request - Server broadcasts
extension_ui_requestevent withrequestId - Client sends
extension_ui_responsecommand with samerequestId - Server resolves pending promise → extension continues
// First request with idempotency key
{"id": "cmd-1", "type": "list_sessions", "idempotencyKey": "key-1"}
{"id": "cmd-1", "type": "response", "command": "list_sessions", "success": true, ...}
// Retry with same key → replayed (free, no rate limit charge)
{"id": "cmd-2", "type": "list_sessions", "idempotencyKey": "key-1"}
{"id": "cmd-2", "type": "response", "command": "list_sessions", "success": true, "replayed": true, ...}- Timeout is a terminal stored outcome (
timedOut: true), not an indeterminate placeholder. - Replay of the same command identity returns the same timeout response.
- Late underlying completion does not overwrite the stored timeout outcome.
# Install dependencies
npm install
# Build
npm run build
# Run tests
npm test # Unit tests (83)
npm run test:integration # Integration tests (26)
npm run test:fuzz # Fuzz tests (17)
# Module tests (141)
node --experimental-vm-modules dist/test-command-classification.js
node --experimental-vm-modules dist/test-session-version-store.js
node --experimental-vm-modules dist/test-command-replay-store.js
node --experimental-vm-modules dist/test-command-execution-engine.js
# Type check + lint
npm run check
# Full CI
npm run ciThis project uses release-please for automated versioning.
- Push to
main→ release-please creates/updates a release PR - Merge the release PR → Creates GitHub release + git tag
- Release published → GitHub Action publishes to npm with provenance
npm run release:checkThis validates:
package.jsonhas required fieldsdist/exists with compiled files- Entry point has correct shebang
npm packproduces expected files- Full CI passes
| Document | Purpose |
|---|---|
| AGENTS.md | Crystallized learnings, patterns, anti-patterns |
| PROTOCOL.md | Normative wire contract |
| ADR-0001 | Atomic outcome storage decision |
| ROADMAP.md | Phase tracking and milestones |
MIT