Configuration
This is the full configuration reference. For a friendlier overview, see Settings & Customization.
Every key you can meaningfully set is documented below. Your config.json also carries a handful of keys the app writes for itself and never surfaces in the UI, such as remembered window bounds and pop-out positions, saved workspace layouts, which announcements you have dismissed, and the model lists discovered per agent. They are safe to leave alone, and deleting one just makes the app re-derive it.
Configuration Cascade
Section titled “Configuration Cascade”Kangentic resolves settings in three layers:
- Built-in defaults - sensible defaults for all settings
- Global user config - your personal defaults for all projects
- Project overrides - per-repository settings
Effective config = deep-merge(defaults, global config, project config).
New Project Seeding
Section titled “New Project Seeding”When you create a new project, Kangentic seeds its .kangentic/config.json with only a subset of your most recently configured project’s settings: theme, agent.permissionMode, and git.*. Everything else falls back to the built-in defaults. (terminal.* used to be seeded here; it became global-only in v0.31.0 and is no longer per-project.) Project-specific data - notably browser.* (including browser.defaultUrl) and saved backlog import sources - is stored per-project and is never copied into a new project, so one repository’s dev-server URL or issue-tracker connections cannot leak into another.
Configuration Files
Section titled “Configuration Files”Global: %APPDATA%\kangentic\config.json
Project: <project>/.kangentic/config.json
Global: ~/Library/Application Support/kangentic/config.json
Project: <project>/.kangentic/config.json
Global: ~/.config/kangentic/config.json
Project: <project>/.kangentic/config.json
Project settings override global settings when both are present.
Top-Level Settings
Section titled “Top-Level Settings”| Key | Type | Default | Scope | Description |
|---|---|---|---|---|
theme | string | "dark" | Both | UI theme: dark, light, moon, forest, ocean, ember, sand, mint, sky, peach |
sidebarVisible | boolean | true | Global only | Show/hide the sidebar |
boardLayout | string | "horizontal" | Global only | Board scroll direction: horizontal or vertical |
cardDensity | string | "default" | Global only | Task card density: compact, default, or comfortable |
columnWidth | string | "default" | Global only | Column width: narrow, default, or wide |
showTaskNumbers | boolean | true | Global only | Show each task’s #N (display ID) number on its board card. Labeled Ticket Numbers in Settings > Task |
terminalPanelVisible | boolean | true | Global only | Show the bottom terminal panel |
statusBarVisible | boolean | true | Global only | Show the status bar at the bottom of the window |
animationsEnabled | boolean | true | Global only | Enable transition animations across the UI |
diffViewMode | string | "split" | Global only | Default layout for Git file diffs in the Changes panel: split (side by side) or inline (unified) |
diffDefaultScope | string | "working" | Global only | Scope a freshly opened Changes panel shows: working (uncommitted edits), staged (index), or branch (the full branch vs its base) |
diffIgnoreWhitespace | boolean | false | Global only | Hide whitespace-only changes in the diff to filter out reformatting noise |
diffCollapseUnchanged | boolean | false | Global only | Fold away large unchanged regions, showing only the changed hunks with a little context |
diffWrapLines | boolean | false | Global only | Soft-wrap long lines onto the next row instead of scrolling the diff horizontally. Applies to both split and inline mode |
diffUseInlineWhenNarrow | boolean | true | Global only | Render a narrow diff pane inline (unified) even when split is selected, instead of squeezing two columns. Off forces side by side at any pane width |
diffFileSort | string | "name" | Global only | Changes panel file ordering: name, status (additions first, deletions last), size (most-changed first), or ext (by extension). In the flat list, status adds a heading and count at each group boundary |
diffFlatList | boolean | false | Global only | Show changed files as a flat list of full paths instead of a nested directory tree |
windowLightDismiss | string | "focused" | Global only | Whether clicking empty space outside a task-detail window dismisses windows: off (never), single (only when exactly one window is open), focused (the focused window, whichever is open), or all (every open window). Dismissing keeps the agent running and returns its terminal to the bottom panel. A persisted single migrates to focused once on upgrade |
skipDeleteConfirm | boolean | false | Global only | Skip confirmation dialog on task delete |
skipBoardConfigConfirm | boolean | false | Global only | Skip confirmation when applying board config changes |
autoFocusIdleSession | boolean | false | Global only | Auto-switch to session tab when agent goes idle |
autoNameRateLimitPerHour | number | 60 | Global only | Maximum auto-name CLI calls per rolling 60-minute window, capping cost on burst task creation. 0 disables the limit. Config-file only (no Settings toggle) |
restoreWindowPosition | boolean | true | Global only | Restore window position and size from last session |
hotkeyOverrides | Record<string, string> | {} | Global only | Rebound hotkeys, mapping a keybinding action id such as commandBar.toggle to a combo. A combo is either a keyboard chord (Mod+Shift+K, where Mod is Cmd on macOS and Ctrl elsewhere) or a mouse button (Mouse:Middle, Mouse:Back, Mouse:Forward). Absent ids use the registry default. Edited in the Hotkeys tab and replaced wholesale on save, so a reset removes the key. See Hotkeys |
statusBarPeriod | string | "live" | Global only | Deprecated: the status-bar usage strip was replaced by the Usage Stats Dashboard in v0.30.0. Read once as a seed fallback for usageStatsPeriod, never written anymore |
Usage Stats Settings
Section titled “Usage Stats Settings”Persistence for the Usage Stats Dashboard. Both values are one global selection shared across all projects.
| Key | Type | Default | Scope | Description |
|---|---|---|---|---|
usageStatsPeriod | string | "live" | Global only | Saved time range for the usage dashboard: live, today, week, month, all |
usageStatsScope | string | "project" | Global only | Saved dashboard scope: project (current project) or all (app-wide rollup) |
Agent Monitor Settings
Section titled “Agent Monitor Settings”Persisted view preferences for the Agent Monitor, shared by the in-app overlay and the pop-out window.
| Key | Type | Default | Scope | Description |
|---|---|---|---|---|
monitor.layout | string | "cards" | Global only | Monitor layout: cards, table, or list |
monitor.groupBy | string | "project" | Global only | Grouping: project or state |
monitor.sort | string | "longest-running" | Global only | Row order within a group: longest-running or recently-started |
monitor.liveOnly | boolean | false | Global only | Show only sessions with a live agent (the Idle and Active buckets), hiding Paused - which covers both suspended and queued sessions - and Recently finished. It deliberately never hides Idle: those are agents waiting on you |
monitor.textFilter | string | "" | Global only | Persisted toolbar filter text |
monitor.projectFilter | string[] | [] | Global only | Project ids the monitor is scoped to; empty means every project. Written by the toolbar’s Projects multi-select and kept across restarts (sanitized to a deduped list). An id naming a project with no sessions in the next non-empty snapshot is dropped and re-saved, so the filter always stays representable in the control |
monitor.stateFilter | string[] | [] | Global only | Restrict the monitor to these session states: needs-you, working, idle, finished. The values map to the monitor’s section labels Idle, Active, Paused, and Recently finished, in that order. No control writes it today; edit config.json directly |
Backlog Settings
Section titled “Backlog Settings”| Key | Type | Default | Scope | Description |
|---|---|---|---|---|
backlog.priorities | array | See below | Both | Customizable priority levels with labels and colors |
backlog.labelColors | object | {} | Both | Default color mappings for backlog labels ({ "label-name": "#hex" }) |
Default priorities:
| Index | Label | Color |
|---|---|---|
| 0 | None | #6b7280 |
| 1 | Low | #3b82f6 |
| 2 | Medium | #eab308 |
| 3 | High | #f97316 |
| 4 | Urgent | #ef4444 |
Terminal Settings
Section titled “Terminal Settings”| Key | Type | Default | Scope | Description |
|---|---|---|---|---|
terminal.shell | string | null | null | Global only | Shell executable path. null = auto-detect |
terminal.fontFamily | string | "Menlo, Consolas, \"Courier New\", monospace" | Global only | Terminal font family. The Settings picker is a system-font autocomplete populated from your installed fonts |
terminal.fontSize | number | 14 | Global only | Terminal font size (px) |
terminal.cursorStyle | string | "block" | Global only | Cursor style: block, underline, or bar |
terminal.backspaceSendsCtrlH | boolean | false | Global only | Labeled Word delete on Backspace: plain Backspace sends Ctrl+H (0x08) instead of Delete (0x7f), so Claude Code’s TUI deletes the previous word instead of one character. Off by default; Ctrl+W, Alt+Backspace, and Ctrl+Backspace already word-delete regardless |
terminal.colors | TerminalColorOverrides | {} | Global only | Custom terminal background, foreground, and cursor color, set via swatches in the Terminal tab’s Colors section. Unset slots fall back to the built-in defaults (background #0c0c0c, foreground/cursor #e4e4e7). The 16-color ANSI palette (Windows Terminal “Campbell”) is a fixed built-in scheme, not individually editable |
terminal.showPreview | boolean | false | Global only | Show a live terminal preview snippet on task cards. Config-file only (no Settings toggle) |
terminal.panelHeight | number | 250 | Global only | Bottom panel height (px) |
terminal.panelCollapsed | boolean | false | Global only | Persisted collapsed state of the bottom terminal panel |
Agent Settings
Section titled “Agent Settings”Agent settings are unified across all thirteen coding agents: Claude Code, Codex CLI, Gemini CLI, Cursor CLI, GitHub Copilot CLI, Grok Build, Antigravity CLI, OpenCode, Aider, Qwen Code, Kimi Code, Factory Droid, and Warp/Oz CLI. The local-chat Ollama adapter is also detected and can take a CLI-path override (it appears in agent.cliPaths below), but it has no permission modes or model/effort settings of its own.
| Key | Type | Default | Scope | Description |
|---|---|---|---|---|
agent.permissionMode | string | "acceptEdits" | Both | Default permission mode for spawned agents |
agent.cliPaths | object | {} | Global only | Per-agent CLI path overrides, keyed by agent name (claude, codex, gemini, cursor, copilot, grok, antigravity, opencode, aider, qwen, kimi, droid, warp, ollama). null = auto-detect. Example: { "claude": null, "codex": "/usr/local/bin/codex", "kimi": "/Users/me/.local/bin/kimi" } |
agent.launchOptions | object | {} | Global only | Per-agent boolean startup toggles (agent name to option id to enabled), shown as Launch Options rows in the Agent tab when the selected agent declares one. Today only Codex declares one, Disable ChatGPT Apps (disableApps), which launches with --disable apps to skip the optional cloud ChatGPT Apps connector that can hang startup |
agent.executionServers | object | {} | Global only | Remote-server identity for agents that support remote execution (today OpenCode), keyed by agent name: { url, auth }, where auth is none, HTTP basic, or a bearer token read from an env var. Machine-scoped like agent.cliPaths - it names a server, not a project |
agent.execution | object | {} | Both | Per-agent, per-project execution mode: { mode: "local" | "remote", workingDirectory }. An absent entry means local. workingDirectory is a path on the server for this project’s tasks. Stored per-project and never seeded into new projects |
agent.maxConcurrentSessions | number | 8 | Global only | Max concurrent PTY sessions across all agents |
agent.queueOverflow | string | "queue" | Global only | Overflow behavior: queue or reject |
agent.idleTimeoutMinutes | number | 0 | Global only | Auto-suspend sessions after N minutes idle. 0 = disabled |
agent.autoResumeSessionsOnRestart | boolean | true | Global only | When true, agent sessions that were running at last close auto-resume when Kangentic restarts. When false, sessions stay paused and require a manual Resume click on each task. Turn off if auto-resuming many agents at once overwhelms your machine. |
Permission Modes
Section titled “Permission Modes”Each agent advertises its own supported permission modes, and the Edit Column and Settings dropdowns update dynamically when you switch agents. The full set of modes is:
| Mode | Behavior | Supported by |
|---|---|---|
plan | Read-only tools auto-approved; edits require approval | Claude, Codex, Gemini, Copilot, Grok, Antigravity, OpenCode (Plan agent), Aider, Qwen, Kimi, Warp |
default | Uses the agent’s built-in defaults (e.g., Claude Code’s .claude/settings.json allowlist) | Claude, Codex, Gemini, Cursor, Copilot, Grok, Antigravity, Aider, Qwen, Kimi, Droid, Warp |
acceptEdits | File edits auto-approved; other actions prompt (OpenCode: maps to its Build agent) | Claude, Codex, Gemini, Copilot, Grok, Antigravity, OpenCode, Aider, Qwen |
bypassPermissions | Full autonomy, no permission prompts at all | Claude, Codex, Gemini, Cursor, Copilot, Grok, Antigravity, Aider, Qwen, Kimi, Warp |
dontAsk | Deny everything not already allowed, no interactive prompts | Claude, Codex, Copilot, Grok |
auto | Classifier-driven auto-approval | Claude, Copilot, Grok |
Per-agent defaults:
| Agent | Default permission mode | Notes |
|---|---|---|
| Claude Code | acceptEdits | |
| Codex CLI | acceptEdits | |
| Gemini CLI | acceptEdits | |
| Cursor CLI | bypassPermissions | Non-interactive mode is the default so the stream-JSON init event fires and the ContextBar model pill resolves |
| GitHub Copilot CLI | acceptEdits | |
| Grok Build | acceptEdits | All six Kangentic modes pass through 1:1 via --permission-mode; labels describe grok’s own behavior |
| Antigravity CLI | acceptEdits | Mapped onto agy’s autonomy flags (--mode plan, --mode accept-edits, --dangerously-skip-permissions); default is agy’s request-review mode |
| OpenCode | acceptEdits | Labels surface OpenCode’s native Plan and Build agents - selecting Plan maps to OpenCode’s read-only built-in agent |
| Aider | bypassPermissions | Aider is an edit-first CLI that expects broad file-write access |
| Qwen Code | acceptEdits | Labeled “Auto Edit” - soft fork of Gemini CLI |
| Kimi Code | default | Labels: Plan, Default (Confirm Actions), YOLO |
| Factory Droid | default | Single “Default” entry; autonomy is controlled in the Droid TUI (Shift+Tab cycles low/medium/high) |
| Warp (Oz CLI) | default | Permission-mode labels are informational only; Warp manages permissions via agent profiles (--profile) |
Permission mode is resolved in priority order:
- Task’s
permission_mode(if set) - pinned in the New Task dialog’s Advanced section or the task-detail edit form; it wins for the task’s whole lifetime, and column moves cannot change it - Column’s
permission_mode(if set) agent.permissionModefrom config
Git Settings
Section titled “Git Settings”| Key | Type | Default | Scope | Description |
|---|---|---|---|---|
git.worktreesEnabled | boolean | true | Both | Create isolated git worktrees per task |
git.autoCleanup | boolean | true | Both | Delete branches when worktrees are removed |
git.defaultBaseBranch | string | "main" | Both | Default base branch tasks start from: both the ref a worktree is cut from and the one a non-worktree task’s branch checkout is fast-forwarded from |
git.copyFiles | string[] | [] | Both | Files to copy from repo root into new worktrees |
git.initScript | string | null | null | Both | Shell script run in each new worktree after creation (e.g. npm install). Runs to completion before the agent spawns; a non-zero exit fails worktree setup |
git.linkNodeModules | boolean | true | Both | Symlink the repo-root node_modules into each new worktree so agents skip a fresh install. Disable to let git.initScript install dependencies in the worktree itself |
git.prRefreshIntervalMinutes | number | null | 5 | Both | How often (in minutes) to refresh linked pull-request state in the background while a project is open. null disables the periodic refresh; PR state still refreshes when the project opens |
Context Bar Settings
Section titled “Context Bar Settings”| Key | Type | Default | Scope | Description |
|---|---|---|---|---|
contextBar.showShell | boolean | true | Global only | Show shell name in context bar |
contextBar.showVersion | boolean | true | Global only | Show agent CLI version |
contextBar.showElapsed | boolean | true | Global only | Show a ticking wall-clock elapsed time since the session started |
contextBar.showCost | boolean | true | Global only | Show session cost |
contextBar.showToolCalls | boolean | true | Global only | Show the cumulative count of completed tool calls. Click the pill for a per-tool breakdown |
contextBar.showAgentActive | boolean | false | Global only | Show the agent’s active time as reported by the CLI. Opt-in by default (it overlaps conceptually with elapsed time) to keep the bar lean |
contextBar.showTokens | boolean | true | Global only | Show token usage |
contextBar.showContextFraction | boolean | true | Global only | Show context window fraction |
contextBar.showProgressBar | boolean | true | Global only | Show context window progress bar |
contextBar.showRateLimits | boolean | true | Global only | Show adapter-reported rate-limit bars (Claude reports 5-hour session and 7-day weekly windows; hidden for adapters that don’t report rate limits) |
The model and effort pills are always visible when the adapter reports them. Both pills double as click-targets for the per-task model/effort picker popover, so they no longer have show/hide toggles. Effort levels are surfaced for adapters whose discoverCapabilities reports a non-empty effortLevels list (Claude Code in particular).
Sidebar Settings
Section titled “Sidebar Settings”| Key | Type | Default | Scope | Description |
|---|---|---|---|---|
sidebar.width | number | 400 | Global only | Sidebar width in pixels |
Browser Settings
Section titled “Browser Settings”Settings for the embedded browser pane.
| Key | Type | Default | Scope | Description |
|---|---|---|---|---|
browser.enabled | boolean | true | Both | When false, the Browser pill is hidden in the task detail window header, and an agent calling kangentic_browser_open_pane is refused with a message telling it to ask you to enable the pane |
browser.defaultUrl | string | undefined | undefined | Both | Project-default URL used when a task has no per-task override. Set only deliberately, via Save as project default in the pane or this setting; a task navigation never seeds it (it did before v0.36.0). Stored per-project; never seeded into new projects |
Agent Browser Settings
Section titled “Agent Browser Settings”A cross-project security policy governing whether and how an agent may drive the embedded Browser pane via the kangentic_browser_* MCP tools. These are separate from the per-project browser.* pane settings above and live under the Agent Browser settings tab. They are resolved with the defaults below when unset (they are not written into the built-in DEFAULT_CONFIG).
| Key | Type | Default | Scope | Description |
|---|---|---|---|---|
browserAutomation.enabled | boolean | true | Global only | Master switch. When false, the kangentic_browser_* tools are not registered at all |
browserAutomation.allowInteraction | boolean | true | Global only | Allow click, type, keypress, and drag. When false, agents are observe-only (screenshots and DOM reads still work) |
browserAutomation.allowNavigation | boolean | true | Global only | Allow navigating the pane to other URLs. Turn off to confine agents to the page you loaded |
browserAutomation.allowEval | boolean | false | Global only | Allow arbitrary JavaScript eval in the loaded page (kangentic_browser_eval). Off by default - the one unbounded primitive, running with the page’s cookies |
browserAutomation.restrictNavigationToLocalhost | boolean | false | Global only | Only allow navigation to localhost / private hosts, never public sites. Off by default (any http(s) URL allowed) |
Dev-Server Ports
Section titled “Dev-Server Ports”The scan range Kangentic draws from when an agent asks for a free dev-server port with kangentic_reserve_dev_ports. Config-file only: there is no Settings UI, and the keys are not written into the built-in DEFAULT_CONFIG.
Kangentic never starts or supervises a dev server, and nothing is reserved up front. A task holds ports only once its agent has asked for them, and the reservation lives until the task or its project is deleted.
The ledger itself is deliberately in the global database, not per project: ports are a shared resource, so a per-project ledger could not see that another project already holds 4200. That scopes it to one Kangentic instance rather than the whole machine. A bind probe, run against every candidate before it is handed out, is what keeps two instances (or any other process) from colliding.
| Key | Type | Default | Scope | Description |
|---|---|---|---|---|
devServer.portRangeStart | number | 7300 | Global only | First port considered when reserving |
devServer.portRangeEnd | number | 7499 | Global only | Last port considered when reserving, inclusive |
Dictation Settings
Section titled “Dictation Settings”Local push-to-talk voice-to-text into whatever text field or terminal holds focus. Global/shared scope (hardware and user level, not per-project); lives under the Dictation settings tab. The push-to-talk key binding is set via keybindings (the dictation.pushToTalk action), not here.
| Key | Type | Default | Scope | Description |
|---|---|---|---|---|
dictation.enabled | boolean | false | Global only | Master toggle: show the mic button and enable push-to-talk |
dictation.engineMode | string | "auto" | Global only | Transcription engine selection: auto (tiers by detected hardware), sherpa-onnx, whisper-cpp, hybrid, or remote (uses the cloud backend below). The non-auto values force a specific engine for latency-vs-accuracy comparison |
dictation.modelId | string | null | null | Global only | The final (accurate) model. null = the tier default (Parakeet); "none" = keep the live text with no refinement pass |
dictation.liveModelId | string | null | null | Global only | The live (preview) model. null = the streaming Zipformer; "none" = no live preview |
dictation.mode | string | (derived) | Global only | Quality preset: fast, balanced, or accurate (each locks the live + refinement models), or custom (unlocks manual model choice) |
dictation.punctuation | boolean | true | Global only | Add punctuation and capitalization to committed text |
dictation.language | string | "en" | Global only | BCP-47 language. v1 ships English only |
dictation.autoSubmit | boolean | true | Global only | Press Enter automatically after inserting the text; set false to leave it in the input for review. Refused regardless of this setting for a field inside a multi-field form, and for any field inside a page loaded in the Browser pane - see Dictation |
dictation.releaseBufferMs | number | 250 | Global only | Keep the mic open this many ms after releasing push-to-talk so the last word isn’t clipped (0-500, snaps to 50ms steps; 0 = stop immediately) |
dictation.experience | string | "popup" | Global only | Live UI surface while dictating: popup (floating panel), docked (bar by the terminal input), or live (type into the resolved target as you speak, each revision replacing the last in place). The stored default is popup, but live is what actually ships |
dictation.remote | object | (unset) | Global only | OpenAI-compatible /v1/audio/transcriptions endpoint for the final text, used when engineMode is remote. The live preview still runs on-device; only the final clip is sent |
Memory Settings
Section titled “Memory Settings”Local conversation search and recall. Global/shared scope (per-machine, on-device); lives under the Memory settings tab, next to Dictation (both are keyless, on-device, model-backed features). Kangentic indexes the structured transcript of each agent conversation into a local per-project index that powers the Quick Find Conversations group (for you) and the kangentic_search MCP tool (for agents). Keyword search is on by default; the semantic (embedding) layer is opt-in. See Conversation Memory for the full feature.
| Key | Type | Default | Scope | Description |
|---|---|---|---|---|
memory.indexingEnabled | boolean | true | Global only | Index agent conversation transcripts locally for search and recall. When false, no indexing runs, no conversation hits appear in Quick Find or kangentic_search, and the embedding worker never starts. Fully local and keyless |
memory.semanticEnabled | boolean | false | Global only | Enable the semantic (embedding) layer on top of keyword search. Turning it on triggers a one-time local download of the selected memory.embeddingModel and background embedding of the index. Keyword search works regardless; if the model or vector extension is unavailable, search transparently falls back to keyword-only |
memory.embeddingModel | string | "bge-base" | Global only | Which local embedding model powers semantic search, chosen by quality in the Memory tab. Options (all bge-*-en-v1.5, ONNX, keyless, offline): bge-small (Balanced, 384d, ~34 MB), bge-base (Accurate, 768d, ~110 MB), bge-large (Best accuracy, 1024d, ~337 MB). Switching re-embeds the index in the background |
memory.acceleration | string | "auto" | Global only | Which hardware the embedding model runs on: auto (default) and gpu prefer a GPU execution provider (DirectML on Windows, WebGPU elsewhere) and fall back to CPU; cpu forces the universal path |
Notification Settings
Section titled “Notification Settings”| Key | Type | Default | Scope | Description |
|---|---|---|---|---|
notifications.desktop.onAgentIdle | boolean | true | Global only | Desktop notification when agent goes idle |
notifications.desktop.onAgentCrash | boolean | true | Global only | Desktop notification when a session exits with an error |
notifications.desktop.onPlanComplete | boolean | true | Global only | Desktop notification when planning completes |
notifications.desktop.onSpawnStalled | boolean | true | Global only | Desktop notification when a task spawn has been preparing (worktree/git) longer than the stall threshold |
notifications.toasts.onAgentIdle | boolean | true | Global only | In-app toast when agent goes idle |
notifications.toasts.onAgentCrash | boolean | true | Global only | In-app toast when a session exits, cleanly or with an error. The notifications.desktop.onAgentCrash row above fires on error exits only |
notifications.toasts.onPlanComplete | boolean | true | Global only | In-app toast when planning completes |
notifications.toasts.onSpawnStalled | boolean | true | Global only | In-app toast (with a Cancel action) when a task spawn stalls preparing its worktree |
notifications.toasts.durationSeconds | number | 4 | Global only | How long toasts display |
notifications.toasts.maxCount | number | 5 | Global only | Maximum simultaneous toasts on screen |
notifications.cooldownSeconds | number | 10 | Global only | Minimum seconds between repeated notifications |
Column-Level Settings
Section titled “Column-Level Settings”Each column (swimlane) can override settings individually:
| Field | Type | Default | Description |
|---|---|---|---|
description | string | null | null | Free-form description of the column’s purpose. Shown as a header tooltip and shared with your team via kangentic.json. null when unset |
permission_mode | string | null | null | Permission mode override for this column |
auto_spawn | boolean | true | Whether moving a task here spawns an agent |
auto_command | string | null | null | Command injected into running sessions on task arrival |
auto_command_mode | string | 'immediate' | When that command fires: immediate delivers on arrival, and the CLI queues it if the agent is mid-turn, while deferred holds it until the current turn completes. Neither mode interrupts a running turn. A freshly spawned session ignores both and waits for the agent’s first activity |
plan_exit_target_id | string | null | null | Target column when plan-mode agent exits |
agent_override | string | null | null | Use a specific agent for sessions in this column (one of "claude", "codex", "gemini", "cursor", "copilot", "grok", "antigravity", "opencode", "aider", "qwen", "kimi", "droid", "warp", "ollama"). null inherits the project default agent |
model_override | string | null | null | Adapter-specific model identifier passed at spawn (e.g. Claude --model opus, Codex --model gpt-5-codex). Live-applied via the agent’s /model slash on column transition when supported |
effort_override | string | null | null | Adapter-specific effort/reasoning level passed at spawn (e.g. Claude --effort xhigh). Live-applied via the agent’s /effort slash on column transition when supported |
handoff_context | boolean | false | When enabled, point the next agent at the prior agent’s native session history file when a task moves into this column. Any agent can receive one; whether context carries depends on the outgoing agent. Claude, Codex, Gemini, Grok, Antigravity, OpenCode, Aider, Qwen, Kimi, and Droid leave a readable history; Cursor, Copilot, Warp, and Ollama leave nothing Kangentic can hand on |
session_target | string | 'main' | Which session track a task runs on in this column: main (the task’s shared main conversation, resumed as it moves between normal columns) or isolated (this column’s own separate, context-isolated session, keyed by the column). Leaving an isolated column resumes the main session. Forced to main for To Do / Done columns |
session_spawn_strategy | string | 'create_or_resume' | What to do with that session track on column entry: create_or_resume (resume the track’s session if one exists, else spawn) or always_spawn_new (always spawn a fresh, independent pass, retiring the prior session). The default is context-aware: isolated columns default to always_spawn_new, main columns to create_or_resume. Governs column entry only - an app restart or pause/resume still resumes an in-progress session |
The available models and effort levels are surfaced from each adapter’s discoverCapabilities probe - the Edit Column dropdown shows only what the active CLI supports. See Custom Workflows for details on how these interact.
Themes
Section titled “Themes”Kangentic includes 10 built-in themes:
- Dark - Default dark theme
- Moon - Cool-toned dark theme
- Forest - Green-accented dark theme
- Ocean - Blue-accented dark theme
- Ember - Warm orange-accented dark theme
- Light - Default light theme
- Sand - Warm neutral light theme
- Mint - Green-accented light theme
- Sky - Blue-accented light theme
- Peach - Warm pink-accented light theme
Set the theme in the settings panel or in your global config file.
Global-Only Settings
Section titled “Global-Only Settings”These settings cannot be overridden per-project:
agent.maxConcurrentSessionsagent.queueOverflowagent.cliPathsagent.idleTimeoutMinutesagent.autoResumeSessionsOnRestartagent.launchOptionsagent.executionServerssidebarVisibleskipDeleteConfirmskipBoardConfigConfirmautoFocusIdleSessionautoNameRateLimitPerHourboardLayoutcardDensitycolumnWidthshowTaskNumbersterminalPanelVisiblestatusBarVisibleanimationsEnableddiffViewModediffDefaultScopediffIgnoreWhitespacediffCollapseUnchangeddiffWrapLinesdiffUseInlineWhenNarrowdiffFileSortdiffFlatListwindowLightDismisssidebar.widthterminal.shellterminal.fontFamilyterminal.fontSizeterminal.cursorStyleterminal.colorsterminal.backspaceSendsCtrlHterminal.panelHeightterminal.panelCollapsedterminal.showPreviewrestoreWindowPositionstatusBarPeriod(deprecated)usageStatsPeriodusageStatsScopemonitor.*(all Agent Monitor view settings)mcpServer.enabledmcpServer.bindAddressmcpServer.callbackHostnotifications.*(all notification settings)contextBar.*(all context bar settings)browserAutomation.*(all Agent Browser settings)dictation.*(all dictation settings)memory.*(all conversation-memory settings)mobileBridge.*(all mobile-bridge settings)developer.*(all developer settings)hotkeyOverrides
MCP Server Settings
Section titled “MCP Server Settings”| Key | Type | Default | Scope | Description |
|---|---|---|---|---|
mcpServer.enabled | boolean | true | Global only | Enable/disable the MCP server that lets agents interact with the board |
mcpServer.bindAddress | string | "127.0.0.1" | Global only | Network interface the in-process MCP HTTP server listens on. Not exposed in the Settings UI; edit config.json directly. The loopback default keeps the server local; to reach it from another machine use a wildcard like 0.0.0.0 (which still binds loopback), never a single non-loopback interface. Read once at startup |
mcpServer.callbackHost | string | undefined | unset | Global only | Extra hostname allowlisted alongside bindAddress for the server’s DNS-rebinding protection, so a legitimate external request is not rejected. Not exposed in the Settings UI; edit config.json directly |
When enabled, each agent session gets access to MCP tools for creating tasks, searching the board, browsing the backlog, and reading session transcripts. See the MCP Server reference for the full list of tools. As of v0.15.0 the MCP server runs as an in-process streamable HTTP transport (replacing the earlier file-bridge). Disable this if you don’t want agents to be able to modify the board.
As a runaway-loop safeguard, the MCP server caps task creation at 500 tasks per app launch. Once the cap is hit, kangentic_create_task returns an error until you restart Kangentic. This is a fixed limit, not a configurable setting.
Mobile Bridge Settings
Section titled “Mobile Bridge Settings”The desktop half of the mobile companion app link, configured in Settings > Mobile Devices. These keys are global: they describe this desktop installation, not any one project. The bridge ships in production builds and is off until you turn it on.
| Key | Type | Default | Scope | Description |
|---|---|---|---|---|
mobileBridge.enabled | boolean | false | Global only | Master switch. While off, no relay connection is held and pairing is unavailable |
mobileBridge.relayMode | string | resolves to "hosted" | Global only | Which relay to dial: hosted (the Kangentic-operated relay at wss://relay.kangentic.com), or custom (your own, from relayUrl). A third value, local, is dev-build only: a shipped build reports and dials hosted even if a persisted local reaches it. Deliberately absent from the shipped defaults rather than set to "hosted", so that a config written before this key existed, but carrying a relayUrl, is still inferred as custom instead of being silently moved onto the hosted relay |
mobileBridge.relayUrl | string | "" | Global only | The relay address to dial, consulted only when relayMode is custom. Must be wss://, or ws:// for loopback only. An empty or invalid value falls back to the hosted relay, so the dialed address is never blank |
Pairing, the paired-device roster, and the install link are UI surfaces on the same tab rather than config keys. See Pairing a Phone for the ceremony and Kangentic Relay for what the relay does and how to run your own.
Developer Settings
Section titled “Developer Settings”Power-user toggles for diagnosing the activity engine and other internal subsystems. All are global-only. In shipped builds they default to off; several turn on automatically in dev builds (npm start and /preview), as noted per key below. Toggle the whole panel from anywhere with Ctrl+Shift+D / Cmd+Shift+D.
| Key | Type | Default | Description |
|---|---|---|---|
developer.activityDebugOverlay | boolean | false | Show the floating activity-engine debug overlay (live counters, current activity reason, and recent transitions per running session). Also writes a per-session JSON snapshot under .kangentic/debug/ on each state change |
developer.persistConsoleLogs | boolean | dev: true, prod: false | Persist info/debug/log console output to .kangentic/logs/<date>.log (errors and warnings are always persisted). Read via the kangentic_tail_logs MCP tool |
developer.recordIpcTraffic | boolean | false | Record every IPC handler call (channel, args, result, duration) to .kangentic/logs/ipc-<date>.jsonl. Sensitive channels are redacted. Off in production and regular dev; auto-enabled only in the ephemeral /preview instance, whose logs are wiped on close. Non-trivial disk impact |
developer.previewInspectionServer | boolean | dev: true, prod: false | Bind a localhost-only HTTP inspection bridge powering the dev-only devtools MCP tools. The UI affordance is excluded from production builds; the key persists for type compatibility but has no effect in shipped binaries |
developer.previewEvalEnabled | boolean | dev: true, prod: false | Stricter gate on top of previewInspectionServer that enables high-risk inspection endpoints (eval, synthetic session events, raw PTY input). On in dev builds, like previewInspectionServer; the UI affordance is dropped from production builds |
Environment Variables
Section titled “Environment Variables”| Variable | Description |
|---|---|
KANGENTIC_DATA_DIR | Override the config/data directory path. Takes priority over the launcher’s --data-dir flag when both are set |
KANGENTIC_TELEMETRY | Set to 0 to disable all anonymous telemetry: usage analytics and error reporting |
KANGENTIC_ERROR_REPORTING | Set to 0 to disable crash and error reporting only, leaving usage analytics on |
KANGENTIC_ANNOUNCEMENTS_URL | Point the in-app announcements feed at a different URL (see Notifications) |
Telemetry & Analytics
Section titled “Telemetry & Analytics”Kangentic sends anonymous usage analytics to Aptabase and crash and error reports to Sentry. No code or task content is collected, one per-launch event carries a stable install identifier, and stack-frame paths are normalized to the app root before an error report leaves your machine - see Privacy & Analytics. Set KANGENTIC_TELEMETRY=0 to turn off both, or KANGENTIC_ERROR_REPORTING=0 to turn off error reporting alone.
See Privacy & Analytics for full details on what is collected and how to opt out.
Kangentic is free and open source. A star helps other people find it.
Star on GitHub