zeph_acp/lib.rs
1// SPDX-FileCopyrightText: 2026 Andrei G <bug-ops>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! ACP (Agent Client Protocol) server for IDE embedding.
5//!
6//! `zeph-acp` exposes the Zeph agent over the Agent Client Protocol so that
7//! IDEs such as Zed can connect to it as a first-class AI assistant.
8//!
9//! # Architecture
10//!
11//! ```text
12//! IDE / client
13//! │ JSON-RPC over stdio / HTTP-SSE / WebSocket
14//! ▼
15//! transport ──► ZephAcpAgent (ACP SDK Agent impl)
16//! │
17//! ├─ AgentSpawner ──► agent loop (LoopbackChannel)
18//! ├─ AcpPermissionGate ──► IDE tool-call approval
19//! ├─ AcpFileExecutor ──► IDE fs/* proxying
20//! ├─ AcpShellExecutor ──► IDE terminal/* proxying
21//! └─ AcpLspProvider ──► IDE LSP ext_method proxying
22//! ```
23//!
24//! # Transports
25//!
26//! | Transport | Entry point | Feature flag |
27//! |-----------|-------------|--------------|
28//! | stdio (default) | [`serve_stdio`] | always |
29//! | HTTP + SSE | [`acp_router`] | `acp-http` |
30//! | WebSocket | [`acp_router`] | `acp-http` |
31//!
32//! # Feature flags
33//!
34//! | Flag | Description |
35//! |------|-------------|
36//! | `acp-http` | HTTP/SSE and WebSocket transports via axum |
37//! | `unstable-session-close` | ACP session close extension |
38//! | `unstable-session-fork` | ACP session fork extension |
39//! | `unstable-session-resume` | ACP session resume extension |
40//! | `unstable-session-usage` | ACP session token-usage extension |
41//! | `unstable-session-model` | ACP session model-switching extension |
42//! | `unstable-elicitation` | ACP elicitation schema types |
43//! | `unstable-logout` | ACP logout extension |
44//!
45//! # Quick start (stdio)
46//!
47//! ```rust,no_run
48//! use std::sync::Arc;
49//! use parking_lot::RwLock;
50//! use zeph_acp::{AgentSpawner, AcpServerConfig, serve_stdio};
51//!
52//! # async fn run() -> Result<(), zeph_acp::AcpError> {
53//! let spawner: AgentSpawner = Arc::new(|channel, ctx, session| {
54//! Box::pin(async move {
55//! // run your agent loop here
56//! drop((channel, ctx, session));
57//! })
58//! });
59//!
60//! let config = AcpServerConfig {
61//! agent_name: "my-agent".to_owned(),
62//! agent_version: "0.1.0".to_owned(),
63//! ..AcpServerConfig::default()
64//! };
65//!
66//! serve_stdio(spawner, config).await?;
67//! # Ok(())
68//! # }
69//! ```
70
71pub mod agent;
72pub mod client;
73pub(crate) mod custom;
74pub mod error;
75pub mod fs;
76pub mod lsp;
77pub mod mcp_bridge;
78pub mod permission;
79pub mod terminal;
80pub mod transport;
81
82pub use agent::{AcpContext, AgentSpawner, ProviderFactory, SessionContext, run_agent};
83pub use client::{
84 AcpClientError, RunOutcome, SubagentConfig, SubagentHandle, run_session, spawn_subagent,
85};
86pub use error::AcpError;
87pub use fs::AcpFileExecutor;
88pub use lsp::{AcpLspProvider, DiagnosticsCache, LspProvider};
89pub use mcp_bridge::acp_mcp_servers_to_entries;
90pub use permission::AcpPermissionGate;
91pub use terminal::AcpShellExecutor;
92pub use transport::{AcpServerConfig, serve_connection, serve_stdio};
93
94#[cfg(feature = "acp-http")]
95pub use agent::SendAgentSpawner;
96#[cfg(feature = "acp-http")]
97pub use transport::{AcpHttpState, acp_router};