7.5 KiB
𝄑 dirigate
ACP bridge and mock server for AI agent orchestration.
Connect stdio-based ACP agents (Claude Code, Zed) to a remote Dirigent server — or run a fixture-backed mock for local development and testing.
Caution
Alpha software. Dirigate is under active development and not fully battle-tested. The ACP specification itself is still evolving, and dirigate tracks it on a best-effort basis. APIs and CLI flags may change between releases.
# Bridge Claude Code to a running Dirigent instance
dirigate bridge --server-url http://your-server:3001/acp
Dirigent Protocol and ACP
Dirigate speaks the Dirigent Protocol, which is a superset of the Agent-Client Protocol (ACP). Dirigent Protocol started as an early attempt at an HTTP-based ACP implementation and carries additional signaling used by the Dirigent orchestration platform (session lifecycle, multi-agent coordination, archival events).
The goal is full ACP parity at all times. As the ACP HTTP specification evolves, dirigate tracks it and aims to provide a fully ACP-compliant smart adapter as its primary function. The Dirigent-specific extensions ride alongside as optional protocol signals — an ACP-only client can ignore them entirely and still get a conformant experience.
In short: dirigate is an ACP adapter first, Dirigent extension carrier second.
Why Dirigate
ACP clients speak JSON-RPC over stdio. Dirigent listens over HTTP/SSE. Dirigate bridges the two — reliably, with correct streaming semantics.
The core challenge: an ACP server returns the JSON-RPC response immediately, but the actual agent output keeps arriving as SSE chunks. If the bridge naively forwards the response right away, the client thinks the turn is done and stops listening — before the content has arrived.
Dirigate solves this with RPC response buffering: the response is held until turn.complete arrives via SSE, so all chunks and notifications reach the client first, and the response arrives last. The client gets clean "all content, then done" semantics — exactly what stdio JSON-RPC expects.
Feature Overview
| Mode | Command | Maturity | Description |
|---|---|---|---|
| Bridge | dirigate bridge |
beta | Relay a stdio ACP client to a Dirigent ACP Server over HTTP/SSE |
| Mock server | dirigate serve |
beta | Fixture-based ACP server for client development and testing |
| Interactive client | dirigate connect |
concept | Debug and explore any ACP agent interactively |
| Session ingest | dirigate ingest |
concept | Import sessions from OpenCode.ai into fixture format (requires ingest feature) |
Install
cargo install --git https://git.g4b.org/dirigence/dirigate
Requires a working Rust toolchain.
Quick Start: Bridge Mode
Bridge mode is the primary use case. It lets any stdio ACP client reach a remote Dirigent server.
1. Start Dirigent
Start the Dirigent server with the ACP server enabled:
# Default ACP endpoint: http://localhost:3001/acp
DIRIGENT_ACP_ENABLED=true dirigent
2. Configure your ACP client
Claude Code — add to .claude/settings.json:
{
"mcpServers": {
"dirigent": {
"command": "dirigate",
"args": ["bridge"]
}
}
}
Zed — add to settings.json:
{
"agent_servers": {
"dirigent": {
"command": "dirigate",
"args": ["bridge"]
}
}
}
Remote server:
DIRIGENT_SERVER_URL=http://remote:3001/acp dirigate bridge
Or with the flag:
dirigate bridge --server-url http://remote:3001/acp
Bridge options
| Flag | Env | Default | Description |
|---|---|---|---|
-s, --server-url |
DIRIGENT_SERVER_URL |
http://localhost:3001/acp |
ACP server URL |
-v, --verbose |
false | Log all JSON-RPC messages | |
--timeout |
30 | HTTP request timeout in seconds | |
--auto-reconnect |
true | Reconnect SSE stream on disconnect |
Architecture: RPC Response Buffering
The bridge implements a minimal buffering mechanism that preserves real-time streaming while maintaining correct JSON-RPC request/response pairing over stdio.
Without buffering, the client would receive the "id":1 response at the moment the HTTP POST returns — before any chunks arrive — and immediately consider the turn complete. Dirigate holds that response until turn.complete signals that all content has been delivered.
What is buffered: only the final RPC response (approximately 50 bytes). What is not buffered: all chunks and notifications, forwarded immediately as they arrive.
Mock Server
Start a fixture-backed ACP server for testing ACP clients without a running agent:
dirigate serve --fixtures ./fixtures --port 8080
Fixtures are YAML files defining sessions and response behavior:
version: "1"
streaming:
enabled: true
tokens_per_chunk: 4
chunk_interval_ms: 50
sessions:
- id: "session-123"
title: "Test Session"
messages:
- role: "agent"
content: "Hello! How can I help you?"
responders:
default_strategy: Echo
Response modes: sequential, random, pattern, static, echo
Server options:
| Flag | Default | Description |
|---|---|---|
-f, --fixtures |
./fixtures |
Fixture directory |
-p, --port |
8080 |
Bind port |
--host |
127.0.0.1 |
Bind address |
--stdio |
false | Use stdio transport instead of HTTP |
Interactive Client
Connect to any ACP agent for debugging and exploration:
# Spawn a local agent over stdio
dirigate connect --command "my-agent --acp" --auto-session
# Connect to an HTTP ACP server
dirigate connect --url http://localhost:8080 --auto-session
Interactive commands:
| Command | Description |
|---|---|
/session list |
List available sessions |
/session new |
Create a new session |
/session <id> |
Switch to a session |
/cancel |
Cancel current generation |
/quit |
Exit |
| (any text) | Send as a message to the current session |
Session Ingest (feature-gated)
Import sessions from OpenCode.ai into fixture format:
cargo install --git https://git.g4b.org/dirigence/dirigate --features ingest
dirigate ingest \
-u http://localhost:12225 \
--session-id my-session-123 \
--output ./fixtures/my-session.yaml
Library Usage
Dirigate ships as both a CLI tool and a library. To use it as a dependency:
# Cargo.toml
[dependencies]
dirigate = { git = "https://git.g4b.org/dirigence/dirigate" }
# With session ingestion support
dirigate = { git = "https://git.g4b.org/dirigence/dirigate", features = ["ingest"] }
Debugging
# Verbose JSON-RPC logging
dirigate bridge --verbose
# Full debug output via RUST_LOG
RUST_LOG=debug dirigate bridge --verbose
# Trace level for maximum detail
RUST_LOG=trace dirigate bridge --verbose
About This Repository
This is a downstream mirror. Dirigate is developed inside the upstream
Dirigent monorepo and exported here
for standalone distribution. Issues and pull requests are accepted on the
develop branch, but canonical development happens upstream.
License
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT License (LICENSE-MIT)
at your option.