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; bma-executor-sdk connects hands or brains to BMA. beeos-ai/bma-executor-sdk implements the Executor Protocol bma.executor.v1.1 (it also accepts v1). Protocol types are generated from the contract in contracts/bma/executor; the runtimes are handwritten. The BMA server and bmad speak the same contract, so a harness built with the SDK cannot be told apart from BMA by an executor, and vice versa.

Install

Credentials

Pass the API origin without a path as the base URL (https://api.staging.bma.beeos.ai on staging); the SDK adds the route. The built-in default https://api.bma.beeos.ai is not live yet. Set machine_id (Go Options.MachineID, TypeScript machineId, Python machine_id; default BMA_MACHINE_ID) for a machine; without it a machine token still works through the legacy POST /api/v1/executors/token alias, which the server serves until contract 2.0. machine_id and the environment id are alternatives. The long-lived credential is only sent to the token endpoint, which returns a 5-minute JWT; only the JWT goes on the WebSocket. Model credentials of a local brain are separate and never read or forwarded by the SDK.

Executor quick start

An executor connects out to BMA and answers tool calls.
Behavior shared by all three languages:
  • Each built-in tool has its own typed handler (client.Tools.Bash.Handle / client.tools.bash.handle / @client.tools.bash.handler) receiving that tool’s input (BashInput, ReadInput, …); input missing a required member fails before the handler runs. shell and files are advertised while a handler of the group is registered, unless you set enabled: false; a handler registered after start is announced with executor.capabilities.update, and a call for a tool without a handler is refused with -32012. The computer_* tools have no handler slot yet. Return text, content blocks or a bash result (rendered as stdout, stderr, exit_code: N, cut to a preview beyond 48 KiB); a ToolError is reported to the model with is_error: true, any other error is outcome: "failed". Other protocol methods are typed by the contract: onRequest('process.start', …) / on_request(methods.PROCESS_START, …) / bmaexecutor.Requests.ProcessStart.Handle(client, …).
  • tool.cancel (and the deadline) cancels the handler; the result is reported with outcome: "canceled". A repeated tool.call id is acknowledged but not run twice.
  • tool.result is retried on executor_busy (-32009), timeout (-32004) or retryable: true, idempotent by tool_call_id. If every attempt fails, OnToolResultLost / onToolResultLost / on_tool_result_lost receives the result so you can persist it. Results are never dropped silently.
  • Call SessionReady after workspace and MCP setup and SessionEnded after cleanup; only your code knows when those are done.
  • Close code 4004 means another executor with the same identity replaced this one: stop, do not reconnect.

Use the execution core (Go)

Core gives you a complete hand without writing tool handlers. One Core can serve the BMA cloud and a local brain at the same time, with per-brain workspaces and session isolation:
bash is not a sandbox: every brain runs as the executor’s OS user. Only attach brains you trust with that machine. CoreOptions.DenyEnv keeps executor secrets (for example the machine token) out of every child process.

Harness quick start

Be the brain: accept executors and drive their tools, for example a local agent that uses a local hand without a round trip to the cloud.
CallTool is idempotent by tool_call_id. A disconnected executor keeps its sessions and pending calls for the lease (60 s by default); after that, pending calls fail with “tool outcome unknown”. Transports: WebSocket (ws://, wss://), WebSocket over a Unix socket (unix://) or Windows named pipe (npipe://), and in-process. Messages are identical on every transport.

Agent capability

An executor that runs its own model loop serves the agent capability: BMA sends natural-language turns, the executor streams Managed Agents events back. See Agent capability.
The SDK assigns event ids and sequences, resends unacknowledged events after a reconnect, and frames each turn with session.status_running and a final session.status_idle.

Examples

TypeScript projects that type-check dependencies need @types/ws (the SDK’s transport types import ws), or skipLibCheck.

Naming

Why the SDK is called bma-executor-sdk:
  • It is named after its protocol. The SDK implements the bma.executor protocol, and its executor, harness and agent ends are that protocol’s roles. Protocol SDKs follow the same rule: the MCP SDK (@modelcontextprotocol/sdk), the ACP SDK (@agentclientprotocol/sdk) and the A2A SDK (a2a-sdk) each cover every role of their protocol.
  • OpenAI uses the same word for the same part. In the OpenAI Agents API, the process you run in a self-hosted environment, codex exec-server, is called “the executor”: it registers with an environment ID and a restricted API key, connects outbound over WebSocket, and reconnects when the connection drops (OpenAI: self-hosted environments).
  • It is not an “agent SDK”. In the industry an agent SDK (OpenAI Agents SDK, Claude Agent SDK, Google ADK) is a framework that runs the agent loop inside your application. This SDK contains no agent loop: bring your own, for example one built with one of those SDKs, and connect it with the agent end.