⚠️ Alpha — work in progress. This adapter now covers the core ACP tocodex app-serverbridge, but both Codex app-server and the ACP projection are still evolving. APIs and behavior may change before a stable release. Use at your own risk, pin a specific version, and expect sharp edges. Feedback and issues are welcome.
Brokk Codex ACP is an Agent Client Protocol server for Codex.
The project is intentionally built around codex app-server instead of linking
directly against unstable Codex internals. The ACP server should stay thin:
translate ACP requests and notifications to the app-server protocol, then let
Codex own threads, turns, skills, tools, apps, plugins, MCP, models, and
permissions.
See PLANS.md for the implementation plan.
Alpha. The adapter has a working app-server-backed ACP serving path with session lifecycle, turn streaming, approvals, skills, app/plugin/MCP catalog commands, config options, and history replay. It is still stabilizing against Codex app-server API changes and ACP extension decisions, so breaking changes should be expected until a stable release.
The project currently includes:
- Cargo package metadata.
- GPL-3.0-or-later licensing metadata.
- A CLI with
probeandservecommands. - A JSON-RPC client that can spawn and initialize
codex app-server --stdio. - An ACP serving loop backed by
agent-client-protocol. - ACP handlers for
initialize,session/new,session/load,session/resume,session/list,session/close,session/delete,session/fork,session/prompt, andsession/cancel. session/forkis exposed through the ACP Rust crate's unstable RFD/extension feature, not as stable ACP v1 behavior.session/listpreserves app-server thread preview, status, recency, model provider, agent, session, path, ephemeral, fork, and parent-thread metadata under_meta.brokk_codex_acp, and reports previously observed additional directories from adapter state persisted under Codex home.- Initial prompt streaming from Codex
item/agentMessage/deltanotifications to ACP agent message chunks. - Text, resource-link, embedded resource, and image prompt blocks routed to
Codex app-server
turn/startinputs. Embedded resources are passed through app-serveradditionalContext. ACPContentBlock::Audiois not advertised because app-serverturn/starthas no matching user-input variant; realtime audio is exposed through the/realtimecommands instead. - Initial turn event projection for reasoning chunks and summary boundaries, command/file/tool item lifecycles, command output, structured plan updates, plan text deltas, turn diffs, and usage updates.
- Initial skills discovery through app-server
skills/list, projected as ACP available commands for enabled skills alongside adapter-owned commands. - Structured
$skill-nameand/skill skill-nameinvocation when app-server returns a skill path, with plain-text fallback otherwise. - Structured app and plugin mention invocation when app-server catalogs resolve
$app-slugor@plugin-nameprompt tokens, with plain-text fallback otherwise. - App-server
skills/config/writemapping for skill enable/disable state, exposed through ACP session config options namedskill:<name>. - App-server
skills/extraRoots/setmapping through/skill-roots <paths...>; roots are process-local and not persisted by Codex app-server. - Initial slash-command routing for
/rename <title>,/archive,/goal,/compact,/config [cwd],/config-requirements,/review,/init,/new,/resume,/fork,/delete,/account,/login,/login-cancel <loginId>,/logout,/apps,/plugins,/plugin <pluginName@marketplacePath>,/plugin-install <pluginName@marketplacePath>,/plugin-skill <remoteMarketplaceName> <remotePluginId> <skillName>,/plugin-uninstall <pluginId>,/marketplace-add <source> [ref] [sparsePathsCsv],/marketplace-remove <name>,/marketplace-upgrade [name],/feature <name> enable|disable,/features,/rate-limits,/realtime start [text|audio],/realtime text <role> <text>,/realtime speech <text>,/realtime audio <base64> <sampleRate> <channels> [samples],/realtime stop,/realtime voices,/remote-control [status|enable|disable],/usage,/workspace-messages,/mcp,/mcp-login <server>,/mcp-refresh,/mcp-reload,/mcp-resource <server> <uri>,/mcp-tool <server> <tool> [json-arguments],/hooks,/memory,/model,/model-provider,/permissions,/ps,/skill-roots,/stop, and/status, mapped to app-server thread, review, catalog, and config endpoints with ACP session update, turn-stream, config-option, or agent-message summary projection as appropriate. Unsupported leading slash commands return an explicit ACP error instead of being forwarded to the model. - Initial command, file-change, and permission-profile approval routing from
app-server approval requests to ACP
session/request_permission, with the selected decision sent back to app-server in the response shape each app-server request expects. Rich command approval decisions such as exec-policy and network-policy amendments keep their original app-server payload and are returned unchanged when selected. - App-server automatic approval review lifecycle notifications are projected as user-visible ACP diagnostics without changing approval decision flow.
- Server-initiated
currentTime/readrequests are answered with the adapter host's current Unix timestamp so external-clock reminders do not block turns. - Server-initiated
mcpServer/elicitation/requestform and URL requests are bridged to ACPelicitation/createwhen the client can answer them, with the explicit cancel fallback preserved for clients without that surface. - Server-initiated
tool/requestUserInputanditem/tool/requestUserInputrequests are bridged to ACPelicitation/createform requests when the client can answer them, with explicit empty-answer fallbacks preserved. - App-server
serverRequest/resolvednotifications are projected as compact ACP diagnostics so clients can observe approval and elicitation cleanup. - Unsupported server-initiated app-server requests receive explicit JSON-RPC method-not-found errors instead of being silently ignored.
- Unexpected
attestation/generaterequests receive an explicit JSON-RPC failure because this adapter does not provide a native attestation token. - Thread-scoped and app-scoped MCP server startup status notifications are projected as user-visible ACP diagnostic messages.
- Global app-server configuration warnings are projected as user-visible ACP diagnostic messages for every known session.
- Global Windows sandbox setup completion notifications are projected as user-visible ACP diagnostic messages for every known session.
- Global account, rate-limit, and MCP OAuth login notifications are projected as user-visible ACP diagnostic messages for every known session.
- App list update notifications are projected as user-visible ACP diagnostic messages for every known session.
- Global remote-control status notifications are projected as user-visible ACP diagnostic messages for every known session.
- Fuzzy file search session progress and completion notifications are projected as compact user-visible ACP diagnostic messages.
- Model reroute, safety-buffering, and verification notifications are projected as user-visible ACP diagnostic messages.
- Turn moderation metadata notifications are projected as user-visible ACP diagnostic messages.
- Thread realtime lifecycle, SDP, raw item, transcript text, and output-audio notifications are projected as user-visible ACP diagnostic messages. Audio payloads are summarized because ACP v1 has no native realtime audio stream.
- Initial ACP session config options for
model,reasoning_effort,service_tier,approval_policy,collaboration_mode, andpermission_profile, populated from app-servermodel/list,collaborationMode/list, andpermissionProfile/list, with writes routed throughthread/settings/update. - Dynamic tool callbacks are routed through a custom ACP extension request
(
_brokk_codex_acp/dynamic_tool_call) when the client can answer, with the existing explicit failure response kept as the fallback for clients that do not implement the extension. - File-change tool updates, including live patch updates, emit structured ACP
diffcontent for app-server{path, diff}entries, while turn-level unified diff previews remain text because app-server does not attach per-file old/new content to those events. - Background app-server response/notification dispatch, including refresh of
skill commands, session titles, and session config options when
skills/changed,thread/name/updated,thread/archived,thread/status/changed,thread/goal/updated,thread/goal/cleared, orthread/settings/updatednotifications are observed.
Native realtime audio playback remains deferred because ACP v1 has no realtime
audio stream surface; output-audio events are summarized as diagnostics today.
History replay converts the known app-server item variants and falls back to
raw diagnostics for newly added variants until they get first-class ACP
projections. Terminal content is currently projected through Codex app-server
command output and terminal interaction events; ACP terminal/create embedding
should only be added if app-server exposes a client-terminal handoff instead of
owning command execution itself.
Verify that Codex app-server can start:
cargo run -- probeUse a custom Codex binary:
cargo run -- probe --codex-bin /path/to/codexStart the ACP server:
cargo run -- servecargo fmt
cargo clippy --all-targets --all-features -- -D warnings
cargo testRun the opt-in smoke test against a real local Codex app-server:
BROKK_CODEX_ACP_SMOKE_CODEX_BIN=/path/to/codex \
cargo test --test real_app_server_smoke -- --ignoredThe ignored smoke suite checks initialization, basic app-server catalogs, and thread lifecycle primitives against the configured Codex binary. It may create and delete a temporary Codex thread.
Releases are cut from v*.*.* tags. The GitHub release workflow verifies that
the tag version matches Cargo.toml, builds archives, and uploads SHA-256
checksums for:
x86_64-unknown-linux-gnuaarch64-unknown-linux-gnux86_64-pc-windows-msvcuniversal-apple-darwin
Android is intentionally not part of the required release matrix for now because Codex itself does not currently compile for Android.
The crate publishing workflow follows the same tag discipline. On tag pushes it
verifies the Cargo.toml version, runs cargo publish --dry-run, authenticates
with crates.io trusted publishing, and publishes brokk-codex-acp. Manual
workflow runs default to dry-run mode unless publish is explicitly enabled.
Before the first publish, configure crates.io trusted publishing for this
repository, the .github/workflows/publish-crate.yml workflow, and the
release GitHub environment.
This project is licensed under GPL-3.0-or-later.