LaufwerkLaufwerk
API reference

Agents and adapters

Every agent constructor property, Codex and Claude Code settings, tools, skills, permissions and diagnostics.

An agent is reusable configuration. A session is one conversation and execution lifecycle using it. Set model options on the adapter, instructions/tools on the agent, and filesystem access on the session.

execution.agent(settings)

Local and Docker execution objects expose this factory. It constructs a HarnessAgent with the correct workspace binding and supplies sandbox and sandboxConfig: { workDir: "workspace" } itself.

PropertyTypeRequiredDefault / meaning
harnessHarnessAgentAdapterYesAdapter from createCodex() or createClaudeCode()
idstringNoAgent metadata identifier; separate from session key
instructionsstringNoPersistent instructions passed to the native runtime
toolsAI SDK ToolSetNoNamed custom tools; execute callbacks run on the host
skillsreadonly HarnessAgentSkill[]NoInjected skills; rejected by the local factory when nonempty
permissionMode"allow-reads" | "allow-edits" | "allow-all"No"allow-all"; native built-in tool approval policy
toolApprovalReadonly<Record<string, ToolApprovalStatus>>NoApproval policy for named custom tools
activeToolsArray of built-in/custom tool namesNoAllow only these tools; mutually exclusive with inactiveTools
inactiveToolsArray of built-in/custom tool namesNoExclude these tools; mutually exclusive with activeTools
stopWhenAI SDK stop condition or array of conditionsNoYield after a completed tool step when a condition matches; otherwise natural completion/pause
onSandboxSessionSession setup callbackNoDeprecated upstream option; see lifecycle hooks below
telemetryAI SDK TelemetryOptionsNoUpstream telemetry configuration; not required for Laufwerk activity logs
debugHarnessDebugConfigNoBridge diagnostic capture/filter settings
onLog(event: HarnessDiagnostic) => voidNoDiagnostic event sink

There are no direct model, temperature, reasoningEffort, workspace, access or key properties on this factory. stopWhen is an upstream turn-yield condition, not a wall-clock timeout or overall workflow budget; Laufwerk may continue a suspended turn. id does not create a session or make two sessions share history.

Example: configure both providers

agents-example.ts
import { createDockerExecution } from "@laufwerk/execution";
import { createCodex } from "@laufwerk/sdk/harness/codex";
import { createClaudeCode } from "@laufwerk/sdk/harness/claude-code";

export const codexExecution = createDockerExecution({ credentials: "codex-subscription" });
export const coder = codexExecution.agent({
  id: "coder",
  harness: createCodex({ reasoningEffort: "high", webSearch: false }),
  instructions: "Implement the requested change and report verification evidence.",
  permissionMode: "allow-all",
});

export const claudeExecution = createDockerExecution({ credentials: "claude-subscription" });
export const reviewer = claudeExecution.agent({
  id: "reviewer",
  harness: createClaudeCode({ maxTurns: 12, thinking: { type: "adaptive" } }),
  instructions: "Inspect the proposed changes and explain concrete defects.",
  permissionMode: "allow-reads",
});

Both can attach to a Docker workspace. Different credential settings belong on their respective execution providers. Credentials must already be configured; construction alone does not authenticate or allocate a container.

createCodex(settings?)

Import from @laufwerk/sdk/harness/codex. All settings are optional. The exported codex value is a preconstructed adapter equivalent to createCodex().

PropertyTypeDefault / meaning
modelstringPinned adapter default "gpt-5.5"; an explicit ID must be available to your account/runtime
reasoningEffort"low" | "medium" | "high"Native CLI default when omitted; these are all values accepted by this pinned type
webSearchbooleantrue permits live web search; omit to use adapter behavior
mcpServersRecord<string, unknown>Native Codex MCP configuration keyed by server name
authCodexAuthOptionsOptional explicit provider authentication; see below
portnumberFirst port exposed by the sandbox; override only with a compatible declared port
startupTimeoutMsnumber120000; milliseconds waiting for the bridge port, not model-turn timeout
mintBridgeToken(sandboxId: string) => stringRandom 32-byte hexadecimal bridge token

CodexAuthOptions

All groups and their properties are optional:

GroupAccepted properties (all string)
openaiCompatibleapiKey, baseUrl, modelProviderName, queryParamsJson
openaiapiKey, baseUrl, organization, project
gatewayapiKey, baseUrl

queryParamsJson is a JSON-encoded string, not a JavaScript object. Use one intended authentication route. These upstream adapter options are distinct from Laufwerk's subscription credential setup. The local/Docker providers deliberately remove ambient API-billing environment variables in subscription mode; do not assume that setting a host API key switches that mode.

createClaudeCode(settings?)

Import from @laufwerk/sdk/harness/claude-code. All properties are optional. The upstream claudeCode singleton uses default settings.

PropertyTypeDefault / meaning
modelstringNative CLI model default
maxTurnsnumberNative CLI turn cap; default delegated to CLI
envReadonly<Record<string, string>>Environment overrides for the Claude process
thinkingClaudeCodeThinkingConfig{ type: "adaptive", display: "summarized" }
mcpServersRecord<string, unknown>Native Claude MCP configuration keyed by server name
authClaudeCodeAuthOptionsOptional explicit authentication
portnumberFirst declared sandbox port
startupTimeoutMsnumber120000 milliseconds
mintBridgeToken(sandboxId: string) => stringRandom 32-byte hexadecimal bridge token

ClaudeCodeThinkingConfig is either { type: "adaptive" | "enabled", display?: "summarized" | "omitted" } or { type: "disabled" }. The disabled variant has no display field.

ClaudeCodeAuthOptions has optional anthropic with optional string apiKey, authToken, baseUrl; and optional gateway with optional string apiKey, baseUrl. Account/model availability is external to these TypeScript types.

MCP configuration boundary

mcpServers accepts a map in the selected native runtime's format. Its values are typed unknown, so a successful TypeScript check does not validate an MCP server configuration. Configure the server executable/URL and credentials for the environment where the agent runs, not just for the host. The Claude adapter reserves the server name harness-tools and rejects a user entry with that name.

Custom tools

tools is a name-to-AI-SDK-tool map. The core authoring fields are description, inputSchema, and execute(input, options); the AI SDK also defines advanced tool metadata, approval and streaming hooks. Use its tool reference for that upstream API. Laufwerk does not introduce a second tool schema.

Custom execute callbacks run on the host. The callback's experimental_sandbox provides restricted access to the session environment when you deliberately use it. A read-only workspace mount does not restrict arbitrary host-side custom code. A custom tool overrides a built-in of the same name.

custom-tool-example.ts
import { createDockerExecution } from "@laufwerk/execution";
import { createCodex } from "@laufwerk/sdk/harness/codex";
import { tool } from "@laufwerk/sdk/ai";
import { z } from "zod";

const execution = createDockerExecution({ credentials: "codex-subscription" });
export const calculator = execution.agent({
  harness: createCodex(),
  tools: {
    add: tool({
      description: "Add two finite numbers.",
      inputSchema: z.object({ a: z.number().finite(), b: z.number().finite() }),
      execute: async ({ a, b }) => ({ total: a + b }),
    }),
  },
  toolApproval: { add: "approved" },
});

AI SDK tool schemas commonly use Zod; workflow and session output schemas use Effect Schema. They are different arguments with different contracts.

Permissions and tool filters

allow-reads permits native read operations while other operations can request approval. allow-edits additionally permits edits; allow-all permits built-in operations without that approval boundary. Native adapters classify operations. These policies do not replace workspace access or container isolation.

ToolApprovalStatus accepts undefined, "not-applicable", "approved", "user-approval", "denied", or an object with matching type. The object variants { type: "approved", reason?: string } and { type: "denied", reason?: string } accept a reason; the other object variants do not. Undefined has the same meaning as not-applicable. The permissive statuses execute the custom tool; user-approval pauses for a decision; denied returns an execution-denied result. toolApproval is a status map, not a callback.

Tool filters use names from the selected adapter's builtins plus custom tool names. Codex's typed builtins are bash and webSearch; Claude exposes a larger native tool set. Inspect keyof typeof agent.tools for the exact inferred union rather than copying tool names from a different provider. Unsupported native capabilities can fail through Harness errors rather than silently providing the requested behavior.

Skills

Each HarnessAgentSkill contains:

PropertyTypeRequired
namestring (kebab-case identifier)Yes
descriptionstringYes
contentstring (full skill text)Yes
filesreadonly { path: string; content: string }[]No

File paths are skill-relative POSIX paths; absolute paths and .. segments are rejected by adapters. Local execution uses installed native skills and rejects injection to avoid writing injected skills into the user's home profile. Use Docker for injected skills.

new HarnessAgent(settings) and lifecycle hooks

Import HarnessAgent from @laufwerk/sdk/harness. The direct constructor accepts all settings above plus required sandbox: HarnessV1SandboxProvider and optional sandboxConfig. Use this for legacy/custom providers. For local/Docker workspace binding, use execution.agent; a raw constructor does not set Laufwerk's marker.

sandboxConfig accepts:

PropertyTypeMeaning
workDirOptional stringFixed path relative to the sandbox's default working directory
bootstrapHashOptional stringCaller-controlled bootstrap identity; required with onBootstrap
onBootstrapOptional async callbackReceives { session, workDir, abortSignal? }; prepares reusable environment after adapter bootstrap
onSessionOptional async callbackReceives { session, sessionWorkDir, abortSignal? }; runs on fresh and resumed acquisition

Both callbacks return Promise<void>; session is the restricted sandbox and abortSignal is an AbortSignal. Make per-session setup safe to repeat. The deprecated onSandboxSession has the same shape as onSession. The execution factory omits sandboxConfig from its accepted options, so do not try to pass that property through it.

Direct Harness generate, stream and native session methods are upstream APIs; they do not provide Laufwerk's named durable Session.run/open boundary.

Diagnostics

HarnessDebugConfig has optional enabled: boolean, level: "error" | "warn" | "info" | "debug" | "trace" (default "debug"), and subsystems: readonly string[] for dotted-prefix filtering. Environment diagnostic settings fill unset values.

onLog receives HarnessDiagnostic:

PropertyType
levelDiagnostic level union above
messagestring
subsystemstring
kind"log" | "event"
timestampnumber, host receipt epoch milliseconds
sourceOptional string
streamOptional "stdout" | "stderr"
attrsOptional Record<string, unknown>
errorOptional { name?: string; message: string; stack?: string }
sessionIdOptional string

TelemetryOptions accepts these optional properties in the pinned AI SDK:

PropertyType / default
isEnabledboolean; enabled when an integration is registered
recordInputsboolean; defaults to true
recordOutputsboolean; defaults to true
functionIdstring; grouping identifier
includeRuntimeContextMap of top-level runtime-context keys to inclusion booleans; excluded unless true
includeToolsContextInclusion maps for context keys, grouped by tool name
integrationsOne AI SDK Telemetry integration or an array; overrides global integrations for the call

See AI SDK telemetry for integration configuration, and Laufwerk logging for recorded workflow/activity logs. Session failures are surfaced through SessionError; direct Harness APIs additionally expose HarnessError, HarnessCapabilityUnsupportedError, and HarnessSandboxAuthenticationError.

On this page