bmaexecutor

package module
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: Nov 6, 2026 License: Apache-2.0 Imports: 33 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.0
TypeScript npm @beeos-ai/bma-executor-sdk npm install @beeos-ai/bma-executor-sdk@1.0.0
Python PyPI bma-executor-sdk (bma_executor_sdk) pip install bma-executor-sdk==1.0.0
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/executors/token (managed-agents) and a machine daemon token (no environment id) to {BaseURL}/api/v1/executors/token (bma-api), and uploads artifacts below /v1/executors, 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 uses a machine token through Options.TokenSource and no environment id. Go clients negotiate bma.executor.v1.1 by default (Options.Protocol).

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); 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: bind an agent to the machine with PUT /orgs/{orgID}/projects/{projectID}/agents/{agentID}/executor-binding; 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

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 (
	DefaultBaseURL              = "https://api.bma.beeos.ai"
	DefaultRequestTimeout       = 30 * time.Second
	DefaultMaxReconnectAttempts = 10
	DefaultReconnectBaseDelay   = 500 * time.Millisecond
	// 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"
	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 (
	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 (
	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 MaxReconnectAttempts failed.
	ErrReconnectExhausted = errors.New("bmaexecutor: executor reconnect attempts exhausted")
)
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 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 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"},
	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]
}{
	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"},
}

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"`
	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/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/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"`
}

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, ...) or exhausted reconnects.

func (*Client) Err

func (c *Client) Err() error

Err explains Done: nil after Stop or executor.close, ErrReplaced after 4004, 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) 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/executors/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).

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 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 POST /v1/executors/token body. The bearer is an environment key, or a machine daemon token. 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 POST /v1/executors/token response.

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 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, for example "spawn_failed" for process.start.
	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 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/executors/token), or a machine daemon token for a
	// machine-scoped executor (empty EnvironmentID; POST
	// /api/v1/executors/token).
	EnvironmentKey string
	// EnvironmentID is the selfhost environment; empty registers a
	// machine-scoped executor.
	EnvironmentID 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 POST /v1/executors/token 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 (default 10);
	// a negative value reconnects until Stop.
	MaxReconnectAttempts int
	ReconnectBaseDelay   time.Duration
	// ReconnectMaxDelay caps the reconnect backoff before jitter. Defaults
	// to 30s.
	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 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
}

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"`
	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 (*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 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 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:
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