Files
dirigate/README.md
T
2026-05-29 18:21:24 +02:00

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.

RPC response buffering sequence diagram

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

at your option.