Kanbus Configuration (Python + Rust)
Kanbus uses a single configuration file to define project identity, hierarchy, workflows, and priorities. The same schema and behaviors apply to both implementations.
Location
.kanbus.yml
The file must exist; there is no fallback path. A missing file is a hard error with a clear message.
Event history storage
- Event files are written to
project/events/(shared issues) orproject-local/events/(local issues). - Each event is a standalone JSON file named with a UTC timestamp and UUID suffix. Filenames use hyphens instead of colons in the time portion so they are valid on Windows, e.g.
2026-02-21T06-09-40.180Z__<event_id>.json. - Inside the JSON record,
occurred_atremains RFC3339 with colons, e.g.2026-02-21T06:09:40.180Z. - Event records include
schema_version,event_id,issue_id,event_type,occurred_at,actor_id, and an action-specificpayload. - Beads mode (
kanbus --beads) still writes event history toproject/events/even when issue records live in.beads/issues.jsonl. - Some repositories, including Kanbus itself, gitignore
project/events/because event files are runtime audit data. Other Anthus repos may commit them. A missingproject/events/directory in git does not mean Kanbus skips event recording.
Loading semantics (dotyaml parity)
- Load
.env(unless disabled), setting variables only when they are not already defined. - Parse
.kanbus.yml, interpolating{{ VAR|default }}expressions from the environment. - Flatten the resulting config into environment variables with the
KANBUS_prefix (nested keys joined by underscores, lists as comma-separated strings, booleans astrue/false, null as empty string). - Never override an environment variable that is already set unless
override=trueis explicitly requested.
These rules mirror the Python dotyaml package and must be matched in the Rust crate.
Field reference
Every key accepted at the top level of .kanbus.yml. Unknown keys are errors. This table is generated from the configuration model by tools/generate_configuration_reference.py and checked in CI.
<!-- BEGIN GENERATED: project-configuration-fields --> <!-- Generated by tools/generate_configuration_reference.py; do not edit by hand. -->
| Key | Type | Default | Description |
|---|---|---|---|
project_directory |
str |
required | Relative path to the primary project directory. |
virtual_projects |
Dict[str, VirtualProjectConfig] |
{} |
Map of label to virtual project configuration. |
new_issue_project |
Optional[str] |
None |
Project label for new issue creation routing. |
ignore_paths |
List[str] |
[] |
Paths to exclude from project discovery. |
console_port |
Optional[int] |
None |
Optional port for the web console server. |
project_key |
str |
required | Issue ID project key (prefix). |
project_id |
Optional[str] |
None |
Stable UUID identifying the project across clones and worktrees; scopes realtime topics. |
name |
Optional[str] |
None |
Optional human-readable board title. |
project_management_template |
Optional[str] |
None |
Optional template path for CONTRIBUTING_AGENT.md. |
methodologies |
Optional[List[Union[str, ProjectMethodologyBundleReference]]] |
None |
Methodology names assembled into CONTRIBUTING_AGENT.md. |
hierarchy |
List[str] |
required | Hierarchy ordering. |
types |
List[str] |
required | Non-hierarchical types. |
workflows |
Dict[str, Dict[str, List[str]]] |
required | Workflow definitions. |
transition_labels |
Dict[str, Dict[str, Dict[str, str]]] |
{} |
Display label for every workflow transition, keyed by workflow, from-status, then to-status. |
initial_status |
str |
required | Initial status for new issues. |
priorities |
Dict[int, PriorityDefinition] |
required | Priority map. |
default_priority |
int |
required | Default priority. |
assignee |
Optional[str] |
None |
Default assignee identifier. |
time_zone |
Optional[str] |
None |
Preferred display time zone. |
statuses |
List[StatusDefinition] |
[] |
Status definitions with display names, categories, and colors. |
categories |
List[CategoryDefinition] |
[] |
Status category definitions with display names and colors. |
sort_order |
Dict[str, Any] |
{} |
Optional status/category sort rules for console columns. |
type_colors |
Dict[str, str] |
{} |
Optional map of issue type to color name. |
beads_compatibility |
bool |
False |
Default Beads compatibility mode. |
events |
bool |
True |
Whether Kanbus generates events under project/events and commits them with kbs commit. |
wiki_directory |
Optional[str] |
None |
Optional directory containing wiki pages. |
ai |
Optional[AiConfiguration] |
None |
Optional AI provider and model configuration. |
right_now |
RightNowConfiguration |
see section | Right-now summary configuration. |
standup |
StandupConfiguration |
see section | Standup report configuration. |
jira |
Optional[JiraConfiguration] |
None |
Optional Jira synchronization configuration. |
snyk |
Optional[SnykConfiguration] |
None |
Optional Snyk vulnerability synchronization configuration. |
realtime |
RealtimeConfig |
see section | Realtime gossip configuration. |
coordination |
CoordinationConfiguration |
see section | Multi-agent coordination configuration. |
router |
Optional[IssueRouterConfiguration] |
None |
Optional issue router configuration. |
overlay |
OverlayConfig |
see section | Overlay cache configuration. |
hooks |
HooksConfiguration |
see section | Lifecycle hook configuration. |
github_security |
Optional[GithubSecurityConfiguration] |
None |
Optional GitHub security synchronization configuration. |
| <!-- END GENERATED: project-configuration-fields --> |
Minimal configuration
project_directory: project
project_key: kbs
hierarchy: [initiative, epic, task, sub-task]
types: [bug, story, chore]
workflows:
default:
open: [in_progress, closed]
in_progress: [open, closed]
closed: [open]
initial_status: open
priorities:
0: {name: critical}
1: {name: high}
2: {name: medium}
3: {name: low}
default_priority: 2
transition_labels:
default:
open: {in_progress: Start work, closed: Drop}
in_progress: {open: Pause, closed: Finish}
closed: {open: Reopen}
categories:
- {name: To do}
- {name: Done}
statuses:
- {key: open, name: Open, category: To do}
- {key: in_progress, name: In Progress, category: To do}
- {key: closed, name: Closed, category: Done}
kbs init writes a complete starting configuration; edit that rather than starting from scratch.
Validation rules
Beyond the schema, loading fails when:
hierarchyis empty, or a type name appears twice acrosshierarchyandtypes.workflows.defaultis missing, ortransition_labelsdoes not label every transition of every workflow.default_priorityis not a key ofpriorities.categoriesorstatusesis empty, a category or status key or name is duplicated, or a status references an undefined category.wiki_directoryescapes the project root.- A virtual project label equals
project_key, ornew_issue_projectnames an unknown project. - The enabled issue router references undefined provider profiles, classes, or statuses, or
review_wipexceedsproject_wip.
Environment integration
- Prefix for exported env vars is fixed to
KANBUS_. .envloading is enabled by default; disable with a loader flag.override=trueis an opt-in flag to let YAML values overwrite existing env vars; default is non-overriding.
Realtime gossip + overlay
realtime:
transport: auto # auto | uds | mqtt
broker: auto # auto | off | mqtt://... | mqtts://...
autostart: false # autostart mosquitto if unreachable (the gossip bridge always autostarts)
keepalive: false # keep autostarted broker running
uds_socket_path: null # override UDS socket path
mqtt_custom_authorizer_name: null # optional AWS IoT custom authorizer name
mqtt_api_token: null # optional API token for custom authorizer auth
topics:
project_events: "projects/{project}/events"
overlay:
enabled: true
ttl_s: 86400
coordination:
providers: [git] # git | [mqtt, git] | [mutex_api, mqtt, git]
contention_window: 5s # Competing claims use this window for tie-break
default_lease_ttl: 300s # Initial claim lifetime and default renewal step
mutex_api:
endpoint: null # e.g. https://mutex.example.test
bearer_token: null # sent as Authorization: Bearer <token>
Coordination durations are positive integer values followed by s, m, or
h (for example 5s, 2m, or 1h). The provider lists are ordered strongest
first: [git], [mqtt, git], or [mutex_api, mqtt, git]. Git records remain
the durable coordination history. Git-only claims are soft; MQTT adds shared
visibility; the Mutex API adds hard exclusion for live leases. The Mutex API
client uses POST, PUT, DELETE, and GET on
{endpoint}/api/coordination/leases/{resource} with bearer authentication.
When its endpoint or token is missing, or the service is unavailable, Kanbus
falls back through configured MQTT and Git providers. A live-lease conflict
and owner mismatch remain errors. For a hard claim, Kanbus appends the Git
claim event only after the API accepts the acquire; if that append fails it
tries to release the lease and reports the durable-write failure.
Claims, renewals, and releases are immutable records in project/events/,
keyed by the resource in the event's issue_id subject field. These events do
not change issue assignees or statuses. Git coordination is soft: workers can
record competing claims, and the winner is selected from claims in the initial
contention window by (claim_id, owner, event_id). Later claims do not replace
an active winner; expiry or release makes the resource eligible again.
Notes:
broker=autouses discovery precedence:~/.kanbus/run/broker.jsonthenmqtt://127.0.0.1:1883. This is an explicit exception to the no-fallback policy.- Overlay snapshots live under
project/.overlay/and are safe to delete. - Environment overrides (higher precedence than YAML):
KANBUS_COORDINATION_MUTEX_API_ENDPOINT,KANBUS_COORDINATION_MUTEX_API_BEARER_TOKEN,KANBUS_REALTIME_TRANSPORT,KANBUS_REALTIME_BROKER,KANBUS_REALTIME_AUTOSTART,KANBUS_REALTIME_KEEPALIVE,KANBUS_REALTIME_UDS_SOCKET_PATH,KANBUS_REALTIME_MQTT_CUSTOM_AUTHORIZER_NAME,KANBUS_REALTIME_MQTT_API_TOKEN,KANBUS_REALTIME_TOPICS_PROJECT_EVENTS,KANBUS_OVERLAY_ENABLED,KANBUS_OVERLAY_TTL_S.
Examples
Default software project
project_key: "KAN"
issue_types: [bug, story, chore]
workflow_bindings:
bug: default
story: default
chore: default
initial_status: open
priorities: [critical, high, medium, low, trivial]
default_priority: medium
priority_import_aliases:
P0: critical
P1: high
P2: medium
P3: low
priority_accept_unmapped: true
Beads import mapping
project_key: "BDX"
issue_types: [bug, task]
workflow_bindings:
bug: default
task: default
priorities: [urgent, high, normal, low]
default_priority: normal
priority_import_aliases:
P0: urgent
P1: high
P2: normal
P3: low
priority_accept_unmapped: false
Methodologies
methodologies selects the process guidance assembled into the generated CONTRIBUTING_AGENT.md, in the listed order. Entries are built-in names (bdd, git-flow) or { path: <folder> } for a bundle in the repository. When the key is absent the default is [bdd, git-flow]; methodologies: [] produces core guidance only.
methodologies:
- bdd
- git-flow
- path: methodologies/crap
See Methodologies for the bundle format, tools, and the kbs methodology commands.
AI and right-now defaults
Kanbus routes LLM calls through LiteLLM (ai.provider: litellm). The product default model is gpt-5.6-luna (OpenAI via OPENAI_API_KEY).
ai:
provider: litellm
model: gpt-5.6-luna
right_now:
enabled: true
default_tree_expanded: false
max_length: 120
model: gpt-5.6-luna
Right-now summaries are generated only when they are displayed: kbs now and the console Now panel generate a summary that is missing or older than the issue or one of its direct children. Board-mutating commands (create, update, comment, dep, delete) never call an LLM. Each generation is logged to project/events/llm_usage.jsonl; a call whose model has no known price is logged with "cost": null, and kbs cost reports it under Unpriced Calls instead of counting it as $0.
Credentials
Run kbs setup ai (or kanbus setup ai) once per user to store an LLM API key. It prompts for
the key (hidden input) and writes it to ~/.kanbus.env (mode 600), so every project on the
machine picks it up without a per-project .env.
Lookup order: shell environment, then ~/.kanbus.env, then the project .env file.
kbs setup ai # interactive prompt
pbpaste | kbs setup ai --from-stdin # read from stdin, e.g. a clipboard or secrets manager
kbs setup ai --variable ANTHROPIC_API_KEY # store a different provider's variable
kbs setup ai --status # show which source (if any) provides the key
Check kbs setup ai --status or kbs doctor to confirm a key is configured. Never store API
keys in .kanbus.yml.
For a LiteLLM proxy instead of a direct provider key, set LITELLM_API_KEY alongside
LITELLM_API_BASE or LITELLM_PROXY_URL (the Rust kbs now/standup path also accepts
OPENAI_API_BASE); these follow the same shell-environment / ~/.kanbus.env / project-.env
lookup order.
Machine-wide settings
Any KANBUS_* environment override can also live in ~/.kanbus.env, so every clone and
worktree on the machine shares it, using the same kbs setup env NAME --value ... (or
--from-stdin) command used for credentials. Environment overrides always beat .kanbus.yml.
This is useful for settings that should be consistent machine-wide rather than per project, such
as the realtime transport/broker/autostart/keepalive variables, KANBUS_REALTIME_MQTT_API_TOKEN,
KANBUS_REALTIME_MQTT_CUSTOM_AUTHORIZER_NAME, and the coordination mutex endpoint/token
(KANBUS_COORDINATION_MUTEX_API_ENDPOINT, KANBUS_COORDINATION_MUTEX_API_BEARER_TOKEN).
kbs setup env KANBUS_REALTIME_BROKER --value mqtt://127.0.0.1:1883
pbpaste | kbs setup env KANBUS_REALTIME_MQTT_API_TOKEN --from-stdin
Standup windows
Standup reports resolve completed vs active buckets from shared window settings. Field names are locked for config, CLI, and console API:
standup:
window: rolling # rolling | calendar
lookback: 24h # rolling duration; hours required (1d = 24h sugar)
skip_weekends: false # calendar only; ignored when window is rolling
timezone: America/New_York # optional IANA zone; unset uses system local
Defaults:
- Global:
window: rolling,lookback: 24h,skip_weekends: false meeting-scriptprofile override:window: calendar,skip_weekends: truedirector-briefprofile: inherits global rolling + 24h
standup.lookback_hours is not accepted (extra=forbid). Migrate to standup.lookback with a duration string such as 24h or 1d.
CLI overrides (same names as config/API): --window, --lookback, --skip-weekends / --no-skip-weekends.
Optional sync sections
github_security:
repo: owner/repo
dependabot:
min_severity: low
state: open
parent_epic: kanbus-abc123
github_security.repois optional; if omitted, Kanbus auto-detects fromgit remote origin.github_security.dependabot.min_severitydefaults tolow.github_security.dependabot.statedefaults toopen.github_security.dependabot.parent_epicis optional.