Policy settings

Every setting of a team policy with type, default and allowed values, the five presets, and the authority table.

Every team has exactly one policy. It decides which repositories and paths kanman may touch, which executor and models it uses, how much it may spend, when a human must approve, and how much work runs in parallel. For the ideas behind it, read Policies, presets and authority levels.

You edit the policy in the app under Teams, your team, Settings. The settings are spread over these sections:

Section Path Settings
Policy /<workspace>/teams/<team>/settings/policy Preset, denied_paths, max_changed_files, max_changed_lines, and under Advanced max_concurrency, intake_scope, require_acceptance_spec, rework_attempts, gate_failure_budget, routing and authority_overrides
Budgets .../settings/budgets budget_run_cents, budget_day_cents, budget_month_cents; shows billing_mode
Approvals .../settings/approvals plan_approval, plan_approval_min_size, merge_policy, auto_merge_max_lines
Hours .../settings/hours working_hours, is_paused
Executor .../settings/executor executor, fallback_executor; shows the model per story
Repositories .../settings/repos allowed_repos
Maintenance .../settings/maintenance Shows maintenance and cadence and the findings

billing_mode and ai_config_id are chosen when you set up the team. The keys on this page are the names kanman uses in the audit log and in the policy snapshot of every run.

Who can change it

Only workspace admins can change a policy; other members see the settings read-only. Every change increases the policy version by one and writes a policy_changed entry to the audit log with the changed values and the old and new version. Each run stores the policy it started with, so you can always see which rules applied to a run.

Scope

What kanman may touch.

allowed_repos

Type: array
Default: []
Allowed: {"provider": "github" or "gitlab", "repoFullName": "org/repo", "branches": ["main"]}

Repositories and base branches kanman may work on. Branch entries are globs; a repository without a branch list allows any base branch. An empty list allows no repository at all. Work in a repository that is not listed stops with a policy_exception decision.

denied_paths

Type: array of globs
Default: from the preset
Allowed: Glob patterns, for example infra/**

Paths the executor must not change. kanman checks them while the executor works (through check_policy) and again on the final diff. A change to a denied path stops the run with a policy_exception decision. .kanman/acceptance/** is always denied in addition and cannot be removed or allowed once.

max_changed_files

Type: integer
Default: 30
Allowed: 1 or more

Maximum number of files one change may touch. Larger changes fail the policy_diff gate.

max_changed_lines

Type: integer
Default: 800
Allowed: 1 or more

Maximum added plus deleted lines of one change.

secret_names

Type: array of strings
Default: []
Allowed: Variable names

Names of secrets the executor may receive. Values stay in your CI or vault; only names are stored. A variable must also be listed in ci_var_keys of .kanman/verify.json.

Coming in a later release

Editing secret_names in the app and passing these secrets to the executor arrive in a later release. Until then the executor receives no secrets.

Executor and routing

Which coding agent and models do the work.

executor

Type: string
Default: claude-code
Allowed: claude-code, codex

The coding agent that implements stories. Shown as Claude Code or Codex under Settings > Executor.

fallback_executor

Type: string or null
Default: null
Allowed: claude-code, codex

The executor meant to take over when the main executor is unavailable.

Coming in a later release

Switching to the fallback executor automatically arrives in a later release. Until then the setting is stored but runs always use executor.

routing

Type: object
Default: see below

Model tier, turn budget and ceremony per complexity class, plus the reviewer settings.

Default value:

{
  "trivial":  { "modelTier": "small",    "turnBudget": 60,  "ceremony": "none" },
  "routine":  { "modelTier": "mid",      "turnBudget": 120, "ceremony": "plan_self_review" },
  "complex":  { "modelTier": "flagship", "turnBudget": 200, "ceremony": "approaches_then_plan" },
  "reviewer": { "vendor": "different_from_executor", "modelTier": "mid" },
  "modelOverrides": {}
}
Ceremony What happens before code is written
none The executor starts directly.
plan_self_review A short plan, then a self-review of the change before submitting.
approaches_then_plan Several scored approaches, then a plan based on the best one.

Default models per tier:

Tier Claude Code Codex
small haiku gpt-5-mini
mid sonnet gpt-5
flagship opus gpt-5

The Claude Code names always point to the current model of that family. modelOverrides pins a model by complexity class (for example "routine"), by tier (for example "mid") or for the "reviewer"; a class entry wins over a tier entry. With "vendor": "different_from_executor" the reviewer uses the other vendor’s model of its tier, so code written by Claude Code is reviewed by a Codex model and the other way round.

In the app you change the model tier and the turn budget (1 to 1000) per class under Settings > Policy, Advanced.

billing_mode

Type: string
Default: pass_through
Allowed: byok, pass_through

Who pays the model provider: your own contract (byok) or kanman, billed at cost plus 15 percent (pass_through). Chosen in the team setup and shown under Settings > Budgets.

ai_config_id

Type: reference or null
Default: null
Allowed: The key saved under Settings > AI providers

The provider key used with byok. Claude Code works with an Anthropic or Amazon Bedrock key, Codex with an OpenAI or Azure OpenAI key. A run with a missing, inactive or unsuitable key fails with a clear error instead of falling back to pass-through.

Budgets

All amounts are in euro cents. Budgets are hard stops. Work with the class of service expedite and incident work is never stopped by budgets.

budget_run_cents

Type: integer
Default: 200 (2.00 EUR)
Allowed: 1 or more

Maximum cost of one run, across all attempts. When it is reached the run stops with Stopped: budget reached, no pull request is created, and a budget_stop decision offers to double the run budget.

budget_day_cents

Type: integer or null
Default: null (no limit)
Allowed: 1 or more

Maximum spend of the team per day, in the time zone of working_hours (UTC if none). When it is used up, no new run starts until the next day.

budget_month_cents

Type: integer or null
Default: null (no limit)
Allowed: 1 or more

Maximum spend of the team per calendar month, in the same time zone. When it is used up, no new run starts until the next month.

Approvals

When a human has to say yes. Edited only under Settings > Approvals.

plan_approval

Type: string
Default: always
Allowed: always, by_size, never

When a human must approve the plan before code is written. The run plans read-only first, and the plan arrives as a plan_approval decision.

plan_approval_min_size

Type: string or null
Default: null
Allowed: S, M, L

With by_size: stories of this size or larger need approval. Without a value, or for a story without a size, every plan needs approval.

merge_policy

Type: string
Default: human
Allowed: human, auto_if_small

Who merges. With human the story stays in Review with a mergeable pull request until a person merges it. auto_if_small merges automatically when every gate passed and the change is no larger than auto_merge_max_lines; larger changes raise a merge_approval decision. While your main branch is red, kanman holds automatic merges.

auto_merge_max_lines

Type: integer or null
Default: null
Allowed: 1 or more

With auto_if_small: the largest change, in lines, that may be merged automatically.

authority_overrides

Type: object
Default: {}
Allowed: {"<kind>": "NOTIFY"} or "ESCALATE"

Raises the authority level of individual decision kinds. See the authority table. In the app this is When kanman acts on its own under Settings > Policy, Advanced, with the levels Default, Tell me and Ask me first.

Working hours and concurrency

When and how much kanman works.

working_hours

Type: object or null
Default: null (always)
Allowed: {"tz", "days", "start", "end"}

When new runs may start, for example {"tz": "Europe/Berlin", "days": [1,2,3,4,5], "start": "08:00", "end": "19:00"}. Days are 1 (Monday) to 7 (Sunday). Runs in progress finish. Expedite stories and incidents start outside working hours too.

max_concurrency

Type: integer
Default: 1
Allowed: 1 to 20

How many runs of this team may be active at the same time. The effective value is capped by the team’s plan: Pilot 3, Team 5, Self-hosted 20, and 1 for a team without a plan. Stories wait in Ready until a slot is free.

is_paused

Type: boolean
Default: false
Allowed: true, false

A paused team starts no new runs; runs in progress finish. Set it with Pause kanman for this team under Settings > Hours, or ask kanman on the team’s intake page, for example “pause the team”.

Gates

How strict the outcome gate is. The gate itself, the diff guard and the clean-room run cannot be switched off.

require_acceptance_spec

Type: boolean
Default: true
Allowed: true; false only with the Trial preset

Whether a story needs a red acceptance spec before it can reach Ready. With false, kanman falls back to CI, the test plan and the reviewer run, and the evidence pack says that no outcome proof exists. Setting false with any other preset is rejected with Only the Trial preset can work without acceptance specs.

rework_attempts

Type: integer
Default: 1
Allowed: 0, 1

Automatic rework attempts after a failed verification, with the gate output and the reviewer’s findings as input. With 0, a failed verification goes straight to the decision inbox.

gate_failure_budget

Type: integer
Default: 3
Allowed: 1 to 10

How many failures of the same gate a story may collect, across all its runs and attempts, before kanman parks the run and asks with a Repeated gate failure decision. Failures of the test environment itself do not count.

Personality knobs

These are the settings presets change, together with max_concurrency and the default denied_paths.

preset_id

Type: string
Default: trial
Allowed: trial, focused, balanced, autonomous, hardening

The preset the policy is based on. See Presets. The team setup suggests Balanced.

is_custom

Type: boolean
Default: false
Allowed: read only

true once a preset knob differs from the preset. The app then shows “Custom (based on Balanced)”.

intake_scope

Type: string
Default: humans_and_kanman
Allowed: humans_only, humans_and_kanman

Who may file the stories kanman works on.

  • humans_only: kanman only works on stories people filed. kanman never files a story itself: with maintenance on, every finding waits as a proposal in Decisions, and only a person accepting it files the story.
  • humans_and_kanman: kanman may also file stories itself. With maintenance on, findings of the allowed kinds (allowedKinds) are filed as maintenance stories without asking; all other findings still wait as proposals.

Stories from intake are always approved by a person before they are written to the tracker, whatever this setting says.

maintenance

Type: object
Default: {"enabled": false, "dripPerDay": 0, "maxPerRun": 1, "allowedKinds": []}

Maintenance mode: on or off, how many maintenance stories and proposals may be filed and started per day, how many findings one scan may file at most, and which kinds become stories without asking. Today the Hardening preset is the way to turn it on.

cadence

Type: object
Default: {"reportWeekday": 1, "loopDoctorMinutes": 15, "scannerDays": 7}

Weekday of the team report (1 = Monday), how often the health check looks at the team’s runs, and how often maintenance scanners run for the team. The health check currently runs every 15 minutes for every team.

Presets

Presets only change the personality knobs and the default denied paths. Safety settings (sandbox, diff guard, clean-room run, always-denied paths) are the same for every preset.

Preset max_concurrency intake_scope Maintenance require_acceptance_spec Default denied_paths
Trial 1 humans_only off false infra/**, **/*.tf, .github/workflows/**
Focused 1 humans_only off true infra/**, **/*.tf, .github/workflows/**
Balanced 2 humans_and_kanman off true infra/**, **/*.tf, .github/workflows/**
Autonomous 4 humans_and_kanman off true .github/workflows/**
Hardening 2 humans_and_kanman on: 2 per day, at most 1 per scan true infra/**, **/*.tf, .github/workflows/**

Hardening allows the maintenance kinds cve, outdated_dep, unused_dep, lockfile_drift and broken_doc_link. All presets use cadence {"reportWeekday": 1, "loopDoctorMinutes": 15, "scannerDays": 7}.

Pick a preset under Settings > Policy. Switching applies right away; if the team is custom, kanman asks first because your changes to these knobs are replaced. Budgets, approvals, working hours, routing and authority overrides are not part of a preset and stay as they are.

Authority table

Every decision kanman takes has a kind, and the kind has a base authority level. The table is fixed code, not a prompt.

Level Meaning Decision kinds
AUTO Act silently, visible in the audit log write_ac, set_priority_in_band, link_duplicate, resequence, nudge_run
NOTIFY Act and record a notice close_duplicate, split_story, pause_thrashing_run
ESCALATE Stop and ask in the decision inbox, with a recommendation and 2 to 4 options expand_scope, change_security_posture, touch_production_data, overspend, contradict_operator, touch_denied_path, plan_approval, merge

Rules:

  • Unknown kinds default to NOTIFY.
  • Risk only raises the level: an irreversible action, a high blast radius or a cost of 20.00 EUR or more makes it ESCALATE; a medium blast radius or a cost of 5.00 EUR or more makes it at least NOTIFY.
  • authority_overrides can only raise a kind, never lower it.
  • touch_production_data, change_security_posture and overspend are always ESCALATE (safety floor).
  • plan_approval and merge take their base level from the approval settings (plan_approval, merge_policy); an override can only make them stricter.

Example: always ask before kanman links duplicates:

{
  "authority_overrides": {
    "link_duplicate": "ESCALATE"
  }
}

An override that would lower a level (for example "merge": "NOTIFY" while a person merges) has no effect: the stricter level always wins. Values other than NOTIFY and ESCALATE are ignored.

Full example

{
  "preset_id": "balanced",
  "is_custom": true,
  "version": 7,
  "allowed_repos": [
    { "provider": "github", "repoFullName": "acme/billing", "branches": ["main"] }
  ],
  "denied_paths": ["infra/**", "**/*.tf", ".github/workflows/**", "migrations/**"],
  "max_changed_files": 30,
  "max_changed_lines": 800,
  "executor": "claude-code",
  "fallback_executor": null,
  "billing_mode": "pass_through",
  "ai_config_id": null,
  "budget_run_cents": 300,
  "budget_day_cents": 3000,
  "budget_month_cents": 40000,
  "plan_approval": "by_size",
  "plan_approval_min_size": "M",
  "merge_policy": "human",
  "auto_merge_max_lines": null,
  "authority_overrides": {},
  "working_hours": { "tz": "Europe/Berlin", "days": [1, 2, 3, 4, 5], "start": "08:00", "end": "19:00" },
  "max_concurrency": 2,
  "secret_names": [],
  "require_acceptance_spec": true,
  "rework_attempts": 1,
  "gate_failure_budget": 3,
  "intake_scope": "humans_and_kanman",
  "maintenance": { "enabled": false, "dripPerDay": 0, "maxPerRun": 1, "allowedKinds": [] },
  "cadence": { "reportWeekday": 1, "loopDoctorMinutes": 15, "scannerDays": 7 },
  "is_paused": false
}

Last updated: January 1, 0001

Open kanman