bmaexecutor

package module
v1.2.0 Latest Latest
Warning

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

Go to latest
Published: Nov 8, 2026 License: Apache-2.0 Imports: 35 Imported by: 0

README

bma-executor-sdk

Connect your machine (hands) or your own agent (brain) to BMA — the executor, harness and agent ends of the bma.executor protocol.

bma-sdk drives and uses agents (REST / façade client); bma-executor-sdk connects hands or brains to BMA.

Go, TypeScript and Python SDKs for the BMA (BeeOS Managed Agents) Executor Protocol bma.executor.v1.1, with protocol types generated from the contract in contracts/bma/executor and handwritten runtimes. bmad is built on the Go SDK, and the BMA server speaks the same contract.

Moved from beeos-ai/bma-sdks (archived) in 0.4.9. The Go import path changed from github.com/beeos-ai/bma-sdks/executor to github.com/beeos-ai/bma-executor-sdk; the npm and PyPI package names are unchanged.

Language Package Install
Go Go Reference github.com/beeos-ai/bma-executor-sdk (package bmaexecutor, this directory) go get github.com/beeos-ai/bma-executor-sdk@v1.0.2
TypeScript npm @beeos-ai/bma-executor-sdk npm install @beeos-ai/bma-executor-sdk@1.0.2
Python PyPI bma-executor-sdk (bma_executor_sdk) pip install bma-executor-sdk==1.0.2
Version 1.0.0 (tag v1.0.0, all three languages), see CHANGELOG
Protocol bma.executor.v1.1 (the harness also accepts v1; contract 1.1.0, lock.json)
Runtimes Go 1.24+, Node.js 20+ (ESM), Python 3.10+
Integration guide docs/executor (中文)
I want to Start here
Understand roles, deployment shapes and what is available Overview (中文)
Write an executor (a "hand" the BMA cloud or a local brain drives) Quick start (中文), then the protocol reference (中文)
Drive an executor (be the harness / local brain) Local connection and auth (中文) and Harness below and in the TypeScript and Python READMEs
Connect a full local agent (turns in, agent events out) Agent capability (中文)

The rest of this README is the Go module; see typescript/README.md and python/README.md for the other languages.

Executor quick start

An executor registers with BMA (or a local harness) and answers tool calls:

package main

import (
	"context"
	"errors"
	"log"
	"os"
	"os/exec"

	bmaexecutor "github.com/beeos-ai/bma-executor-sdk"
)

func main() {
	client, err := bmaexecutor.NewClient(bmaexecutor.Options{
		BaseURL:        os.Getenv("BMA_BASE_URL"),
		EnvironmentKey: os.Getenv("BMA_ENVIRONMENT_KEY"),
		EnvironmentID:  os.Getenv("BMA_ENVIRONMENT_ID"),
		Executor:       bmaexecutor.ExecutorInfo{Name: "my-executor", OS: "linux", Arch: "arm64", Version: "0.1.0"},
	})
	if err != nil {
		log.Fatal(err)
	}
	// One typed slot per built-in tool; only registered tools are advertised.
	client.Tools.Bash.Handle(func(ctx context.Context, in bmaexecutor.BashInput, tool bmaexecutor.ToolContext) (bmaexecutor.ToolOutput, error) {
		out, err := exec.CommandContext(ctx, "bash", "-lc", in.Command).Output()
		code := 0
		var exitErr *exec.ExitError
		if errors.As(err, &exitErr) {
			code = exitErr.ExitCode()
		} else if err != nil {
			return bmaexecutor.ToolOutput{}, err // outcome failed
		}
		return bmaexecutor.BashResult{Stdout: string(out), ExitCode: code}.Output(), nil
	})
	if _, err := client.Start(context.Background()); err != nil {
		log.Fatal(err)
	}
	select {}
}

Set Options.BaseURL to your BMA deployment: the hosted service is in early access and the default DefaultBaseURL (https://api.bma.beeos.ai) does not resolve yet. It is the deployment origin, the same value as BMA_BASE_URL in bma-sdk (for example https://api.staging.bma.beeos.ai); the SDK posts an environment key to {BaseURL}/v1/environments/{EnvironmentID}/token and a machine daemon token to {BaseURL}/v1/machines/{MachineID}/token (the channel URL comes back in the token response as ws_url), uploads artifacts to {BaseURL}/v1/environments/{EnvironmentID}/artifacts, and drops a trailing /api/v1 (the 0.x bma-sdk API-root form) instead of nesting the paths. The SDK does not read BMA_BASE_URL itself; the example passes it through. A TokenSource (for example StaticToken) carries its own channel URL.

A machine-scoped executor sets Options.MachineID (empty reads BMA_MACHINE_ID; EnvironmentID and MachineID are alternatives) with the machine daemon token in EnvironmentKey, or uses a machine token through Options.TokenSource. Without a machine id the client falls back to the legacy /api/v1/executors/token alias. Go clients negotiate bma.executor.v1.1 by default (Options.Protocol).

A machine-scoped executor must declare process or agent

The platform binds a machine-scoped connection as the machine's runtime, and refuses the registration of an executor that advertises neither the process nor the agent capability: it answers executor.register, then closes with 4002 "runtime registration refused". The default Options.Capabilities (shell and files only) is such an executor. Declare process (and serve process.*) or agent (ServeAgent), and give Executor.Version as MAJOR.MINOR.PATCH:

core, _ := bmaexecutor.NewCore(bmaexecutor.CoreOptions{WorkRoot: dir})
_ = core.Register(bmaexecutor.NewProcessCapability(core, bmaexecutor.ProcessOptions{})) // advertises process.enabled
client, _ := bmaexecutor.NewClient(bmaexecutor.Options{
	TokenSource:  bmaexecutor.StaticToken(wsURL, machineToken), // or a token source that exchanges the machine token
	Executor:     bmaexecutor.ExecutorInfo{Name: "my-machine", OS: "linux", Arch: "arm64", Version: "1.0.0"},
	Capabilities: core.Capabilities(),
})
_ = core.Attach("cloud", client)
_, _ = client.Start(ctx)
if err := client.WaitReady(ctx); err != nil { // registered and still open one heartbeat later
	log.Fatal(err)
}

The SDK treats this as a configuration error: after 3 registrations in a row refused right after executor.register (close 4002 "runtime registration refused", or an executor.register error capability_unavailable / invalid_params), the client ends and Done closes with Err() wrapping ErrRegistrationRefused; other 4002 closes (for example "daemon runtime ended") reconnect as before. State() is ready as soon as executor.register returns, which a refused registration also does; WaitReady(ctx) returns only after the registration stayed open for one heartbeat interval, or with the error of a client that ended.

Executor types follow one mapping: required members are values, optional members are values with omitempty (named structs and nullable members are pointers), enums are untyped constants (Code* error codes on RPCError.Code), and opaque payloads such as ToolCallParams.Input stay json.RawMessage. Tool handlers receive the decoded per-tool input (BashInput, ReadInput, ...) through client.Tools.<Name>.Handle; return TextOutput, BashResult{...}.Output() (rendered like Core: stdout, stderr, exit_code: N) or a ToolOutput, NewToolError(text) for a tool-level error the model sees (is_error: true), any other error for outcome: "failed". The harness calls them as session.Tools.Bash.Call(ctx, BashInput{Command: "ls"}, CallToolOptions{}). Other protocol methods are typed too: Requests.ProcessStart.Handle(client, fn), Calls.SessionEvent.Call(ctx, client, params), Notifications.ToolProgress.Notify(ctx, client, params) (tables generated from the contract by tools/gen_methods.py).

Lifecycle, cancellation, and results
  • tool.cancel from the harness cancels the context.Context passed to the tool handler. The client responds {"canceled":true} and reports the result with outcome: "canceled"; handlers must stop their process group when the context is done.
  • A repeated tool.call with the same tool_call_id is acknowledged but not executed twice.
  • Call SessionReady after workspace and MCP setup, and SessionEnded after every child process and MCP server has stopped. The SDK does not infer these transitions because only the adapter knows when setup and cleanup finished.
  • tool.result is retried with exponential backoff on -32009 (executor_busy), -32004 (timeout), or data.retryable: true. Results are idempotent by tool_call_id. When every attempt fails, OnToolResultLost is called with the original result so the adapter can persist and replay it; the client never drops a result silently.
  • Large output is reported as artifact references, not base64 in tool.result: Client.UploadArtifact uploads the bytes, NewArtifactRef and NewArtifactContentBlock build the blocks.
  • OpenMCPChannel opens the MCP channel for a session and server key and exchanges raw MCP JSON-RPC frames over whatever transport the control channel uses.
  • Session handler errors that are an *RPCError keep their code and data on the wire (for example retryable executor_busy).

Execution core: one hand, any brain

Core is the executor's execution core, independent of who drives it. core.Attach(brain, client) installs the session and tool handlers on a Client; attach one Client per harness, so one executor process serves the BMA cloud and a local harness at the same time:

core, _ := bmaexecutor.NewCore(bmaexecutor.CoreOptions{WorkRoot: dir, MaxSessions: 8, MaxSessionsPerBrain: 4})
_ = core.Register(bmaexecutor.NewProcessCapability(core, bmaexecutor.ProcessOptions{}))
cloud, _ := bmaexecutor.NewClient(bmaexecutor.Options{EnvironmentKey: key, EnvironmentID: env, Executor: info, Capabilities: core.Capabilities()})
local, _ := bmaexecutor.NewClient(bmaexecutor.Options{EnvironmentID: "local", Executor: info, Capabilities: core.Capabilities(),
	TokenSource: bmaexecutor.StaticToken("ws://127.0.0.1:7777", localToken)})
_ = core.Attach("cloud", cloud)
_ = core.Attach("local", local)
  • Tools: bash (login shell in its own process group; env limited to PATH/HOME/USER/LANG/TMPDIR plus request env and CoreOptions.Env; tool.cancel, the deadline, timeout_ms and session.stop kill the whole group; a non-zero exit is a succeeded call reporting exit_code) and read/write/edit/glob/grep, confined to the session workspace WorkRoot/<brain>/<session> (override with CoreOptions.Workspace). Other tools return capability_unavailable.
  • Capabilities: core.Register(cap) before Attach adds methods behind capability bits; core.Capabilities() advertises them. NewProcessCapability(core, ProcessOptions{...}) serves process.* (PTY where supported; FileTransfer and GitCredentials hooks enable those process.start fields; Launch chooses the directory, wraps argv in a sandbox or refuses a command process or package install with a data.reason; SessionFiles syncs per-session files under a declared session_files.root, see session context); NewSkillInstallCapability(installer) serves skill.install; implement Capability for your own methods (for example terminal.*). A SessionScoped capability gets the brain's *CoreSession and OnSessionEnd runs before session.ended.
  • Private environment: CoreOptions.DenyEnv names executor-private variables (for example machine tokens) that no bash tool, process, terminal or stdio MCP server inherits and no request may set.
  • stdio MCP: every session.assign.mcp_servers[] entry with connection_origin: environment starts one process per (brain, session, server_key), verifies command_sha256 when given, runs the command without a shell with only its configured transport.env plus transport.secret_env (server-resolved secret values, advertised as capabilities.mcp.secret_env, injected into that process only; nothing is inherited from the executor; a secret: value left in env, a loader variable or a DenyEnv name fails session.assign with invalid_params), and bridges stdin/stdout lines to that server's MCP channel. If either side ends both are restarted, until the session ends, with jittered exponential backoff capped at 30s (reset once a channel stays open for 1s); after 5 consecutive failures the core sends session.status error / mcp_unavailable: <key> once per outage and keeps retrying.
  • Isolation: sessions are keyed by (brain, session_id); a tool.call reaches only sessions its own brain assigned; MCP channels and workspaces are per brain and session. Bash is not a sandbox: every brain runs as the executor's OS user, so only attach brains you trust with this machine.
  • Capacity: MaxSessions (default 16) across brains and MaxSessionsPerBrain (default MaxSessions) per brain. A full core answers session.assign with executor_busy (-32009, retryable: true).

Harness quick start

Harness is the harness ("brain") end: an http.Handler that accepts executor control and MCP channels, plus the API that drives them. It speaks the same protocol as the BMA service, so an executor cannot tell them apart.

harness := bmaexecutor.NewHarness(bmaexecutor.HarnessOptions{
	Authenticate: authenticate, // func(*http.Request) (bmaexecutor.Principal, error); nil only on loopback
})
go http.Serve(listener, harness)

executor, _ := harness.WaitExecutor(ctx)
session, _ := executor.AssignSession(ctx, bmaexecutor.SessionAssignParams{SessionID: "sess_1"})
_ = session.Ready(ctx)
result, _ := session.CallTool(ctx, bmaexecutor.ToolCallParams{
	Tool: bmaexecutor.ToolNameBash, Input: bmaexecutor.NewToolInput(bmaexecutor.ToolInput{Command: "ls"}),
})
mcp, _ := session.MCP(ctx, "echo") // raw MCP JSON-RPC: Write/Read
_ = session.Stop(ctx, "done")
  • Authenticate sees every upgrade (control and MCP). A returned Principal.ExecutorID pins the identity: resume.executor_id must match and only that executor may open MCP channels for its sessions.
  • CallTool is idempotent by tool_call_id (generated when empty): a repeat joins the in-flight call or returns the recorded result. Canceling its context stops waiting only; CancelTool sends tool.cancel.
  • Resume: a disconnected executor keeps its sessions and pending calls for LeaseTTL (default 60s). A newer connection replaces the old one with close code 4004. Lease expiry, executor.close or a dropped session fails pending calls with ErrToolOutcomeUnknown: the tool may or may not have run.
  • Pending calls live in harness memory; there is no durable result store.

Local socket and in-process transports

Options.Dial defaults to WebSocket on ws://, wss://, unix:///path.sock or npipe:////./pipe/<name> (Windows; ListenNamedPipe, NamedPipeListener, NamedPipeDialer).

Shape Executor Harness
Executor dials a local harness StaticToken("ws://127.0.0.1:port", token) or StaticToken("unix:///path.sock", token) (UnixSocketDialer(path)) or StaticToken("npipe:////./pipe/<name>", token) (NamedPipeDialer(name)) http.Serve(listener, harness) on a TCP or unix listener
Harness dials the executor (executor listens) dial, closeFn, _ := ListenUnixSocket(path, token) → Options.Dial: dial (0700 directory, 0600 socket, bearer token) harness.DialExecutor(ctx, path, token); the harness also dials the sessions' MCP channels
Same process Options.Dial: InProcessDialer(harness, principal) Harness.ServeConn (used by InProcessDialer)

Details and authentication rules: local connection.

Agent executors

An executor that runs its own model loop and tools (for example a desktop app) serves the agent capability: the platform sends natural-language turns, the executor streams Anthropic Managed Agents events back.

client.ServeAgent(myAgent, bmaexecutor.AgentCapability{
	Models:          []bmaexecutor.AgentModel{{ID: "my-model", ThinkingLevels: []string{"low", "high"}}},
	PermissionModes: []string{"default", "accept_edits"},
})

myAgent implements AgentHandler: OpenTurn reports the effective configuration, RunTurn does the work with turn.Emit (durable events), turn.Delta (streaming previews), turn.Inputs() (turn.input) and turn.RequestInteraction (approvals and questions), and CloseSession releases the local conversation. The SDK assigns event ids and sequences, resends unacknowledged events after a reconnect, and frames every turn with session.status_running and a final session.status_idle whose turn_outcome is completed, canceled or failed.

The harness side is HarnessOptions.Agent (AgentPlatform) plus Executor.StartTurn, SendTurnInput, CancelTurn, CloseAgentSession and RespondInteraction. The BMA platform side is in preview: the binding of an agent to the machine is made by the BMA team (the public /v1 API has no route for it yet); its sessions accept text input only. See agent capability.

Examples

Run from the repository root:

Example What it shows Run
examples/local-brain a local harness with a scripted "model" drives Core over loopback: bash, then the stdio echo-mcp server through the MCP channel go run ./examples/local-brain
examples/cloud-hand the same Core as a hand for the BMA cloud harness BMA_BASE_URL=... BMA_ENVIRONMENT_ID=... BMA_ENVIRONMENT_KEY=... go run ./examples/cloud-hand -work-root ~/bma-work
examples/agentexecutor the agent capability against a simulated platform, including a dropped connection go run ./examples/agentexecutor
examples/sandboxed-folder a machine executor whose Launch hook reads the session context, checks the owner, picks the local folder for a metadata reference and wraps the command in macOS sandbox-exec BMA_BASE_URL=... BMA_MACHINE_TOKEN=... go run ./examples/sandboxed-folder -owner u_42 -folder ws_7=$HOME/projects/site

Tests

go vet ./... && go test -race ./...

The tests cover the conformance examples in contracts/bma/executor/examples, executor ↔ harness over every transport with reconnect and lease, Core, capabilities and the agent capability. The TypeScript and Python packages run interop suites against the Go peers in internal/interop.

Development

The executor contract snapshot and the generated types (generated.go, typescript/src/generated/executor.ts, python/src/bma_executor_sdk/generated.py) are generated in the BMA repository: make contract-sdk SDK_DIR=<this checkout>. tools/check_contract.py verifies them against contracts/bma/executor/lock.json; --source <beeos-managed-agents checkout> also compares the snapshot with BMA.

python3 tools/check_contract.py [--source ../beeos-managed-agents]
go vet ./... && go test -race ./...
(cd python && uv sync && uv run pytest -q)                        # interop tests need Go
(cd typescript && npm ci && npm run build && npm test)            # Go + Python interop

Release

One tag v<version> releases all three languages at the same version: it must be on main and match typescript/package.json and python/pyproject.toml. release.yaml first runs ci.yaml, then publishes.

Channel Publishes Credentials
Go nothing; the module comes from the tag none
npm @beeos-ai/bma-executor-sdk with provenance secret NPM_TOKEN in the releases environment
PyPI bma-executor-sdk a PyPI Trusted Publisher on bma-executor-sdk: owner beeos-ai, repository bma-executor-sdk, workflow release.yaml, environment releases

License

Apache License 2.0. See LICENSE and NOTICE.

Documentation

Overview

Package bmaexecutor implements the BMA Executor Protocol (bma.executor.v1.1, generated from contracts/bma): the executor end (Client: token bootstrap, pluggable transport, JSON-RPC 2.0, registration, heartbeat, reconnect with resume, dispatch, tool cancellation, retried results, artifacts, MCP channel), the execution Core with registrable capabilities (process.*, skill.install, ...), and the harness end (Harness).

Index

Constants

View Source
const (
	// MachineIDEnv is the environment variable that carries the machine id of
	// a machine-scoped executor (injected by the machine pool template).
	MachineIDEnv = "BMA_MACHINE_ID"

	DefaultBaseURL        = "https://api.bma.beeos.ai"
	DefaultRequestTimeout = 30 * time.Second
	// DefaultMaxReconnectAttempts is 0: reconnect until Stop, as gRPC's
	// connection backoff and long-running agents (GitHub Actions runner,
	// Buildkite agent) do.
	DefaultMaxReconnectAttempts = 0
	DefaultReconnectBaseDelay   = time.Second
	// DefaultToolResultRetryAttempts is the total number of tool.result attempts.
	DefaultToolResultRetryAttempts = 5
	// DefaultToolResultRetryBaseDelay is the first retry backoff for tool.result.
	DefaultToolResultRetryBaseDelay = 250 * time.Millisecond
)
View Source
const (
	DefaultCoreMaxSessions       = 16
	DefaultCoreMaxMCPServers     = 4
	DefaultCoreBashTimeout       = 10 * time.Minute
	DefaultCoreMaxOutputBytes    = 1024 * 1024
	DefaultCoreInlineResultBytes = 48 * 1024

	// DefaultMaxArtifactBytes bounds one artifact upload (v1.1 §6.5).
	DefaultMaxArtifactBytes = 16 * 1024 * 1024
)
View Source
const (
	AgentEventTypeAgentMessage         = "agent.message"
	AgentEventTypeAgentThinking        = "agent.thinking"
	AgentEventTypeAgentToolUse         = "agent.tool_use"
	AgentEventTypeAgentToolResult      = "agent.tool_result"
	AgentEventTypeAgentMcpToolUse      = "agent.mcp_tool_use"
	AgentEventTypeAgentMcpToolResult   = "agent.mcp_tool_result"
	AgentEventTypeSessionStatusRunning = "session.status_running"
	AgentEventTypeSessionStatusIdle    = "session.status_idle"
	AgentEventTypeSessionError         = "session.error"
)

AgentEventType values. Durable events an agent executor emits with session.event. Names and members follow Anthropic Managed Agents session events. user.* events are written by the platform, never by the executor.

View Source
const (
	AgentInputBlockTypeText = "text"
	AgentInputBlockTypeFile = "file"
)

AgentInputBlockType values. Agent input block type.

View Source
const (
	ChannelControl = "control"
	ChannelMCP     = "mcp"
)

ChannelScope values. Channels a short-lived executor JWT may open.

View Source
const (
	ComputerActionClick  = "click"
	ComputerActionType   = "type"
	ComputerActionKey    = "key"
	ComputerActionScroll = "scroll"
	ComputerActionDrag   = "drag"
)

ComputerAction values. Input actions accepted by the computer_action tool.

View Source
const (
	ConnectionStateDisconnected = "disconnected"
	ConnectionStateConnecting   = "connecting"
	ConnectionStateRegistered   = "registered"
	ConnectionStateReady        = "ready"
	ConnectionStateDraining     = "draining"
	ConnectionStateClosed       = "closed"
)

ConnectionState values. Executor control channel state machine.

View Source
const (
	ContentBlockTypeText     = "text"
	ContentBlockTypeImage    = "image"
	ContentBlockTypeResource = "resource"
	ContentBlockTypeArtifact = "artifact"
)

ContentBlockType values. Tool result content block type.

View Source
const (
	EventDeltaTypeAgentMessage  = "agent.message"
	EventDeltaTypeAgentThinking = "agent.thinking"
)

EventDeltaType values. Durable event type a streaming preview belongs to.

View Source
const (
	FileTransferUpload   = "upload"
	FileTransferDownload = "download"
)

FileTransferDirection values. File transfer direction relative to the machine.

View Source
const (
	InteractionCancelReasonResolvedLocally = "resolved_locally"
	InteractionCancelReasonTurnCanceled    = "turn_canceled"
	InteractionCancelReasonExpired         = "expired"
	InteractionCancelReasonToolCanceled    = "tool_canceled"
)

InteractionCancelReason values. Why the executor withdrew an open interaction.

View Source
const (
	InteractionKindPermission = "permission"
	InteractionKindQuestion   = "question"
)

InteractionKind values. Interaction kinds; they map 1:1 to platform agent interactions.

View Source
const (
	InteractionOutcomeAllow    = "allow"
	InteractionOutcomeDeny     = "deny"
	InteractionOutcomeAnswered = "answered"
	InteractionOutcomeExpired  = "expired"
	InteractionOutcomeCanceled = "canceled"
)

InteractionOutcome values. How the platform resolved an interaction. allow/deny answer permission, answered answers question, expired and canceled close either kind without an answer.

View Source
const (
	InteractionScopeOnce    = "once"
	InteractionScopeSession = "session"
)

InteractionScope values. How long a permission grant lasts on the executor: this tool use only, or the rest of the session.

View Source
const (
	CodeParseError            = -32700
	CodeInvalidRequest        = -32600
	CodeMethodNotFound        = -32601
	CodeInvalidParams         = -32602
	CodeInternalError         = -32603
	CodeUnauthorized          = -32000
	CodeForbidden             = -32001
	CodeNotFound              = -32002
	CodeLeaseExpired          = -32003
	CodeTimeout               = -32004
	CodeCanceled              = -32005
	CodePayloadTooLarge       = -32006
	CodeSessionNotActive      = -32007
	CodeMCPUnavailable        = -32008
	CodeExecutorBusy          = -32009
	CodeUnsupportedProtocol   = -32010
	CodeResourceUnavailable   = -32011
	CodeCapabilityUnavailable = -32012
	CodeConflict              = -32013
)

JSONRPCErrorCode values. Executor protocol JSON-RPC error codes. -32011..-32013 are v1.1 additions.

View Source
const (
	MCPConnectionOriginService     = "service"
	MCPConnectionOriginEnvironment = "environment"
)

MCPConnectionOrigin values. Who connects the MCP server. environment means the executor starts/connects it; service means the harness connects.

View Source
const (
	MCPTransportTypeStdio = "stdio"
	MCPTransportTypeHttp  = "http"
)

MCPTransportType values.

View Source
const (
	PackageManagerApt = "apt"
	PackageManagerPip = "pip"
	PackageManagerNpm = "npm"
)

PackageManager values. Package manager for process.start package_install.

View Source
const (
	PermissionModeAlwaysAllow = "always_allow"
	PermissionModeAlwaysAsk   = "always_ask"
)

PermissionMode values. Tool permission mode; always_ask means the harness already resolved approval.

View Source
const (
	ProcessRunning = "running"
	ProcessExited  = "exited"
	ProcessFailed  = "failed"
	ProcessKilled  = "killed"
)

ProcessStateName values. Process state (v1.1 §3.3).

View Source
const (
	StreamStdout = "stdout"
	StreamStderr = "stderr"
)

ProcessStream values. Process output stream (v1.1 §3.2).

View Source
const (
	ProtocolV1  = "bma.executor.v1"
	ProtocolV11 = "bma.executor.v1.1"
)

ProtocolVersion values. Value of both the WebSocket subprotocol and executor.register protocol. A v1.1 server serves v1 executors and never sends them v1.1 methods.

View Source
const (
	SessionEventTypeAgentToolResult      = "agent.tool_result"
	SessionEventTypeAgentMessage         = "agent.message"
	SessionEventTypeAgentThinking        = "agent.thinking"
	SessionEventTypeAgentToolUse         = "agent.tool_use"
	SessionEventTypeAgentMcpToolUse      = "agent.mcp_tool_use"
	SessionEventTypeAgentMcpToolResult   = "agent.mcp_tool_result"
	SessionEventTypeSessionStatusRunning = "session.status_running"
	SessionEventTypeSessionStatusIdle    = "session.status_idle"
	SessionEventTypeSessionError         = "session.error"
)

SessionEventType values. Durable event types an executor may emit. Event names follow Anthropic Managed Agents; the executor must not invent new names. A tool executor emits agent.tool_result only; an agent executor (capability agent) emits every type, shaped as schemas/agent.json AgentEvent.

View Source
const (
	SessionStatusStarting = "starting"
	SessionStatusRunning  = "running"
	SessionStatusIdle     = "idle"
	SessionStatusStopping = "stopping"
	SessionStatusStopped  = "stopped"
	SessionStatusError    = "error"
)

SessionStatus values. Lifecycle status reported by the executor.

View Source
const (
	StdinOpen   = "open"
	StdinClosed = "closed"
)

StdinMode values. process.start stdin mode. Empty or "closed" closes stdin at start; "open" keeps it open for process.write.

View Source
const (
	StopReasonTypeEndTurn          = "end_turn"
	StopReasonTypeRetriesExhausted = "retries_exhausted"
)

StopReasonType values. Anthropic stop_reason types an executor may report. requires_action is not in the list: the platform projects it from open interactions.

View Source
const (
	ToolNameBash            = "bash"
	ToolNameRead            = "read"
	ToolNameWrite           = "write"
	ToolNameEdit            = "edit"
	ToolNameGlob            = "glob"
	ToolNameGrep            = "grep"
	ToolNameListFiles       = "list_files"
	ToolNameComputerObserve = "computer_observe"
	ToolNameComputerAction  = "computer_action"
)

ToolName values. Built-in tool names. bmad serves bash only and answers -32012 for the rest.

View Source
const (
	ToolOutcomeSucceeded = "succeeded"
	ToolOutcomeFailed    = "failed"
	ToolOutcomeCanceled  = "canceled"
)

ToolOutcome values. Tool outcome.

View Source
const (
	TurnOutcomeCompleted = "completed"
	TurnOutcomeCanceled  = "canceled"
	TurnOutcomeFailed    = "failed"
)

TurnOutcome values. BMA extension on session.status_idle: how the turn ended.

View Source
const (
	MethodExecutorRegister           = "executor.register"
	MethodExecutorHeartbeat          = "executor.heartbeat"
	MethodExecutorTokenRefresh       = "executor.token.refresh"
	MethodExecutorCapabilitiesUpdate = "executor.capabilities.update"
	MethodExecutorDrain              = "executor.drain"
	MethodExecutorClose              = "executor.close"
	MethodSessionAssign              = "session.assign"
	MethodSessionReady               = "session.ready"
	MethodSessionEvent               = "session.event"
	MethodSessionStatus              = "session.status"
	MethodSessionStop                = "session.stop"
	MethodSessionEnded               = "session.ended"
	MethodToolCall                   = "tool.call"
	MethodToolResult                 = "tool.result"
	MethodToolCancel                 = "tool.cancel"
	MethodToolProgress               = "tool.progress"
	MethodProcessStart               = "process.start"
	MethodProcessRead                = "process.read"
	MethodProcessWrite               = "process.write"
	MethodProcessInterrupt           = "process.interrupt"
	MethodProcessTerminate           = "process.terminate"
	MethodProcessList                = "process.list"
	MethodProcessStatus              = "process.status"
	MethodTerminalOpen               = "terminal.open"
	MethodTerminalAttach             = "terminal.attach"
	MethodTerminalClose              = "terminal.close"
	MethodSkillInstall               = "skill.install"
	MethodWorkspaceBackup            = "workspace.backup"
	MethodFsMount                    = "fs.mount"
	MethodFsUnmount                  = "fs.unmount"
	MethodTurnStart                  = "turn.start"
	MethodTurnInput                  = "turn.input"
	MethodTurnCancel                 = "turn.cancel"
	MethodSessionClose               = "session.close"
	MethodSessionEventDelta          = "session.event_delta"
	MethodInteractionRequest         = "interaction.request"
	MethodInteractionResponse        = "interaction.response"
	MethodInteractionCancel          = "interaction.cancel"
)
View Source
const (
	DefaultHarnessHeartbeatInterval = 15 * time.Second
	DefaultHarnessLeaseTTL          = 60 * time.Second
)
View Source
const (
	// MaxProcessesPerSession bounds running processes; ended processes are
	// retained separately (see retainEndedLocked).
	MaxProcessesPerSession = 64
	ProcessBufferBytes     = 1024 * 1024
)

Process limits (v1.1 §1.3, §3). They match DefaultLimits.

View Source
const (
	// The referenced workspace is gone or its directory does not exist.
	ReasonWorkspaceUnavailable = "workspace_unavailable"
	// The request leaves what the executor's local policy allows.
	ReasonWorkspaceBoundary = "workspace_boundary"
	// The request writes where the local policy only allows reads.
	ReasonWorkspaceReadOnly = "workspace_read_only"
	// The session is not one this machine serves (an owner check failed).
	ReasonSessionRejected = "session_rejected"
	// The local user denied the access.
	ReasonLocalConfirmationDenied = "local_confirmation_denied"
	// Nobody answered the local confirmation in time.
	ReasonLocalConfirmationExpired = "local_confirmation_expired"
	// The process could not be started.
	ReasonSpawnFailed = "spawn_failed"
	// A process.start replay changed the spec of an existing process id.
	ReasonProcessIDSpecMismatch = "process_id_spec_mismatch"
)

Recommended error.data.reason values (contracts/bma README, open set): an executor that refuses a process.start or a tool.call answers with a JSON-RPC error whose data.reason is one of these, and BMA passes it to the tool result's error_code and the turn's session.error.code unchanged. Any other value is passed through as well. TypeScript ErrorReason and Python ErrorReason carry the same names and values.

View Source
const (
	IOModePTY = "pty"
)

IOMode values. process.start io_mode. "pty" runs the command on a 24x80 pseudo-terminal: stdout is the PTY output, stdin writes go to the PTY and close_stdin is rejected. Requires process.pty.

View Source
const MetadataAgentSessionID = "agent_session_id"

MetadataAgentSessionID is the process.start metadata key naming the agent session a process runs for (the session SessionContext and SessionFiles look up).

View Source
const (
	StderrMerge = "merge"
)

StderrMode values. process.start stderr mode. "merge" redirects stderr into stdout at the OS level so one cursor covers both.

Variables

View Source
var (
	// ErrNotConnected is returned when a call is attempted before the channel opens.
	ErrNotConnected = errors.New("bmaexecutor: executor channel is not connected")
	// ErrClientStopped is returned after Stop or a terminal close code.
	ErrClientStopped = errors.New("bmaexecutor: client stopped")
	// ErrReplaced is Err after the harness closed with 4004: a newer
	// connection for this executor is authoritative and this one must stop.
	ErrReplaced = errors.New("bmaexecutor: executor connection was replaced (4004)")
	// ErrReconnectExhausted is Err after a positive MaxReconnectAttempts
	// failed; it wraps the last failure.
	ErrReconnectExhausted = errors.New("bmaexecutor: executor reconnect attempts exhausted")
	// ErrCredentialRejected is wrapped by the token request error when the
	// token endpoint answers 401 or 403 (an invalid or revoked environment
	// key or machine token). A reconnect does not retry it: the client ends
	// with it as Err. A TokenSource may wrap it for the same effect.
	ErrCredentialRejected = errors.New("bmaexecutor: executor credential rejected")
	// ErrRegistrationRefused is Err after the platform refused the
	// executor's registration maxRefusedRegistrations times in a row: the
	// close 4002 "runtime registration refused" right after
	// executor.register, or an executor.register error for the executor's
	// capabilities. It is a configuration error (a machine-scoped executor
	// must declare the process or agent capability) that reconnecting
	// cannot fix. It wraps the last refusal.
	ErrRegistrationRefused = errors.New("bmaexecutor: executor registration refused")
)
View Source
var (
	// ErrSessionEnded is returned for requests on a session that has ended.
	ErrSessionEnded = errors.New("bmaexecutor: session ended")
	// ErrToolOutcomeUnknown means the executor was lost (lease expiry,
	// executor.close, session ended, or a restarted executor that no longer
	// reports the session) before a tool.result arrived. The tool may or may
	// not have run; the caller decides whether a retry is safe.
	ErrToolOutcomeUnknown = errors.New("bmaexecutor: tool outcome unknown: executor lost before tool.result")
	// ErrAssignRejected is returned when session.assign answers accepted=false.
	ErrAssignRejected = errors.New("bmaexecutor: executor rejected session.assign")
)
View Source
var Calls = struct {
	SessionReady       CallMethod[SessionReadyParams, Ack]
	SessionEvent       CallMethod[SessionEventParams, SessionEventResult]
	SessionEnded       CallMethod[SessionEndedParams, Ack]
	ToolResult         CallMethod[ToolResultParams, Ack]
	InteractionRequest CallMethod[InteractionRequestParams, InteractionRequestResult]
	InteractionCancel  CallMethod[InteractionCancelParams, Ack]
}{
	SessionReady:       CallMethod[SessionReadyParams, Ack]{Method: "session.ready"},
	SessionEvent:       CallMethod[SessionEventParams, SessionEventResult]{Method: "session.event"},
	SessionEnded:       CallMethod[SessionEndedParams, Ack]{Method: "session.ended"},
	ToolResult:         CallMethod[ToolResultParams, Ack]{Method: "tool.result"},
	InteractionRequest: CallMethod[InteractionRequestParams, InteractionRequestResult]{Method: "interaction.request"},
	InteractionCancel:  CallMethod[InteractionCancelParams, Ack]{Method: "interaction.cancel"},
}

Calls are the executor-to-harness requests a client sends: Calls.SessionEvent.Call(ctx, client, params).

View Source
var ErrAgentSessionClosed = errors.New("bmaexecutor: agent session closed")

ErrAgentSessionClosed is returned by AgentTurn methods after session.close.

View Source
var ErrMachineTokenRequired = errors.New("bmaexecutor: a machine-scoped executor (machine daemon token in EnvironmentKey, empty EnvironmentID) is required")

ErrMachineTokenRequired is returned by the machine-token HTTP features (SessionContext, SessionContextByID, SessionFiles) of a client that is not a machine-scoped executor: Options.EnvironmentKey must hold the machine daemon token and Options.EnvironmentID must be empty.

View Source
var ErrNamedPipeUnsupported = errors.New("bmaexecutor: Windows named pipes are not supported on this platform")

ErrNamedPipeUnsupported is returned by the named pipe transport on platforms other than Windows.

View Source
var ErrSessionContextNotFound = errors.New("bmaexecutor: session context not found")

ErrSessionContextNotFound is returned when the process is not on this machine (or ended more than 15 minutes ago), or the session is not bound to this machine.

View Source
var Methods = map[string]MethodSpec{
	MethodExecutorRegister:           {Name: MethodExecutorRegister, Direction: DirectionExecutorToHarness, Notification: false, Since: "bma.executor.v1", Capability: "", IdempotentBy: ""},
	MethodExecutorHeartbeat:          {Name: MethodExecutorHeartbeat, Direction: DirectionExecutorToHarness, Notification: false, Since: "bma.executor.v1", Capability: "", IdempotentBy: ""},
	MethodExecutorTokenRefresh:       {Name: MethodExecutorTokenRefresh, Direction: DirectionExecutorToHarness, Notification: false, Since: "bma.executor.v1.1", Capability: "", IdempotentBy: ""},
	MethodExecutorCapabilitiesUpdate: {Name: MethodExecutorCapabilitiesUpdate, Direction: DirectionExecutorToHarness, Notification: true, Since: "bma.executor.v1", Capability: "", IdempotentBy: ""},
	MethodExecutorDrain:              {Name: MethodExecutorDrain, Direction: DirectionHarnessToExecutor, Notification: false, Since: "bma.executor.v1", Capability: "", IdempotentBy: ""},
	MethodExecutorClose:              {Name: MethodExecutorClose, Direction: DirectionBidirectional, Notification: true, Since: "bma.executor.v1", Capability: "", IdempotentBy: ""},
	MethodSessionAssign:              {Name: MethodSessionAssign, Direction: DirectionHarnessToExecutor, Notification: false, Since: "bma.executor.v1", Capability: "", IdempotentBy: ""},
	MethodSessionReady:               {Name: MethodSessionReady, Direction: DirectionExecutorToHarness, Notification: false, Since: "bma.executor.v1", Capability: "", IdempotentBy: ""},
	MethodSessionEvent:               {Name: MethodSessionEvent, Direction: DirectionExecutorToHarness, Notification: false, Since: "bma.executor.v1", Capability: "", IdempotentBy: "jsonrpc_id"},
	MethodSessionStatus:              {Name: MethodSessionStatus, Direction: DirectionExecutorToHarness, Notification: true, Since: "bma.executor.v1", Capability: "", IdempotentBy: ""},
	MethodSessionStop:                {Name: MethodSessionStop, Direction: DirectionHarnessToExecutor, Notification: false, Since: "bma.executor.v1", Capability: "", IdempotentBy: ""},
	MethodSessionEnded:               {Name: MethodSessionEnded, Direction: DirectionExecutorToHarness, Notification: false, Since: "bma.executor.v1", Capability: "", IdempotentBy: ""},
	MethodToolCall:                   {Name: MethodToolCall, Direction: DirectionHarnessToExecutor, Notification: false, Since: "bma.executor.v1", Capability: "", IdempotentBy: ""},
	MethodToolResult:                 {Name: MethodToolResult, Direction: DirectionExecutorToHarness, Notification: false, Since: "bma.executor.v1", Capability: "", IdempotentBy: "tool_call_id"},
	MethodToolCancel:                 {Name: MethodToolCancel, Direction: DirectionHarnessToExecutor, Notification: false, Since: "bma.executor.v1", Capability: "", IdempotentBy: ""},
	MethodToolProgress:               {Name: MethodToolProgress, Direction: DirectionExecutorToHarness, Notification: true, Since: "bma.executor.v1", Capability: "", IdempotentBy: ""},
	MethodProcessStart:               {Name: MethodProcessStart, Direction: DirectionHarnessToExecutor, Notification: false, Since: "bma.executor.v1.1", Capability: "process.enabled", IdempotentBy: "session_id+process_id"},
	MethodProcessRead:                {Name: MethodProcessRead, Direction: DirectionHarnessToExecutor, Notification: false, Since: "bma.executor.v1.1", Capability: "process.enabled", IdempotentBy: ""},
	MethodProcessWrite:               {Name: MethodProcessWrite, Direction: DirectionHarnessToExecutor, Notification: false, Since: "bma.executor.v1.1", Capability: "process.enabled", IdempotentBy: ""},
	MethodProcessInterrupt:           {Name: MethodProcessInterrupt, Direction: DirectionHarnessToExecutor, Notification: false, Since: "bma.executor.v1.1", Capability: "process.enabled", IdempotentBy: ""},
	MethodProcessTerminate:           {Name: MethodProcessTerminate, Direction: DirectionHarnessToExecutor, Notification: false, Since: "bma.executor.v1.1", Capability: "process.enabled", IdempotentBy: ""},
	MethodProcessList:                {Name: MethodProcessList, Direction: DirectionHarnessToExecutor, Notification: false, Since: "bma.executor.v1.1", Capability: "process.enabled", IdempotentBy: ""},
	MethodProcessStatus:              {Name: MethodProcessStatus, Direction: DirectionExecutorToHarness, Notification: true, Since: "bma.executor.v1.1", Capability: "process.enabled", IdempotentBy: ""},
	MethodTerminalOpen:               {Name: MethodTerminalOpen, Direction: DirectionHarnessToExecutor, Notification: false, Since: "bma.executor.v1.1", Capability: "terminal.enabled", IdempotentBy: "terminal_id"},
	MethodTerminalAttach:             {Name: MethodTerminalAttach, Direction: DirectionHarnessToExecutor, Notification: false, Since: "bma.executor.v1.1", Capability: "terminal.enabled", IdempotentBy: ""},
	MethodTerminalClose:              {Name: MethodTerminalClose, Direction: DirectionHarnessToExecutor, Notification: false, Since: "bma.executor.v1.1", Capability: "terminal.enabled", IdempotentBy: "terminal_id"},
	MethodSkillInstall:               {Name: MethodSkillInstall, Direction: DirectionHarnessToExecutor, Notification: false, Since: "bma.executor.v1.1", Capability: "skills.install", IdempotentBy: "skill_id+revision_id+digest"},
	MethodWorkspaceBackup:            {Name: MethodWorkspaceBackup, Direction: DirectionHarnessToExecutor, Notification: false, Since: "bma.executor.v1.1", Capability: "workspace.backup", IdempotentBy: "backup_id"},
	MethodFsMount:                    {Name: MethodFsMount, Direction: DirectionHarnessToExecutor, Notification: false, Since: "bma.executor.v1.1", Capability: "fs.fuse", IdempotentBy: "session_id+view"},
	MethodFsUnmount:                  {Name: MethodFsUnmount, Direction: DirectionHarnessToExecutor, Notification: false, Since: "bma.executor.v1.1", Capability: "fs.fuse", IdempotentBy: "session_id"},
	MethodTurnStart:                  {Name: MethodTurnStart, Direction: DirectionHarnessToExecutor, Notification: false, Since: "bma.executor.v1.1", Capability: "agent", IdempotentBy: "turn_id"},
	MethodTurnInput:                  {Name: MethodTurnInput, Direction: DirectionHarnessToExecutor, Notification: false, Since: "bma.executor.v1.1", Capability: "agent", IdempotentBy: "input_id"},
	MethodTurnCancel:                 {Name: MethodTurnCancel, Direction: DirectionHarnessToExecutor, Notification: false, Since: "bma.executor.v1.1", Capability: "agent", IdempotentBy: ""},
	MethodSessionClose:               {Name: MethodSessionClose, Direction: DirectionHarnessToExecutor, Notification: false, Since: "bma.executor.v1.1", Capability: "agent", IdempotentBy: ""},
	MethodSessionEventDelta:          {Name: MethodSessionEventDelta, Direction: DirectionExecutorToHarness, Notification: true, Since: "bma.executor.v1.1", Capability: "agent", IdempotentBy: ""},
	MethodInteractionRequest:         {Name: MethodInteractionRequest, Direction: DirectionExecutorToHarness, Notification: false, Since: "bma.executor.v1.1", Capability: "agent", IdempotentBy: "interaction_id"},
	MethodInteractionResponse:        {Name: MethodInteractionResponse, Direction: DirectionHarnessToExecutor, Notification: false, Since: "bma.executor.v1.1", Capability: "agent", IdempotentBy: "interaction_id"},
	MethodInteractionCancel:          {Name: MethodInteractionCancel, Direction: DirectionExecutorToHarness, Notification: false, Since: "bma.executor.v1.1", Capability: "agent", IdempotentBy: "interaction_id"},
}

Methods is the complete method catalog.

View Source
var Notifications = struct {
	ExecutorCapabilitiesUpdate NotificationMethod[ExecutorCapabilitiesUpdateParams]
	SessionStatus              NotificationMethod[SessionStatusParams]
	ToolProgress               NotificationMethod[ToolProgressParams]
	ProcessStatus              NotificationMethod[ProcessStatusParams]
	SessionEventDelta          NotificationMethod[SessionEventDeltaParams]
}{
	ExecutorCapabilitiesUpdate: NotificationMethod[ExecutorCapabilitiesUpdateParams]{Method: "executor.capabilities.update"},
	SessionStatus:              NotificationMethod[SessionStatusParams]{Method: "session.status"},
	ToolProgress:               NotificationMethod[ToolProgressParams]{Method: "tool.progress"},
	ProcessStatus:              NotificationMethod[ProcessStatusParams]{Method: "process.status"},
	SessionEventDelta:          NotificationMethod[SessionEventDeltaParams]{Method: "session.event_delta"},
}

Notifications are the executor-to-harness notifications a client sends: Notifications.ToolProgress.Notify(ctx, client, params).

View Source
var Requests = struct {
	ProcessStart     RequestMethod[ProcessStartParams, ProcessState]
	ProcessRead      RequestMethod[ProcessReadParams, ProcessReadResult]
	ProcessWrite     RequestMethod[ProcessWriteParams, ProcessWriteResult]
	ProcessInterrupt RequestMethod[ProcessSignalParams, ProcessState]
	ProcessTerminate RequestMethod[ProcessSignalParams, ProcessState]
	ProcessList      RequestMethod[ProcessListParams, ProcessListResult]
	TerminalOpen     RequestMethod[TerminalOpenParams, TerminalOpenResult]
	TerminalAttach   RequestMethod[TerminalAttachParams, TerminalAttachResult]
	TerminalClose    RequestMethod[TerminalCloseParams, TerminalCloseResult]
	SkillInstall     RequestMethod[SkillInstallParams, SkillInstallResult]
	WorkspaceBackup  RequestMethod[WorkspaceBackupParams, WorkspaceBackupResult]
	FsMount          RequestMethod[FsMountParams, FsMountResult]
	FsUnmount        RequestMethod[FsUnmountParams, FsUnmountResult]
}{
	ProcessStart:     RequestMethod[ProcessStartParams, ProcessState]{Method: "process.start"},
	ProcessRead:      RequestMethod[ProcessReadParams, ProcessReadResult]{Method: "process.read"},
	ProcessWrite:     RequestMethod[ProcessWriteParams, ProcessWriteResult]{Method: "process.write"},
	ProcessInterrupt: RequestMethod[ProcessSignalParams, ProcessState]{Method: "process.interrupt"},
	ProcessTerminate: RequestMethod[ProcessSignalParams, ProcessState]{Method: "process.terminate"},
	ProcessList:      RequestMethod[ProcessListParams, ProcessListResult]{Method: "process.list"},
	TerminalOpen:     RequestMethod[TerminalOpenParams, TerminalOpenResult]{Method: "terminal.open"},
	TerminalAttach:   RequestMethod[TerminalAttachParams, TerminalAttachResult]{Method: "terminal.attach"},
	TerminalClose:    RequestMethod[TerminalCloseParams, TerminalCloseResult]{Method: "terminal.close"},
	SkillInstall:     RequestMethod[SkillInstallParams, SkillInstallResult]{Method: "skill.install"},
	WorkspaceBackup:  RequestMethod[WorkspaceBackupParams, WorkspaceBackupResult]{Method: "workspace.backup"},
	FsMount:          RequestMethod[FsMountParams, FsMountResult]{Method: "fs.mount"},
	FsUnmount:        RequestMethod[FsUnmountParams, FsUnmountResult]{Method: "fs.unmount"},
}

Requests are the harness-to-executor requests a client serves: Requests.ProcessStart.Handle(client, fn).

Functions

func CloseCode

func CloseCode(err error) int

CloseCode returns the close code carried by err, or -1.

func NamedPipeListener

func NamedPipeListener(name string) (net.Listener, error)

NamedPipeListener listens on the Windows named pipe \\.\pipe\<name> for the current user only (remote clients are refused). Serve Harness on it, as on a Unix socket listener.

func NewParams

func NewParams(method string) any

NewParams returns a pointer to a zero params object for method, or nil for an unknown method.

func NewResult

func NewResult(method string) any

NewResult returns a pointer to a zero result for a request method, or nil for a notification or an unknown method.

func NewToolInput

func NewToolInput(input ToolInput) json.RawMessage

NewToolInput encodes a built-in tool input for ToolCallParams.Input.

func Pipe

func Pipe(protocol string) (executor Conn, harness Conn)

Pipe returns the two ends of an in-process connection that negotiated protocol: one for the executor (Client), one for the harness (Harness.ServeConn). Frames are copied, so neither side can mutate the other's buffers.

func RequestID

func RequestID(ctx context.Context) string

RequestID returns the JSON-RPC id of the inbound request whose handler received ctx (the idempotency key of retried requests), or "".

func SendExecutorCapabilitiesUpdate

func SendExecutorCapabilitiesUpdate(ctx context.Context, rpc RPC, params ExecutorCapabilitiesUpdateParams) error

SendExecutorCapabilitiesUpdate sends the executor.capabilities.update notification.

func SendExecutorClose

func SendExecutorClose(ctx context.Context, rpc RPC, params ExecutorCloseParams) error

SendExecutorClose sends the executor.close notification.

func SendProcessStatus

func SendProcessStatus(ctx context.Context, rpc RPC, params ProcessStatusParams) error

SendProcessStatus sends the process.status notification.

func SendSessionEventDelta

func SendSessionEventDelta(ctx context.Context, rpc RPC, params SessionEventDeltaParams) error

SendSessionEventDelta sends the session.event_delta notification.

func SendSessionStatus

func SendSessionStatus(ctx context.Context, rpc RPC, params SessionStatusParams) error

SendSessionStatus sends the session.status notification.

func SendToolProgress

func SendToolProgress(ctx context.Context, rpc RPC, params ToolProgressParams) error

SendToolProgress sends the tool.progress notification.

func StaticToken

func StaticToken(wsURL, token string) func(context.Context) (ExecutorTokenResponse, error)

StaticToken is a TokenSource for a harness reached directly, typically a local harness. token may be empty when the harness has no Authenticate hook.

Types

type Ack

type Ack struct {
	Accepted bool `json:"accepted"`
}

Ack Generic acknowledgement returned by executor RPC methods.

func SendInteractionCancel

func SendInteractionCancel(ctx context.Context, rpc RPC, params InteractionCancelParams) (Ack, error)

SendInteractionCancel calls interaction.cancel.

func SendSessionEnded

func SendSessionEnded(ctx context.Context, rpc RPC, params SessionEndedParams) (Ack, error)

SendSessionEnded calls session.ended.

func SendSessionReady

func SendSessionReady(ctx context.Context, rpc RPC, params SessionReadyParams) (Ack, error)

SendSessionReady calls session.ready.

func SendToolResult

func SendToolResult(ctx context.Context, rpc RPC, params ToolResultParams) (Ack, error)

SendToolResult calls tool.result.

type AgentCapability

type AgentCapability struct {
	Enabled bool `json:"enabled"`
	// Models the local agent can run. An empty list means the executor picks its own model and ignores AgentTurnConfig.model.
	Models []AgentModel `json:"models,omitempty"`
	// Permission mode ids the local agent understands, for example default, accept_edits, plan, bypass_permissions. The executor defines the ids; the platform only passes one back in AgentTurnConfig.permission_mode.
	PermissionModes []string `json:"permission_modes,omitempty"`
	// Interaction kinds the executor may open with interaction.request.
	InteractionKinds []string `json:"interaction_kinds,omitempty"`
	// The executor resolves file input blocks (session file ids) itself.
	FileInputs bool `json:"file_inputs,omitempty"`
	// Concurrent agent sessions. turn.start for a new session beyond it answers -32009 executor_busy.
	MaxSessions int64 `json:"max_sessions,omitempty"`
	// The executor keeps the state of its turns across a process restart. When it registers again without a session whose turn was running, the platform starts the same turn again in a new event epoch (turn.start with the same turn_id, input_id and executor_session_ref, then the turn.input the turn already received) and the executor continues the turn from its own state. Without it such a turn ends failed (session.error, session.status_idle retries_exhausted) and is not sent again: an executor without that state would run the turn again from its opening input and repeat tool calls whose effects already happened.
	TurnResume bool `json:"turn_resume,omitempty"`
	// Per-turn credentials the executor asks the platform to hand it in turn.start metadata: brain_tools (tools_mcp_url, tools_mcp_token: the session's tools endpoint) and harness_model (model_base_url, model_token: the session's model endpoint). A declaration only states what the executor can use; the platform decides by the executor's identity and hands them only to an executor registered as a platform service, never to a tenant executor. Tokens are computed for each turn.start, are valid until the turn ends, and are never stored.
	PlatformCredentials []string                `json:"platform_credentials,omitempty"`
	Harness             *AgentHarnessCapability `json:"harness,omitempty"`
}

AgentCapability agent capability. Present with enabled=true when the executor runs a complete agent and accepts turn.start, turn.input, turn.cancel, session.close and interaction.response.

type AgentErrorInfo

type AgentErrorInfo struct {
	Type    string `json:"type"`
	Message string `json:"message,omitempty"`
}

AgentErrorInfo Typed session error.

type AgentEventRecord

type AgentEventRecord struct {
	SessionID string
	TurnID    string
	EventID   string
	Sequence  int64
	Type      string
	// Event is the event object as sent, for example an AgentMessageEvent.
	Event json.RawMessage
}

AgentEventRecord is one validated durable agent event.

type AgentHandler

type AgentHandler interface {
	// OpenTurn decides whether to accept a turn.start and reports the
	// configuration the agent will actually apply. It runs before turn.start
	// is answered, so it must not do the turn's work. An *RPCError keeps its
	// code (for example -32001 for a cwd outside the allowed roots).
	OpenTurn(ctx context.Context, params TurnStartParams) (TurnStartResult, error)
	// RunTurn does the turn's work and returns when the turn is over. ctx is
	// canceled by turn.cancel and session.close. A nil error ends the turn as
	// completed, a canceled ctx as canceled, any other error as failed (the
	// SDK emits session.error first).
	RunTurn(ctx context.Context, turn *AgentTurn) error
	// CloseSession releases the local conversation after session.close.
	CloseSession(ctx context.Context, sessionID, reason string) error
}

AgentHandler is a complete local agent (model loop and tools) served over the executor protocol. The SDK owns the wire: turn.start/input/cancel, session.close, event ids and sequences, ACK tracking and resend after reconnect, interactions, and the session.status_running / status_idle events that frame every turn.

type AgentHarnessCapability added in v1.0.0

type AgentHarnessCapability struct {
	// Agent profile id, for example dsh.
	ID string `json:"id"`
	// Installed agent package version.
	Version string `json:"version"`
	// Protocol the executor speaks to the agent, for example acp/1.
	Protocol string `json:"protocol,omitempty"`
	// Name the agent reported about itself (ACP initialize agentInfo.name).
	AgentName string `json:"agent_name,omitempty"`
	// Version the agent reported about itself (ACP initialize agentInfo.version); may differ from version.
	AgentVersion string `json:"agent_version,omitempty"`
	// token: agent.message and agent.thinking stream as deltas. committed: each message arrives whole once the agent committed it.
	Streaming string `json:"streaming,omitempty"`
	// A conversation continues in a new agent process (ACP session/resume).
	SessionResume bool `json:"session_resume,omitempty"`
	// A conversation can be reloaded with its history replayed (ACP session/load).
	SessionLoad bool `json:"session_load,omitempty"`
	// The agent accepts image input.
	ImageInputs bool `json:"image_inputs,omitempty"`
	// Which tool calls reach interaction.request. full: every call the agent's policy asks about. escalation_only: only calls that leave the agent's own sandbox; calls inside it (including workspace writes) are never asked. none: the agent never asks, so platform approval covers no tool call.
	PermissionRelay string `json:"permission_relay,omitempty"`
	// The agent reports typed errors; false means session.error carries agent_error with the agent's text.
	StructuredErrors bool `json:"structured_errors,omitempty"`
	// tokens: the agent reports token usage. context_only: it reports context window occupancy only; usage is metered by the model proxy.
	Usage string `json:"usage,omitempty"`
}

AgentHarnessCapability What the third-party agent the executor hosts (for example an ACP agent) supports; an omitted boolean is false. Sent with executor.capabilities.update once the agent has started; absent until then and after a reconnect until the next turn. Informational: the platform records it and reflects it in the session harness capabilities.

type AgentInputBlock

type AgentInputBlock struct {
	Type      string `json:"type"`
	Text      string `json:"text,omitempty"`
	FileID    string `json:"file_id,omitempty"`
	Name      string `json:"name,omitempty"`
	MimeType  string `json:"mime_type,omitempty"`
	SizeBytes int64  `json:"size_bytes,omitempty"`
}

AgentInputBlock One block of user input. A file block references a platform session file by file_id; the executor downloads it through the executor files API. File bytes never travel on the control channel.

type AgentMCPToolResultEvent

type AgentMCPToolResultEvent struct {
	Type         string         `json:"type"`
	MCPToolUseID string         `json:"mcp_tool_use_id"`
	Content      []ContentBlock `json:"content,omitempty"`
	IsError      bool           `json:"is_error,omitempty"`
}

AgentMCPToolResultEvent Result of an agent.mcp_tool_use.

type AgentMCPToolUseEvent

type AgentMCPToolUseEvent struct {
	Type                string               `json:"type"`
	MCPServerName       string               `json:"mcp_server_name"`
	Name                string               `json:"name"`
	Input               map[string]any       `json:"input"`
	EvaluatedPermission *EvaluatedPermission `json:"evaluated_permission,omitempty"`
}

AgentMCPToolUseEvent An MCP tool the local agent is calling. Its event_id is the mcp_tool_use_id.

type AgentMessageEvent

type AgentMessageEvent struct {
	Type    string         `json:"type"`
	Content []ContentBlock `json:"content"`
}

AgentMessageEvent Final assistant text. Streaming previews for the same event_id arrive earlier as session.event_delta.

type AgentModel

type AgentModel struct {
	ID          string `json:"id"`
	DisplayName string `json:"display_name,omitempty"`
	// Thinking or reasoning-effort levels the model accepts, for example off, low, medium, high.
	ThinkingLevels       []string `json:"thinking_levels,omitempty"`
	DefaultThinkingLevel string   `json:"default_thinking_level,omitempty"`
}

AgentModel One model the local agent can run.

type AgentPlatform

type AgentPlatform interface {
	// AckedSequence is the highest contiguous sequence already persisted for
	// the session (0 when none). The harness asks once per session per process
	// so a restarted platform keeps deduplicating resent events.
	AckedSequence(ctx context.Context, sessionID string) (int64, error)
	// AgentEvent persists one durable event and returns once it is durable;
	// only then is it acknowledged to the executor and may be published to
	// clients. It is called once per event, in sequence order per session.
	AgentEvent(ctx context.Context, executor *Executor, event AgentEventRecord) error
	// AgentDelta relays a transient preview (Anthropic event_start /
	// event_delta). Never persisted.
	AgentDelta(executor *Executor, delta SessionEventDeltaParams)
	// InteractionRequested opens (or, for a repeated interaction_id, returns)
	// the platform interaction and returns its id. Answer it later with
	// Executor.RespondInteraction.
	InteractionRequested(ctx context.Context, executor *Executor, request InteractionRequestParams) (string, error)
	// InteractionCanceled closes the platform interaction without an answer.
	InteractionCanceled(ctx context.Context, executor *Executor, cancel InteractionCancelParams) error
}

AgentPlatform is the platform half of the agent capability: where durable agent events, previews and interactions go. BMA implements it on top of its session event log and agent interactions; tests and local tools can keep everything in memory.

type AgentThinkingEvent

type AgentThinkingEvent struct {
	Type    string         `json:"type"`
	Content []ContentBlock `json:"content,omitempty"`
}

AgentThinkingEvent Model thinking. content may be empty when the model only reports that it thought.

type AgentToolResultEvent

type AgentToolResultEvent struct {
	Type      string         `json:"type"`
	ToolUseID string         `json:"tool_use_id"`
	Content   []ContentBlock `json:"content,omitempty"`
	IsError   bool           `json:"is_error,omitempty"`
}

AgentToolResultEvent Result of an agent.tool_use.

type AgentToolUseEvent

type AgentToolUseEvent struct {
	Type                string               `json:"type"`
	Name                string               `json:"name"`
	Input               map[string]any       `json:"input"`
	EvaluatedPermission *EvaluatedPermission `json:"evaluated_permission,omitempty"`
}

AgentToolUseEvent A built-in or custom tool the local agent is calling. Its event_id is the tool_use_id.

type AgentTurn

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

AgentTurn is the handle RunTurn uses to talk to the platform.

func (*AgentTurn) CancelInteraction

func (t *AgentTurn) CancelInteraction(interactionID, reason string)

CancelInteraction withdraws an open interaction, for example after the user answered it in the local UI (InteractionCancelReasonResolvedLocally). A later interaction.response for it answers accepted=false.

func (*AgentTurn) Delta

func (t *AgentTurn) Delta(eventID, eventType string, index int64, text string)

Delta streams a transient preview of the durable event eventID. It is best-effort: dropped while disconnected and never resent.

func (*AgentTurn) Emit

func (t *AgentTurn) Emit(event any) (string, error)

Emit queues one durable event (one of the Agent*Event / Session*Event structs) and returns its event id. Delivery is asynchronous, ordered and at-least-once; the platform deduplicates by event id.

func (*AgentTurn) EmitWithID

func (t *AgentTurn) EmitWithID(eventID string, event any) (string, error)

EmitWithID is Emit with a caller-chosen event id (from NewEventID).

func (*AgentTurn) Flush

func (t *AgentTurn) Flush(ctx context.Context) error

Flush waits until every event emitted so far is acknowledged.

func (*AgentTurn) Inputs

func (t *AgentTurn) Inputs() <-chan TurnInputParams

Inputs delivers turn.input messages in arrival order.

func (*AgentTurn) NewEventID

func (t *AgentTurn) NewEventID() string

NewEventID returns a fresh event id, for a message that is streamed with Delta before it is emitted with EmitWithID.

func (*AgentTurn) Params

func (t *AgentTurn) Params() TurnStartParams

func (*AgentTurn) RequestInteraction

func (t *AgentTurn) RequestInteraction(ctx context.Context, params InteractionRequestParams) (InteractionResponseParams, error)

RequestInteraction asks the platform for an approval or an answer and waits for interaction.response. It flushes first so the platform already has the agent.tool_use the request references. When ctx ends or ExpiresAt passes, it withdraws the interaction with interaction.cancel; an expiry returns outcome expired, which the agent must treat as a deny. The answer is advice: the local agent still makes the final decision.

func (*AgentTurn) SessionID

func (t *AgentTurn) SessionID() string

func (*AgentTurn) TurnID

func (t *AgentTurn) TurnID() string

type AgentTurnConfig

type AgentTurnConfig struct {
	Model          string `json:"model,omitempty"`
	ThinkingLevel  string `json:"thinking_level,omitempty"`
	PermissionMode string `json:"permission_mode,omitempty"`
	// Working directory on the executor host. The executor rejects a directory outside its allowed roots with -32001 forbidden.
	Cwd string `json:"cwd,omitempty"`
	// Extra system instructions from the platform agent definition.
	System string `json:"system,omitempty"`
}

AgentTurnConfig Requested (turn.start) or effective (TurnStartResult.effective) turn configuration. Every member is optional in a request; the executor reports the values it actually applied.

type ArtifactCapability

type ArtifactCapability struct {
	Upload   bool  `json:"upload"`
	MaxBytes int64 `json:"max_bytes,omitempty"`
}

ArtifactCapability v1.1 artifact upload (POST /v1/environments/{environment_id}/artifacts; legacy alias POST /v1/executors/artifacts). Environment-scoped executors only.

type ArtifactRef

type ArtifactRef struct {
	ArtifactID string `json:"artifact_id"`
	Name       string `json:"name,omitempty"`
	MimeType   string `json:"mime_type"`
	SizeBytes  int64  `json:"size_bytes"`
	// sha256:<hex> of the content.
	Digest    string `json:"digest"`
	CreatedAt string `json:"created_at,omitempty"`
}

ArtifactRef Artifact reference returned by POST /v1/environments/{environment_id}/artifacts (legacy alias POST /v1/executors/artifacts) and listed in tool.result artifacts (v1.1 §6.5).

func NewArtifactRef

func NewArtifactRef(artifactID, name, mimeType string, sizeBytes int64) ArtifactRef

NewArtifactRef builds an artifact reference for tool.result.

type BashInput added in v1.0.0

type BashInput struct {
	// Shell command line.
	Command string `json:"command"`
	// Working directory, relative to the session workspace.
	Cwd string `json:"cwd,omitempty"`
	// Per-call timeout; the executor default applies when absent.
	TimeoutMS int64 `json:"timeout_ms,omitempty"`
	// Extra environment variables.
	Env map[string]string `json:"env,omitempty"`
}

BashInput bash input: run command with a login shell.

type BashResult added in v1.0.0

type BashResult struct {
	Stdout   string
	Stderr   string
	ExitCode int
	// Truncated reports that the handler already cut the output short.
	Truncated bool
}

BashResult is a finished command, rendered as Core renders it.

func (BashResult) Output added in v1.0.0

func (r BashResult) Output() ToolOutput

Output renders stdout and stderr (when not empty) and `exit_code: N`, as Core does. Output larger than DefaultCoreInlineResultBytes, or marked Truncated, is cut to Core's preview: half the limit of stdout, a quarter of stderr, and `exit_code: N (output truncated to fit the result; M bytes total)`.

type CallMethod added in v1.0.0

type CallMethod[P, R any] struct{ Method string }

CallMethod is an executor-to-harness request with params P and result R.

func (CallMethod[P, R]) Call added in v1.0.0

func (m CallMethod[P, R]) Call(ctx context.Context, client *Client, params P) (R, error)

Call sends the request on the client's control channel and decodes its result; a JSON-RPC error answer is an *RPCError.

type CallToolOptions added in v1.0.0

type CallToolOptions struct {
	// ToolCallID is the idempotency id of the call; generated when empty.
	ToolCallID string
	DeadlineMS int64
	Permission *ToolPermission
}

CallToolOptions are the optional fields of a typed harness tool call.

type Capabilities

type Capabilities struct {
	Shell       *ShellCapability `json:"shell,omitempty"`
	Files       *FilesCapability `json:"files,omitempty"`
	MCP         *MCPCapability   `json:"mcp,omitempty"`
	Chrome      bool             `json:"chrome,omitempty"`
	ComputerUse bool             `json:"computer_use,omitempty"`
	// v1 boolean or v1.1 DisplayCapability object.
	Display      json.RawMessage         `json:"display,omitempty"`
	Process      *ProcessCapability      `json:"process,omitempty"`
	Artifacts    *ArtifactCapability     `json:"artifacts,omitempty"`
	Terminal     *TerminalCapability     `json:"terminal,omitempty"`
	Skills       *SkillsCapability       `json:"skills,omitempty"`
	Workspace    *WorkspaceCapability    `json:"workspace,omitempty"`
	Agent        *AgentCapability        `json:"agent,omitempty"`
	SessionFiles *SessionFilesCapability `json:"session_files,omitempty"`
	Fs           *FsCapability           `json:"fs,omitempty"`
}

Capabilities Executor capability object. The server only sends a method to an executor that advertised its capability; otherwise the executor answers -32012 capability_unavailable.

type Capability

type Capability struct {
	// Advertise sets the capability bits on the register capabilities.
	Advertise     func(*Capabilities)
	Methods       map[string]Handler
	SessionScoped bool
	OnSessionEnd  func(*CoreSession)
}

Capability is an extension of the core: a set of methods behind one or more capability bits. The core advertises the bits through Capabilities, routes the methods for every attached brain and, for SessionScoped capabilities, answers session_not_active (-32007) for unknown sessions and calls OnSessionEnd before a session reports session.ended.

func NewProcessCapability

func NewProcessCapability(core *Core, opts ProcessOptions) Capability

NewProcessCapability serves process.start/read/write/interrupt/terminate/list and process.status (v1.1 §3) on core sessions: pipes or a PTY, bounded cursor-addressed output, idempotent starts and writes, timeouts, process group signals, and file transfers and Git credentials through opts. A session's processes are terminated when it stops.

func NewSkillInstallCapability

func NewSkillInstallCapability(install SkillInstaller) (Capability, error)

NewSkillInstallCapability serves skill.install (skills.install) with install. Installs run one at a time.

type ChannelTarget

type ChannelTarget struct {
	Channel   string // ChannelControl or ChannelMCP
	SessionID string
	ServerKey string
}

ChannelTarget names the channel a Dialer opens: the control channel, or the MCP channel of one session.assign mcp_servers entry (?channel=mcp&session_id=&server_key= on WebSocket transports).

type Client

type Client struct {
	// Tools has one typed slot per built-in tool: Tools.Bash.Handle(...).
	// Capabilities shell, files and computer_use follow what is registered.
	Tools Tools
	// contains filtered or unexported fields
}

Client is an outbound executor client.

func NewClient

func NewClient(options Options) (*Client, error)

NewClient validates options and returns a disconnected client.

func (*Client) ActiveSessions

func (c *Client) ActiveSessions() []string

ActiveSessions returns the sessions currently assigned to this executor.

func (*Client) ConnectionID

func (c *Client) ConnectionID() string

ConnectionID returns the current connection id.

func (*Client) Done

func (c *Client) Done() <-chan struct{}

Done is closed when the client stops for good: Stop, executor.close, a terminal close code (4004 replaced, 4003 unsupported protocol, ...), a credential rejected on reconnect, or exhausted reconnects.

func (*Client) Err

func (c *Client) Err() error

Err explains Done: nil after Stop or executor.close, ErrReplaced after 4004, ErrCredentialRejected, ErrReconnectExhausted, or the terminal close error.

func (*Client) ExecutorID

func (c *Client) ExecutorID() string

ExecutorID returns the id assigned by executor.register.

func (*Client) OnDrain

func (c *Client) OnDrain(handler DrainHandler)

OnDrain registers the executor.drain handler.

func (*Client) OnSessionAssign

func (c *Client) OnSessionAssign(handler SessionAssignHandler)

OnSessionAssign registers the session.assign handler.

func (*Client) OnSessionStop

func (c *Client) OnSessionStop(handler SessionStopHandler)

OnSessionStop registers the session.stop handler.

func (*Client) OnToolCallAccept

func (c *Client) OnToolCallAccept(accept func(ToolCallParams) error)

OnToolCallAccept registers a check run before a tool.call is acknowledged. An error answers the request instead (a *RPCError keeps its code, for example session_not_active or capability_unavailable) and the tool does not run.

func (*Client) OpenMCPChannel

func (c *Client) OpenMCPChannel(ctx context.Context, sessionID, serverKey string) (*MCPChannel, error)

OpenMCPChannel opens the MCP channel (?channel=mcp on WebSocket transports) with a fresh executor token through Options.Dial. sessionID and serverKey identify the environment-owned MCP server from session.assign.mcp_servers.

func (*Client) ReportToolResult

func (c *Client) ReportToolResult(ctx context.Context, params ToolResultParams) (Ack, error)

ReportToolResult sends tool.result once per tool_call_id, retrying retryable failures (executor_busy, timeout, a disconnect) with exponential backoff across reconnects. A duplicate call for an accepted tool_call_id returns accepted without sending another frame.

func (*Client) ServeAgent

func (c *Client) ServeAgent(handler AgentHandler, capability AgentCapability)

ServeAgent advertises the agent capability and routes the agent methods to handler. Call it before Start.

func (*Client) SessionContext added in v1.1.0

func (c *Client) SessionContext(ctx context.Context, processID string) (SessionContext, error)

SessionContext returns the context of the agent session processID runs for (process.start metadata names it as agent_session_id). It needs a machine-scoped executor (ErrMachineTokenRequired). Results are cached per session; a failure is not.

func (*Client) SessionContextByID added in v1.1.0

func (c *Client) SessionContextByID(ctx context.Context, sessionID string) (SessionContext, error)

SessionContextByID returns the context of an agent session bound to this machine, for capabilities without a process (an agent turn.start carries only the session id). Cached like SessionContext.

func (*Client) SessionEnded

func (c *Client) SessionEnded(ctx context.Context, params SessionEndedParams) (Ack, error)

SessionEnded reports that every process and MCP server for the session has stopped. The session leaves ActiveSessions after the harness accepts.

func (*Client) SessionReady

func (c *Client) SessionReady(ctx context.Context, params SessionReadyParams) (Ack, error)

SessionReady reports that the executor accepted session.assign and has prepared the session. Call it after workspace and MCP setup complete.

func (*Client) Start

Start fetches an executor token, connects, registers, and starts heartbeats. After a failed Start the client may be started again.

func (*Client) State

func (c *Client) State() ConnectionState

State returns the current connection state.

func (*Client) Stop

func (c *Client) Stop(ctx context.Context, reason string) error

Stop sends executor.close, closes the connection, and fails pending calls.

func (*Client) UploadArtifact

func (c *Client) UploadArtifact(ctx context.Context, sessionID, name, mimeType string, content []byte) (ArtifactRef, error)

UploadArtifact implements POST /v1/environments/{environment_id}/artifacts (v1.1 §6.5) with the current executor token. It must finish before a tool.result references the artifact; the upload is idempotent by (session, digest).

func (*Client) WaitReady added in v1.0.4

func (c *Client) WaitReady(ctx context.Context) error

WaitReady blocks until the executor is registered and the registration stayed open for one heartbeat interval. State() is ready as soon as executor.register returns, but a machine-scoped executor that declared neither the process nor the agent capability is closed with 4002 right after that, so only WaitReady separates a usable executor from a registration that is about to be refused. It returns the error of a client that ended (Err, or ErrClientStopped after Stop) and ctx.Err() on timeout.

type CloseError

type CloseError struct {
	Code   int
	Reason string
}

CloseError is the error Read returns after the peer closed with a code.

func (*CloseError) Error

func (e *CloseError) Error() string

type ComputerActionInput added in v1.0.0

type ComputerActionInput struct {
	Action string `json:"action"`
	// Display to act on.
	Display string `json:"display,omitempty"`
}

ComputerActionInput computer_action input.

type ComputerObserveInput added in v1.0.0

type ComputerObserveInput struct {
	// Display to observe.
	Display string `json:"display,omitempty"`
}

ComputerObserveInput computer_observe input.

type Conn

type Conn interface {
	Read(ctx context.Context) ([]byte, error)
	Write(ctx context.Context, frame []byte) error
	// Close ends the connection with a WebSocket-style close code; the peer
	// reads it as a *CloseError.
	Close(code int, reason string) error
	// Subprotocol is the negotiated executor protocol.
	Subprotocol() string
}

Conn is one executor control connection: ordered JSON-RPC text frames in both directions. The protocol does not depend on the transport; the SDK ships WebSocket (cloud, executor dials out), a local socket (Unix domain socket carrying the same WebSocket upgrade) and an in-process pipe.

func NewWebSocketConn

func NewWebSocketConn(ws *websocket.Conn) Conn

NewWebSocketConn wraps an accepted or dialed WebSocket as a Conn.

type ConnectionState

type ConnectionState string

ConnectionState is the executor control channel state (ConnectionState* values).

type ContentBlock

type ContentBlock struct {
	Type       string `json:"type"`
	Text       string `json:"text,omitempty"`
	Data       string `json:"data,omitempty"`
	MimeType   string `json:"mime_type,omitempty"`
	URL        string `json:"url,omitempty"`
	ArtifactID string `json:"artifact_id,omitempty"`
}

ContentBlock Tool result content block. An artifact block carries artifact_id and mime_type instead of text (v1.1 §6.5).

func NewArtifactContentBlock

func NewArtifactContentBlock(ref ArtifactRef) ContentBlock

NewArtifactContentBlock builds the content block that points at an artifact from inside tool.result content.

type Core

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

Core is the executor's execution core ("hands"): bash with process-group cancellation, file tools, a stdio MCP supervisor, per-session cleanup and registered capabilities (process.*, terminal.*, skill.install, ...). It is independent of who drives it: Attach it to one Client per harness ("brain"), whether that is the BMA cloud or a local harness on a local socket, and every brain gets the same protocol behavior.

Isolation: sessions are keyed by (brain, session_id), so two brains may use the same session id without seeing each other; a request can only reach sessions its own brain assigned, and each session has its own workspace, processes and MCP servers. Capacity is shared: MaxSessions across brains, MaxSessionsPerBrain per brain. Bash is not a sandbox: every brain runs as the executor's OS user.

func NewCore

func NewCore(opts CoreOptions) (*Core, error)

NewCore validates options and creates WorkRoot.

func (*Core) Attach

func (c *Core) Attach(brain string, client *Client) error

Attach serves session.assign, session.stop, tool.call and every registered capability method for one brain on client. Call it before client.Start. brain names the harness ("cloud", "local", ...) and must be unique per core.

func (*Core) Capabilities

func (c *Core) Capabilities() Capabilities

Capabilities is what an attached Client should advertise.

func (*Core) Close

func (c *Core) Close()

Close stops every session of every brain without reporting session.ended.

func (*Core) Env

func (c *Core) Env(explicit map[string]string) ([]string, error)

Env builds a bash or process environment: baseEnv from the executor, the request env (bounded, loader and DenyEnv variables rejected), then CoreOptions.Env.

func (*Core) Register

func (c *Core) Register(capability Capability) error

Register adds a capability. Call it before Attach; a method may be registered once.

type CoreOptions

type CoreOptions struct {
	// WorkRoot holds every session workspace: WorkRoot/<brain>/<session>.
	WorkRoot string
	// Workspace overrides the per-session directory (for example a machine
	// executor whose sessions all share one directory, or a desktop app
	// mapping a brain to a project folder). Tools are confined to it.
	Workspace func(brain, sessionID string) string
	// MaxSessions bounds active sessions across all attached brains;
	// MaxSessionsPerBrain bounds one brain (defaults to MaxSessions). A full
	// core answers session.assign with executor_busy (-32009, retryable).
	MaxSessions         int
	MaxSessionsPerBrain int
	// MaxMCPServersPerSession bounds session.assign.mcp_servers (default 4).
	MaxMCPServersPerSession int
	// BashTimeout applies when neither tool.call deadline_ms nor the bash
	// timeout_ms is set (default 10 minutes).
	BashTimeout time.Duration
	// MaxOutputBytes caps each captured bash stream (default 1 MiB).
	MaxOutputBytes int
	// InlineResultBytes is the largest bash output returned inline (default
	// 48 KiB, under the 64 KiB control frame). Larger output is uploaded as
	// an artifact when UploadArtifacts is set, otherwise truncated.
	InlineResultBytes int
	// UploadArtifacts advertises the artifacts capability and offloads large
	// bash results with Client.UploadArtifact. Only environment-scoped
	// executors have an artifact store.
	UploadArtifacts bool
	// Env is set on every bash tool and process and cannot be overridden by
	// a request (for example BMA_HOME).
	Env map[string]string
	// DenyEnv reports executor-private variables (credentials, state paths)
	// that no bash tool, process or stdio MCP server may see: they are
	// dropped from the inherited environment and a request setting one is
	// rejected. NewCore rejects an Env entry it denies.
	DenyEnv func(name string) bool
	// RunAs, when set, is the OS identity every bash tool, process and stdio
	// MCP server runs as, so a privileged executor (for example root) keeps
	// its own credentials and state out of the workload's reach. HOME and
	// USER in bash and process environments are the workload's. File tools
	// (read/write/edit/glob/grep) run inside the executor and would bypass
	// that boundary, so they are refused. Unix only.
	RunAs *RunAs
	// EndAfterToolCall marks sessions that carry exactly one tool call: the
	// core ends them (session.ended "completed") after the result is
	// delivered. BMA's durable selfhost queue assigns such sessions.
	EndAfterToolCall func(SessionAssignParams) bool
	OnLog            func(LogEvent)
}

CoreOptions configures the execution core.

type CoreSession

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

CoreSession is one assigned session of one brain.

func (*CoreSession) Assignment

func (s *CoreSession) Assignment() SessionAssignParams

Assignment is the session.assign that created the session.

func (*CoreSession) Brain

func (s *CoreSession) Brain() string

func (*CoreSession) Client

func (s *CoreSession) Client() *Client

func (*CoreSession) Context

func (s *CoreSession) Context() context.Context

Context is canceled when the session stops.

func (*CoreSession) ID

func (s *CoreSession) ID() string

func (*CoreSession) ResolveCwd

func (s *CoreSession) ResolveCwd(cwd string) (string, error)

ResolveCwd returns the real directory for a working directory request: a relative cwd is under the workspace, an absolute one must resolve (through symlinks) under it.

func (*CoreSession) Value

func (s *CoreSession) Value(key any, create func() any) any

Value returns the per-session value for key, creating it with create on first use. Capabilities keep their session state here.

func (*CoreSession) Workspace

func (s *CoreSession) Workspace() string

type Cursors

type Cursors struct {
	Stdout int64 `json:"stdout"`
	Stderr int64 `json:"stderr"`
}

Cursors Per-stream byte cursors.

type DaemonHTTPError added in v1.1.0

type DaemonHTTPError struct {
	StatusCode int
	// Code and Message are BMA's error body when it sent one.
	Code    string
	Message string
}

DaemonHTTPError is a non-2xx answer of a BMA daemon route.

func (*DaemonHTTPError) Error added in v1.1.0

func (e *DaemonHTTPError) Error() string

type Dialer

type Dialer func(ctx context.Context, token ExecutorTokenResponse, protocol string, target ChannelTarget) (Conn, error)

Dialer opens an executor channel after the token source returned token. The default dials token.WSURL over WebSocket: ws://, wss:// or unix:///path/to.sock or npipe:////./pipe/<name> (the same WebSocket upgrade on a Unix domain socket or a Windows named pipe, as in the TypeScript and Python SDKs).

func InProcessDialer

func InProcessDialer(h *Harness, principal Principal) Dialer

InProcessDialer connects the executor to h in the same process: every dial creates a fresh Pipe and serves its harness end with principal, as the control channel or as an MCP channel.

func ListenNamedPipe

func ListenNamedPipe(name, token string) (Dialer, func() error, error)

ListenNamedPipe is ListenUnixSocket on a Windows named pipe \\.\pipe\<name>: the executor listens and the next local harness that dials it with Authorization: Bearer token (Harness.DialExecutor with the pipe name or an npipe:// URL) becomes its brain.

func ListenUnixSocket

func ListenUnixSocket(path, token string) (Dialer, func() error, error)

ListenUnixSocket makes the executor the listening side on a local machine: it creates a 0700 directory and a 0600 Unix socket at path and returns a Dialer that waits for the next local harness ("brain") to connect with Authorization: Bearer token. The roles do not change: the brain is still the harness and the executor still registers. The brain (Harness. DialExecutor) also dials the MCP channels of its sessions; an MCP dial waits for that connection. Use it as Options.Dial with TokenSource StaticToken("ws://local/", "") so the executor reconnects by accepting again. Close the returned closer to stop listening.

func NamedPipeDialer

func NamedPipeDialer(name string) Dialer

NamedPipeDialer dials a harness serving Harness.ServeHTTP on the Windows named pipe \\.\pipe\<name> (NamedPipeListener). token.WSURL is ignored; StaticToken("npipe:////./pipe/"+name, token) with the default dialer is equivalent.

func UnixSocketDialer

func UnixSocketDialer(path string) Dialer

UnixSocketDialer dials a harness listening on the Unix domain socket at path (the harness serves Harness.ServeHTTP on that listener). token.WSURL is ignored; StaticToken("unix://"+path, token) with the default dialer is equivalent.

func WebSocketDialer

func WebSocketDialer(httpClient *http.Client) Dialer

WebSocketDialer dials token.WSURL (ws://, wss://, unix:// or npipe://) with the bearer token in the Authorization header. httpClient may carry a proxy or a custom transport; nil uses http.DefaultClient. A unix:// URL always dials its socket.

type DisplayCapability

type DisplayCapability struct {
	RFB bool `json:"rfb,omitempty"`
	// The machine can host its own desktop for a desktop session (it carries bma-desktop-session, started through process.start). Absent means unknown (an executor that predates the field).
	Desktop bool `json:"desktop,omitempty"`
}

DisplayCapability v1.1 display object. v1 sent a boolean; the server accepts both.

type DrainHandler

type DrainHandler func(ctx context.Context, params ExecutorDrainParams) (ExecutorDrainResult, error)

DrainHandler handles an inbound executor.drain.

type EditInput added in v1.0.0

type EditInput struct {
	// File path, relative to the session workspace.
	Path string `json:"path"`
	// Text that must occur exactly once.
	OldString string `json:"old_string"`
	// Replacement text.
	NewString string `json:"new_string"`
}

EditInput edit input: replace the single occurrence of old_string.

type EvaluatedPermission

type EvaluatedPermission struct {
	Type string `json:"type"`
}

EvaluatedPermission Permission decision the executor applied to a tool use. ask means the executor opened an interaction.request for it.

type Executor

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

Executor is one registered executor. It outlives a single connection: a reconnect with resume.executor_id within the lease attaches to the same Executor and keeps its sessions and pending tool calls.

func (*Executor) AgentCapability

func (e *Executor) AgentCapability() (*AgentCapability, error)

AgentCapability returns the advertised agent capability, nil when absent.

func (*Executor) AssignSession

func (e *Executor) AssignSession(ctx context.Context, params SessionAssignParams) (*Session, error)

AssignSession binds a session to this executor and sends session.assign. WorkID and the lease token are generated when empty. The session is bound before the request is sent, so session.ready and MCP channels that race the assign response are accepted.

func (*Executor) Call

func (e *Executor) Call(ctx context.Context, method string, params, out any) error

Call sends a harness-to-executor request for a capability method (process.*, terminal.*, skill.install, ...) and decodes its result. A JSON-RPC error answer is an *RPCError.

func (*Executor) CancelTurn

func (e *Executor) CancelTurn(ctx context.Context, params TurnCancelParams) (TurnCancelResult, error)

CancelTurn sends turn.cancel. The turn's end is still reported by its session.status_idle event.

func (*Executor) Capabilities

func (e *Executor) Capabilities(out any) error

Capabilities decodes the advertised capabilities into out (for example *Capabilities, or a v1.1 capability struct).

func (*Executor) CloseAgentSession

func (e *Executor) CloseAgentSession(ctx context.Context, params SessionCloseParams) (SessionCloseResult, error)

CloseAgentSession sends session.close.

func (*Executor) Drain

func (e *Executor) Drain(ctx context.Context, reason string) (ExecutorDrainResult, error)

Drain asks the executor to stop accepting sessions; existing sessions run to completion. Heartbeats report drain=true from now on.

func (*Executor) ID

func (e *Executor) ID() string

func (*Executor) Info

func (e *Executor) Info() ExecutorInfo

func (*Executor) Protocol

func (e *Executor) Protocol() string

Protocol is the negotiated subprotocol of the current connection.

func (*Executor) RespondInteraction

func (e *Executor) RespondInteraction(ctx context.Context, params InteractionResponseParams) (InteractionResponseResult, error)

RespondInteraction delivers the platform's answer. accepted=false means the executor no longer waits for it (answered already, withdrawn, or unknown); mark the platform interaction stale.

func (*Executor) SendTurnInput

func (e *Executor) SendTurnInput(ctx context.Context, params TurnInputParams) (Ack, error)

SendTurnInput sends turn.input; a conflict means the turn is over and the input belongs in a new turn.start.

func (*Executor) Sessions

func (e *Executor) Sessions() []*Session

Sessions returns the sessions bound to this executor.

func (*Executor) StartTurn

func (e *Executor) StartTurn(ctx context.Context, params TurnStartParams) (TurnStartResult, error)

StartTurn sends turn.start. It is safe to repeat with the same turn_id after a timeout or reconnect.

type ExecutorCapabilitiesUpdateParams

type ExecutorCapabilitiesUpdateParams struct {
	Capabilities Capabilities `json:"capabilities"`
}

ExecutorCapabilitiesUpdateParams is the params object of executor.capabilities.update.

type ExecutorCloseParams

type ExecutorCloseParams struct {
	Reason string `json:"reason"`
}

ExecutorCloseParams is the params object of executor.close.

type ExecutorDrainParams

type ExecutorDrainParams struct {
	Reason     string `json:"reason"`
	DeadlineMS int64  `json:"deadline_ms,omitempty"`
}

ExecutorDrainParams is the params object of executor.drain.

type ExecutorDrainResult

type ExecutorDrainResult struct {
	Accepted       bool     `json:"accepted"`
	ActiveSessions []string `json:"active_sessions"`
}

ExecutorDrainResult executor.drain result.

type ExecutorHeartbeatParams

type ExecutorHeartbeatParams struct {
	ConnectionID   string        `json:"connection_id"`
	ActiveSessions []string      `json:"active_sessions"`
	Load           *ExecutorLoad `json:"load,omitempty"`
}

ExecutorHeartbeatParams is the params object of executor.heartbeat.

type ExecutorHeartbeatResult

type ExecutorHeartbeatResult struct {
	ServerTime string `json:"server_time"`
	LeaseTTLMS int64  `json:"lease_ttl_ms"`
	Drain      bool   `json:"drain"`
}

ExecutorHeartbeatResult executor.heartbeat result.

func SendExecutorHeartbeat

func SendExecutorHeartbeat(ctx context.Context, rpc RPC, params ExecutorHeartbeatParams) (ExecutorHeartbeatResult, error)

SendExecutorHeartbeat calls executor.heartbeat.

type ExecutorInfo

type ExecutorInfo struct {
	Name    string `json:"name"`
	OS      string `json:"os"`
	Arch    string `json:"arch"`
	Version string `json:"version"`
}

ExecutorInfo Executor identity reported at token bootstrap and registration.

type ExecutorLoad

type ExecutorLoad struct {
	CPUPercent    float64 `json:"cpu_percent,omitempty"`
	MemoryPercent float64 `json:"memory_percent,omitempty"`
}

ExecutorLoad Advisory executor load reported with executor.heartbeat. The server does not act on it.

type ExecutorRegisterParams

type ExecutorRegisterParams struct {
	Protocol string `json:"protocol"`
	// Selfhost environment id; empty for a machine-scoped executor.
	EnvironmentID string          `json:"environment_id"`
	Executor      ExecutorInfo    `json:"executor"`
	Capabilities  Capabilities    `json:"capabilities"`
	Resume        *ExecutorResume `json:"resume,omitempty"`
}

ExecutorRegisterParams is the params object of executor.register.

type ExecutorRegisterResult

type ExecutorRegisterResult struct {
	ExecutorID           string  `json:"executor_id"`
	ConnectionID         string  `json:"connection_id"`
	ServerTime           string  `json:"server_time"`
	HeartbeatIntervalMS  int64   `json:"heartbeat_interval_ms"`
	LeaseTTLMS           int64   `json:"lease_ttl_ms"`
	MaxControlFrameBytes int64   `json:"max_control_frame_bytes"`
	MaxMCPFrameBytes     int64   `json:"max_mcp_frame_bytes"`
	Drain                bool    `json:"drain"`
	Protocol             string  `json:"protocol,omitempty"`
	Limits               *Limits `json:"limits,omitempty"`
}

ExecutorRegisterResult executor.register result. protocol and limits are v1.1 only.

func SendExecutorRegister

func SendExecutorRegister(ctx context.Context, rpc RPC, params ExecutorRegisterParams) (ExecutorRegisterResult, error)

SendExecutorRegister calls executor.register.

type ExecutorResume

type ExecutorResume struct {
	ExecutorID       string   `json:"executor_id,omitempty"`
	LastConnectionID string   `json:"last_connection_id,omitempty"`
	ActiveSessions   []string `json:"active_sessions,omitempty"`
}

ExecutorResume Reattach state sent on reconnect.

type ExecutorTokenRefreshParams

type ExecutorTokenRefreshParams struct {
	Token string `json:"token"`
}

ExecutorTokenRefreshParams is the params object of executor.token.refresh.

type ExecutorTokenRefreshResult

type ExecutorTokenRefreshResult struct {
	// RFC 3339 time of the new connection deadline.
	ExpiresAt string `json:"expires_at"`
}

ExecutorTokenRefreshResult executor.token.refresh result: the connection now closes with 4001 at expires_at.

func SendExecutorTokenRefresh

func SendExecutorTokenRefresh(ctx context.Context, rpc RPC, params ExecutorTokenRefreshParams) (ExecutorTokenRefreshResult, error)

SendExecutorTokenRefresh calls executor.token.refresh.

type ExecutorTokenRequest

type ExecutorTokenRequest struct {
	EnvironmentID string       `json:"environment_id"`
	Executor      ExecutorInfo `json:"executor"`
}

ExecutorTokenRequest Token request body for POST /v1/machines/{machine_id}/token (bearer: machine daemon token) and POST /v1/environments/{environment_id}/token (bearer: environment key); the legacy alias POST /v1/executors/token takes either bearer. The id in the path must equal the credential's machine or environment, otherwise 404; on the new paths environment_id may be empty or absent for a machine and, when sent for an environment, must equal the path id. An empty environment_id with a machine token requests a machine-scoped executor: its executor_id is exec_<machine_id>, stable across refreshes, and the JWT carries machine_id and daemon_token_id.

type ExecutorTokenResponse

type ExecutorTokenResponse struct {
	ExecutorID string `json:"executor_id"`
	// Short-lived executor JWT, sent only in the Authorization header of the channel upgrade.
	Token string `json:"token"`
	// Seconds.
	ExpiresIn    int64    `json:"expires_in"`
	WSURL        string   `json:"ws_url"`
	ChannelScope []string `json:"channel_scope"`
}

ExecutorTokenResponse Token response of POST /v1/machines/{machine_id}/token, POST /v1/environments/{environment_id}/token and the legacy alias POST /v1/executors/token.

type FileTransferError

type FileTransferError struct {
	Code          string `json:"code"`
	Message       string `json:"error"`
	CurrentDigest string `json:"current_digest,omitempty"`
}

FileTransferError Failed file transfer.

type FileTransferResult

type FileTransferResult struct {
	Path   string             `json:"path,omitempty"`
	Digest string             `json:"digest,omitempty"`
	Error  *FileTransferError `json:"error,omitempty"`
}

FileTransferResult Ended file transfer outcome: the uploaded path and digest, the downloaded digest, or an error.

type FileTransferer

type FileTransferer interface {
	TransferFile(ctx context.Context, processID string, transfer ProcessFileTransfer) (FileTransferResult, error)
}

FileTransferer moves one file for a process.start file_transfer. A failure is returned both as the error (the process output, exit code 1) and as FileTransferResult.Error, which the harness reports.

type FilesCapability

type FilesCapability struct {
	Enabled    bool     `json:"enabled"`
	ReadRoots  []string `json:"read_roots,omitempty"`
	WriteRoots []string `json:"write_roots,omitempty"`
}

FilesCapability v1 file tools.

type FsCapability added in v1.2.0

type FsCapability struct {
	Fuse  bool     `json:"fuse"`
	Views []string `json:"views,omitempty"`
}

FsCapability Session file views mounted by the executor as FUSE file systems backed by bma-file (docs/adr/0021). Declared only after the executor probed that it can mount. Absent or fuse=false: the session files stay on the copy-and-scan protocol (session_files). views lists the views the executor can mount; the harness only mounts those. Machine-scoped executors only.

type FsMount added in v1.2.0

type FsMount struct {
	// uploads (FS1). Open enum: outputs, skills and memory follow.
	View     string `json:"view"`
	Path     string `json:"path"`
	Readonly bool   `json:"readonly"`
	Token    string `json:"token"`
	// Reserved mount tuning (string values); unknown keys are ignored.
	Options map[string]string `json:"options,omitempty"`
}

FsMount One view to mount. path is the absolute mount point on the executor host (derived from session_files by the harness). readonly is also fixed inside token; the executor mounts read-only when it is true. token is a capability token for this session and machine: keep it in memory only, never write it to disk, argv, environment or logs.

type FsMountParams added in v1.2.0

type FsMountParams struct {
	SessionID string `json:"session_id"`
	// Complete prefix of the bma-file routes for this machine, ending in /v1/machines/{machine_id}/fs (for example https://executor.example.com/v1/machines/mach_01/fs). The executor appends "/<op>" and nothing else; it does not compose the machine id itself. The previous <origin>/v1/fs/<op> routes stay as an alias until they are removed.
	ServiceURL string    `json:"service_url"`
	Mounts     []FsMount `json:"mounts"`
}

FsMountParams is the params object of fs.mount.

type FsMountResult added in v1.2.0

type FsMountResult struct {
	State     string `json:"state"`
	ErrorCode string `json:"error_code,omitempty"`
	Error     string `json:"error,omitempty"`
}

FsMountResult fs.mount result. state is "mounted" once every listed view is mounted and serving, or "failed" with error_code and error (nothing stays half-mounted).

type FsUnmountParams added in v1.2.0

type FsUnmountParams struct {
	SessionID string `json:"session_id"`
	Flush     bool   `json:"flush,omitempty"`
}

FsUnmountParams is the params object of fs.unmount.

type FsUnmountResult added in v1.2.0

type FsUnmountResult struct {
	State        string `json:"state"`
	PendingBytes int64  `json:"pending_bytes"`
	ErrorCode    string `json:"error_code,omitempty"`
	Error        string `json:"error,omitempty"`
}

FsUnmountResult fs.unmount result. pending_bytes is data not yet committed to bma-file when flush was requested (always 0 for read-only views).

type GitCredentialGranter

type GitCredentialGranter interface {
	Grant(processID string, env []string) ([]string, func(), error)
}

GitCredentialGranter backs process.start git_credentials: Grant returns the environment that lets processID fetch Git credentials while it runs, and a release function called when the process ends.

type GlobInput added in v1.0.0

type GlobInput struct {
	// Glob pattern.
	Pattern string `json:"pattern"`
	// Base directory, relative to the session workspace.
	Path string `json:"path,omitempty"`
}

GlobInput glob input: list paths matching pattern.

type GrepInput added in v1.0.0

type GrepInput struct {
	// Regular expression.
	Pattern string `json:"pattern"`
	// Directory to search, relative to the session workspace.
	Path string `json:"path,omitempty"`
	// File name filter.
	Glob string `json:"glob,omitempty"`
}

GrepInput grep input: search file lines with a regular expression.

type Handler

type Handler func(ctx context.Context, req Request) (any, error)

Handler serves one harness-to-executor request method registered by a Capability. A *RPCError result is sent as is; any other error becomes internal_error.

type Harness

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

Harness is the harness ("brain") end of the executor protocol: an http.Handler that accepts executor control and MCP channels, plus the session.assign / tool.call / tool.cancel / session.stop API that drives them. It is the same protocol the BMA service speaks, so an executor built on this SDK cannot tell a local harness from the cloud.

func NewHarness

func NewHarness(opts HarnessOptions) *Harness

NewHarness returns a harness with defaults applied.

func (*Harness) DialExecutor

func (h *Harness) DialExecutor(ctx context.Context, path, token string) error

DialExecutor connects this harness to an executor that listens on the local Unix socket at path (ListenUnixSocket) or Windows named pipe (ListenNamedPipe; path is \\.\pipe\<name> or an npipe:// URL) and serves the connection until it closes. A local brain uses it to drive the hand already running on the machine instead of starting another one.

func (*Harness) Executors

func (h *Harness) Executors() []*Executor

Executors returns the executors currently registered (connected or within their reconnect lease).

func (*Harness) ServeConn

func (h *Harness) ServeConn(transport Conn, principal Principal)

ServeConn serves one executor control connection on any transport (an in-process Pipe end, a dialed local socket, ...) until it closes. The caller authenticated the peer; principal pins its identity.

func (*Harness) ServeHTTP

func (h *Harness) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP accepts /v1/executors/channel style upgrades: the control channel by default, the MCP channel with ?channel=mcp&session_id=...&server_key=...

func (*Harness) WaitExecutor

func (h *Harness) WaitExecutor(ctx context.Context) (*Executor, error)

WaitExecutor returns a connected executor, waiting for one to register.

type HarnessMCPChannel

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

HarnessMCPChannel is the harness end of one MCP channel, isolated by (session_id, server_key), on any transport. Frames are raw MCP JSON-RPC exactly as the MCP server sent them: the harness is the MCP client.

func (*HarnessMCPChannel) Close

func (m *HarnessMCPChannel) Close() error

func (*HarnessMCPChannel) Read

func (m *HarnessMCPChannel) Read(ctx context.Context) ([]byte, error)

Read returns the next raw MCP frame. A closed channel returns an error; the executor reopens a fresh one (and a fresh MCP server process), so call Session.MCP again and re-initialize.

func (*HarnessMCPChannel) Write

func (m *HarnessMCPChannel) Write(ctx context.Context, frame []byte) error

type HarnessOptions

type HarnessOptions struct {
	// Authenticate verifies every WebSocket upgrade (control and MCP). nil
	// accepts every connection: use that only on a loopback listener.
	Authenticate func(r *http.Request) (Principal, error)
	// HeartbeatInterval and LeaseTTL are returned by executor.register. A
	// disconnected executor keeps its sessions and pending tool calls for
	// LeaseTTL; then they end and pending calls fail with
	// ErrToolOutcomeUnknown.
	HeartbeatInterval time.Duration
	LeaseTTL          time.Duration
	// RequestTimeout bounds harness-to-executor requests. Defaults to 30s.
	RequestTimeout time.Duration
	// Protocols are the accepted subprotocols in preference order. Defaults
	// to ProtocolV11 then ProtocolV1.
	Protocols []string

	// OnExecutor runs after each successful executor.register.
	OnExecutor func(*Executor)
	// OnSessionEvent persists session.event. nil accepts with a generated id.
	// The harness answers a retried JSON-RPC id with the first result.
	OnSessionEvent  func(ctx context.Context, executor *Executor, params SessionEventParams) (SessionEventResult, error)
	OnSessionStatus func(executor *Executor, params SessionStatusParams)
	OnToolProgress  func(executor *Executor, params ToolProgressParams)
	// OnProcessStatus receives the advisory process.status notification.
	OnProcessStatus func(executor *Executor, params ProcessStatusParams)
	OnLog           func(LogEvent)
	// Agent receives agent-capability traffic: agent session events,
	// previews and interactions. nil rejects them as unknown methods.
	Agent AgentPlatform
}

HarnessOptions configures a Harness.

type HarnessToolSlot added in v1.0.0

type HarnessToolSlot[In any] struct {
	// contains filtered or unexported fields
}

HarnessToolSlot calls one built-in tool from the harness end.

func (HarnessToolSlot[In]) Call added in v1.0.0

func (s HarnessToolSlot[In]) Call(ctx context.Context, input In, options CallToolOptions) (ToolResultParams, error)

Call sends tool.call with a typed input and waits for tool.result, as Session.CallTool.

type HarnessTools added in v1.0.0

HarnessTools has one typed entry per built-in tool: session.Tools.Bash.Call(...). computer_observe and computer_action have none until the contract defines their input members.

type InteractionCancelParams

type InteractionCancelParams struct {
	SessionID     string `json:"session_id"`
	InteractionID string `json:"interaction_id"`
	Reason        string `json:"reason"`
}

InteractionCancelParams is the params object of interaction.cancel.

type InteractionQuestion

type InteractionQuestion struct {
	Prompt        string                      `json:"prompt"`
	Options       []InteractionQuestionOption `json:"options,omitempty"`
	MultiSelect   bool                        `json:"multi_select,omitempty"`
	AllowFreeText bool                        `json:"allow_free_text,omitempty"`
}

InteractionQuestion Question shown to the user.

type InteractionQuestionOption

type InteractionQuestionOption struct {
	ID    string `json:"id"`
	Label string `json:"label"`
}

InteractionQuestionOption One answer option of a question interaction.

type InteractionRequestParams

type InteractionRequestParams struct {
	SessionID string `json:"session_id"`
	TurnID    string `json:"turn_id"`
	// Executor-assigned, unique within the session.
	InteractionID string `json:"interaction_id"`
	Kind          string `json:"kind"`
	// Required for permission.
	ToolUseID string         `json:"tool_use_id,omitempty"`
	ToolName  string         `json:"tool_name,omitempty"`
	ToolInput map[string]any `json:"tool_input,omitempty"`
	// Grant scopes the user may pick for permission; defaults to once.
	Scopes []string `json:"scopes,omitempty"`
	// Required for question.
	Question *InteractionQuestion `json:"question,omitempty"`
	// RFC 3339 time after which the executor stops waiting.
	ExpiresAt string `json:"expires_at,omitempty"`
}

InteractionRequestParams is the params object of interaction.request.

type InteractionRequestResult

type InteractionRequestResult struct {
	Accepted              bool   `json:"accepted"`
	PlatformInteractionID string `json:"platform_interaction_id"`
}

InteractionRequestResult interaction.request result. Idempotent by interaction_id: a repeat returns the same platform interaction.

func SendInteractionRequest

func SendInteractionRequest(ctx context.Context, rpc RPC, params InteractionRequestParams) (InteractionRequestResult, error)

SendInteractionRequest calls interaction.request.

type InteractionResponder

type InteractionResponder struct {
	ActorID string `json:"actor_id,omitempty"`
	Surface string `json:"surface,omitempty"`
}

InteractionResponder Who answered, for local audit. surface is the client that resolved it, for example desktop, mobile, web, slack.

type InteractionResponseParams

type InteractionResponseParams struct {
	SessionID     string `json:"session_id"`
	InteractionID string `json:"interaction_id"`
	Outcome       string `json:"outcome"`
	// Granted scope for allow.
	Scope       string `json:"scope,omitempty"`
	DenyMessage string `json:"deny_message,omitempty"`
	// Selected option ids or free text for answered.
	Answers   []string              `json:"answers,omitempty"`
	Responder *InteractionResponder `json:"responder,omitempty"`
}

InteractionResponseParams is the params object of interaction.response.

type InteractionResponseResult

type InteractionResponseResult struct {
	Accepted bool `json:"accepted"`
}

InteractionResponseResult interaction.response result. accepted=false when the interaction is unknown or already resolved (first answer wins); the platform then marks its copy stale.

type JSONRPCError

type JSONRPCError struct {
	Code    int               `json:"code"`
	Message string            `json:"message"`
	Data    *JSONRPCErrorData `json:"data,omitempty"`
}

JSONRPCError JSON-RPC 2.0 error object.

type JSONRPCErrorData

type JSONRPCErrorData struct {
	// Capacity or timeout failure the caller should retry with backoff.
	Retryable bool   `json:"retryable,omitempty"`
	Detail    string `json:"detail,omitempty"`
	// Missing capability for -32012, for example "tool:read" or "process.pty".
	Capability string `json:"capability,omitempty"`
	// Machine-readable cause; an open set that the harness passes through unchanged (process.start: the tool result error_code and the process state reason; turn.start: the session.error code). Recommended values: workspace_unavailable, workspace_boundary, workspace_read_only, session_rejected, local_confirmation_denied, local_confirmation_expired, spawn_failed / process_id_spec_mismatch for process.start, and capability_missing for executor.register. Receivers must accept values they do not know.
	Reason string `json:"reason,omitempty"`
	// bma.terminal.v1 error code for a failed terminal.* call.
	TerminalCode string `json:"terminal_code,omitempty"`
	// Agent session.event gap (-32013): the sequence the harness expects next.
	ExpectedSequence int64 `json:"expected_sequence,omitempty"`
}

JSONRPCErrorData JSON-RPC error.data. Members are code-specific; unknown members are ignored.

type JSONRPCErrorResponse

type JSONRPCErrorResponse struct {
	JSONRPC string       `json:"jsonrpc"`
	ID      string       `json:"id"`
	Error   JSONRPCError `json:"error"`
}

JSONRPCErrorResponse JSON-RPC 2.0 error response envelope.

type JSONRPCNotification

type JSONRPCNotification struct {
	JSONRPC string          `json:"jsonrpc"`
	Method  string          `json:"method"`
	Params  json.RawMessage `json:"params"`
}

JSONRPCNotification JSON-RPC 2.0 notification envelope (no id).

type JSONRPCRequest

type JSONRPCRequest struct {
	JSONRPC string          `json:"jsonrpc"`
	ID      string          `json:"id"`
	Method  string          `json:"method"`
	Params  json.RawMessage `json:"params"`
}

JSONRPCRequest JSON-RPC 2.0 request envelope.

type JSONRPCSuccessResponse

type JSONRPCSuccessResponse struct {
	JSONRPC string          `json:"jsonrpc"`
	ID      string          `json:"id"`
	Result  json.RawMessage `json:"result"`
}

JSONRPCSuccessResponse JSON-RPC 2.0 success response envelope.

type LaunchFunc added in v1.1.0

type LaunchFunc func(ctx context.Context, req LaunchRequest) (LaunchSpec, error)

LaunchFunc is called once per new command process or package install (not for replays or file transfers), after the session's files are synced and before it is spawned. A package install calls the package manager and may run install scripts, so a hook that confines or refuses commands should check LaunchRequest.PackageInstall too. It may choose the directory (for example from the session's metadata), wrap argv in a sandbox command (sandbox-exec, bwrap) and change the environment. Returning an error refuses the start: an *RPCError (NewReasonError) is answered as is, so the harness sees its data.reason; any other error is answered as spawn_failed.

type LaunchRequest added in v1.1.0

type LaunchRequest struct {
	ProcessContext
	// PackageInstall is set for a process.start package_install and nil for
	// a command. Argv, Cwd and Env are then the installer's fixed command
	// (PackageInstallCommand): the hook may wrap it, change its environment
	// or directory, or refuse it, but the packages come from here.
	PackageInstall *ProcessPackageInstall
	Argv           []string
	// Cwd is the requested cwd as sent (not resolved or confined); for a
	// package install, the installer command's Dir.
	Cwd string
	// DefaultCwd is the session workspace, the cwd used when the hook
	// returns no Dir and the request names none.
	DefaultCwd string
	// Env is the complete environment the process would get.
	Env []string
}

LaunchRequest is one command process or package install about to start.

type LaunchSpec added in v1.1.0

type LaunchSpec struct {
	// Dir is an absolute directory; it is not confined to the workspace.
	Dir  string
	Argv []string
	// Env is the complete environment.
	Env []string
}

LaunchSpec is how the process starts. An empty field keeps the request's value: no Dir resolves the requested cwd inside the session workspace as without a hook, no Argv runs the requested command, a nil Env keeps the computed environment.

type Lease

type Lease struct {
	Token        string `json:"token"`
	FencingToken int64  `json:"fencing_token"`
}

Lease Fencing lease for a session assignment.

type Limits

type Limits struct {
	MaxInflightRequests       int   `json:"max_inflight_requests"`
	MaxConcurrentProcessReads int   `json:"max_concurrent_process_reads"`
	MaxProcessReadBytes       int   `json:"max_process_read_bytes"`
	MaxProcessWriteBytes      int   `json:"max_process_write_bytes"`
	MaxProcessesPerSession    int   `json:"max_processes_per_session"`
	MaxArtifactBytes          int64 `json:"max_artifact_bytes"`
}

Limits Limits the executor must enforce, advertised in the v1.1 executor.register result (v1.1 §1.3).

type ListFilesInput added in v1.0.0

type ListFilesInput struct {
	// Directory, relative to the session workspace.
	Path string `json:"path,omitempty"`
}

ListFilesInput list_files input.

type LogEvent

type LogEvent struct {
	Level   LogLevel
	Message string
	Err     error
}

LogEvent is emitted through Options.OnLog.

type LogLevel

type LogLevel string
const (
	LogDebug LogLevel = "debug"
	LogInfo  LogLevel = "info"
	LogWarn  LogLevel = "warn"
	LogError LogLevel = "error"
)

type MCPCapability

type MCPCapability struct {
	Stdio      bool `json:"stdio,omitempty"`
	HTTP       bool `json:"http,omitempty"`
	MaxServers int  `json:"max_servers,omitempty"`
	// The executor accepts transport.secret_env on stdio servers: resolved secret values it injects only into the server process environment, never persisting, logging or echoing them. Without it the server keeps secret: references in env, which the executor rejects.
	SecretEnv bool `json:"secret_env,omitempty"`
}

MCPCapability Environment-origin MCP servers.

type MCPChannel

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

MCPChannel is a raw MCP JSON-RPC transport on the executor MCP channel. The payload is unframed MCP JSON-RPC: the caller sends initialize, notifications/initialized, tools/list and tools/call directly, exactly as the protocol appendix defines. It runs on the client's transport: WebSocket, a Unix socket or in-process.

func (*MCPChannel) Close

func (m *MCPChannel) Close() error

Close closes the MCP channel.

func (*MCPChannel) Read

func (m *MCPChannel) Read(ctx context.Context) ([]byte, error)

Read returns one MCP JSON-RPC frame: one transport message per call.

func (*MCPChannel) Write

func (m *MCPChannel) Write(ctx context.Context, payload []byte) error

Write sends one MCP JSON-RPC frame as a text message.

type MCPContentBlock

type MCPContentBlock struct {
	Type     string `json:"type"`
	Text     string `json:"text,omitempty"`
	Data     string `json:"data,omitempty"`
	MimeType string `json:"mimeType,omitempty"`
	Resource any    `json:"resource,omitempty"`
}

MCPContentBlock MCP tool content block. Large binary content must go to artifact storage.

type MCPImplementation

type MCPImplementation struct {
	Name    string `json:"name"`
	Version string `json:"version"`
}

MCPImplementation

type MCPInitializeParams

type MCPInitializeParams struct {
	ProtocolVersion string            `json:"protocolVersion"`
	Capabilities    map[string]any    `json:"capabilities"`
	ClientInfo      MCPImplementation `json:"clientInfo"`
}

MCPInitializeParams

type MCPInitializeResult

type MCPInitializeResult struct {
	ProtocolVersion string            `json:"protocolVersion"`
	Capabilities    map[string]any    `json:"capabilities"`
	ServerInfo      MCPImplementation `json:"serverInfo"`
}

MCPInitializeResult

type MCPJSONRPCError

type MCPJSONRPCError struct {
	Code    int64  `json:"code"`
	Message string `json:"message"`
	Data    any    `json:"data,omitempty"`
}

MCPJSONRPCError

type MCPJSONRPCErrorResponse

type MCPJSONRPCErrorResponse struct {
	JSONRPC string          `json:"jsonrpc"`
	ID      json.RawMessage `json:"id"`
	Error   MCPJSONRPCError `json:"error"`
}

MCPJSONRPCErrorResponse

type MCPJSONRPCNotification

type MCPJSONRPCNotification struct {
	JSONRPC string         `json:"jsonrpc"`
	Method  string         `json:"method"`
	Params  map[string]any `json:"params,omitempty"`
}

MCPJSONRPCNotification

type MCPJSONRPCRequest

type MCPJSONRPCRequest struct {
	JSONRPC string          `json:"jsonrpc"`
	ID      json.RawMessage `json:"id"`
	Method  string          `json:"method"`
	Params  map[string]any  `json:"params,omitempty"`
}

MCPJSONRPCRequest

type MCPJSONRPCSuccessResponse

type MCPJSONRPCSuccessResponse struct {
	JSONRPC string          `json:"jsonrpc"`
	ID      json.RawMessage `json:"id"`
	Result  any             `json:"result"`
}

MCPJSONRPCSuccessResponse

type MCPProgressParams

type MCPProgressParams struct {
	ProgressToken json.RawMessage `json:"progressToken"`
	Progress      float64         `json:"progress"`
	Total         float64         `json:"total,omitempty"`
}

MCPProgressParams

type MCPServerConfig

type MCPServerConfig struct {
	ServerKey        string             `json:"server_key"`
	ConnectionOrigin string             `json:"connection_origin"`
	Transport        MCPServerTransport `json:"transport"`
}

MCPServerConfig

type MCPServerTransport

type MCPServerTransport struct {
	Type string `json:"type"`
	// stdio: absolute or allowlisted executable. No shell, no sh -c.
	Command string   `json:"command,omitempty"`
	Args    []string `json:"args,omitempty"`
	// stdio: working directory under the session workspace.
	Cwd string            `json:"cwd,omitempty"`
	Env map[string]string `json:"env,omitempty"`
	// stdio: sensitive variables the server resolved from env secret: references for this session, sent only to an executor that advertises capabilities.mcp.secret_env. The executor adds them to the server process environment only; it must not write them to disk, logs, argv or events, and drops them when the session ends. A name must not also appear in env.
	SecretEnv map[string]string `json:"secret_env,omitempty"`
	TimeoutMS int64             `json:"timeout_ms,omitempty"`
	// Pins the executable when supplied.
	CommandSHA256 string `json:"command_sha256,omitempty"`
	// http: Streamable HTTP MCP endpoint.
	URL string `json:"url,omitempty"`
}

MCPServerTransport Transport for one MCP server. stdio requires command; http requires url. Fields for the other transport are omitted.

type MCPTool

type MCPTool struct {
	Name        string         `json:"name"`
	Description string         `json:"description,omitempty"`
	InputSchema map[string]any `json:"inputSchema"`
}

MCPTool

type MCPToolsCallParams

type MCPToolsCallParams struct {
	Name      string         `json:"name"`
	Arguments map[string]any `json:"arguments"`
}

MCPToolsCallParams

type MCPToolsCallResult

type MCPToolsCallResult struct {
	Content           []MCPContentBlock `json:"content"`
	IsError           bool              `json:"isError,omitempty"`
	StructuredContent any               `json:"structuredContent,omitempty"`
}

MCPToolsCallResult

type MCPToolsListParams

type MCPToolsListParams struct {
	Cursor string `json:"cursor,omitempty"`
}

MCPToolsListParams

type MCPToolsListResult

type MCPToolsListResult struct {
	Tools      []MCPTool `json:"tools"`
	NextCursor *string   `json:"nextCursor,omitempty"`
}

MCPToolsListResult

type MethodDirection

type MethodDirection string

MethodDirection is the direction a JSON-RPC method travels.

const (
	DirectionExecutorToHarness MethodDirection = "executor-to-harness"
	DirectionHarnessToExecutor MethodDirection = "harness-to-executor"
	DirectionBidirectional     MethodDirection = "bidirectional"
)

type MethodSpec

type MethodSpec struct {
	Name         string
	Direction    MethodDirection
	Notification bool
	Since        string
	Capability   string
	IdempotentBy string
}

MethodSpec describes one executor protocol method. Since is the first protocol that has it; Capability is the capability bit the harness checks before sending it (empty: always available).

type NotificationMethod added in v1.0.0

type NotificationMethod[P any] struct{ Method string }

NotificationMethod is an executor-to-harness notification with params P.

func (NotificationMethod[P]) Notify added in v1.0.0

func (m NotificationMethod[P]) Notify(ctx context.Context, client *Client, params P) error

Notify sends the notification on the client's control channel.

type Options

type Options struct {
	// EnvironmentKey is the bearer of the token exchange: an environment key
	// (POST /v1/environments/{EnvironmentID}/token), or a machine daemon token
	// for a machine-scoped executor (POST /v1/machines/{MachineID}/token).
	EnvironmentKey string
	// EnvironmentID is the selfhost environment. EnvironmentID and MachineID
	// are alternatives: setting both is an error. With neither the client
	// registers a machine-scoped executor on the legacy alias
	// POST /api/v1/executors/token (removed in contract 2.0).
	EnvironmentID string
	// MachineID is the machine of a machine-scoped executor, taken from
	// BMA_MACHINE_ID (MachineIDEnv) when empty and EnvironmentID is empty.
	// The id must equal the machine of the credential, otherwise the server
	// answers 404.
	MachineID    string
	Executor     ExecutorInfo
	Capabilities Capabilities
	// Protocol is the WebSocket subprotocol and executor.register protocol.
	// Defaults to ProtocolV11.
	Protocol string

	BaseURL string
	WSURL   string
	// TokenSource replaces the token exchange bootstrap, for example
	// StaticToken for a local harness. When set, EnvironmentKey and BaseURL
	// are not used.
	TokenSource func(ctx context.Context) (ExecutorTokenResponse, error)
	// Dial opens the control connection. Defaults to WebSocketDialer with
	// HTTPClient; see UnixSocketDialer, ListenUnixSocket and InProcessDialer.
	Dial Dialer
	// HTTPClient is used for the token request, artifact uploads and the
	// default WebSocket dial. Defaults to http.DefaultClient.
	HTTPClient *http.Client
	// RequestTimeout bounds one JSON-RPC request. Defaults to 30s.
	RequestTimeout time.Duration
	// HeartbeatInterval overrides the interval returned by executor.register.
	HeartbeatInterval time.Duration
	// HeartbeatLoad is sampled for each heartbeat.
	HeartbeatLoad func() *ExecutorLoad
	// MaxReconnectAttempts bounds consecutive failed reconnects; the client
	// then ends with ErrReconnectExhausted (see Done and Err). Zero (the
	// default) or a negative value reconnects until Stop.
	MaxReconnectAttempts int
	// ReconnectBaseDelay is the first reconnect backoff (default 1s); it
	// doubles per failed attempt up to ReconnectMaxDelay, with jitter.
	ReconnectBaseDelay time.Duration
	// ReconnectMaxDelay caps the reconnect backoff before jitter. Defaults
	// to 60s.
	ReconnectMaxDelay time.Duration
	Random            func() float64
	// ToolResultRetryAttempts is the total number of attempts for tool.result,
	// session.ready and session.ended, including the first. It defaults to 5;
	// set it to 1 to disable retries.
	ToolResultRetryAttempts int
	// ToolResultRetryBaseDelay is the first backoff for retryable failures.
	// It defaults to 250ms and doubles per attempt up to 10s.
	ToolResultRetryBaseDelay time.Duration
	// OnToolResultLost is called by the dispatch path when a tool result could
	// not be accepted after all retries, or the error is not retryable. The
	// adapter must persist the result and replay it with the same
	// tool_call_id; the client never drops a result silently.
	OnToolResultLost func(params ToolResultParams, err error)
	OnLog            func(LogEvent)
}

Options configures a Client.

type PackageInstallCommand

type PackageInstallCommand struct {
	Argv       []string
	Dir        string
	Env        []string
	Privileged bool
}

PackageInstallCommand is the fixed command one package install runs. Env is its complete environment. Privileged runs it with the executor's own identity instead of CoreOptions.RunAs: system package managers need root, user-level ones must not get it.

type PackageInstaller

type PackageInstaller interface {
	PackageInstallCommand(processID string, install ProcessPackageInstall) (PackageInstallCommand, error)
}

PackageInstaller builds the command for a process.start package_install. The core has already checked manager and packages against the contract (one of apt, pip, npm; plain package names only), so the installer passes the packages as separate arguments after its own fixed options.

type Principal

type Principal struct {
	ExecutorID string
}

Principal is what HarnessOptions.Authenticate learns from an upgrade request. A non-empty ExecutorID pins the executor identity: register and MCP channels must belong to it.

type ProcessCapability

type ProcessCapability struct {
	Enabled      bool `json:"enabled"`
	MaxProcesses int  `json:"max_processes,omitempty"`
	BufferBytes  int  `json:"buffer_bytes,omitempty"`
	// Accepts process.start io_mode "pty".
	PTY bool `json:"pty,omitempty"`
	// Accepts process.start file_transfer.
	FileTransfer bool `json:"file_transfer,omitempty"`
	// Accepts process.start git_credentials.
	GitCredentials bool `json:"git_credentials,omitempty"`
	// Accepts process.start package_install.
	PackageInstall bool `json:"package_install,omitempty"`
}

ProcessCapability v1.1 process.* support. pty, file_transfer, package_install and git_credentials are additive: the harness only sends the matching process.start fields to an executor that set them, and fails the process explicitly otherwise.

type ProcessContext added in v1.1.0

type ProcessContext struct {
	// SessionID is the executor session (session.assign) of the process.
	SessionID string
	ProcessID string
	// AgentSessionID is process.start metadata agent_session_id: the agent
	// session the process runs for ("" when the harness named none). Pass it
	// to Client.SessionContextByID, or the process id to
	// Client.SessionContext, to read the session's metadata.
	AgentSessionID string
	Metadata       map[string]string
}

ProcessContext identifies the process a hook runs for.

type ProcessFileTransfer

type ProcessFileTransfer struct {
	Direction string `json:"direction"`
	LocalPath string `json:"local_path"`
}

ProcessFileTransfer Replaces argv: the executor moves one file between the machine and the process BMA file endpoint and reports the outcome in ProcessState.file_transfer. Requires process.file_transfer.

type ProcessListParams

type ProcessListParams struct {
	SessionID string `json:"session_id"`
}

ProcessListParams is the params object of process.list.

type ProcessListResult

type ProcessListResult struct {
	Processes []ProcessState `json:"processes"`
}

ProcessListResult process.list result.

type ProcessOptions

type ProcessOptions struct {
	// Env is set on every process (not on bash tools) over the request env,
	// for example a canonical skill root such as BMA_HOME.
	Env            map[string]string
	FileTransfer   FileTransferer
	GitCredentials GitCredentialGranter
	// PackageInstaller serves process.start package_install.
	PackageInstaller PackageInstaller
	// Launch runs before each new command process starts; see LaunchFunc.
	Launch LaunchFunc
	// SessionFiles syncs each agent session's files below its root, which
	// is advertised as capabilities.session_files.root; see SessionFiles.
	SessionFiles *SessionFiles
}

ProcessOptions configures the process capability. Nil hooks leave the matching capability bit unset, and the core rejects those process.start fields with capability_unavailable.

type ProcessPackageInstall

type ProcessPackageInstall struct {
	Manager  string   `json:"manager"`
	Packages []string `json:"packages"`
}

ProcessPackageInstall Replaces argv: the executor installs packages with a fixed command it builds itself, streaming the package manager output as the process output. apt installs from the machine's configured (official) sources with the executor's own privileges; pip (--user) and npm (global under the workload user's ~/.local) run as the workload user. Package names are plain names only: no options, versions, paths or URLs. Requires process.package_install.

type ProcessReadParams

type ProcessReadParams struct {
	SessionID string `json:"session_id"`
	ProcessID string `json:"process_id"`
	Stream    string `json:"stream"`
	Cursor    int64  `json:"cursor"`
	MaxBytes  int    `json:"max_bytes,omitempty"`
	WaitMS    int64  `json:"wait_ms,omitempty"`
}

ProcessReadParams is the params object of process.read.

type ProcessReadResult

type ProcessReadResult struct {
	ProcessID string `json:"process_id"`
	Stream    string `json:"stream"`
	// Base64 bytes from from_cursor to next_cursor.
	Data           string              `json:"data"`
	FromCursor     int64               `json:"from_cursor"`
	NextCursor     int64               `json:"next_cursor"`
	EarliestCursor int64               `json:"earliest_cursor"`
	Gap            bool                `json:"gap"`
	Truncated      bool                `json:"truncated"`
	EOF            bool                `json:"eof"`
	State          string              `json:"state"`
	EndedAt        string              `json:"ended_at,omitempty"`
	Reason         string              `json:"reason,omitempty"`
	ExitCode       *int                `json:"exit_code"`
	ExitSignal     *string             `json:"exit_signal"`
	FileTransfer   *FileTransferResult `json:"file_transfer,omitempty"`
}

ProcessReadResult process.read result.

type ProcessSignalParams

type ProcessSignalParams struct {
	SessionID string `json:"session_id"`
	ProcessID string `json:"process_id"`
	// Only meaningful for process.terminate.
	GraceMS *int64 `json:"grace_ms,omitempty"`
}

ProcessSignalParams is the params object of process.interrupt and process.terminate.

type ProcessStartParams

type ProcessStartParams struct {
	SessionID string `json:"session_id"`
	ProcessID string `json:"process_id"`
	// Command and arguments (at most 256 entries, 4 KiB each, 16 KiB total). Must be empty when file_transfer or package_install is set.
	Argv  []string          `json:"argv"`
	Cwd   string            `json:"cwd,omitempty"`
	Env   map[string]string `json:"env,omitempty"`
	Stdin string            `json:"stdin,omitempty"`
	// Empty keeps separate stdout/stderr streams.
	Stderr string `json:"stderr,omitempty"`
	WaitMS int64  `json:"wait_ms,omitempty"`
	// Kills the process and ends it as failed with reason "timeout".
	TimeoutMS int64 `json:"timeout_ms,omitempty"`
	// Who started the process. A process an agent tool started (a command, a file transfer, a package install) always carries agent_session_id (the public agent session id) and tool_call_id; it carries no initiator. A process the platform started on its own, such as the machine desktop agent, carries initiator "platform" and no agent_session_id. A process with neither is not started by the harness: an executor that resolves a directory, files or owner per session refuses it (reason session_rejected) instead of using a default. Human console terminals are terminal.attach, not process.start.
	Metadata map[string]string `json:"metadata,omitempty"`
	// Requires capability process.pty.
	IOMode string `json:"io_mode,omitempty"`
	// Requires capability process.file_transfer. Excludes argv entries, io_mode and git_credentials.
	FileTransfer *ProcessFileTransfer `json:"file_transfer,omitempty"`
	// Requires capability process.package_install. Excludes argv entries, io_mode, file_transfer and git_credentials.
	PackageInstall *ProcessPackageInstall `json:"package_install,omitempty"`
	// Installs a per-process Git credential helper for https://github.com that fetches short-lived tokens for this process while it runs. Requires capability process.git_credentials.
	GitCredentials bool `json:"git_credentials,omitempty"`
}

ProcessStartParams is the params object of process.start.

type ProcessState

type ProcessState struct {
	ProcessID    string              `json:"process_id"`
	State        string              `json:"state"`
	PID          int                 `json:"pid,omitempty"`
	StartedAt    string              `json:"started_at,omitempty"`
	EndedAt      string              `json:"ended_at,omitempty"`
	Reason       string              `json:"reason,omitempty"`
	Cursors      Cursors             `json:"cursors"`
	ExitCode     *int                `json:"exit_code"`
	ExitSignal   *string             `json:"exit_signal"`
	Stderr       string              `json:"stderr,omitempty"`
	Accepted     bool                `json:"accepted,omitempty"`
	FileTransfer *FileTransferResult `json:"file_transfer,omitempty"`
}

ProcessState Result of process.start/interrupt/terminate and one process.list entry. ended_at (RFC 3339, executor clock) is set once the process is no longer running; reason explains a "failed" state (for example "timeout"). A spawn failure never creates a state: it is the process.start error with data.reason "spawn_failed".

type ProcessStatusParams

type ProcessStatusParams struct {
	SessionID  string  `json:"session_id"`
	ProcessID  string  `json:"process_id"`
	State      string  `json:"state"`
	ExitCode   *int    `json:"exit_code,omitempty"`
	ExitSignal *string `json:"exit_signal,omitempty"`
	EndedAt    string  `json:"ended_at,omitempty"`
	Reason     string  `json:"reason,omitempty"`
	ObservedAt string  `json:"observed_at"`
}

ProcessStatusParams is the params object of process.status.

type ProcessWriteParams

type ProcessWriteParams struct {
	SessionID  string `json:"session_id"`
	ProcessID  string `json:"process_id"`
	Data       string `json:"data,omitempty"`
	CloseStdin bool   `json:"close_stdin,omitempty"`
}

ProcessWriteParams is the params object of process.write.

type ProcessWriteResult

type ProcessWriteResult struct {
	Accepted bool `json:"accepted"`
}

ProcessWriteResult process.write result.

type RPC

type RPC interface {
	Call(ctx context.Context, method string, params any, result any) error
	Notify(ctx context.Context, method string, params any) error
}

RPC is the transport contract implemented by the handwritten client.

type RPCError

type RPCError struct {
	Code    int
	Message string
	Data    *JSONRPCErrorData
}

RPCError is a JSON-RPC error returned by the peer, or returned by a handler to answer with a specific code and data.

func NewReasonError added in v1.1.0

func NewReasonError(code int, reason, message string) *RPCError

NewReasonError returns the JSON-RPC error a handler or a Launch hook returns to refuse a request with a machine-readable reason, for example NewReasonError(CodeForbidden, ReasonSessionRejected, "not this machine's user").

func (*RPCError) Error

func (e *RPCError) Error() string

type ReadInput added in v1.0.0

type ReadInput struct {
	// File path, relative to the session workspace.
	Path string `json:"path"`
	// First line to return, 1-based.
	Offset int64 `json:"offset,omitempty"`
	// Maximum number of lines.
	Limit int64 `json:"limit,omitempty"`
}

ReadInput read input: return lines of a text file.

type Request

type Request struct {
	Brain  string
	Method string
	// ID is the JSON-RPC request id, the idempotency key of retried writes.
	ID     string
	Params json.RawMessage
	// Session is the active session named by params.session_id for a
	// SessionScoped capability, nil otherwise.
	Session *CoreSession
	Client  *Client
}

Request is one inbound request routed to a Capability handler.

type RequestMethod added in v1.0.0

type RequestMethod[P, R any] struct{ Method string }

RequestMethod is a harness-to-executor request with params P and result R.

func (RequestMethod[P, R]) Handle added in v1.0.0

func (m RequestMethod[P, R]) Handle(client *Client, handler func(ctx context.Context, params P) (R, error))

Handle serves the request on client, replacing an earlier handler. Params that do not decode are answered -32602; return an *RPCError for another JSON-RPC error. RequestID(ctx) is the request's JSON-RPC id.

type RunAs

type RunAs struct {
	UID, GID uint32
	// Groups are the supplementary groups (for example one that may write a
	// shared session directory); empty means none.
	Groups []uint32
	// Home and User replace the executor's HOME and USER.
	Home, User string
}

RunAs is a workload OS identity (CoreOptions.RunAs).

type Session

type Session struct {
	// Tools has one typed entry per built-in tool: Tools.Bash.Call(...).
	Tools HarnessTools
	// contains filtered or unexported fields
}

Session is one session bound to an executor.

func (*Session) CallTool

func (s *Session) CallTool(ctx context.Context, params ToolCallParams) (ToolResultParams, error)

CallTool sends tool.call and waits for its tool.result. It is idempotent by ToolCallID (generated when empty): repeating an id joins the in-flight call or returns the recorded result without re-dispatching. Canceling ctx stops waiting only; use CancelTool to abort the tool. The result is recorded even if nobody is waiting, so a later CallTool with the same id returns it.

func (*Session) CancelTool

func (s *Session) CancelTool(ctx context.Context, toolCallID, reason string) (bool, error)

CancelTool sends tool.cancel. The waiting CallTool still receives the executor's tool.result (outcome canceled when the abort won the race).

func (*Session) Done

func (s *Session) Done() <-chan struct{}

func (*Session) EndReason

func (s *Session) EndReason() string

EndReason is set once Done is closed.

func (*Session) Executor

func (s *Session) Executor() *Executor

func (*Session) ID

func (s *Session) ID() string

func (*Session) MCP

func (s *Session) MCP(ctx context.Context, serverKey string) (*HarnessMCPChannel, error)

MCP waits for the MCP channel for serverKey (one of the session.assign mcp_servers) and returns it. A newer channel for the same key replaces the old one; the session's end closes all of them.

func (*Session) Ready

func (s *Session) Ready(ctx context.Context) error

Ready waits for session.ready.

func (*Session) Stop

func (s *Session) Stop(ctx context.Context, reason string) error

Stop sends session.stop; the executor terminates the session's processes and MCP servers before answering. The session ends locally on success.

func (*Session) WorkID

func (s *Session) WorkID() string

type SessionAssignHandler

type SessionAssignHandler func(ctx context.Context, params SessionAssignParams) (SessionAssignResult, error)

SessionAssignHandler handles an inbound session.assign.

type SessionAssignParams

type SessionAssignParams struct {
	SessionID     string            `json:"session_id"`
	WorkID        string            `json:"work_id"`
	AgentID       string            `json:"agent_id,omitempty"`
	EnvironmentID string            `json:"environment_id"`
	DeadlineMS    int64             `json:"deadline_ms,omitempty"`
	Lease         Lease             `json:"lease"`
	Resources     []json.RawMessage `json:"resources,omitempty"`
	MCPServers    []MCPServerConfig `json:"mcp_servers,omitempty"`
	Metadata      map[string]string `json:"metadata,omitempty"`
}

SessionAssignParams is the params object of session.assign.

type SessionAssignResult

type SessionAssignResult struct {
	Accepted  bool   `json:"accepted"`
	SessionID string `json:"session_id"`
}

SessionAssignResult session.assign result.

type SessionCloseParams

type SessionCloseParams struct {
	SessionID string `json:"session_id"`
	Reason    string `json:"reason"`
}

SessionCloseParams is the params object of session.close.

type SessionCloseResult

type SessionCloseResult struct {
	Closed bool `json:"closed"`
}

SessionCloseResult session.close result.

type SessionContext added in v1.1.0

type SessionContext struct {
	ID            string            `json:"id"`
	EnvironmentID string            `json:"environment_id"`
	Metadata      map[string]string `json:"metadata"`
	CreatedAt     time.Time         `json:"created_at"`
}

SessionContext is what BMA tells this machine about an agent session it serves (GET /api/v1/daemon/processes/{process_id}/session and GET /api/v1/daemon/sessions/{session_id}): the session's environment and the metadata its creator set, never agent configuration or credentials. Executors read it to resolve a reference the caller put in metadata (a project folder, an owner) before running anything, as Claude Managed Agents workers read the session's metadata for a claimed work item.

type SessionEndedParams

type SessionEndedParams struct {
	SessionID string `json:"session_id"`
	Reason    string `json:"reason"`
}

SessionEndedParams is the params object of session.ended.

type SessionErrorEvent

type SessionErrorEvent struct {
	Type  string         `json:"type"`
	Error AgentErrorInfo `json:"error"`
}

SessionErrorEvent A turn-level error. A failed turn still ends with session.status_idle turn_outcome=failed.

type SessionEvent

type SessionEvent struct {
	Type      string         `json:"type"`
	ToolUseID string         `json:"tool_use_id,omitempty"`
	Content   []ContentBlock `json:"content,omitempty"`
	IsError   bool           `json:"is_error,omitempty"`
}

SessionEvent Durable session event emitted by the executor.

type SessionEventDeltaParams

type SessionEventDeltaParams struct {
	SessionID string `json:"session_id"`
	TurnID    string `json:"turn_id"`
	EventID   string `json:"event_id"`
	EventType string `json:"event_type"`
	// Content block index within the event.
	Index int64 `json:"index"`
	// Text appended to the block.
	Text string `json:"text"`
}

SessionEventDeltaParams is the params object of session.event_delta.

type SessionEventParams

type SessionEventParams struct {
	SessionID string `json:"session_id"`
	// Agent sessions; the turn that produced the event.
	TurnID string `json:"turn_id,omitempty"`
	// Agent sessions; executor-assigned, unique within the session, stable across resends.
	EventID string `json:"event_id,omitempty"`
	// Agent sessions; starts at 1 and increases by 1 per durable event within the session.
	Sequence int64           `json:"sequence,omitempty"`
	Event    json.RawMessage `json:"event"`
}

SessionEventParams is the params object of session.event.

type SessionEventResult

type SessionEventResult struct {
	Accepted bool   `json:"accepted"`
	EventID  string `json:"event_id"`
	// Agent sessions: highest contiguous sequence the platform has persisted for the session. A duplicate event is accepted and reports the current value.
	AckedSequence int64 `json:"acked_sequence,omitempty"`
}

SessionEventResult session.event result.

func SendSessionEvent

func SendSessionEvent(ctx context.Context, rpc RPC, params SessionEventParams) (SessionEventResult, error)

SendSessionEvent calls session.event.

type SessionFileTransferer added in v1.1.0

type SessionFileTransferer interface {
	FileTransferer
	TransferSessionFile(ctx context.Context, process ProcessContext, transfer ProcessFileTransfer) (FileTransferResult, error)
}

SessionFileTransferer is a FileTransferer that also learns which session the transfer runs for (for example to check the path against the folder that session may use). When ProcessOptions.FileTransfer implements it, TransferSessionFile is called instead of TransferFile.

type SessionFiles added in v1.1.0

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

SessionFiles syncs the session files of an executor that declares capabilities.session_files. Pass it as ProcessOptions.SessionFiles (the process capability then advertises the root and syncs before each process of an agent session) and run Run for the output uploads. It needs a machine-scoped executor (ErrMachineTokenRequired).

func NewSessionFiles added in v1.1.0

func NewSessionFiles(opts SessionFilesOptions) (*SessionFiles, error)

NewSessionFiles validates the root and creates it (0700) if needed.

func (*SessionFiles) Dirs added in v1.1.0

func (f *SessionFiles) Dirs(sessionID string) (uploads, outputs string)

Dirs returns the uploads and outputs directories of an agent session, for example for a Launch hook that confines a sandbox to them.

func (*SessionFiles) Root added in v1.1.0

func (f *SessionFiles) Root() string

Root is the advertised capabilities.session_files.root.

func (*SessionFiles) Run added in v1.1.0

func (f *SessionFiles) Run(ctx context.Context)

Run uploads changed outputs until ctx ends, then uploads what is left.

type SessionFilesCapability added in v1.1.0

type SessionFilesCapability struct {
	// Absolute, already-expanded, clean path on the executor host (no ~, no . or .. segments, no trailing /).
	Root string `json:"root"`
}

SessionFilesCapability Executor-owned per-session file layout. The harness derives <root>/<agent_session_id>/uploads (read-only session inputs) and <root>/<agent_session_id>/outputs (deliverables) from it, with agent_session_id as sent in process.start metadata, and uses these real paths in prompts, tool descriptions, write rules and the session files manifest. Absent: the harness keeps /mnt/session/uploads and /mnt/session/outputs. Fixed at executor.register: executor.capabilities.update does not change it. Machine-scoped executors only.

type SessionFilesOptions added in v1.1.0

type SessionFilesOptions struct {
	// Root is the absolute, already-expanded directory that holds every
	// session's files; it is advertised as capabilities.session_files.root
	// and BMA shows the agent <Root>/<session id>/{uploads,outputs}. Keep it
	// apart from the executor's own state and IPC directories.
	Root string
	// MaxOutputBytes is the largest output uploaded (default and maximum
	// 1 GiB); larger files are skipped and logged.
	MaxOutputBytes int64
	OnLog          func(LogEvent)
}

SessionFilesOptions configures NewSessionFiles.

type SessionMemoryResource

type SessionMemoryResource struct {
	Type          string `json:"type"`
	MemoryStoreID string `json:"memory_store_id"`
	MountPath     string `json:"mount_path"`
}

SessionMemoryResource A memory store mounted into the session workspace.

type SessionReadyParams

type SessionReadyParams struct {
	SessionID  string `json:"session_id"`
	WorkID     string `json:"work_id"`
	LeaseToken string `json:"lease_token"`
}

SessionReadyParams is the params object of session.ready.

type SessionStatusIdleEvent

type SessionStatusIdleEvent struct {
	Type        string     `json:"type"`
	StopReason  StopReason `json:"stop_reason"`
	TurnOutcome string     `json:"turn_outcome"`
}

SessionStatusIdleEvent The turn ended. It is the last event of its turn_id; the platform publishes the turn as finished only after it accepted this event and every lower sequence.

type SessionStatusParams

type SessionStatusParams struct {
	SessionID string `json:"session_id"`
	Status    string `json:"status"`
	Detail    string `json:"detail,omitempty"`
}

SessionStatusParams is the params object of session.status.

type SessionStatusRunningEvent

type SessionStatusRunningEvent struct {
	Type string `json:"type"`
}

SessionStatusRunningEvent The local agent started working on the turn.

type SessionStopHandler

type SessionStopHandler func(ctx context.Context, params SessionStopParams) (SessionStopResult, error)

SessionStopHandler handles an inbound session.stop.

type SessionStopParams

type SessionStopParams struct {
	SessionID  string `json:"session_id"`
	Reason     string `json:"reason"`
	DeadlineMS int64  `json:"deadline_ms,omitempty"`
}

SessionStopParams is the params object of session.stop.

type SessionStopResult

type SessionStopResult struct {
	Stopped bool `json:"stopped"`
}

SessionStopResult session.stop result.

type ShellCapability

type ShellCapability struct {
	Enabled bool `json:"enabled"`
}

ShellCapability v1 one-shot shell tools.

type SkillInstallParams

type SkillInstallParams struct {
	MachineID     string `json:"machine_id"`
	SkillID       string `json:"skill_id"`
	RevisionID    string `json:"revision_id"`
	Digest        string `json:"digest"`
	DownloadToken string `json:"download_token"`
	// Unix seconds.
	DownloadExpiresAt int64 `json:"download_expires_at"`
}

SkillInstallParams is the params object of skill.install.

type SkillInstallResult

type SkillInstallResult struct {
	State     string `json:"state"`
	ErrorCode string `json:"error_code,omitempty"`
	Error     string `json:"error,omitempty"`
}

SkillInstallResult skill.install result. state is "ready", or "failed" with error_code and error.

type SkillInstaller

type SkillInstaller func(ctx context.Context, params SkillInstallParams) SkillInstallResult

SkillInstaller installs one skill revision; the result state is "ready" or "failed" with error_code and error. It must be idempotent by (skill_id, revision_id, digest).

type SkillsCapability

type SkillsCapability struct {
	Install bool `json:"install"`
}

SkillsCapability skill.install support. Machine-scoped executors only.

type StopReason

type StopReason struct {
	Type string `json:"type"`
}

StopReason Why the turn stopped.

type TerminalAttachParams

type TerminalAttachParams struct {
	TerminalID string       `json:"terminal_id"`
	Epoch      int64        `json:"epoch"`
	StreamID   string       `json:"stream_id"`
	CanWrite   bool         `json:"can_write"`
	FromSeq    int64        `json:"from_seq"`
	AckSeq     int64        `json:"ack_seq"`
	Host       TerminalHost `json:"host"`
}

TerminalAttachParams is the params object of terminal.attach.

type TerminalAttachResult

type TerminalAttachResult struct {
	Accepted    bool   `json:"accepted"`
	WriterEpoch uint64 `json:"writer_epoch"`
}

TerminalAttachResult terminal.attach result, returned after the host socket is connected and the attached frame was written on it.

type TerminalCapability

type TerminalCapability struct {
	Enabled     bool     `json:"enabled"`
	Kinds       []string `json:"kinds,omitempty"`
	MaxSessions int      `json:"max_sessions,omitempty"`
}

TerminalCapability v1.1 terminal.* support. Machine-scoped executors only.

type TerminalCloseParams

type TerminalCloseParams struct {
	TerminalID string `json:"terminal_id"`
	Reason     string `json:"reason,omitempty"`
}

TerminalCloseParams is the params object of terminal.close.

type TerminalCloseResult

type TerminalCloseResult struct {
	Closed   bool `json:"closed"`
	ExitCode *int `json:"exit_code,omitempty"`
}

TerminalCloseResult terminal.close result. Idempotent: closing an unknown or closed terminal returns closed=true.

type TerminalErrorData

type TerminalErrorData struct {
	TerminalCode string `json:"terminal_code,omitempty"`
}

TerminalErrorData JSON-RPC error.data of a failed terminal.* call. terminal_code is the bma.terminal.v1 code the harness relays to the attach (for example terminal_writer_busy).

type TerminalHost

type TerminalHost struct {
	URL    string `json:"url"`
	Ticket string `json:"ticket"`
}

TerminalHost Outbound host socket for one attach. The ticket is a single-use, short-lived bearer credential sent only in the Authorization header, never in the URL.

type TerminalOpenParams

type TerminalOpenParams struct {
	TerminalID string `json:"terminal_id"`
	// human or agent.
	Kind  string            `json:"kind"`
	Shell string            `json:"shell,omitempty"`
	Argv  []string          `json:"argv,omitempty"`
	Cwd   string            `json:"cwd,omitempty"`
	Env   map[string]string `json:"env,omitempty"`
	Rows  uint16            `json:"rows,omitempty"`
	Cols  uint16            `json:"cols,omitempty"`
}

TerminalOpenParams is the params object of terminal.open.

type TerminalOpenResult

type TerminalOpenResult struct {
	TerminalID  string `json:"terminal_id"`
	Epoch       int64  `json:"epoch"`
	PID         int    `json:"pid"`
	Rows        uint16 `json:"rows"`
	Cols        uint16 `json:"cols"`
	EarliestSeq int64  `json:"earliest_seq"`
	LatestSeq   int64  `json:"latest_seq"`
	CreatedAt   string `json:"created_at"`
}

TerminalOpenResult terminal.open result. epoch starts at 1 and increments when the executor recreates the PTY under the same terminal_id; attach is fenced by it.

type ToolCallParams

type ToolCallParams struct {
	SessionID  string          `json:"session_id"`
	ToolCallID string          `json:"tool_call_id"`
	Tool       string          `json:"tool"`
	Input      json.RawMessage `json:"input"`
	DeadlineMS int64           `json:"deadline_ms,omitempty"`
	Permission *ToolPermission `json:"permission,omitempty"`
}

ToolCallParams is the params object of tool.call.

func (ToolCallParams) DecodeInput

func (p ToolCallParams) DecodeInput() (ToolInput, error)

DecodeInput decodes tool.call input into the built-in ToolInput shape. The wire keeps input raw because each tool defines which members it reads.

type ToolCancelParams

type ToolCancelParams struct {
	SessionID  string `json:"session_id"`
	ToolCallID string `json:"tool_call_id"`
	Reason     string `json:"reason,omitempty"`
}

ToolCancelParams is the params object of tool.cancel.

type ToolCancelResult

type ToolCancelResult struct {
	Canceled bool `json:"canceled"`
}

ToolCancelResult tool.cancel result.

type ToolContext added in v1.0.0

type ToolContext struct {
	SessionID  string
	ToolCallID string
	Permission *ToolPermission
	// Progress sends tool.progress for this call (best-effort).
	Progress func(message string)
	// contains filtered or unexported fields
}

ToolContext describes the call a handler serves.

type ToolError added in v1.0.0

type ToolError struct {
	Content []ContentBlock
}

ToolError is a tool-level error reported to the model (outcome succeeded, is_error true), as Core reports a missing file. Same role as the Anthropic SDK ToolError.

func NewToolError added in v1.0.0

func NewToolError(text string) *ToolError

NewToolError returns a ToolError with one text block.

func (*ToolError) Error added in v1.0.0

func (e *ToolError) Error() string

type ToolInput

type ToolInput struct {
	Command   string            `json:"command,omitempty"`
	Cwd       string            `json:"cwd,omitempty"`
	TimeoutMS int64             `json:"timeout_ms,omitempty"`
	Env       map[string]string `json:"env,omitempty"`
	Path      string            `json:"path,omitempty"`
	Offset    int64             `json:"offset,omitempty"`
	Limit     int64             `json:"limit,omitempty"`
	Content   string            `json:"content,omitempty"`
	OldString string            `json:"old_string,omitempty"`
	NewString string            `json:"new_string,omitempty"`
	Pattern   string            `json:"pattern,omitempty"`
	Glob      string            `json:"glob,omitempty"`
	Display   string            `json:"display,omitempty"`
	Action    string            `json:"action,omitempty"`
}

ToolInput Superset of every built-in tool input, decoded by executors that read input generically. tool.call selects the exact per-tool schema through x-bma-params-discriminator; unknown members are ignored.

type ToolOutput added in v1.0.0

type ToolOutput struct {
	Content   []ContentBlock
	IsError   bool
	Artifacts []ArtifactRef
	// Outcome is empty for succeeded; ToolOutcomeCanceled reports a call the
	// handler abandoned because ctx was canceled.
	Outcome string
}

ToolOutput is a handler's result; the client fills in the ids and duration.

func TextOutput added in v1.0.0

func TextOutput(text string) ToolOutput

TextOutput is a ToolOutput of one text block.

type ToolPermission

type ToolPermission struct {
	Mode string `json:"mode"`
}

ToolPermission Tool permission resolved by the harness.

type ToolProgressParams

type ToolProgressParams struct {
	SessionID  string `json:"session_id"`
	ToolCallID string `json:"tool_call_id"`
	Message    string `json:"message"`
}

ToolProgressParams is the params object of tool.progress.

type ToolResultParams

type ToolResultParams struct {
	SessionID  string         `json:"session_id"`
	ToolCallID string         `json:"tool_call_id"`
	Outcome    string         `json:"outcome"`
	IsError    bool           `json:"is_error"`
	Content    []ContentBlock `json:"content"`
	DurationMS int64          `json:"duration_ms,omitempty"`
	Artifacts  []ArtifactRef  `json:"artifacts,omitempty"`
}

ToolResultParams is the params object of tool.result.

type ToolSlot added in v1.0.0

type ToolSlot[In any] struct {
	// contains filtered or unexported fields
}

ToolSlot serves tool.call for one built-in tool.

func (ToolSlot[In]) Handle added in v1.0.0

func (s ToolSlot[In]) Handle(handler func(ctx context.Context, input In, tool ToolContext) (ToolOutput, error))

Handle registers the handler of this tool, replacing an earlier one. The shell and files capabilities follow the registered handlers; registering after Start sends executor.capabilities.update, as MCP servers announce tools registered after connecting (tools/list_changed). Input missing a member the contract requires fails the call before the handler runs.

type Tools added in v1.0.0

type Tools struct {
	Bash      ToolSlot[BashInput]
	Read      ToolSlot[ReadInput]
	Write     ToolSlot[WriteInput]
	Edit      ToolSlot[EditInput]
	Glob      ToolSlot[GlobInput]
	Grep      ToolSlot[GrepInput]
	ListFiles ToolSlot[ListFilesInput]
}

Tools has one typed slot per built-in tool: client.Tools.Bash.Handle(...). computer_observe and computer_action have no slot until the contract defines their input members.

type TurnCancelParams

type TurnCancelParams struct {
	SessionID string `json:"session_id"`
	TurnID    string `json:"turn_id"`
	Reason    string `json:"reason,omitempty"`
}

TurnCancelParams is the params object of turn.cancel.

type TurnCancelResult

type TurnCancelResult struct {
	Canceled bool `json:"canceled"`
}

TurnCancelResult turn.cancel result. canceled=false when the turn is unknown or already ended; the turn still ends with its own session.status_idle event.

type TurnInputParams

type TurnInputParams struct {
	SessionID string            `json:"session_id"`
	TurnID    string            `json:"turn_id"`
	InputID   string            `json:"input_id"`
	Input     []AgentInputBlock `json:"input"`
}

TurnInputParams is the params object of turn.input.

type TurnStartParams

type TurnStartParams struct {
	// Platform session id.
	SessionID string `json:"session_id"`
	TurnID    string `json:"turn_id"`
	// Platform input id of the user message that starts the turn.
	InputID            string            `json:"input_id"`
	Input              []AgentInputBlock `json:"input"`
	ExecutorSessionRef string            `json:"executor_session_ref,omitempty"`
	Config             *AgentTurnConfig  `json:"config,omitempty"`
	DeadlineMS         int64             `json:"deadline_ms,omitempty"`
	Metadata           map[string]string `json:"metadata,omitempty"`
}

TurnStartParams is the params object of turn.start.

type TurnStartResult

type TurnStartResult struct {
	Accepted bool   `json:"accepted"`
	TurnID   string `json:"turn_id"`
	// Opaque local session handle (for example the local agent's conversation id). The platform stores it and sends it back in the next turn.start so the executor can resume the local conversation after a restart.
	ExecutorSessionRef string `json:"executor_session_ref"`
	// true when the executor continued an existing local conversation, false when it started a new one.
	Resumed   bool            `json:"resumed"`
	Effective AgentTurnConfig `json:"effective"`
}

TurnStartResult turn.start result. Idempotent by turn_id: a repeated turn.start for a turn the executor already accepted returns the same result without starting a second run.

type WorkspaceBackupParams

type WorkspaceBackupParams struct {
	BackupID          string   `json:"backup_id"`
	Paths             []string `json:"paths"`
	Exclude           []string `json:"exclude,omitempty"`
	SkipIfFingerprint string   `json:"skip_if_fingerprint,omitempty"`
}

WorkspaceBackupParams is the params object of workspace.backup.

type WorkspaceBackupResult

type WorkspaceBackupResult struct {
	State       string `json:"state"`
	Fingerprint string `json:"fingerprint,omitempty"`
	Digest      string `json:"digest,omitempty"`
	SizeBytes   int64  `json:"size_bytes,omitempty"`
	Entries     int    `json:"entries,omitempty"`
	Skipped     int    `json:"skipped,omitempty"`
	Error       string `json:"error,omitempty"`
}

WorkspaceBackupResult workspace.backup result. digest and size_bytes describe the archive as the server stored it; skipped counts entries that could not be read (missing from the archive).

type WorkspaceCapability

type WorkspaceCapability struct {
	Backup bool `json:"backup"`
}

WorkspaceCapability workspace.backup support and the startup restore of a pending backup. Machine-scoped executors only.

type WriteInput added in v1.0.0

type WriteInput struct {
	// File path, relative to the session workspace.
	Path string `json:"path"`
	// Full file content.
	Content string `json:"content"`
}

WriteInput write input: create or replace a file.

Directories

Path Synopsis
examples
agentexecutor command
Command agentexecutor is a scripted local agent ("brain and hands" on this machine) served to the platform through the executor SDK's agent capability.
Command agentexecutor is a scripted local agent ("brain and hands" on this machine) served to the platform through the executor SDK's agent capability.
cloud-hand command
Command cloud-hand runs this machine as an executor ("hand") for the BMA cloud harness: the cloud assigns sessions and sends tool calls; the SDK execution core runs bash/file tools and the stdio MCP servers named in session.assign, and reports results back over the same connection.
Command cloud-hand runs this machine as an executor ("hand") for the BMA cloud harness: the cloud assigns sessions and sends tool calls; the SDK execution core runs bash/file tools and the stdio MCP servers named in session.assign, and reports results back over the same connection.
echo-mcp command
Command echo-mcp is a minimal stdio MCP server with one tool, "echo".
Command echo-mcp is a minimal stdio MCP server with one tool, "echo".
local-brain command
Command local-brain is a minimal local harness ("brain") driving the same executor execution core as the cloud, over loopback with the same protocol:
Command local-brain is a minimal local harness ("brain") driving the same executor execution core as the cloud, over loopback with the same protocol:
sandboxed-folder command
Command sandboxed-folder runs this machine as a BMA executor whose processes work in a local folder chosen per session, inside a macOS sandbox-exec profile that only allows writes to that folder and the session's outputs.
Command sandboxed-folder runs this machine as a BMA executor whose processes work in a local folder chosen per session, inside a macOS sandbox-exec profile that only allows writes to that folder and the session's outputs.
internal
conformance/agentharness command
Command agentharness is the Go agent-platform peer of the cross-language tests: a Go SDK Harness with an in-memory AgentPlatform that prints "LISTEN <ws-url>", starts one turn ("hello") on the first executor, allows its permission interaction, and expects the durable events session.status_running, agent.message "<language>:hello:allow", session.status_idle (completed) with sequences 1..3.
Command agentharness is the Go agent-platform peer of the cross-language tests: a Go SDK Harness with an in-memory AgentPlatform that prints "LISTEN <ws-url>", starts one turn ("hello") on the first executor, allows its permission interaction, and expects the durable events session.status_running, agent.message "<language>:hello:allow", session.status_idle (completed) with sequences 1..3.
conformance/executor command
Command executor is the Go executor peer of the cross-language tests: a Go SDK Client that dials the harness at os.Args[1] (bearer "conformance"), answers bash with "go:<command>", blocks on the bash command "block" until canceled, echoes MCP frames on server key "echo", and serves an agent that asks for permission, then emits agent.message "go:<first input text>".
Command executor is the Go executor peer of the cross-language tests: a Go SDK Client that dials the harness at os.Args[1] (bearer "conformance"), answers bash with "go:<command>", blocks on the bash command "block" until canceled, echoes MCP frames on server key "echo", and serves an agent that asks for permission, then emits agent.message "go:<first input text>".
conformance/harness command
Command harness is the cross-language conformance peer: a Go SDK Harness that prints "LISTEN <ws-url>", waits for one executor and drives the standard scenario.
Command harness is the cross-language conformance peer: a Go SDK Harness that prints "LISTEN <ws-url>", waits for one executor and drives the standard scenario.
interop/goexecutor command
Command goexecutor is the Go executor peer of the cross-language interop tests (python/tests/test_executor_interop.py).
Command goexecutor is the Go executor peer of the cross-language interop tests (python/tests/test_executor_interop.py).
interop/goharness command
Command goharness is the Go harness peer of the cross-language interop tests (python/tests/test_executor_interop.py).
Command goharness is the Go harness peer of the cross-language interop tests (python/tests/test_executor_interop.py).
interop/mcpexecutor command
Command mcpexecutor is the Go executor peer of the cross-language interop tests (TypeScript and Python).
Command mcpexecutor is the Go executor peer of the cross-language interop tests (TypeScript and Python).
interop/mcpharness command
Command mcpharness is the Go harness peer of the cross-language interop tests (TypeScript and Python).
Command mcpharness is the Go harness peer of the cross-language interop tests (TypeScript and Python).

Jump to

Keyboard shortcuts

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