ArborACP
ACP controller/client, native agent, and generic adapter runtime. This core package depends on arbor_rpc and contains no vendor adapter runtime modules. Add the optional arbor_acp_adapters package to use built-in Claude, Codex, Pi, or ZCode integrations.
Version 2.0.0-rc.1 is an unpublished implementation snapshot. ArborACP is the library name; its Hex package and OTP application are arbor_acp, and its module namespace is Arbor.ACP.*.
The planned prerelease is for downstream migration testing. See the v1 to v2 migration guide for replacing the v1 package/namespace and selecting the optional adapter bundle. Publication is pending; the stable-release 48-hour gate has not passed.
Installing the transitive arbor_rpc source package on macOS/Darwin or Linux
requires a C17 compiler, even when no subprocess is used. CC selects one
compiler executable. There is no prebuilt-helper promise; assembled releases
include the built helper and need no runtime compiler. Windows native subprocess
operations are unsupported; framing is separate. See the RPC source-install policy.
Installation
Use Elixir ~> 1.17 with a compatible OTP release. While RC1 is unpublished,
use reviewed local checkouts of the ACP workspace and the separate ArborRPC
repository. In a consumer project next to those checkouts:
defp deps do
[
{:arbor_rpc, path: "../arbor_rpc", override: true},
{:arbor_acp, path: "../arbor_acp/packages/arbor_acp"}
]
end
Adjust the paths to your checkout layout, then run mix deps.get. The explicit
RPC override replaces the unpublished transitive Hex dependency. Package
development instead uses ARBOR_RPC_PATH, as shown below. Once RC1 is actually
published, the planned Hex dependency is {:arbor_acp, "~> 2.0.0-rc.1"}; that
command is not an available installation route yet.
First session
The credential-free example starts a native Elixir echo agent, creates a session, prints streamed updates, and closes its subprocess. From this package directory:
export ARBOR_RPC_PATH=/absolute/path/to/arbor_rpc
export ARBOR_V2_LOCAL=1
mix deps.get
mix compile
mix run examples/acp/controller.exs
Expect streamed echo text followed by a prompt result containing
"stopReason" => "end_turn". ARBOR_V2_LOCAL=1 makes the controller forward
the local dependency settings to the child agent. No vendor CLI, account, or
API key is needed. See the example notes.
The ACP guide covers native client connections, session lifecycle, streaming, handlers, content, limits, registry discovery and writing an agent. For vendor CLIs, use the optional adapter package. See the changelog for the planned RC changes.
Runtime and custom adapters
Native agents implement Arbor.ACP.Agent.Handler and run with Arbor.ACP.run_agent/1. Controllers start with Arbor.ACP.start_client/1. Custom adapters implement Arbor.ACP.Adapter and use the generic bridge. Public Arbor.ACP.AdapterSupport helpers own name/value validation, workspace authorization, and adapter policy over shared RPC subprocess handles; adapter packages must not call core Internal modules.
Adapter.environment_defaults/1 is an optional callback for vendor-owned environment policy. It accepts unset values (false) and is applied after the generic baseline, before env/1 and explicit caller :env. Existing env/1 output stays unchanged.
Managed adapters identify frame credit with the pure optional subprocess_receipt/2 callback. The bridge ACKs after bounded output admission. shutdown/1 supports legacy state and explicit success/error tuples; bridge close exposes known cleanup failures. See the adapter subprocess contract for exact signatures and migration details.
Native child stdio also uses an owned shared handle. Temporary readers retain child lifetime, and filtered reads preserve the original deadline/cutoff. Direct subscribers use generation-tagged RPC events and explicit ACK. The built-in client keeps its bounded pull handoff; transport close and client disconnect expose known cleanup failures.
AdapterSupport.Subprocess.capture/4 runs finite utility commands with the same
adapter defaults, env/1, caller environment overrides and child PATH/cwd policy
as managed children. It combines stderr by default and returns original bytes
plus exit status. Its defaults are 5 seconds and 1 MiB; timeout, pressure and known
cleanup failures remain explicit. Each capturing caller owns the utility child,
including when a different :owner option is supplied. Cleanup uses its separate
finite budget after the read deadline; shared kernel/Port allocation and platform limits
still apply.
See examples/acp for a native echo agent and controller, and test/interop for the pinned official SDK probes. Legacy wire metadata and storage locations are preserved. Shared subprocess write admission, cleanup receipts and host-owned logging have revision-specific qualification checkpoints. The corrected RPC write handoff retains original deadlines and bounded credits. MCP owns its separate handler runtime/scheduler; broader platform coverage and completion of the final 48-hour stable-release gate remain pending.
Stdio host logging
The host owns logging policy. Agent stdio connection preserves Logger levels, handlers, filters and Application settings, including when using default stdio. Route every diagnostic handler to stderr or another non-protocol sink before starting applications. A release can use:
config :logger, :default_handler, config: [type: :standard_error]
Normal logging remains enabled. Standalone Mix tasks and the echo-agent example
explicitly route their own default handler to stderr before starting the agent;
they preserve its levels, filters and formatter. In an already running VM,
:logger_std_h requires replacing the host-owned handler to change its :type.
Mix.install/2 may still print dependency/compiler output to stdout; compiled
releases avoid that startup caveat.
Arbor.ACP.Internal.StdioLoggerConfig.configure/0 remains exported with its legacy
behavior as an explicit host opt-in. It sets :arbor_acp :stdio_mode and the
VM-global Logger, :logger application and OTP primary levels to :emergency.
It suppresses unrelated application logs and does not redirect them to stderr.
No transport calls it automatically in 2.0. The old :stdio_mode flag itself has
no automatic logger effect.
Standalone documentation
Clone ArborRPC separately while the dependency is unpublished. From the ACP workspace root, run:
cd packages/arbor_acp
export ARBOR_RPC_PATH=/absolute/path/to/arbor_rpc
MIX_ENV=dev mix deps.get
MIX_ENV=dev mix docs --warnings-as-errors
ExDoc is a dev-only dependency and does not run in consumer applications. Source
links use arbor_acp-v<version> and the packages/arbor_acp/ source prefix.
Version tags are created only for a reviewed release; this unpublished prerelease
snapshot does not imply that those prospective tags already exist.
See the contributor guide for package checks, optional interoperability suites and source-archive validation.