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.
| Property | Type | Required | Default / meaning |
|---|---|---|---|
harness | HarnessAgentAdapter | Yes | Adapter from createCodex() or createClaudeCode() |
id | string | No | Agent metadata identifier; separate from session key |
instructions | string | No | Persistent instructions passed to the native runtime |
tools | AI SDK ToolSet | No | Named custom tools; execute callbacks run on the host |
skills | readonly HarnessAgentSkill[] | No | Injected skills; rejected by the local factory when nonempty |
permissionMode | "allow-reads" | "allow-edits" | "allow-all" | No | "allow-all"; native built-in tool approval policy |
toolApproval | Readonly<Record<string, ToolApprovalStatus>> | No | Approval policy for named custom tools |
activeTools | Array of built-in/custom tool names | No | Allow only these tools; mutually exclusive with inactiveTools |
inactiveTools | Array of built-in/custom tool names | No | Exclude these tools; mutually exclusive with activeTools |
stopWhen | AI SDK stop condition or array of conditions | No | Yield after a completed tool step when a condition matches; otherwise natural completion/pause |
onSandboxSession | Session setup callback | No | Deprecated upstream option; see lifecycle hooks below |
telemetry | AI SDK TelemetryOptions | No | Upstream telemetry configuration; not required for Laufwerk activity logs |
debug | HarnessDebugConfig | No | Bridge diagnostic capture/filter settings |
onLog | (event: HarnessDiagnostic) => void | No | Diagnostic 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
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().
| Property | Type | Default / meaning |
|---|---|---|
model | string | Pinned 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 |
webSearch | boolean | true permits live web search; omit to use adapter behavior |
mcpServers | Record<string, unknown> | Native Codex MCP configuration keyed by server name |
auth | CodexAuthOptions | Optional explicit provider authentication; see below |
port | number | First port exposed by the sandbox; override only with a compatible declared port |
startupTimeoutMs | number | 120000; milliseconds waiting for the bridge port, not model-turn timeout |
mintBridgeToken | (sandboxId: string) => string | Random 32-byte hexadecimal bridge token |
CodexAuthOptions
All groups and their properties are optional:
| Group | Accepted properties (all string) |
|---|---|
openaiCompatible | apiKey, baseUrl, modelProviderName, queryParamsJson |
openai | apiKey, baseUrl, organization, project |
gateway | apiKey, 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.
| Property | Type | Default / meaning |
|---|---|---|
model | string | Native CLI model default |
maxTurns | number | Native CLI turn cap; default delegated to CLI |
env | Readonly<Record<string, string>> | Environment overrides for the Claude process |
thinking | ClaudeCodeThinkingConfig | { type: "adaptive", display: "summarized" } |
mcpServers | Record<string, unknown> | Native Claude MCP configuration keyed by server name |
auth | ClaudeCodeAuthOptions | Optional explicit authentication |
port | number | First declared sandbox port |
startupTimeoutMs | number | 120000 milliseconds |
mintBridgeToken | (sandboxId: string) => string | Random 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.
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:
| Property | Type | Required |
|---|---|---|
name | string (kebab-case identifier) | Yes |
description | string | Yes |
content | string (full skill text) | Yes |
files | readonly { 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:
| Property | Type | Meaning |
|---|---|---|
workDir | Optional string | Fixed path relative to the sandbox's default working directory |
bootstrapHash | Optional string | Caller-controlled bootstrap identity; required with onBootstrap |
onBootstrap | Optional async callback | Receives { session, workDir, abortSignal? }; prepares reusable environment after adapter bootstrap |
onSession | Optional async callback | Receives { 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:
| Property | Type |
|---|---|
level | Diagnostic level union above |
message | string |
subsystem | string |
kind | "log" | "event" |
timestamp | number, host receipt epoch milliseconds |
source | Optional string |
stream | Optional "stdout" | "stderr" |
attrs | Optional Record<string, unknown> |
error | Optional { name?: string; message: string; stack?: string } |
sessionId | Optional string |
TelemetryOptions accepts these optional properties in the pinned AI SDK:
| Property | Type / default |
|---|---|
isEnabled | boolean; enabled when an integration is registered |
recordInputs | boolean; defaults to true |
recordOutputs | boolean; defaults to true |
functionId | string; grouping identifier |
includeRuntimeContext | Map of top-level runtime-context keys to inclusion booleans; excluded unless true |
includeToolsContext | Inclusion maps for context keys, grouped by tool name |
integrations | One 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.