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 leastNOTIFY. authority_overridescan only raise a kind, never lower it.touch_production_data,change_security_postureandoverspendare alwaysESCALATE(safety floor).plan_approvalandmergetake 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
}
Related
Last updated: January 1, 0001
Open kanman