Keel is configured via a keel.toml file. This document describes the available configuration options and how they drive Keel's behavior.
Keel resolves configuration in the following order:
- Project-local:
./keel.toml - User-global:
~/.config/keel.toml - Built-in defaults
You can specify where Keel stores its state (defaults to .keel):
board_dir = ".keel"Keel always supports the local filesystem board. For Keeper-managed multiplayer work, you can switch the storage backend contract to server and provide explicit Keeper and Hub coordinates.
[storage]
backend = "filesystem" # or "server"Use [storage.server] when backend = "server" so Keel knows which Keeper API and Hub authority it is targeting.
[storage]
backend = "server"
[storage.server]
keeper_base_url = "https://keeper.spoke.example"
hub_base_url = "https://hub.spoke.example"keeper_base_url is the future command transport target. hub_base_url is the authentication authority used by keel auth login.
Keel can persist a reusable Hub-backed session record for authenticated operators.
[auth]
session_file = "~/.config/keel/auth-session.json"If session_file is omitted, Keel defaults to ~/.config/keel/auth-session.json when the platform exposes a standard config directory. Relative paths are resolved relative to the keel.toml file that declares them.
keel auth login --email <addr> --password-stdin --hub-url <url>signs in through Spoke Hub and saves a reusable session.keel auth infoinspects the current saved session without printing bearer tokens.keel auth logoutrevokes the saved Hub session when possible and removes the local session file.
keel config show is the canonical way to inspect the effective storage backend and auth-session path that Keel will use at runtime.
Keel uses a flexible, role-based lane topology to route work. This is configured via the [workflow], [roles], and [lanes] sections, and it drives the Pull phase of the turn loop.
The [workflow] section controls the main operating window and queue pressure defaults. The built-in defaults currently assume a 7-7 autonomous window and up to 20 ready backlog stories before overload warnings begin.
[workflow]
open_for_work = true
working_hours_start = 7
working_hours_end = 19
max_battery_packs = 20
battery_decay_minutes = 30Defines the default roles and lanes used by commands like keel next --role <role>, keel roles, keel next --role <role> --explain, and keel flow.
[workflow]
open_for_work = true
working_hours_start = 7
working_hours_end = 19
max_battery_packs = 20
[workflow.defaults]
management_role = "manager"
delivery_role = "operator"
management_lane = "management"
delivery_lane = "delivery"Lanes are work queues that aggregate entities based on their status.
[lanes.delivery]
description = "Active delivery work"
include = ["story.backlog", "story.in-progress"]
exclude = ["story.done"]
parallel = true # Allows parallel execution of independent stories
manual_accept = false # Whether stories in this lane require manual verification
priority = 50 # Rendering and selection priority (higher first)Include/Exclude patterns:
story.backlogstory.in-progressstory.*(all story statuses)voyage.draftbearing.exploring
Roles map a "role family" to a default lane and an operational contract.
[roles.operator]
default_lane = "delivery"
operational_contract = "operator-core"Operational Contract: Refers to a built-in guidance profile that defines the actor's persona, priorities, and workflow hints. This is a binding agreement on how an actor must function when pulling work from the board. It is not a file-based markdown template.
Built-in contracts include:
manager-core: Focused on planning, triage, and strategic alignment.operator-core: Focused on evidence-backed delivery and TDD.
You can provide specific overrides for full role taxonomy strings.
[role_overrides."operator/software:infrastructure"]
operational_contract = "infrastructure-operator"Use the CLI to inspect the resolved topology at runtime:
keel rolesshows role families, default lanes, operational contracts, and overrides.keel next --role <role> --explainshows why a role resolves to a given lane and whether that lane is parallel or manual-accept.keel config showis the canonical rendered view of the merged configuration.
Keel uses scoring to prioritize work. You can switch between built-in modes or define custom ones.
[scoring]
mode = "constrained" # Options: constrained, growth, product, or custom[scoring.modes.aggressive]
impact_weight = 3.0
confidence_weight = 2.0
effort_weight = 1.0
risk_weight = 0.5Disable specific doctor checks if they don't apply to your workflow.
[doctor.checks.voyage-scope-authored-content]
disabled = trueConfigure weights and availability for research providers used in Bearings.
[research.providers.manual]
disabled = false
weight = 1.0
[research.providers.academic]
weight = 1.5The keel health command provides a high-level triage of the system's core subsystems. Use --scene for a visual bio-scan.
| Subsystem | Component | Description |
|---|---|---|
| NEURAL | Stories | Atomic implementation units and verification |
| MOTOR | Voyages | Tactical planning and SRS/SDD authorship |
| STRATEGIC | Epics | High-level initiatives and PRD coherence |
| SENSORY | Bearings | Research artifacts and evidence quality |
| SKELETAL | ADRs | Architecture Decision Records |
| VITAL | Missions | Core strategic objectives |
| AUTONOMIC | Routines | Scheduled automation and materialization |
| CIRCULATORY | Workflow | Board graph integrity and lane topology |
| PACEMAKER | Heartbeat | Derived repository energization and commit stability |
just keel health --sceneboard_dir = ".keel"
[storage]
backend = "server"
[storage.server]
keeper_base_url = "https://keeper.spoke.example"
hub_base_url = "https://hub.spoke.example"
[auth]
session_file = ".keel/auth/session.json"
[workflow.defaults]
management_role = "manager"
delivery_role = "operator"
[roles.manager]
default_lane = "management"
operational_contract = "manager-core"
[roles.operator]
default_lane = "delivery"
operational_contract = "operator-core"
[lanes.management]
description = "Planning and verification"
include = ["bearing.*", "voyage.draft", "story.needs-human-verification"]
priority = 100
manual_accept = true
[lanes.delivery]
description = "Implementation"
include = ["story.backlog", "story.in-progress"]
parallel = true
priority = 50
[scoring]
mode = "constrained"
[doctor.checks.story-id-uniqueness]
disabled = false