agent profiles
An agent profile (config.AgentProfile in config/profile.go) defines how kasmos launches an AI agent for a specific role. Profiles are configured in config.toml under [agents.<role>] and mapped to lifecycle phases via [phases].
fields
| field | type | default | description |
|---|---|---|---|
enabled | bool | false | the role is active and can be dispatched; disabled profiles fall back to default_program |
program | string | — | executable name or path (e.g. claude, opencode, /usr/local/bin/codex) |
flags | []string | [] | extra CLI flags appended after the prompt argument |
model | string | — | model identifier passed to the agent (e.g. claude-sonnet-4-5) |
temperature | float? | — | sampling temperature, if the agent supports it |
effort | string | — | effort level (e.g. low, medium, high), if the agent supports it |
tier | string | "" | Codex SDK only: session speed tier (accepts "fast", "flex", or "default"). Claude SDK and tmux sessions ignore this field. |
execution_mode | string | "tmux" | how the agent process is launched: "tmux" or "sdk" |
permission_default | string | "" | tri-state permission default: "prompt" forces an interactive permission overlay, "bypass" launches with the harness bypass flag, "" / "inherit" preserves the spawn-source default (daemon: bypass; local TUI: prompt). |
execution_mode
tmux(default): kasmos creates a new tmux window, runs the agent inside it, and monitors the window for completion. This mode lets you watch the agent in real time.sdk: kasmos drives the agent via its app-server JSON-RPC protocol (claude and codex only). For any other program, kasmos silently falls back to tmux at runtime. Use this for unattended wave execution with claude or codex.headless: legacy alias for"sdk"— accepted but"sdk"is preferred in new configs.
The mode is normalized by config.NormalizeExecutionMode(): any unrecognized value (including empty string) falls back to "tmux".
tier
Sets the Codex SDK speed tier for any session spawned into this role by orchestration.
Accepted values
| value | result after normalization |
|---|---|
"" (unset) | "" — no tier forwarded |
"fast" | "fast" |
"flex" | "flex" |
"default" | "flex" (normalized to "flex") |
anything else (e.g. "priority") | "" — unrecognized, ignored |
Normalization is handled by config.NormalizeTier in config/profile.go. The match is case-insensitive, leading/trailing whitespace is trimmed, "default" is mapped to "flex", and any other unrecognized string collapses to "".
Gating — the normalized tier value is only forwarded when both conditions hold at session-start time:
- The resolved
execution_modeis"sdk"(aftersession.ResolveExecutionModehas applied the program-compatibility downgrade check). - The
programiscodex. The Claude SDK transport (session/sdk/claude_transport.go) silently ignores the field even whenexecution_mode = "sdk".
Per-spawn override — the S execution-mode picker offers an sdk-fast choice that overrides the profile default for that one spawn only. The override is stored as SDKSpeedTier = "fast" on the instance record; it is not written back to config.toml. See speed tier: profile default + per-spawn override for full details.
Observed behavior — when a tier is in effect:
- The info pane shows a
speed tier: fastrow (ui/info_pane.go). - The spawn audit log records a
speed_tierentry inEvent.Detail(config/auditlog/logger.go).
permission_default
Sets the profile-level default for whether kasmos should prompt for permission approval or launch the harness with its bypass behavior.
Accepted values
| value | result after normalization |
|---|---|
"" (unset) | "" — inherit the spawn-source default |
"inherit" | "" — same as omitted |
"prompt" | "prompt" |
"bypass" | "bypass" |
anything else (e.g. "auto") | "prompt" — unrecognized values ask the operator |
Normalization is handled by config.NormalizePermissionDefault in config/profile.go. The match is case-insensitive, leading/trailing whitespace is trimmed, "inherit" is mapped to "", and any unrecognized value collapses to "prompt".
Spawn-source defaults — when the normalized value is "", the launcher keeps the source's existing behavior:
- Daemon and unattended orchestration spawns default to bypass.
- Local interactive TUI spawns default to prompt.
Per-session override — raw flags still reach the harness. For example, flags = ["--permission-mode", "bypassPermissions"] still makes Claude launch in bypass mode even when permission_default = "prompt". permission_default controls the resolved kasmos SkipPermissions value; explicit harness flags remain lower-level command arguments.
Unattended coder
[agents.coder]
enabled = true
program = "claude"
model = "claude-sonnet-4-5"
execution_mode = "sdk"
permission_default = "bypass"
This makes orchestration-spawned coder sessions use bypass permissions for unattended automation.
Operator-approved reviewer
[agents.reviewer]
enabled = true
program = "claude"
model = "claude-opus-4-5"
execution_mode = "sdk"
permission_default = "prompt"
This makes reviewer sessions wait for operator approval of tool calls even when the daemon starts them.
BuildCommand()
AgentProfile.BuildCommand() constructs the full command string for logging and display:
strings.Join(append([]string{p.Program}, p.Flags...), " ")
For example, a profile with program = "claude" and flags = ["--permission-mode bypassPermissions"] produces:
claude --permission-mode bypassPermissions
The model and other flags that kasmos injects into the prompt are not part of BuildCommand() — they are handled separately by the orchestration layer.
profile resolution
kasmos resolves a profile for a given lifecycle phase via config.Config.ResolveProfile(phase, defaultProgram):
- Look up
phases[phase]→ role name. - Look up
agents[role]→AgentProfile. - If the profile has a non-empty
ProgramandEnabled = true, use it. - Otherwise fall back to
AgentProfile{Program: defaultProgram, ExecutionMode: "tmux"}.
This means you can disable a role without removing it from the config — just set enabled = false.
examples
claude (tmux, interactive)
[agents.coder]
enabled = true
program = "claude"
model = "claude-sonnet-4-5"
execution_mode = "tmux"
flags = ["--permission-mode bypassPermissions"]
Launches claude --permission-mode bypassPermissions in a new tmux window. The -p <prompt> and --model flags are injected by kasmos before appending flags.
opencode (tmux, high-effort planner)
[agents.planner]
enabled = true
program = "opencode"
execution_mode = "tmux"
effort = "high"
Runs opencode in a tmux window with effort = "high". opencode interprets the effort field to choose model tiers and thinking budgets. Note: execution_mode = "sdk" has no effect for opencode — there is no sdk transport for it; kasmos would fall back to tmux silently.
codex (sdk with custom model)
[agents.reviewer]
enabled = true
program = "codex"
model = "o3"
execution_mode = "sdk"
tier = "fast" # forwarded as serviceTier: "fast" on thread/start
flags = ["--approval-mode", "full-auto"]
Drives codex --approval-mode full-auto via the Codex App Server protocol with model = "o3". Setting tier = "fast" requests the fast Codex speed tier for every orchestration-spawned session into this role.
mixed setup (different agents per role)
[phases]
planning = "planner"
elaborating = "architect"
implementing = "coder"
quality_review = "reviewer"
[agents.planner]
enabled = true
program = "opencode"
execution_mode = "tmux"
effort = "high"
[agents.architect]
enabled = true
program = "claude"
model = "claude-sonnet-4-5"
execution_mode = "sdk"
[agents.coder]
enabled = true
program = "claude"
model = "claude-sonnet-4-5"
execution_mode = "tmux"
flags = ["--permission-mode bypassPermissions"]
[agents.reviewer]
enabled = true
program = "claude"
model = "claude-opus-4-5"
execution_mode = "sdk"
disabling a role
[agents.architect]
enabled = false
program = "claude"
When enabled = false, kasmos falls back to default_program for that phase. The program field is still required but is not used.
default program detection
When default_program is not set in config.toml, kasmos calls config.GetDefaultCommand() which tries executables in order:
opencode(preferred)claude
It sources your shell's rc file (~/.zshrc or ~/.bashrc) so shell aliases are visible. If neither is found via the shell, exec.LookPath is used as a fallback.