Agent Client Protocol (ACP)
Run an interactive Kaya program as an ACP agent for clients such as Buzz
ACP is a small protocol boundary around Kaya. It lets an agent client start a session, send prompts, receive streamed updates, and attach MCP tools without moving execution or persistence out of Kaya.
ACP client β Rust ACP adapter (kaya-acp) β kayad session β interactive Kaya program
ββ session MCP toolsThe ACP adapter is a separate Rust binary (kaya-acp) built from source. It is
not included in the native standalone archive's kaya, kayad and
kaya-tool-server cohort. The source-build instructions and linked example
projects below require Kaya repository access.
From a repository checkout, configure the native model route, start the daemon and then run the adapter:
KAYA_CAPABILITY_APPROVAL_MODE=interactive kayad start
cargo run --manifest-path packages/kaya-core-rs/Cargo.toml -p kaya-acp -- /absolute/path/to/job.yamlor with the built binary:
kaya-acp /absolute/path/to/job.yamlStandard output is reserved for ACP JSON-RPC; startup messages and errors go
to standard error. The daemon must already be reachable before starting the
adapter. Programs using chat() without model need a configured session
default; see Text model bindings.
Write an ACP job
An ACP job has two pieces. job.yaml chooses the Kaya program and its initial
inputs:
program: ./main.kaya
inputs:
role: "A practical research assistant"The Kaya program supplies the behavior. It must stop at input() before the
first turn and return to input() after every response:
[system] "You are {{role}}. Be direct and show your work."
while true {
input()
chat(maxToolSteps: 20)
}This is the important distinction: a YAML file is a launch profile, not the agent itself. It points to a Kaya program and supplies inputs and storage settings. The program defines the agent loop. One adapter process can host several isolated client sessions using the same job profile.
A batch program that finishes, or one that never reaches its first input boundary, is rejected during ACP session creation.
Run a Kaya-native coding harness
The first-party
native-coding-agent
example is a coding harness implemented in Kaya itself. Its main.kaya owns
the system prompt, interactive turn loop, model-facing tool list, and
maxToolSteps budget. The engine owns tool-call correlation, suspension,
durable one-shot approvals, and provider lifecycle. The Rust tool server owns
the confined filesystem, Git, model, and sandboxed-command implementations.
That is different from a kaya:agent/run@1 profile. An agent profile starts a
Claude, Codex, OpenCode, or Agy CLI as a child and treats that executable as the
coding harness. The native profile starts no external coding-agent executable;
the model calls Kaya capabilities directly. Build, test, and formatter commands
are still ordinary CLI programs, but they run inside the host-selected,
network-disabled toolchain container rather than becoming native Kaya
implementations.
Copy the example manifests, then replace every placeholder workspace/database path, the model binding, and the immutable toolchain image digest. The filesystem and repository roots must name the same checkout. The configured image must already exist in Docker; the provider never pulls it or falls back to a host shell.
Start the authenticated provider service from the repository root:
export KAYA_TOOL_SERVER_TOKEN='replace-with-a-long-random-token'
export OPENAI_API_KEY='...'
export KAYA_CODING_MODEL='replace-with-a-model-id'
cargo run \
--manifest-path packages/kaya-core-rs/Cargo.toml \
-p kaya-tool-server -- serve \
--manifest /absolute/path/to/tool-server.jsonThen point the daemon host at the matching client manifest and start the ACP agent:
export KAYA_TOOL_SERVER_ENDPOINT=http://127.0.0.1:8789
export KAYA_TOOL_CLIENT_MANIFEST=/absolute/path/to/tool-client.json
kaya-acp packages/kaya-core-rs/kaya-acp/examples/native-coding-agent/job.yamlThe daemon must be started as an interactive approval host. Read-only,
idempotent, closed-workspace inspection runs without interruption. Contextual
patches and sandboxed commands produce an ACP session/request_permission
request and consume the answer only for the exact invocation shown. Start or
restart it explicitly with:
KAYA_CAPABILITY_APPROVAL_MODE=interactive kayad serveUse fail-closed instead for a headless deployment. An unset mode preserves
legacy daemon behavior and installs no coding policy. Kaya never infers that an
approval UI exists from the transport alone. A denied, mismatched, stale, or
replayed answer is rejected before provider dispatch. If the engine cannot
certify whether a started mutation completed, it reports an indeterminate
outcome and does not automatically retry it.
The job's tools block is the session's complete capability authority. Every
model and coding tool has an explicit kaya.model.* or kaya.tool.* alias,
semantic interface/operation, authenticated attachment, and provider selector.
The empty default map in tool-client.example.json proves that the program
does not inherit ambient tools. Roots, executables, container policy,
credentials, and upstream model IDs remain host configuration and never enter
Kaya source or model-visible schemas.
This split also makes provider substitution deliberate: a deployment can bind
kaya.model.native-coding or any tool alias to another conforming provider
without changing main.kaya. Conversely, changing the prompt, tool selection,
turn structure, or tool-step budget requires no engine or provider change.
If setup fails, inspect these boundaries in order:
/v1/catalogmust contain each exact interface/operation admitted by the server token.job.yamlmust grant the same operation and select the configured attachment and provider IDs.KAYA_TOOL_CLIENT_MANIFESTmust be present in the daemon process environment, not only in a later client process.- An existing daemon must be restarted to receive changed tool-client or approval-host environment.
MCP tools from the client
An ACP client can attach stdio MCP servers to session/new. Kaya starts each
server lazily for that daemon session, discovers its tools, and keeps it alive
across turns. Tools are namespaced as:
<server-name>__<tool-name>When generate() or chat() omits tools, the attached MCP tools enter its
model-facing catalog. An explicit literal tools list selects the requested
names; include the exact <server-name>__<tool-name> for each attached tool
that call needs. Kaya function references can share the same list.
MCP launch environment values often contain credentials. Kaya keeps the descriptors in memory, does not copy them into job inputs, and closes the MCP processes with the session.
Native text generation dispatches these calls through Kaya's session MCP
gateway. The selected model alias still needs an admitted text-model route
(its exact grant or an explicitly granted default) and a configured provider
binding that supports the requested tool-calling contract.
Attaching an MCP server creates no model binding. Host-configured named tools
separately require their exact session grants, such as kaya.tool.read_range.
Coding-agent presets use the separate kaya:agent/run@1 route and their own
provider configuration. A provider name or installed coding-agent executable
does not establish compatibility with client-attached MCP. Inspect the selected
binding and structured diagnostic instead of inferring support from a model
family name. See Supported Models.
Workspace metadata
The client's primary working directory becomes the Kaya session's project folder and the MCP subprocess working directory. Additional workspace roots are rejected by default. If a program needs that non-secret metadata, opt in:
kaya-acp ./job.yaml --acp-input-key acpThe job then receives acp.cwd and acp.additionalDirectories. MCP commands
and environment values remain separate from inputs.
Security
A client-provided MCP command can run local code with the daemon user's permissions. The local CLI daemon accepts it by default so desktop agent clients work without extra setup. For a daemon reachable by untrusted clients, disable the capability:
KAYA_DISABLE_CLIENT_MCP=true kayad serveCLI-agent presets additionally enforce the active profile's agentic LLM policy.
Cancellation and lifecycle
ACP cancellation currently stops the whole Kaya session. Kayad does not yet have a safe βabort only this turnβ operation, so a cancelled ACP session cannot accept another prompt. This guarantees that its model and MCP tools are not still running after cancellation is reported.
The adapter speaks stable ACP v1. It supports initialization, new sessions, prompts, streamed text and tool events, capability approval permission prompts, cancellation, and multiple concurrent sessions.
Next: connect a Kaya agent to Buzz.