Package Exports
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@rk0429/agentic-relay) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
agentic-relay
A unified CLI that brings Claude Code, Codex CLI, and Gemini CLI under a single interface -- solving tool fragmentation, enabling multi-layer sub-agent orchestration via MCP, and providing proactive context window monitoring.
Why agentic-relay?
Working with multiple AI coding CLIs means juggling different command syntaxes, configurations, and authentication flows. Nesting sub-agents across tools is not supported natively. And context window exhaustion catches you off guard.
agentic-relay addresses three problems:
| Problem | Solution |
|---|---|
| Tool fragmentation -- three CLIs with different flags, config formats, and auth mechanisms | Unified interface with backend adapters that normalize the differences |
| No nested sub-agents -- parent agents cannot spawn grandchild agents through different backends | MCP server mode lets any MCP-capable client spawn agents across all three backends, with recursion guards |
| Context window surprise -- sessions silently hit token limits | Hooks + ContextMonitor track usage and notify before the limit is reached |
Prerequisites
- Node.js 22+
- One or more backend tools installed: Claude Code, Codex CLI, or Gemini CLI
- macOS 13+ / Ubuntu 22.04+ / Debian 12+
Installation
# Install globally
npm install -g @rk0429/agentic-relay
# Initialize project-level config (optional)
relay init
# Verify installation
relay doctorFrom Source
git clone https://github.com/RK0429/agentic-relay.git
cd agentic-relay
pnpm install
pnpm build
pnpm link --globalQuick Start
# Start an interactive session with Claude Code
relay claude
# One-shot prompt with Codex CLI
relay codex -p "Refactor this function to use async/await"
# Continue the latest Gemini session
relay gemini -c
# Check which backends are available
relay doctorUsage
Backend Commands
relay claude|codex|gemini # Interactive mode
relay claude|codex|gemini -p "query" # Non-interactive (one-shot)
relay claude|codex|gemini -c # Continue latest session
relay claude|codex|gemini -r ID # Resume session by ID
relay claude|codex|gemini --agent NAME # Specify agent
relay claude|codex|gemini --model NAME # Specify modelManagement Commands
relay config show # Show merged config
relay config get <key> # Get config value
relay config set <key> <value> # Set config value
relay auth <backend> login # Authenticate a backend
relay auth <backend> status # Check auth status
relay sessions # List/search sessions
relay update # Update backend tools
relay version # Show versions
relay doctor # Run diagnostics
relay init # Initialize .relay/ configMCP Commands
relay mcp list # List MCP servers
relay mcp add <name> -- CMD # Add MCP server
relay mcp remove <name> # Remove MCP server
relay mcp sync # Sync MCP config to backends
relay mcp serve # Start as MCP server (stdio, default)
relay mcp serve --transport http # Start as MCP server (HTTP)
relay mcp serve --transport http --port 8080 # Custom portConfiguration
agentic-relay uses a three-tier configuration system. Each tier overrides the one above it.
| Tier | Path | Scope |
|---|---|---|
| Global | ~/.relay/config.json |
User-wide defaults |
| Project | .relay/config.json |
Shared across team (commit to VCS) |
| Local | .relay/config.local.json |
Personal overrides (gitignored) |
Example configuration:
{
"defaultBackend": "claude",
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path"]
}
},
"hooks": {
"hooks": [
{
"event": "ContextThreshold",
"command": ["node", "scripts/save-state.js"],
"timeoutMs": 5000,
"onError": "warn"
}
]
},
"contextMonitor": {
"enabled": true,
"thresholdPercent": 75,
"notifyMethod": "hook"
}
}Environment Variables
| Variable | Description | Default |
|---|---|---|
RELAY_HOME |
Home directory for relay | ~/.relay |
RELAY_LOG_LEVEL |
Log level (debug/info/warn/error) | info |
RELAY_MAX_DEPTH |
Max recursion depth in MCP server mode | 5 |
RELAY_CONTEXT_THRESHOLD |
Context warning threshold (%) | 75 |
RELAY_CLAUDE_PERMISSION_MODE |
Claude permission mode (bypassPermissions or default) |
bypassPermissions |
ANTHROPIC_API_KEY |
Passed through to Claude Code (optional with subscription) | -- |
OPENAI_API_KEY |
Passed through to Codex CLI (optional with subscription) | -- |
GEMINI_API_KEY |
Passed through to Gemini CLI (optional with subscription) | -- |
MCP Server Mode
agentic-relay can act as an MCP (Model Context Protocol) server, allowing any MCP-capable client to spawn sub-agents across all three backends. This is how nested sub-agent orchestration works -- a parent agent calls relay via MCP, which spawns a child agent on any backend, and that child can call relay again to spawn a grandchild.
Setup
Add relay as an MCP server in your client's configuration. For Claude Code:
{
"mcpServers": {
"relay": {
"command": "relay",
"args": ["mcp", "serve"]
}
}
}Exposed Tools
| Tool | Description |
|---|---|
spawn_agent |
Spawn a sub-agent on a specified backend |
list_sessions |
Retrieve session history |
get_context_status |
Query context window usage |
Recursion Guard
The MCP server includes a three-layer recursion guard to prevent runaway agent chains:
- Depth limit -- rejects calls that exceed the maximum nesting depth (default: 5)
- Per-session call limit -- caps the total number of spawns within a single session (default: 20)
- Loop detection -- identifies repeated calls with the same backend + prompt hash
Context propagation between parent and child agents uses environment variables: RELAY_TRACE_ID, RELAY_PARENT_SESSION_ID, and RELAY_DEPTH.
Multi-layer Agent Call Flow
sequenceDiagram
participant User
participant Parent as Parent Agent<br>(Claude Code)
participant Relay as agentic-relay<br>(MCP Server)
participant Child as Child Agent<br>(Codex CLI)
participant Relay2 as agentic-relay<br>(MCP Server)
participant Grandchild as Grandchild Agent<br>(Gemini CLI)
User->>Parent: Task request
Parent->>Relay: spawn_agent(codex, prompt)
Note over Relay: RecursionGuard check<br>depth=1, calls=1
Relay->>Child: Codex SDK thread.run("prompt")<br>RELAY_DEPTH=1
Child->>Relay2: spawn_agent(gemini, sub-prompt)
Note over Relay2: RecursionGuard check<br>depth=2, calls=1
Relay2->>Grandchild: gemini -p "sub-prompt"<br>RELAY_DEPTH=2
Grandchild-->>Relay2: Result
Relay2-->>Child: Result
Child-->>Relay: Result
Relay-->>Parent: Result
Parent-->>User: Final answerArchitecture
agentic-relay is organized into six layers.
graph TD
A["CLI Layer<br><i>citty entry point</i>"] --> B["Command Handlers<br><i>backend, mcp, config, auth,<br>update, sessions, version, doctor, init</i>"]
B --> C["Core Layer<br><i>SessionManager, ConfigManager,<br>AuthManager, HooksEngine,<br>ContextMonitor, EventBus</i>"]
B --> D["MCP Server<br><i>RelayMCPServer,<br>spawn_agent, list_sessions,<br>get_context_status, RecursionGuard</i>"]
C --> E["Backend Adapters<br><i>BaseAdapter, ClaudeAdapter,<br>CodexAdapter, GeminiAdapter,<br>FlagMapper</i>"]
C --> F["Infrastructure<br><i>ProcessManager, Logger</i>"]
D --> E
D --> FBackend Adapters
Each backend CLI has different flags, output formats, and session handling. The adapter layer normalizes these differences behind a common BackendAdapter interface. Adding a new backend means implementing this interface and registering it with the AdapterRegistry.
Non-interactive execution uses official SDKs where available:
| Backend | Non-interactive (-p) |
Interactive | Session listing |
|---|---|---|---|
| Claude Code | Agent SDK query() |
CLI spawn | Agent SDK listSessions() |
| Codex CLI | Codex SDK thread.run() |
CLI spawn | -- |
| Gemini CLI | CLI spawn | CLI spawn | CLI --list-sessions |
Hooks Engine
An event-driven hook system that executes external commands via stdin/stdout JSON pipes.
| Event | Trigger |
|---|---|
SessionStart / SessionEnd |
Session lifecycle |
PreToolUse / PostToolUse |
Tool invocation |
PreCompact |
Before context compaction |
ContextThreshold |
Context usage exceeds threshold (relay-specific) |
SubagentSpawn / SubagentComplete |
Sub-agent lifecycle (relay-specific) |
Context Monitor
Monitors context window usage and fires ContextThreshold events when usage exceeds the configured threshold. Notification methods: stderr (direct output) or hook (triggers the Hooks Engine).
Project Structure
src/
bin/relay.ts # Entry point
commands/ # Command handlers
backend.ts # relay claude/codex/gemini
mcp.ts # relay mcp (list/add/remove/sync/serve)
config.ts # relay config
auth.ts # relay auth
update.ts # relay update
sessions.ts # relay sessions
version.ts # relay version
doctor.ts # relay doctor
init.ts # relay init
core/ # Core modules
session-manager.ts
config-manager.ts
auth-manager.ts
hooks-engine.ts
context-monitor.ts
event-bus.ts
adapters/ # Backend adapters
base-adapter.ts
claude-adapter.ts
codex-adapter.ts
gemini-adapter.ts
adapter-registry.ts
flag-mapper.ts
install-guides.ts
mcp-server/ # MCP server mode
server.ts
recursion-guard.ts
tools/
spawn-agent.ts
list-sessions.ts
get-context-status.ts
infrastructure/ # Infrastructure
process-manager.ts
logger.ts
types/ # Type definitions
schemas/ # Zod validation schemasTech Stack
- Runtime: Node.js 22+
- Language: TypeScript
- Package manager: pnpm
- CLI framework: citty
- Bundler: tsup (esbuild-based)
- Backend SDKs: @anthropic-ai/claude-agent-sdk, @openai/codex-sdk
- MCP: @modelcontextprotocol/sdk
- Process management: execa (interactive modes, Gemini CLI)
- Validation: zod
- Logging: consola
- Testing: vitest (507 tests across 28 files)
- Coverage: @vitest/coverage-v8
License
Apache-2.0