Skip to main content
Version: 2.6.0

configuring the sdk backend

the sdk backend is configured per agent role in .kasmos/config.toml using the execution_mode field.

the execution_mode field

each [agents.<role>] block in config.toml accepts an optional execution_mode key:

[agents.coder]
enabled = true
program = "claude"
flags = ["--permission-mode bypassPermissions"]
execution_mode = "sdk"

accepted values:

valuebehavior
"sdk"drives the agent via its app-server JSON-RPC protocol
"headless"legacy alias for "sdk" — accepted but "sdk" is preferred
"tmux"(default) runs the agent inside a tmux session
"" (empty)falls back to "tmux"
any other stringfalls back to "tmux"

the fallback behavior is implemented by config.NormalizeExecutionMode at the config layer:

// config/profile.go
func NormalizeExecutionMode(mode string) string {
switch strings.TrimSpace(mode) {
case ExecutionModeTmux:
return ExecutionModeTmux
case ExecutionModeSDK, "headless":
return ExecutionModeSDK
default:
return ExecutionModeTmux
}
}

and by session.NormalizeExecutionMode at the session layer:

// session/execution.go
func NormalizeExecutionMode(mode ExecutionMode) ExecutionMode {
switch ExecutionMode(strings.TrimSpace(string(mode))) {
case ExecutionModeSDK, "headless":
return ExecutionModeSDK
case ExecutionModeTmux:
return ExecutionModeTmux
default:
return ExecutionModeTmux
}
}

unknown values — including typos like "SDK" or "Headless" — silently fall back to "tmux". the comparison is case-sensitive.

program compatibility

setting execution_mode = "sdk" only takes effect if the program has an sdk transport. currently only claude and codex are supported. for any other program, session.ResolveExecutionMode silently downgrades the mode to tmux:

// session/execution.go
func ResolveExecutionMode(requested ExecutionMode, program string) ExecutionMode {
normalised := NormalizeExecutionMode(requested)
if normalised == ExecutionModeSDK && !sdk.SupportsProgram(program) {
return ExecutionModeTmux
}
return normalised
}

consequence: if you set execution_mode = "sdk" for opencode, gemini, amp, or a custom program, kasmos will silently run it in tmux instead. kas debug output will still show "sdk" from the profile (the normalized config value), but the runtime session is a tmux session.

full agent block example

[agents.coder]
enabled = true
program = "claude"
model = "claude-opus-4-5"
flags = ["--permission-mode bypassPermissions"]
execution_mode = "sdk"

[agents.reviewer]
enabled = true
program = "claude"
execution_mode = "tmux"

this configuration runs the coder agent via the claude app-server protocol while keeping the reviewer in tmux for interactive attach capability.

speed tier: profile default + per-spawn override

execution_mode accepts exactly two stable values: "tmux" and "sdk" (plus the legacy alias "headless"). there is no "sdk-fast" value for execution_mode — the speed tier is a separate concern from the execution mode.

profile default: [agents.<role>].tier sets the per-role Codex SDK speed tier for any session spawned by orchestration into that role. see agent profiles: tier for the full normalization table and gating conditions.

per-spawn override: the S execution-mode picker offers an sdk-fast choice that overrides the profile default for that one spawn. it is stored as SDKSpeedTier = "fast" on the instance record and forwarded by the codex transport as serviceTier: "fast" on thread/start. the choice is not written back to config.toml.

daemon api: external callers can supply the same per-spawn tier via the sdk_speed_tier field on POST /instances.

standalone spawn modes

three TUI entry points (N, s, S) also respect execution_mode when spawning standalone (ad-hoc) agents.

  • s quick launch reads the fixer profile. add execution_mode = "sdk" there to make s sessions use the sdk backend:

    [agents.fixer]
    enabled = true
    program = "claude"
    execution_mode = "sdk"
  • S spawn agent and N new with prompt read the master (and default/chat) profiles respectively. the execution mode resolved from those profiles is used as the default for the spawned session:

    [agents.master]
    enabled = true
    program = "claude"
    execution_mode = "sdk"

unsupported programs always use tmux. if fixer or master programs are set to opencode, gemini, amp, or any custom binary, session.ResolveExecutionMode downgrades to tmux regardless of the execution_mode setting — sdk.SupportsProgram in session/sdk/registry.go determines which programs have a transport.

per-phase role mapping

the [phases] table maps lifecycle phases to agent roles. the execution mode is resolved by looking up the role's profile:

[phases]
implementing = "coder"
quality_review = "reviewer"

when kasmos starts an implementing session, it reads agents.coder.execution_mode, normalizes it, and then calls ResolveExecutionMode with the program to determine the actual backend. the resolution path is:

  1. phases.implementing"coder"
  2. agents.coder.execution_mode"sdk"
  3. config.NormalizeExecutionMode("sdk")"sdk"
  4. session.ResolveExecutionMode(ExecutionModeSDK, "claude")ExecutionModeSDK (claude is supported)
  5. session.NewExecutionSession(ExecutionModeSDK, ...)sdk.New(...)

if the program were opencode instead, step 4 would return ExecutionModeTmux and step 5 would create a tmux session.

for a codex coder with [agents.coder].tier = "fast", the parallel tier resolution path is:

  1. [agents.coder].tier"fast"
  2. config.NormalizeTier("fast")"fast"
  3. sdkSpeedTierForAgent(repoDir, AgentTypeCoder) in daemon/daemon.go"fast"
  4. session.Instance.SDKSpeedTier = "fast"
  5. sdk.Transport.Start(..., SpeedTier: "fast") → codex transport
  6. codexServiceTier("fast")thread/start payload serviceTier: "fast"

the default_program fallback

if a phase has no role mapping, or the role's profile is disabled or has an empty program, kasmos falls back to default_program with tmux mode:

// config/profile.go
func (c *Config) ResolveProfile(phase string, defaultProgram string) AgentProfile {
// ...
if profile.Program == "" || !profile.Enabled {
return AgentProfile{Program: defaultProgram, ExecutionMode: ExecutionModeTmux}
}
profile.ExecutionMode = NormalizeExecutionMode(profile.ExecutionMode)
return profile
}

the fallback always uses ExecutionModeTmux — there is no way to make the default fallback use sdk mode without an explicit [agents.*] block.

inspecting resolved configuration

kas debug

prints the config path and the fully resolved Config struct as JSON, including the normalized execution_mode for each agent profile. use this to confirm that "headless" aliases were resolved to "sdk". the runtime tmux fallback for unsupported programs is not reflected here — as noted above, kas debug shows the profile's configured value ("sdk"), not the actual backend used at session start.