🛰️ export standalone-repo assets (c86caab7)

This commit is contained in:
2026-05-29 18:21:24 +02:00
parent d30783845a
commit f9347690e9
4 changed files with 325 additions and 676 deletions
+195 -217
View File
@@ -1,175 +1,148 @@
# Dirigate
# 𝄑 dirigate
ACP (Agent-Client Protocol) bridge and mock server for testing and proxying ACP connections.
**ACP bridge and mock server for AI agent orchestration.**
## Overview
Connect stdio-based ACP agents (Claude Code, Zed) to a remote Dirigent server — or run a fixture-backed mock for local development and testing.
`dirigate` provides tools for working with ACP clients and servers:
1. **Bridge Mode**: Relay stdio ACP clients to a Dirigent ACP Server via HTTP/SSE
2. **Mock Server**: Serve fixture-based responses for testing ACP clients
3. **Interactive Client**: Connect to ACP agents for debugging and exploration
## Features
- **Bridge Mode**: Connect external ACP clients (like Claude Code) to a Dirigent ACP Server
- **Fixture-based responses**: Define sessions and message flows in YAML for testing
- **Multiple response modes**: Static, random, sequential, and pattern-based
- **Session ingestion**: Import sessions from OpenCode.ai or other sources (feature-gated)
- **ACP compliance**: Full protocol implementation for testing clients
- **CLI tool**: Easy-to-use command-line interface
## Installation
### As a CLI Tool
> [!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.
```bash
cargo install --path packages/conductor
# Bridge Claude Code to a running Dirigent instance
dirigate bridge --server-url http://your-server:3001/acp
```
### As a Library
---
Add to your `Cargo.toml`:
## Dirigent Protocol and ACP
```toml
[dependencies]
conductor = { path = "../conductor" }
```
Dirigate speaks the **Dirigent Protocol**, which is a superset of the [Agent-Client Protocol (ACP)](https://github.com/anthropics/agent-protocol). 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).
For ingestion features:
**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.
```toml
[dependencies]
conductor = { path = "../conductor", features = ["ingest"] }
```
In short: dirigate is an **ACP adapter first**, Dirigent extension carrier second.
## Usage
---
### Bridge Mode (NEW)
## Why Dirigate
Bridge a stdio ACP client to a Dirigent ACP Server via HTTP/SSE:
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
```bash
# Connect to local server (default: http://localhost:3001/acp)
conductor bridge
cargo install --git https://git.g4b.org/dirigence/dirigate
```
# Connect to remote server
conductor bridge --server-url http://remote:3001/acp
Requires a working [Rust toolchain](https://rustup.rs).
# Via environment variable
---
## 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:
```bash
# Default ACP endpoint: http://localhost:3001/acp
DIRIGENT_ACP_ENABLED=true dirigent
```
### 2. Configure your ACP client
**Claude Code** — add to `.claude/settings.json`:
```json
{
"mcpServers": {
"dirigent": {
"command": "dirigate",
"args": ["bridge"]
}
}
}
```
**Zed** — add to `settings.json`:
```json
{
"agent_servers": {
"dirigent": {
"command": "dirigate",
"args": ["bridge"]
}
}
}
```
**Remote server:**
```bash
DIRIGENT_SERVER_URL=http://remote:3001/acp dirigate bridge
# With verbose logging
conductor bridge --verbose
```
**Bridge Architecture:**
```
External ACP Client (Claude Code, etc.)
|
| stdio (stdin/stdout)
v
+-------------------+
| Conductor Bridge |
| - stdin parser |
| - HTTP client |
| - SSE subscriber |
+-------------------+
|
| HTTP/SSE
v
Dirigent ACP Server
```
**Options:**
- `-s, --server-url <URL>` - ACP Server URL (env: `DIRIGENT_SERVER_URL`, default: `http://localhost:3001/acp`)
- `-v, --verbose` - Enable verbose logging of JSON-RPC messages
- `--timeout <SECS>` - Timeout for HTTP requests (default: 30)
- `--auto-reconnect` - Automatically reconnect SSE stream on disconnect (default: true)
**Use Case: Connecting Claude Code to Dirigent**
To use Claude Code with Dirigent:
1. Start the Dirigent web application (which includes the ACP Server)
2. Configure Claude Code to use a command-based ACP agent:
```
dirigate bridge
```
3. Claude Code will now communicate through Conductor to Dirigent
### Mock Server
Or with the flag:
```bash
conductor serve --fixtures ./fixtures --port 8080
dirigate bridge --server-url http://remote:3001/acp
```
Options:
- `-f, --fixtures <DIR>` - Directory containing fixture YAML files (default: `./fixtures`)
- `-p, --port <PORT>` - Port to bind the server to (default: `8080`)
- `--host <HOST>` - Host address to bind to (default: `127.0.0.1`)
- `--stdio` - Use stdin/stdout for JSON-RPC transport
- `-l, --log-level <LEVEL>` - Log level: trace, debug, info, warn, error (default: `info`)
- `--log-format <FORMAT>` - Log format: pretty, json, compact (default: `pretty`)
### Bridge options
### Validate Fixtures
| 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.
<p align="center">
<img src="rpc-buffering.svg" alt="RPC response buffering sequence diagram" width="760">
</p>
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:
```bash
conductor validate ./fixtures
dirigate serve --fixtures ./fixtures --port 8080
```
Validates fixture files without starting the server.
### Interactive Client
Connect to an ACP agent for debugging and exploration:
```bash
# Connect via stdio (spawns a process)
conductor connect --command "claude --acp" --auto-session
# Connect via HTTP
conductor connect --url http://localhost:8080 --auto-session
# Custom protocol version
conductor connect --command "claude --acp" --protocol-version 1 --auto-session
```
**Interactive Commands:**
- `/help` - Display available commands
- `/quit` - Exit the client
- `/session list` - List available sessions
- `/session new` - Create a new session
- `/session <id>` - Switch to a session
- `/cancel` - Cancel generation in current session
- Any other text - Send as message to current session
**Debugging:**
Enable detailed logging to see JSON-RPC packets:
```bash
# See all debug logs including packets
RUST_LOG=debug dirigate connect --command "claude --acp" --auto-session
# See event details
DIRIGENT_VERBOSE=1 dirigate connect --command "claude --acp" --auto-session
```
### Ingest Sessions (requires `ingest` feature)
```bash
conductor ingest \
-u http://localhost:12225 \
--session-id my-session-123 \
--output ./fixtures/my-session.yaml
```
Imports a session from an external source and converts it to fixture format.
## Fixture Format
Fixtures are defined in YAML files:
Fixtures are YAML files defining sessions and response behavior:
```yaml
version: "1"
@@ -182,106 +155,111 @@ streaming:
sessions:
- id: "session-123"
title: "Test Session"
created_at: "2025-01-01T00:00:00Z"
participants:
- id: "assistant"
name: "Assistant"
role: "agent"
messages:
- role: "agent"
content: "Hello! How can I help you?"
responders:
default_strategy: Echo
keyword_map: {}
```
### Response Modes
**Response modes:** `sequential`, `random`, `pattern`, `static`, `echo`
- **sequential**: Return messages in order (default)
- **random**: Return a random message from the fixture
- **pattern**: Match user input against patterns and return corresponding response
- **static**: Always return the same message
- **echo**: Echo back the user's input
**Server options:**
## Project Structure
| 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 |
```
conductor/
|-- src/
| |-- lib.rs # Library entry point
| |-- error.rs # Error types
| |-- logging.rs # Logging infrastructure
| |-- acp/ # ACP protocol implementation
| | |-- mod.rs
| | |-- bridge.rs # Bridge mode (stdio <-> HTTP/SSE)
| | |-- server.rs # HTTP server
| | |-- model.rs # Protocol types
| | |-- stdio.rs # Stdio transport
| | |-- stream.rs # SSE streaming
| |-- fixture/ # Fixture system
| | |-- mod.rs
| | |-- types.rs # Fixture definitions
| | |-- loader.rs # YAML loading
| | |-- responders.rs # Response logic
| |-- ingest/ # Session ingestion (feature-gated)
| | |-- mod.rs
| | |-- opencode.rs # OpenCode.ai ingestion
| |-- cli/ # CLI interface
| | |-- mod.rs
| | |-- args.rs # Argument parsing
| | |-- commands.rs # Command execution
| |-- bin/
| |-- conductor.rs # Binary entry point
|-- Cargo.toml
|-- README.md
```
---
## Configuration
## Interactive Client
### Environment Variables
| Variable | Description | Default |
|----------|-------------|---------|
| `DIRIGENT_SERVER_URL` | ACP Server URL for bridge mode | `http://localhost:3001/acp` |
| `CONDUCTOR_BUFFER_SIZE` | Broadcast channel buffer size for event distribution. Increase for high-volume event scenarios or when experiencing event drops during bursts. Valid values: Any positive integer (usize). Example: `CONDUCTOR_BUFFER_SIZE=500` | `100` |
| `RUST_LOG` | Log level | `info` |
| `DIRIGENT_VERBOSE` | Enable verbose event logging | (unset) |
## Testing
Run tests:
Connect to any ACP agent for debugging and exploration:
```bash
cargo test -p dirigate
# 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
```
Run with all features:
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:
```bash
cargo test -p dirigate --all-features
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
```
## Dependencies
---
### Core
- `clap` - CLI argument parsing
- `serde`, `serde_yaml`, `serde_json` - Serialization
- `tokio` - Async runtime
- `axum` - Web server
- `reqwest` - HTTP client (for bridge mode)
- `reqwest-eventsource` - SSE client (for bridge mode)
- `anyhow`, `thiserror` - Error handling
- `tracing`, `tracing-subscriber` - Logging
## Library Usage
### Optional (ingest feature)
- `dirigent_protocol` - Protocol types
- `opencode_client` - OpenCode.ai client
Dirigate ships as both a CLI tool and a library. To use it as a dependency:
```toml
# 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
```bash
# 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](https://git.g4b.org/dirigence/dirigent) monorepo and exported here
for standalone distribution. Issues and pull requests are accepted on the
`develop` branch, but canonical development happens upstream.
---
## License
Same as the Dirigent project.
Licensed under either of
## Contributing
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE))
- MIT License ([LICENSE-MIT](LICENSE-MIT))
See the main project README for contribution guidelines.
at your option.