How to Use the Pi Web Global Session Registry (`globalThis.__piSessions`)
Access active Agent sessions in Pi Web via globalThis.__piSessions, a Map-backed global registry that stores session wrappers by ID, or use the helper functions in lib/rpc-manager.ts for type-safe interactions.
The agegr/pi-web repository maintains a global registry attached to globalThis called __piSessions to track every active Agent session across the server lifecycle. This registry stores AgentSessionWrapper instances in a Map keyed by session ID, enabling centralized session management and graceful shutdown handling.
Understanding the Global Registry Structure
globalThis.__piSessions is a Map<string, AgentSessionWrapper> where each entry maps a session UUID to its controlling wrapper object. According to the source code in lib/rpc-manager.ts lines 57-66, the registry is created lazily the first time it is accessed, ensuring zero overhead until an Agent session actually starts.
The registry integrates with the Node process lifecycle. A cleanup function registered at initialization automatically destroys all active sessions when the server exits, preventing orphaned Pi SDK processes and ensuring graceful shutdowns.
Helper Functions for Type-Safe Access
While direct access to globalThis.__piSessions works, the exported helpers in lib/rpc-manager.ts handle lazy-initialization, TypeScript typing, and cleanup logic. They also insulate your code from the exact storage mechanism, making future refactors safer.
getRpcSession(sessionId)
Returns the AgentSessionWrapper for a given ID, or undefined if the session does not exist.
- Source:
lib/rpc-manager.tslines 98-100 - Use case: Fetching a specific session to send commands or check health
getRunningRpcSessionIds()
Returns an array of session IDs whose isRunning() flag is currently true.
- Source:
lib/rpc-manager.tslines 19-24 - Use case: Debugging dashboards, admin pages, or status endpoints
hasBusyRpcSessionForCwd(cwd)
Checks whether any session for the supplied working directory is currently starting or running.
- Source:
lib/rpc-manager.tslines 2-7 - Use case: Preventing duplicate session launches for the same project directory
destroyRpcSessionsForCwd(cwd)
Gracefully shuts down all sessions belonging to a specific current working directory.
- Source:
lib/rpc-manager.tslines 10-16 - Use case: Cleanup routines when a project is closed or deleted
subscribeRunningSessions(listener)
Registers a callback that fires whenever the set of running session IDs changes. The listener receives the new ID list as its argument. Pi Web stores these listeners in globalThis.__piRunningListeners and triggers them via notifyRunningChange() whenever a session’s running state flips.
- Source:
lib/rpc-manager.tslines 41-46 - Use case: Real-time UI updates via Server-Sent Events (SSE) or WebSockets
Practical Implementation Examples
Send Commands to a Specific Session
Use getRpcSession to retrieve a wrapper and access the underlying Pi SDK AgentSession via the inner property:
import { getRpcSession } from '@/lib/rpc-manager';
const sessionId = 'c1d2e3f4-5678-90ab-cdef-1234567890ab';
const wrapper = getRpcSession(sessionId);
if (wrapper && wrapper.isAlive()) {
await wrapper.inner.send('some_command', { foo: 'bar' });
}
Monitor Active Sessions
Fetch all currently running session IDs for logging or administrative interfaces:
import { getRunningRpcSessionIds } from '@/lib/rpc-manager';
const runningIds = getRunningRpcSessionIds();
console.log('Currently running sessions:', runningIds);
Clean Up Sessions by Project Directory
Shut down every session associated with a specific path, useful for project-switching workflows:
import { destroyRpcSessionsForCwd } from '@/lib/rpc-manager';
import { resolve } from 'path';
const cwd = resolve('/home/user/my-project');
const count = await destroyRpcSessionsForCwd(cwd);
console.log(`Destroyed ${count} session(s) for ${cwd}`);
React to Session State Changes
Subscribe to registry changes to broadcast updates to connected clients:
import { subscribeRunningSessions, getRunningRpcSessionIds } from '@/lib/rpc-manager';
const unsubscribe = subscribeRunningSessions((ids) => {
console.log('Running sessions changed:', ids);
});
console.log('Initial running sessions:', getRunningRpcSessionIds());
// Cleanup when shutting down your component or route:
unsubscribe();
Direct Registry Access (Advanced)
For low-level enumeration or debugging, access the Map directly. Note that this bypasses the lazy-initialization guard:
const registry = globalThis.__piSessions;
if (registry) {
for (const [id, wrapper] of registry.entries()) {
console.log(`Session ${id} alive: ${wrapper.isAlive()}`);
}
}
Key Source Files
lib/rpc-manager.ts: Implements the global registry, helper APIs, and lifecycle hooks (lines 57-66, 98-100, and throughout).AGENTS.md: High-level design documentation referencingglobalThis.__piSessions.app/api/agent/[id]/route.ts: Example server-side usage ofgetRpcSessionto forward client commands.app/api/sessions/[id]/route.ts: Demonstrates session lookup and shutdown via the registry.
Summary
globalThis.__piSessionsis aMap<string, AgentSessionWrapper>storing all active Pi Web Agent sessions by ID.- The registry initializes lazily on first access and automatically cleans up on process exit.
- Prefer helper functions (
getRpcSession,getRunningRpcSessionIds, etc.) over direct Map access to ensure type safety and proper initialization. - Use
subscribeRunningSessionsto react to session lifecycle changes in real-time applications. - Use
destroyRpcSessionsForCwdfor bulk cleanup of sessions tied to specific project directories.
Frequently Asked Questions
What data type is globalThis.__piSessions?
globalThis.__piSessions is a standard JavaScript Map where keys are session ID strings and values are AgentSessionWrapper instances. The wrapper objects encapsulate the raw Pi SDK AgentSession and provide methods like isAlive(), isRunning(), and shutdown().
When is the global registry initialized?
The registry initializes lazily the first time any helper function or direct access triggers its creation. According to lib/rpc-manager.ts lines 57-66, the initialization checks if (!globalThis.__piSessions) and assigns a new Map() only when needed.
How do I safely check if a session exists without manually touching globalThis?
Import and use getRpcSession(sessionId) from lib/rpc-manager.ts. It returns the AgentSessionWrapper if present, or undefined if the ID is not in the registry. This approach guarantees the registry is initialized before lookup and provides full TypeScript type inference.
Can I listen for new session creation events specifically?
While there is no hook exclusively for "creation," you can use subscribeRunningSessions to detect when a session transitions to a running state. This callback fires whenever the set of running session IDs changes, effectively notifying you of both new sessions starting and existing sessions stopping. The callback receives the complete updated array of running IDs.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →