claudeacp

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 6, 2026 License: GPL-3.0 Imports: 44 Imported by: 0

README

acp-go-claude

Go ACP agent that exposes the local Claude Code CLI as an Agent Client Protocol agent.

Go Reference CI

It wraps the local claude CLI, speaks ACP over JSON-RPC streams, and builds on github.com/coder/acp-go-sdk.

Use it as either:

  • a standalone ACP subprocess: acp-go-claude
  • an embedded Go adapter through claudeacp.Serve

Install

Library:

go get github.com/savid/acp-go-claude

CLI:

go install github.com/savid/acp-go-claude/cmd/acp-go-claude@latest

The acp-go-claude binary speaks ACP over stdin/stdout; an editor or ACP host launches it as a subprocess rather than a human-facing chat UI.

Quickstart

The example programs run from a checkout of this repo, so clone it first:

git clone https://github.com/savid/acp-go-claude && cd acp-go-claude

Run a tiny local client against the agent:

go run ./examples/minimal-client "Reply with a short hello from ACP."

Start an interactive session against the agent:

go run ./examples/interactive-chat

Load and resume a stored session transcript:

go run ./examples/resume-from-file -file ./examples/resume-from-file/session.jsonl

Embedded Go

package main

import (
	"context"
	"log"
	"os"

	claudeacp "github.com/savid/acp-go-claude"
)

func main() {
	err := claudeacp.Serve(context.Background(), os.Stdin, os.Stdout,
		claudeacp.WithDefaultModel("sonnet"),
	)
	if err != nil {
		log.Fatal(err)
	}
}

See the Go API reference for options such as the Claude executable path, config home, scratch directory, default model, session storage, permissions, raw events, and OpenTelemetry providers.

What It Provides

  • ACP session lifecycle: create, prompt, cancel, close, list, load, resume, and extension-based fork.
  • Claude stream-json subprocess management and control-protocol handling.
  • Prompt streaming for messages, thoughts, tool calls, tool results, plans, usage, and session metadata.
  • Embedded static PNG, JPEG, GIF, and WebP prompt images, or the same images handed over as digest-verified local files under a configured read root, plus typed image and resource-link output from native assistant and tool results.
  • Structured output through session-level JSON Schema.
  • Permission modes, permission prompts, plan mode, elicitation, and AskUserQuestion bridging.
  • MCP stdio and HTTP server declarations.
  • Brokered Claude subscription login, setup-token entry, and Anthropic API-key entry over session-scoped _claude/auth/* extension methods. Secret methods use one-shot typed credential harvest and session injection; they never write native credential files.
  • Store-authoritative transcript mirroring, in-memory by default and replaceable with a host-provided SessionStore for cross-process durability.
  • Optional raw Claude stream-json extension notifications.
  • OpenTelemetry spans, metrics, trace propagation, and structured logs without recording prompt or tool secrets by default.
  • Authoritative native-process containment on Linux. Windows native launch fails closed because its process API cannot apply the mandatory Unix UID/GID identity boundary with empty supplementary groups; cross-compilation proves only that this refusal path builds, not runtime support. Darwin fails closed by default and has an explicit best-effort opt-in for operators who accept escaped-descendant and numeric-PGID-reuse risks.

Slash Commands

Claude Code slash commands are projected into ACP AvailableCommand entries and refreshed as the session's command set changes. A slash-prefixed prompt runs the corresponding Claude command.

Docs

Full Go API reference: pkg.go.dev/github.com/savid/acp-go-claude.

Development

make audit
make test-integration-smoke
make test-integration-live
make test-integration-cover

make audit runs the full local gate: format, lint, build, unit tests, coverage, cross-compile, vuln, and docs checks. Live integration tests require a local authenticated claude CLI and are double-gated: the integration build tag plus ACP_GO_CLAUDE_RUN_INTEGRATION=1. make test-integration-smoke runs the integration tier without spending model tokens; tests that spend tokens additionally require ACP_GO_CLAUDE_RUN_LIVE_TOKENS=1, which only make test-integration-live sets. make test-integration-cover runs the integration tier against a coverage-instrumented binary. Set ACP_GO_CLAUDE_MODEL to override the live model. Live tests always launch Claude with an isolated temp CLAUDE_CONFIG_DIR; set ACP_GO_CLAUDE_HOME to choose the source config copied into it. When process env auth is present and ACP_GO_CLAUDE_HOME is unset, tests use a fresh temp home; otherwise they copy the source home and clear copied refresh tokens. If neither env auth nor copied portable file auth is available, tests fail rather than launch without isolated auth.

License

Distributed under the GNU General Public License v3.0. See LICENSE.

Documentation

Overview

Package claudeacp exposes the local Claude Code CLI as an Agent Client Protocol agent.

Most hosts run the agent over a pair of JSON-RPC streams using Serve. Serve starts Claude sessions on demand, maps ACP requests into Claude CLI stream-json/control-protocol messages, and streams ACP session updates back to the client. Hosts must complete ACP initialization before issuing session or other agent methods.

Hosts should use Serve for the JSON-RPC transport. Claude authentication and account configuration remain owned by the local Claude Code installation.

Hosts that need durable remote resume can provide WithSessionStore. A session store receives Claude transcript mirror rows, can back session/list, and can hydrate Claude JSONL into a temporary Claude config directory under the scratch directory (WithScratchDir; default: the system temp directory) for session/load or session/resume when the local Claude transcript is absent.

Prompts may carry embedded base64 image blocks (static PNG, JPEG, GIF, and WebP), validated before the turn starts, and native image results are emitted as typed ACP image or resource-link content. WithImageLimits bounds decoded image bytes in both directions.

Hosts that need adapter telemetry can provide OpenTelemetry providers with WithTracerProvider and WithMeterProvider. The package never configures global OpenTelemetry providers; the acp-go-claude binary handles env-based exporter setup for command-line use. Caller-supplied providers remain owned by the caller, including ForceFlush and Shutdown.

Hosts that need deterministic Claude sessions can use WithClaudeBareMode or per-session ClaudeOptions to launch Claude with --bare.

Linux uses authoritative native-process containment. Windows refuses native launch because it cannot apply the mandatory Unix UID/GID isolation. Darwin rejects native launch unless WithDarwinBestEffortContainment is supplied; that explicit mode reaps the direct child and empties its captured original process group but cannot contain descendants that escape with setsid.

Index

Examples

Constants

View Source
const (
	ForkSessionMethod = "_claude/session/fork"
	RawEventMethod    = "_claude/rawEvent"
	RateLimitsMethod  = "_claude/rateLimits"
)
View Source
const (
	AuthMethodsMethod    = "_claude/auth/methods"
	AuthAuthorizeMethod  = "_claude/auth/authorize"
	AuthCallbackMethod   = "_claude/auth/callback"
	AuthStatusMethod     = "_claude/auth/status"
	AuthCancelMethod     = "_claude/auth/cancel"
	AuthInventoryMethod  = "_claude/auth/inventory"
	AuthCredentialMethod = "_claude/auth/credential" //nolint:gosec // Protocol method name, not a credential.
	AuthDisconnectMethod = "_claude/auth/disconnect"
)

Session-scoped provider-auth extension methods.

View Source
const (
	SessionStoreFormat      = "claude-transcript-jsonl-v1"
	SessionStoreMainSubpath = ""
)

Variables

View Source
var ErrProcessContainmentIncomplete = claude.ErrProcessContainmentIncomplete

ErrProcessContainmentIncomplete means the selected native containment boundary did not complete.

Functions

func CallForkSession

CallForkSession calls the Claude fork extension method and decodes the SDK payload shape.

func CancelRequest

func CancelRequest(sessionID acp.SessionId, turnNonce string) acp.CancelNotification

CancelRequest builds an active-turn cancellation carrying the mandatory route nonce. A blank or oversized nonce leaves Meta nil so cancellation is rejected fail-closed.

func DeleteSessionRequest

func DeleteSessionRequest(sessionID acp.SessionId) acp.UnstableDeleteSessionRequest

DeleteSessionRequest constructs a session/delete request.

func ForkSessionRequest

func ForkSessionRequest(sessionID acp.SessionId, cwd string, opts ...SessionRequestOption) acp.UnstableForkSessionRequest

ForkSessionRequest constructs params for the Claude fork extension method.

func HTTPMCPServer

func HTTPMCPServer(name string, url string, headers map[string]string) acp.McpServer

HTTPMCPServer constructs an ACP HTTP MCP server declaration.

func ListSessionsRequest

func ListSessionsRequest(opts ...ListSessionsRequestOption) acp.ListSessionsRequest

ListSessionsRequest constructs a session/list request.

func LoadSessionRequest

func LoadSessionRequest(sessionID acp.SessionId, cwd string, opts ...SessionRequestOption) acp.LoadSessionRequest

LoadSessionRequest constructs a session/load request with ACP-required empty slices initialized for embedded Go callers.

func NewSessionRequest

func NewSessionRequest(cwd string, opts ...SessionRequestOption) acp.NewSessionRequest

NewSessionRequest constructs a session/new request with ACP-required empty slices initialized for embedded Go callers.

func PromptRequest

func PromptRequest(sessionID acp.SessionId, turnNonce string, blocks ...acp.ContentBlock) acp.PromptRequest

PromptRequest constructs a session/prompt request with a non-nil prompt slice for embedded Go callers. A blank or oversized turn nonce leaves Meta nil so the receiving agent rejects the request fail-closed.

func ResumeSessionRequest

func ResumeSessionRequest(sessionID acp.SessionId, cwd string, opts ...SessionRequestOption) acp.ResumeSessionRequest

ResumeSessionRequest constructs a session/resume request.

func Serve

func Serve(ctx context.Context, input io.Reader, output io.Writer, opts ...Option) (serveErr error)

Serve runs an ACP agent over the provided streams.

Example (Initialize)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

clientToAgentReader, clientToAgentWriter := io.Pipe()
agentToClientReader, agentToClientWriter := io.Pipe()
defer clientToAgentReader.Close()
defer clientToAgentWriter.Close()
defer agentToClientReader.Close()
defer agentToClientWriter.Close()

done := make(chan error, 1)
go func() {
	done <- Serve(ctx, clientToAgentReader, agentToClientWriter)
}()

_, _ = fmt.Fprintln(clientToAgentWriter, `{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":1}}`)
line, _ := bufio.NewReader(agentToClientReader).ReadString('\n')
cancel()
_ = clientToAgentWriter.Close()
<-done

var response struct {
	Result struct {
		AuthMethods       []any `json:"authMethods"`
		AgentCapabilities struct {
			LoadSession     bool `json:"loadSession"`
			McpCapabilities struct {
				Http bool `json:"http"`
			} `json:"mcpCapabilities"`
		} `json:"agentCapabilities"`
	} `json:"result"`
}
_ = json.Unmarshal([]byte(line), &response)

fmt.Println(len(response.Result.AuthMethods) == 0)
fmt.Println(response.Result.AgentCapabilities.LoadSession)
fmt.Println(response.Result.AgentCapabilities.McpCapabilities.Http)
Output:
true
true
true

func SetConfigOptionRequest

func SetConfigOptionRequest(
	sessionID acp.SessionId,
	configID acp.SessionConfigId,
	value acp.SessionConfigValueId,
) acp.SetSessionConfigOptionRequest

SetConfigOptionRequest constructs a value-id session/set_config_option request.

func SetModelRequest

func SetModelRequest(sessionID acp.SessionId, model string) acp.SetSessionConfigOptionRequest

SetModelRequest constructs a model selector update request.

func StdioMCPServer

func StdioMCPServer(name string, command string, args []string, env map[string]string) acp.McpServer

StdioMCPServer constructs an ACP stdio MCP server declaration.

func TextPromptRequest

func TextPromptRequest(sessionID acp.SessionId, turnNonce, text string) acp.PromptRequest

TextPromptRequest constructs a session/prompt request containing one text content block.

Types

type Agent

type Agent struct {
	// contains filtered or unexported fields
}

Agent exposes Claude Code through ACP.

func NewAgent

func NewAgent(opts ...Option) *Agent

NewAgent creates an ACP agent for Claude Code.

func (*Agent) Authenticate

func (a *Agent) Authenticate(ctx context.Context, params acp.AuthenticateRequest) (resp acp.AuthenticateResponse, err error)

Authenticate rejects agent-handled auth methods because Claude owns auth.

func (*Agent) Cancel

func (a *Agent) Cancel(ctx context.Context, params acp.CancelNotification) (err error)

Cancel interrupts an active Claude turn for the session.

func (*Agent) Close

func (a *Agent) Close() error

Close cancels and closes all resources owned by the agent.

func (*Agent) CloseSession

func (a *Agent) CloseSession(ctx context.Context, params acp.CloseSessionRequest) (resp acp.CloseSessionResponse, err error)

CloseSession closes a Claude session process and removes it from the active map.

func (*Agent) ContainmentMode

func (a *Agent) ContainmentMode() RuntimeContainmentMode

ContainmentMode reports the effective platform process boundary.

func (*Agent) HandleExtensionMethod

func (a *Agent) HandleExtensionMethod(ctx context.Context, method string, params json.RawMessage) (any, error)

HandleExtensionMethod handles Claude-specific ACP extension methods. A closed agent rejects every extension call up front (-32600), before method dispatch and before any parameter validation.

func (*Agent) Initialize

func (a *Agent) Initialize(ctx context.Context, params acp.InitializeRequest) (resp acp.InitializeResponse, err error)

Initialize implements ACP initialize.

func (*Agent) ListSessions

func (a *Agent) ListSessions(ctx context.Context, params acp.ListSessionsRequest) (resp acp.ListSessionsResponse, err error)

ListSessions lists active sessions and sessions held by the authoritative store.

func (*Agent) LoadSession

func (a *Agent) LoadSession(ctx context.Context, params acp.LoadSessionRequest) (resp acp.LoadSessionResponse, err error)

LoadSession resumes a Claude session and replays saved transcript updates when available.

func (*Agent) Logout

Logout clears auth state owned by this adapter.

func (*Agent) NewSession

func (a *Agent) NewSession(ctx context.Context, params acp.NewSessionRequest) (resp acp.NewSessionResponse, err error)

NewSession creates and starts a Claude CLI session.

func (*Agent) Prompt

func (a *Agent) Prompt(ctx context.Context, params acp.PromptRequest) (resp acp.PromptResponse, err error)

Prompt sends a user prompt to Claude and streams ACP session updates until the turn ends.

func (*Agent) ResumeSession

func (a *Agent) ResumeSession(ctx context.Context, params acp.ResumeSessionRequest) (resp acp.ResumeSessionResponse, err error)

ResumeSession resumes a Claude session without replaying previous updates.

func (*Agent) SetSessionConfigOption

SetSessionConfigOption handles supported configuration changes.

func (*Agent) SetSessionMode

SetSessionMode exists only because github.com/coder/acp-go-sdk's generated Agent interface still requires it. Remove this when the upstream SDK drops session/set_mode; the local ACP dispatcher intentionally does not route it.

func (*Agent) UnstableDeleteSession

func (a *Agent) UnstableDeleteSession(
	ctx context.Context,
	params acp.UnstableDeleteSessionRequest,
) (acp.UnstableDeleteSessionResponse, error)

UnstableDeleteSession implements ACP session/delete.

type ClaudeOption

type ClaudeOption func(*ClaudeOptions)

ClaudeOption configures ClaudeOptions values.

func WithClaudeBare

func WithClaudeBare(enabled bool) ClaudeOption

WithClaudeBare configures Claude bare mode.

func WithClaudeEnv

func WithClaudeEnv(env map[string]string) ClaudeOption

WithClaudeEnv configures Claude session environment overrides.

func WithClaudeExtraPathDirs

func WithClaudeExtraPathDirs(dirs ...string) ClaudeOption

WithClaudeExtraPathDirs prepends absolute directories to the PATH of this session's Claude process, in the order given and ahead of every inherited entry. A relative or empty entry fails the session-lifecycle request.

func WithClaudeModel

func WithClaudeModel(model string) ClaudeOption

WithClaudeModel configures the initial Claude model.

func WithClaudeOutputSchema

func WithClaudeOutputSchema(schema map[string]any) ClaudeOption

WithClaudeOutputSchema configures Claude JSON Schema structured output.

func WithClaudePermissionMode

func WithClaudePermissionMode(mode string) ClaudeOption

WithClaudePermissionMode configures the initial Claude permission mode.

func WithClaudeSystemPrompt

func WithClaudeSystemPrompt(prompt string) ClaudeOption

WithClaudeSystemPrompt configures the Claude session system prompt.

type ClaudeOptions

type ClaudeOptions struct {
	// Model selects the initial Claude model for this session.
	Model string `json:"model,omitempty"`
	// Bare launches Claude with --bare for this session.
	Bare bool `json:"bare,omitempty"`
	// Env adds environment variables for this Claude session.
	Env map[string]string `json:"env,omitempty"`
	// ExtraPathDirs are absolute directories prepended, in order, to the PATH of
	// this session's Claude process. They precede every inherited entry, so an
	// executable placed here shadows the one PATH would otherwise resolve. Raw
	// PATH stays rejected in Env: this is the only supported way to extend it.
	ExtraPathDirs []string `json:"extraPathDirs,omitempty"`
	// OutputSchema configures Claude Code JSON Schema structured output.
	OutputSchema map[string]any `json:"outputSchema,omitempty"`
	// SystemPrompt overrides the default system prompt for this Claude session.
	SystemPrompt string `json:"systemPrompt,omitempty"`
	// PermissionMode selects the initial Claude permission mode for this session.
	PermissionMode string `json:"permissionMode,omitempty"`
	// ProviderAuth carries host-owned credentials into one session launch.
	ProviderAuth map[string]ProviderAuthBinding `json:"providerAuth,omitempty"`
}

ClaudeOptions is the stable, supported Claude-specific subset accepted at _meta.claude.options. The JSON field names below are part of this package's wire contract; unsupported option keys are rejected.

func NewClaudeOptions

func NewClaudeOptions(opts ...ClaudeOption) ClaudeOptions

NewClaudeOptions constructs ClaudeOptions from functional options.

func (ClaudeOptions) Meta

func (options ClaudeOptions) Meta() map[string]any

Meta returns an ACP _meta object for the supported Claude-specific options.

type ConcurrencyLimits

type ConcurrencyLimits struct {
	MaxActiveSessions        int
	MaxConcurrentClientCalls int
}

ConcurrencyLimits controls per-agent/session backpressure. Zero fields use defaults.

type ImageLimits

type ImageLimits struct {
	MaxInputBytesPerImage     int64
	MaxInputBytesPerPrompt    int64
	MaxOutputBytesPerImage    int64
	MaxOutputBytesPerToolCall int64
}

ImageLimits controls decoded image bytes at the ACP boundary.

type InMemorySessionStore

type InMemorySessionStore struct {
	// contains filtered or unexported fields
}

func NewInMemorySessionStore

func NewInMemorySessionStore() *InMemorySessionStore

func (*InMemorySessionStore) Append

func (s *InMemorySessionStore) Append(ctx context.Context, key SessionKey, entries []SessionStoreEntry) error

func (*InMemorySessionStore) Delete

func (s *InMemorySessionStore) Delete(ctx context.Context, key SessionKey) error

func (*InMemorySessionStore) ListSessions

func (s *InMemorySessionStore) ListSessions(ctx context.Context) ([]SessionSummary, error)

func (*InMemorySessionStore) ListSubkeys

func (s *InMemorySessionStore) ListSubkeys(ctx context.Context, key SessionKey) ([]string, error)

func (*InMemorySessionStore) Load

func (*InMemorySessionStore) Replace

func (s *InMemorySessionStore) Replace(ctx context.Context, main SessionKey, replacements []SessionStoreReplacement) error

type ListSessionsRequestOption

type ListSessionsRequestOption func(*acp.ListSessionsRequest)

ListSessionsRequestOption configures embedded-Go session/list requests.

func WithListSessionsCursor

func WithListSessionsCursor(cursor string) ListSessionsRequestOption

WithListSessionsCursor sets the cursor for session/list pagination.

func WithListSessionsCwd

func WithListSessionsCwd(cwd string) ListSessionsRequestOption

WithListSessionsCwd filters session/list by cwd.

func WithListSessionsMeta

func WithListSessionsMeta(meta map[string]any) ListSessionsRequestOption

WithListSessionsMeta sets metadata on a session/list request.

type Option

type Option func(*Options)

Option configures the Claude ACP agent.

func WithAgentName

func WithAgentName(name string) Option

WithAgentName sets the protocol identifier advertised during ACP initialize.

func WithAgentTitle

func WithAgentTitle(title string) Option

WithAgentTitle sets the human-readable agent name advertised during ACP initialize.

func WithAgentVersion

func WithAgentVersion(version string) Option

WithAgentVersion sets the agent version advertised during ACP initialize and used by adapter OpenTelemetry instrumentation.

func WithClaudeAllowSkipPermissionsFlag

func WithClaudeAllowSkipPermissionsFlag(enabled bool) Option

WithClaudeAllowSkipPermissionsFlag permits adding Claude's skip-permissions capability flag.

func WithClaudeBareMode

func WithClaudeBareMode(enabled bool) Option

WithClaudeBareMode launches Claude sessions with --bare. Bare mode disables Claude's automatic project/context discovery and keychain/OAuth auth; explicit ACP-provided MCP config, system prompt, additional directories, and API-key/apiKeyHelper auth are still passed.

func WithClaudeControlHandlerTimeout

func WithClaudeControlHandlerTimeout(timeout time.Duration) Option

WithClaudeControlHandlerTimeout bounds one inbound Claude control request.

func WithClaudeDefaultPermissionMode

func WithClaudeDefaultPermissionMode(mode string) Option

WithClaudeDefaultPermissionMode sets the initial Claude permission mode.

func WithClaudeDefaultSystemPrompt

func WithClaudeDefaultSystemPrompt(prompt string) Option

WithClaudeDefaultSystemPrompt sets the system prompt passed to Claude sessions.

func WithClaudeDirectAPI

func WithClaudeDirectAPI(enabled bool) Option

WithClaudeDirectAPI controls whether the adapter may call the Anthropic API itself. It is enabled by default and only affects `_claude/rateLimits`: when the harness reports no usage windows the adapter reads them from the API, which can cost a one-token inference request. Disable it to guarantee the adapter never opens a connection of its own; `_claude/rateLimits` then reports only what the harness prints.

func WithClaudeHideAuth

func WithClaudeHideAuth(enabled bool) Option

WithClaudeHideAuth suppresses Claude subscription terminal auth methods.

func WithClaudeInitializeTimeout

func WithClaudeInitializeTimeout(timeout time.Duration) Option

WithClaudeInitializeTimeout bounds the Claude control-protocol initialize request.

func WithClaudeSettingSources

func WithClaudeSettingSources(sources ...SettingSource) Option

WithClaudeSettingSources configures Claude Code filesystem settings sources passed as --setting-sources. With no arguments, user/project/local sources are disabled for launched Claude sessions.

func WithClaudeSettingsFile

func WithClaudeSettingsFile(relpath string) Option

WithClaudeSettingsFile registers a settings-overlay file loaded on top of the base settings.json. relpath is confined to the resolved Claude config directory (the same anchor as WithSeedFiles) and passed to the Claude CLI as --settings <abspath>. It requires an explicit Home: setting it without a resolvable home, an absolute path, a ".." escape, or an empty key fails closed at session start.

func WithConcurrencyLimits

func WithConcurrencyLimits(limits ConcurrencyLimits) Option

WithConcurrencyLimits sets process-local backpressure limits. Zero fields use defaults.

func WithDarwinBestEffortContainment

func WithDarwinBestEffortContainment() Option

WithDarwinBestEffortContainment opts into the explicitly limited Darwin process-group backend. It is invalid on every non-Darwin platform.

func WithDefaultModel

func WithDefaultModel(model string) Option

WithDefaultModel selects a Claude model for newly created sessions.

func WithEnv

func WithEnv(env map[string]string) Option

WithEnv adds environment variables to every launched Claude process. Managed config and identity root variables are rejected during agent initialization.

func WithExecutablePath

func WithExecutablePath(path string) Option

WithExecutablePath sets the Claude CLI executable path. If unset, PATH is searched.

func WithHome

func WithHome(path string) Option

WithHome sets CLAUDE_CONFIG_DIR for launched Claude CLI sessions.

func WithImageLimits

func WithImageLimits(limits ImageLimits) Option

WithImageLimits sets decoded image byte limits. Zero fields disable the corresponding adapter policy limit.

func WithInputHandoffRoot

func WithInputHandoffRoot(dir string) Option

WithInputHandoffRoot sets the absolute directory prompt images may be handed over in as local files instead of embedded base64. An image block with empty `data`, a `file://` uri under this root, and a valid handoff envelope is read and digest-verified before it reaches Claude. The directory is read-only to the adapter, which never writes, moves, or deletes anything under it, and it is the host's to create and clean up. Unset (the default) rejects every handoff-form block; a relative path fails initialization.

func WithLogger

func WithLogger(logger *slog.Logger) Option

WithLogger configures structured diagnostic logging.

func WithMeterProvider

func WithMeterProvider(provider metric.MeterProvider) Option

WithMeterProvider configures the OpenTelemetry meter provider used for adapter metrics. If unset, metrics are no-ops.

func WithProcessIsolation

func WithProcessIsolation(isolation ProcessIsolation) Option

WithProcessIsolation requires every native process to run as the supplied uid/gid with no supplementary groups. BaseEnvironment is the complete native environment base; the adapter never overlays os.Environ.

func WithProviderAuthDirectHome

func WithProviderAuthDirectHome(path string) Option

WithProviderAuthDirectHome names the exact canonical Claude config directory the operator consents to `_claude/auth/disconnect` clearing, which is an account-level removal in a home the operator also uses. The leg is advertised and answers only while this equals the configured Home after path cleaning; it authorizes exactly that directory, never a parent, a child, or a symlink target of it. Unset (the default) advertises six legs instead of seven.

func WithProviderAuthRoot

func WithProviderAuthRoot(path string) Option

WithProviderAuthRoot sets the absolute host-owned durable directory holding the adapter's values-free provider-auth ledger. The ledger records which native slot each connection generation owns and never credential material, authorization URLs, or pasted values. The directory is created 0700 when missing and entries are written 0600. Unset (the default), unusable, or relative leaves every `_claude/auth/*` leg absent from the capability advertisement and answering method-not-found. A configured ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN, CLAUDE_CODE_OAUTH_TOKEN, an agent-wide settings credential, apiKeyHelper, or bare mode does the same because it overrides or ignores the durable login this surface installs; a relative path additionally fails initialization.

func WithRuntimeResourceHooks

func WithRuntimeResourceHooks(hooks RuntimeResourceHooks) Option

WithRuntimeResourceHooks installs host-facing native-root and scratch-root admission hooks.

func WithScratchDir

func WithScratchDir(dir string) Option

WithScratchDir sets the parent directory for all ephemeral on-disk materialization (per-session roots, hydration temp files, probe dirs). Empty means the system temp directory. The directory is created 0700 when missing.

func WithSeedFiles

func WithSeedFiles(files map[string]string) Option

WithSeedFiles registers files written into the session's resolved Claude config directory before the Claude CLI launches. Keys are paths relative to that directory and values are the file contents (e.g. settings.json). Paths are confined to the config directory: absolute paths, ".." escapes, and empty keys fail closed at session start.

func WithSessionStore

func WithSessionStore(store SessionStore) Option

WithSessionStore replaces the default in-memory session authority with a host store.

func WithSessionStoreLoadTimeout

func WithSessionStoreLoadTimeout(timeout time.Duration) Option

WithSessionStoreLoadTimeout bounds session store reads used during restore and listing.

func WithTextMapPropagator

func WithTextMapPropagator(propagator propagation.TextMapPropagator) Option

WithTextMapPropagator configures trace-context propagation for ACP _meta and Claude process launch environment. If unset, W3C trace context plus baggage propagation is used.

func WithTracerProvider

func WithTracerProvider(provider trace.TracerProvider) Option

WithTracerProvider configures the OpenTelemetry tracer provider used for adapter spans. If unset, tracing is a no-op.

func WithTurnTimeout

func WithTurnTimeout(timeout time.Duration) Option

WithTurnTimeout bounds one Claude prompt turn. Zero (the default) disables the deadline. On expiry the native turn is aborted and session/prompt fails with a claude_turn_failed error whose cause is "timeout" (never cancelled).

type Options

type Options struct {
	// AgentName is the protocol identifier advertised during ACP initialize.
	AgentName string
	// AgentTitle is the human-readable agent name advertised during ACP initialize.
	AgentTitle string
	// AgentVersion is the agent version advertised during ACP initialize.
	AgentVersion string

	// ExecutablePath is the Claude CLI executable path. If empty, PATH is searched.
	ExecutablePath string
	// Home sets CLAUDE_CONFIG_DIR for launched Claude CLI sessions.
	Home string
	// ScratchDir is the parent directory for all ephemeral on-disk
	// materialization (per-session roots, hydration temp files, probe dirs).
	// Empty means the system temp directory.
	ScratchDir string
	// InputHandoffRoot is the absolute directory a host hands prompt-image
	// bytes over in. It is a read root only: nothing is ever written, moved, or
	// deleted under it. Empty rejects every handoff-form image block.
	InputHandoffRoot string
	// ProviderAuthRoot is the absolute host-owned durable directory holding the
	// adapter's values-free provider-auth ledger. Empty, bare mode, or
	// agent-wide static authentication leaves every `_claude/auth/*` leg
	// unadvertised.
	ProviderAuthRoot string
	// ProviderAuthDirectHome is the exact canonical Claude config directory the
	// operator consents to a provider-auth leg clearing. Empty, or unequal to
	// Home, leaves `_claude/auth/disconnect` unadvertised.
	ProviderAuthDirectHome string
	// DefaultModel is passed to newly created Claude sessions when non-empty.
	DefaultModel string
	// Env is merged into every launched Claude process environment. Managed
	// config and identity root variables are rejected.
	Env map[string]string
	// ProcessIsolation is the mandatory process boundary for every native
	// launch. Configure it with WithProcessIsolation.
	ProcessIsolation *ProcessIsolation

	// Logger receives structured diagnostic logs. If nil, the default logger is used.
	Logger *slog.Logger
	// TracerProvider records adapter spans. If nil, tracing is a no-op.
	TracerProvider trace.TracerProvider
	// MeterProvider records adapter metrics. If nil, metrics are no-ops.
	MeterProvider metric.MeterProvider
	// TextMapPropagator extracts ACP _meta trace context and injects Claude launch env.
	// If nil, W3C trace context plus baggage propagation is used.
	TextMapPropagator propagation.TextMapPropagator

	// SessionStore replaces the default in-memory authority for transcript discovery and restore.
	SessionStore SessionStore
	// SessionStoreLoadTimeout bounds store reads used for restore and listing.
	SessionStoreLoadTimeout time.Duration
	// ConcurrencyLimits controls process-local backpressure.
	ConcurrencyLimits ConcurrencyLimits
	// ImageLimits controls decoded image bytes accepted from prompts and
	// emitted in session updates.
	ImageLimits ImageLimits
	// SeedFiles maps paths relative to the resolved Claude config directory to
	// file contents written into that directory before each Claude CLI session
	// launches, so the launched CLI reads them as its own config (e.g.
	// settings.json).
	SeedFiles map[string]string
	// SettingsFile is a path relative to the resolved Claude config directory
	// passed to the Claude CLI as --settings, loading an additional settings
	// layer on top of the base settings.json. It requires an explicit Home.
	SettingsFile string

	// DirectAPI allows the adapter to make its own outbound calls to the
	// Anthropic API. It is only consulted by `_claude/rateLimits`, which falls
	// back to the API when the harness reports no usage windows — that fallback
	// may issue a billable one-token inference request against the configured
	// account. Enabled by default; disable it to keep the adapter from
	// contacting any network service on its own behalf.
	DirectAPI bool

	// DefaultPermissionMode is the initial Claude permission mode.
	DefaultPermissionMode string
	// DefaultSystemPrompt is passed to newly created Claude sessions when non-empty.
	DefaultSystemPrompt string
	// HideAuth suppresses Claude subscription terminal auth methods.
	HideAuth bool
	// BareMode launches Claude with --bare for deterministic sessions that opt
	// out of Claude's automatic project/context discovery. Bare mode also
	// requires explicit API-key or apiKeyHelper auth.
	BareMode bool
	// SettingSources controls Claude Code filesystem settings sources loaded by
	// the Claude CLI. Nil uses the adapter default: user, project, local. An
	// empty slice passes --setting-sources= and disables those sources.
	SettingSources []SettingSource

	// AllowSkipPermissionsFlag permits adding Claude's skip-permissions capability flag.
	AllowSkipPermissionsFlag bool
	// InitializeTimeout bounds the Claude control-protocol initialize request.
	InitializeTimeout time.Duration
	// ControlHandlerTimeout bounds one inbound Claude control request.
	ControlHandlerTimeout time.Duration
	// TurnTimeout bounds one Claude prompt turn. Zero (the default) means no
	// deadline. On expiry the turn is aborted and fails with cause "timeout".
	TurnTimeout          time.Duration
	RuntimeResourceHooks RuntimeResourceHooks
	// DarwinBestEffortContainment explicitly accepts Darwin's process-group
	// boundary and its escaped-descendant and numeric-PGID-reuse risks.
	DarwinBestEffortContainment bool
	// contains filtered or unexported fields
}

Options configures the ACP agent process and the Claude CLI sessions it starts.

type ProcessIdentityLockCapability

type ProcessIdentityLockCapability interface {
	Duplicate() (*os.File, error)
}

ProcessIsolation defines the complete operating-system identity and base environment inherited by every native Claude process.

type ProcessIsolation

type ProcessIsolation struct {
	UID                 uint32
	GID                 uint32
	BaseEnvironment     map[string]string
	StandaloneOwnerID   string
	StandaloneStateRoot string
	// IdentityLock is an optional trusted-supervisor descriptor for the
	// host-global UID lock. Linux supervisors validate it and never expose it to
	// the native Claude process. Standalone embeddings should leave it nil.
	IdentityLock    ProcessIdentityLockCapability
	AuthorityDomain ProcessIdentityLockCapability
}

type ProviderAPICredential

type ProviderAPICredential struct {
	Key      string            `json:"key"`
	Metadata map[string]string `json:"metadata"`
}

type ProviderAuthBinding

type ProviderAuthBinding struct {
	ConnectionID      string             `json:"connectionId"`
	Revision          int64              `json:"revision"`
	BindingGeneration int64              `json:"bindingGeneration"`
	Credential        ProviderCredential `json:"credential"`
}

type ProviderCredential

type ProviderCredential struct {
	Type ProviderCredentialType
	API  *ProviderAPICredential
}

func (ProviderCredential) MarshalJSON

func (credential ProviderCredential) MarshalJSON() ([]byte, error)

func (*ProviderCredential) UnmarshalJSON

func (credential *ProviderCredential) UnmarshalJSON(data []byte) error

type ProviderCredentialType

type ProviderCredentialType string
const ProviderCredentialAPI ProviderCredentialType = "api"

type RateLimitWindow

type RateLimitWindow struct {
	// ID is the vendor-native window id, e.g. "session" or "week-all-models".
	ID string `json:"id"`
	// UsedPercent is the harness-reported percentage of the window consumed.
	UsedPercent float64 `json:"usedPercent"`
	// ResetsAt is the RFC3339 reset time, omitted when not reported.
	ResetsAt string `json:"resetsAt,omitempty"`
}

RateLimitWindow is one harness-reported subscription usage window.

type RateLimitsResponse

type RateLimitsResponse struct {
	Windows  []RateLimitWindow `json:"windows"`
	PlanType string            `json:"planType,omitempty"`
}

RateLimitsResponse is the `_claude/rateLimits` response payload. Windows is empty when the harness reports no subscription usage; values are only ever harness-reported.

type RuntimeContainmentMode

type RuntimeContainmentMode string

RuntimeContainmentMode identifies the selected native process boundary.

const (
	RuntimeContainmentAuthoritative RuntimeContainmentMode = "authoritative"
	RuntimeContainmentBestEffort    RuntimeContainmentMode = "best_effort"
	RuntimeContainmentUnavailable   RuntimeContainmentMode = "unavailable"
)

type RuntimeProcessKind

type RuntimeProcessKind string
const (
	RuntimeProcessHomeLockSupervisor RuntimeProcessKind = "home_lock_supervisor"
	RuntimeProcessProviderDescendant RuntimeProcessKind = "provider_descendant"
)

type RuntimeResourceHooks

type RuntimeResourceHooks struct {
	AcquireNativeRoot      func(context.Context, RuntimeResourceKind) (func(), error)
	ReserveScratchRoot     func(context.Context, RuntimeResourceKind) (func(), error)
	ObserveProcess         func(context.Context, RuntimeProcessKind, int64)
	ObserveProcessSnapshot func(context.Context, RuntimeProcessKind, int)
	ObserveStartupStage    func(context.Context, RuntimeResourceKind, RuntimeStartupStage, time.Duration, error)
	ObserveContainment     func(context.Context, RuntimeContainmentMode)
}

RuntimeResourceHooks lets an embedding host enforce native-root and scratch-root limits.

type RuntimeResourceKind

type RuntimeResourceKind string

RuntimeResourceKind identifies the lifecycle scope consuming a host-managed resource.

const (
	RuntimeResourceRuntime   RuntimeResourceKind = "runtime"
	RuntimeResourceSession   RuntimeResourceKind = "session"
	RuntimeResourcePrompt    RuntimeResourceKind = "prompt"
	RuntimeResourceDiscovery RuntimeResourceKind = "discovery"
)

type RuntimeStartupStage

type RuntimeStartupStage string
const (
	RuntimeStartupSpawn         RuntimeStartupStage = "spawn"
	RuntimeStartupReadiness     RuntimeStartupStage = "readiness"
	RuntimeStartupConfiguration RuntimeStartupStage = "configuration"
	RuntimeStartupSession       RuntimeStartupStage = "session"
)

type SessionKey

type SessionKey struct {
	SessionID string
	Subpath   string
}

type SessionRequestOption

type SessionRequestOption func(*sessionRequestConfig)

SessionRequestOption configures embedded-Go ACP session lifecycle requests.

func WithSessionAdditionalDirectories

func WithSessionAdditionalDirectories(paths ...string) SessionRequestOption

WithSessionAdditionalDirectories sets additional workspace directories for a session lifecycle request.

func WithSessionClaudeOptions

func WithSessionClaudeOptions(options ClaudeOptions) SessionRequestOption

WithSessionClaudeOptions merges Claude-specific options into a session lifecycle request's _meta.claude.options object.

func WithSessionMCPServers

func WithSessionMCPServers(servers ...acp.McpServer) SessionRequestOption

WithSessionMCPServers sets MCP servers for a session lifecycle request.

func WithSessionMeta

func WithSessionMeta(meta map[string]any) SessionRequestOption

WithSessionMeta merges metadata into a session lifecycle request.

func WithSessionOutputSchema

func WithSessionOutputSchema(schema map[string]any) SessionRequestOption

WithSessionOutputSchema sets Claude JSON Schema structured output for a session lifecycle request.

func WithSessionRawEvents

func WithSessionRawEvents(enabled bool) SessionRequestOption

WithSessionRawEvents toggles raw Claude event emission for a session lifecycle request.

type SessionStore

type SessionStore interface {
	Append(ctx context.Context, key SessionKey, entries []SessionStoreEntry) error
	Load(ctx context.Context, key SessionKey) ([]SessionStoreEntry, error)
	Replace(ctx context.Context, main SessionKey, replacements []SessionStoreReplacement) error
	Delete(ctx context.Context, key SessionKey) error
	ListSessions(ctx context.Context) ([]SessionSummary, error)
	ListSubkeys(ctx context.Context, key SessionKey) ([]string, error)
}

type SessionStoreEntry

type SessionStoreEntry = json.RawMessage

type SessionStoreReplacement

type SessionStoreReplacement struct {
	Key     SessionKey
	Entries []SessionStoreEntry
}

type SessionSummary

type SessionSummary struct {
	SessionID          string
	UpdatedAtUnixMilli int64
	Cwd                string
	Title              string
	Meta               map[string]any
}

type SettingSource

type SettingSource string

SettingSource selects one Claude Code filesystem settings source.

const (
	// SettingSourceUser loads user-level Claude settings and user Claude Code features.
	SettingSourceUser SettingSource = "user"
	// SettingSourceProject loads project-level Claude settings and Claude Code features from the session cwd.
	SettingSourceProject SettingSource = "project"
	// SettingSourceLocal loads local project Claude settings and local Claude Code features from the session cwd.
	SettingSourceLocal SettingSource = "local"
)

Directories

Path Synopsis
cmd
acp-go-claude command
examples
minimal-client command
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL