Configuration System
June 1, 2026 · View on GitHub
Last reviewed: 2026-05-08
Freshness source: cmd/bd/main.go, cmd/bd/config.go, and
internal/configfile/.
bd has two complementary configuration systems:
- Tool-level configuration (Viper): startup settings, flags, output format, and other CLI behaviour
- Project-level configuration (
bd config): integration data and project-specific settings; startup-sensitive keys are routed toconfig.yaml
Tool-Level Configuration (Viper)
Overview
Tool preferences control how bd behaves globally or per-user. These are stored in config files or environment variables and managed by Viper.
Configuration precedence (highest to lowest):
- Command-line flags (
--json,--dolt-auto-commit, etc.) - Environment variables (
BD_JSON,BD_DOLT_AUTO_COMMIT, etc.) - Merged config files (
~/.beads/config.yaml,~/.config/bd/config.yaml,.beads/config.yaml, andBEADS_DIR/config.yaml) - Defaults
Config File Locations
Config files are merged from lowest to highest priority:
~/.beads/config.yaml- legacy user settings~/.config/bd/config.yaml- user settings; this path is checked explicitly even on platforms whose native user-config directory differs.beads/config.yaml- project-specific tool settings, discovered by walking up from the current directoryBEADS_DIR/config.yaml- highest-priority runtime workspace override whenBEADS_DIRpoints at a different.beadsdirectory
When a project config exists, .beads/config.local.yaml is merged last for
machine-specific overrides that should not be committed.
Supported Settings
Common tool-level settings you can configure:
| Setting | Flag | Environment Variable | Default | Description |
|---|---|---|---|---|
json | --json | BD_JSON | false | Output in JSON format |
no-push | --no-push | BD_NO_PUSH | false | Skip pushing to remote in bd dolt push |
federation.remote | - | BD_FEDERATION_REMOTE | (none) | Dolt remote URL for federation |
federation.sovereignty | - | BD_FEDERATION_SOVEREIGNTY | (none) | Data sovereignty tier: T1, T2, T3, T4 |
dolt.auto-commit | --dolt-auto-commit | BD_DOLT_AUTO_COMMIT | on | (Dolt backend) Automatically create a Dolt commit after successful write commands |
create.require-description | - | BD_CREATE_REQUIRE_DESCRIPTION | false | Require description when creating issues |
validation.on-create | - | BD_VALIDATION_ON_CREATE | none | Template validation on create: none, warn, error |
validation.on-sync | - | BD_VALIDATION_ON_SYNC | none | Template validation before sync: none, warn, error |
git.author | - | BD_GIT_AUTHOR | (none) | Override commit author for beads commits |
git.no-gpg-sign | - | BD_GIT_NO_GPG_SIGN | false | Disable GPG signing for beads commits |
directory.labels | - | - | (none) | Map directories to labels for automatic filtering |
external_projects | - | - | (none) | Map project names to paths for cross-project deps |
backup.enabled | - | BD_BACKUP_ENABLED | false | Enable periodic Dolt-native backup to .beads/backup/ |
backup.interval | - | BD_BACKUP_INTERVAL | 15m | Minimum time between auto-backups |
dolt.auto-push | - | BD_DOLT_AUTO_PUSH | false | Auto-push to Dolt remote after writes (explicit opt-in) |
dolt.auto-push-interval | - | BD_DOLT_AUTO_PUSH_INTERVAL | 5m | Minimum time between auto-pushes |
dolt.auto-push-timeout | - | BD_DOLT_AUTO_PUSH_TIMEOUT | 30s | Timeout for a single auto-push attempt |
dolt.shared-server | --shared-server | BEADS_DOLT_SHARED_SERVER | false | Share a single Dolt server across all projects at ~/.beads/shared-server/ |
db | --db | BD_DB | (auto-discover) | Database path |
actor | --actor | BEADS_ACTOR | git config user.name | Actor name for audit trail (see below) |
Backend note: Dolt is the only storage backend. By default, Dolt runs in embedded mode (in-process, no server). Use bd init --server or BEADS_DOLT_SERVER_MODE=1 for server mode. See DOLT.md for details.
Dolt Auto-Commit (SQL commit vs Dolt commit)
When using the Dolt backend, there are two different kinds of “commit”:
- SQL transaction commit: what happens when a
bdcommand updates tables successfully (durable in the Dolt working set). - Dolt version-control commit: what records those changes into Dolt’s history (visible in
bd vc log, push/pull/merge workflows).
By default, bd is configured to auto-commit Dolt history after each successful write command:
- Default:
dolt.auto-commit: on - Disable for a single command:
bd --dolt-auto-commit off create "No commit for this one"
- Disable in config (
.beads/config.yamlor~/.config/bd/config.yaml):
dolt:
auto-commit: off
Caveat: enabling this creates more Dolt commits over time (one per write command). This is intentional so changes are not left only in the working set.
Auto-Backup
Periodic Dolt-native backup to .beads/backup/ provides an off-machine recovery path. Local Dolt snapshots (via dolt.auto-commit) remain the primary safety net; backup is a secondary layer.
This is a full database backup, unlike bd export or .beads/issues.jsonl.
It preserves Dolt state such as tables, branches, commit history, and
working-set data.
backup:
enabled: true # Enable auto-backup after write commands
interval: 15m # Minimum time between auto-backups
How it works:
- After each write command (in PersistentPostRun),
bdchecks the Dolt HEAD commit hash against the last backup state - If data changed and the throttle interval has passed, a Dolt-native backup is synced to
.beads/backup/ - Full database state and commit history are preserved in the backup
- State is tracked in
.beads/backup/backup_state.json
Manual commands:
bd backup init <path>— register a backup destination (filesystem or DoltHub URL)bd backup sync— push to the configured backup destinationbd backup restore [path]— restore from a backup (--forceto overwrite)bd backup remove— unregister the backup destinationbd backup status— show backup configuration and last sync time
Dolt Auto-Push
By default, bd does not push automatically after write commands. Auto-push is explicit opt-in because concurrent pushes to git-protocol Dolt remotes can corrupt or strand remote history when multiple writers race.
dolt:
auto-push: false # Explicit opt-in only; set true for single-writer setups
auto-push-interval: 5m # Minimum time between auto-pushes
auto-push-timeout: 30s # Bound one push attempt when the remote is unreachable
How it works:
- After each write command (in PersistentPostRun, after auto-commit and auto-backup),
bdchecks whether a push is due - Pushes are debounced: skipped if the last push was less than
dolt.auto-push-intervalago - Change detection: skipped if the Dolt HEAD commit hasn't changed since last push
- Push failures are warnings only (non-fatal)
- Last push time and commit are tracked in the metadata table
Opt in:
dolt:
auto-push: true
Actor Identity Resolution
The actor name (used for created_by in issues and audit trails) is resolved in this order:
--actorflag (explicit override)BEADS_ACTORenvironment variableBD_ACTORenvironment variable (deprecated alias, kept for backwards compatibility)git config user.name$USERenvironment variable (system username fallback)"unknown"(final fallback)
For most developers, no configuration is needed - beads will use your git identity automatically. This ensures your issue authorship matches your commit authorship.
To override, set BEADS_ACTOR in your shell profile:
export BEADS_ACTOR="my-github-handle"
Sync Mode Configuration
The sync mode controls how beads synchronizes data with git and/or Dolt remotes.
Sync Mode
Beads uses dolt-native sync mode exclusively. Dolt remotes handle sync directly with cell-level merge. Use bd export for issue portability, and bd backup init / bd backup sync / bd backup restore for Dolt-native backups.
Federation Configuration
federation.remote: Dolt remote URL (e.g.,dolthub://org/beads,gs://bucket/beads,s3://bucket/beads,az://account.blob.core.windows.net/container/beads)federation.sovereignty: Data sovereignty tier:T1: Full sovereignty - data never leaves controlled infrastructureT2: Regional sovereignty - data stays within region/jurisdictionT3: Provider sovereignty - data with trusted cloud providerT4: No restrictions - data can be anywhere
Example Configuration
# .beads/config.yaml
# Optional: Dolt federation
federation:
remote: dolthub://myorg/beads
sovereignty: T2
Example Config File
~/.config/bd/config.yaml:
# Default to JSON output for scripting
json: true
# Dolt auto-commit (creates Dolt history commit after each write)
dolt:
auto-commit: on
.beads/config.yaml (project-specific):
# Require descriptions on all issues (enforces context for future work)
create:
require-description: true
# Template validation settings (bd-t7jq)
# Validates that issues include required sections based on issue type
# Values: none (default), warn (print warning), error (block operation)
validation:
on-create: warn # Warn when creating issues missing sections
on-sync: none # No validation on sync (backwards compatible)
# Git commit signing options (GH#600)
# Useful when you have Touch ID commit signing that prompts for each commit
git:
author: "beads-bot <beads@example.com>" # Override commit author
no-gpg-sign: true # Disable GPG signing
# Directory-aware label scoping for monorepos (GH#541)
# When running bd ready/list from a matching directory, issues with
# that label are automatically shown (as if --label-any was passed)
directory:
labels:
packages/maverick: maverick
packages/agency: agency
packages/io: io
# Feedback title formatting for mutating commands (GH#1384)
# 0 = hide titles, N > 0 = truncate to N characters
output:
title-length: 255
# Cross-project dependency resolution (bd-h807)
# Maps project names to paths for resolving external: blocked_by references
# Paths can be relative (from cwd) or absolute
external_projects:
beads: ../beads
other-project: /path/to/other-project
Why Two Systems?
Tool settings (Viper) are user preferences:
- How should I see output? (
--json) - Should Dolt auto-commit? (
--dolt-auto-commit) - How should the CLI behave?
Project config (bd config) is project data:
- What's our Jira URL?
- What are our Linear tokens?
- How do we map statuses?
This separation is correct: tool settings are user-specific, project config is team-shared.
Agents benefit from bd config's structured CLI interface over manual YAML editing.
Project-Level Configuration (bd config)
Overview
Project configuration is:
- Per-project: Isolated to each
.beads/database - Version-control-friendly: Stored in the database, queryable and scriptable
- Machine-readable: JSON output for automation
- Namespace-based: Organized by integration or purpose
Commands
Set Configuration
bd config set <key> <value>
bd config set --json <key> <value> # JSON output
Examples:
bd config set jira.url "https://company.atlassian.net"
bd config set jira.project "PROJ"
bd config set jira.status_map.todo "open"
Get Configuration
bd config get <key>
bd config get --json <key> # JSON output
Examples:
bd config get jira.url
# Output: https://company.atlassian.net
bd config get --json jira.url
# Output: {"key":"jira.url","value":"https://company.atlassian.net"}
List All Configuration
bd config list
bd config list --json # JSON output
Example output:
Configuration:
compact_tier1_days = 90
compact_tier1_dep_levels = 2
jira.project = PROJ
jira.url = https://company.atlassian.net
JSON output:
{
"compact_tier1_days": "90",
"compact_tier1_dep_levels": "2",
"jira.project": "PROJ",
"jira.url": "https://company.atlassian.net"
}
Unset Configuration
bd config unset <key>
bd config unset --json <key> # JSON output
Example:
bd config unset jira.url
Namespace Convention
Configuration keys use dot-notation namespaces to organize settings:
Core Namespaces
compact_*- Compaction settings (used bybd admin compact)issue_prefix- Issue ID prefix (managed bybd init)issue_id_mode- ID generation mode:hash(default) orcounter(sequential integers)max_collision_prob- Maximum collision probability for adaptive hash IDs (default: 0.25)min_hash_length- Minimum hash ID length (default: 4)max_hash_length- Maximum hash ID length (default: 8)import.orphan_handling- How to handle hierarchical issues with missing parents during import (default:allow)import.path- Input filename relative to.beads/for implied JSONL imports, includingbd init --from-jsonland empty-DB auto-import (default:issues.jsonl). Use a relative filename/path such asbeads.jsonlso the import remains project-local and portable across machines.export.auto- Refresh the JSONL export after every write command (default:false). This is for viewers, interchange, and issue-level migration; it is not cross-machine sync and not a full database backup.export.path- Output filename relative to.beads/(default:issues.jsonl)export.interval- Minimum time between auto-exports (default:60s)export.git-add- Rungit addon the export file after writing (default:false)export.error_policy- Error handling strategy for exports (default:strict)export.retry_attempts- Number of retry attempts for transient errors (default: 3)export.retry_backoff_ms- Initial backoff in milliseconds for retries (default: 100)export.skip_encoding_errors- Skip issues that fail JSON encoding (default: false)export.write_manifest- Write .manifest.json with export metadata (default: false)auto_export.error_policy- Override error policy for auto-exports (default:best-effort)import.auto- Legacy hook fallback that imports JSONL after git merge/checkout only when no Dolt remote is configured (default:true)sync.branch- Name of the dedicated sync branch for beads data (see docs/PROTECTED_BRANCHES.md)sync.require_confirmation_on_mass_delete- Require interactive confirmation before pushing when >50% of issues vanish during a merge AND more than 5 issues existed before (default:false)
Upgrade note: export.auto and export.git-add are opt-in. Older releases
briefly made .beads/issues.jsonl look like the default git-tracked source of
truth; current releases treat it as an optional export for viewers,
interchange, and issue-level migration. If your workflow depends on fresh JSONL
or on the pre-commit hook staging that file, set both values explicitly:
bd config set export.auto true
bd config set export.git-add true
Use bd dolt push / bd dolt pull for cross-machine sync and bd backup for
restorable database backups.
Integration Namespaces
Use these namespaces for external integrations:
jira.*- Jira integration settingslinear.*- Linear integration settingsgithub.*- GitHub integration settingsado.*- Azure DevOps integration settingscustom.*- Custom integration settings
Status and Type Customization
status.custom- Custom issue statuses with optional categories (comma-separated)types.custom- Custom issue types (comma-separated)
Custom statuses support category annotations that control behavior:
# Format: name:category (category is optional)
bd config set status.custom "in_review:active,qa_testing:wip,on_hold:frozen,archived:done"
# Categories: active, wip, done, frozen
# - active: shows in bd ready, included in default bd list
# - wip: excluded from bd ready, included in default bd list
# - done: excluded from bd ready AND default bd list (terminal)
# - frozen: excluded from bd ready AND default bd list (on hold)
# - (none): excluded from bd ready, included in default bd list (backward compatible)
Custom types:
bd config set types.custom "agent,molecule,event"
See bd statuses and bd types commands to list all configured statuses and types.
Example: Sequential Counter IDs (issue_id_mode=counter)
By default, beads generates hash-based IDs (e.g., bd-a3f2, bd-7f3a8). For projects that prefer
short sequential IDs (e.g., bd-1, bd-2, bd-3), enable counter mode:
bd config set issue_id_mode counter
Valid values:
| Value | Behavior |
|---|---|
hash | (default) Hash-based IDs, adaptive length, collision-safe |
counter | Sequential integers per prefix: bd-1, bd-2, bd-3, ... |
Counter mode behavior:
- Each prefix (
bd,plug, etc.) has its own independent counter - Counter is stored atomically in the database; concurrent creates within a single Dolt session are safe
- Explicit
--idflag always overrides counter mode (the counter is not incremented)
Enabling counter mode:
bd config set issue_id_mode counter
# Now new issues get sequential IDs
bd create "First issue" -p 1
# → bd-1
bd create "Second issue" -p 2
# → bd-2
Migration warning: If you switch an existing repository to counter mode, seed the counter to avoid collisions with existing IDs. Find your highest current integer ID and set the counter accordingly:
# Check your highest existing sequential ID (if any)
bd list --json | jq -r '.[].id' | grep -E '^bd-[0-9]+$' | sort -t- -k2 -n | tail -1
# Seed the counter (e.g., if highest existing ID is bd-42)
bd config set issue_id_mode counter
# The counter auto-initializes at 0; new issues start at 1
# If you already have bd-1 through bd-42, manually set counter:
# (no direct CLI for seeding — use bd dolt sql or create/delete N issues)
For fresh repositories switching to counter mode before any issues exist, no seeding is needed.
Per-prefix counter isolation:
Each issue prefix maintains its own counter independently. In multi-repo or routed setups,
bd-* issues and plug-* issues each start at 1:
# Prefix "bd" and prefix "plug" have independent counters
bd create "Core task" -p 1 # → bd-1
bd create "Plugin task" -p 1 # → plug-1 (if prefix is "plug")
Tradeoff — hash vs. counter:
| Hash IDs | Counter IDs | |
|---|---|---|
| Human readability | Lower (e.g., bd-a3f2) | Higher (e.g., bd-1) |
| Distributed/concurrent safety | Excellent (collision-free across branches) | Needs care (counters can diverge on parallel branches) |
| Predictability | Unpredictable | Sequential |
| Best for | Multi-agent, multi-branch workflows | Single-writer or project-management UIs |
Counter IDs are well-suited for linear project-management workflows and human-facing issue tracking. Hash IDs are safer when multiple agents or branches create issues concurrently, since each hash is independently unique without coordination.
See ADAPTIVE_IDS.md for full documentation on hash-based ID generation.
Example: Adaptive Hash ID Configuration
# Configure adaptive ID lengths (see docs/ADAPTIVE_IDS.md)
# Default: 25% max collision probability
bd config set max_collision_prob "0.25"
# Start with 4-char IDs, scale up as database grows
bd config set min_hash_length "4"
bd config set max_hash_length "8"
# Stricter collision tolerance (1%)
bd config set max_collision_prob "0.01"
# Force minimum 5-char IDs for consistency
bd config set min_hash_length "5"
See ADAPTIVE_IDS.md for detailed documentation.
Example: Export Error Handling
Controls how export operations handle errors when fetching issue data (labels, comments, dependencies).
# Strict: Fail fast on any error (default for user-initiated exports)
bd config set export.error_policy "strict"
# Best-effort: Skip failed operations with warnings (good for auto-export)
bd config set export.error_policy "best-effort"
# Partial: Retry transient failures, skip persistent ones with manifest
bd config set export.error_policy "partial"
bd config set export.write_manifest "true"
# Required-core: Fail on core data (issues/deps), skip enrichments (labels/comments)
bd config set export.error_policy "required-core"
# Customize retry behavior
bd config set export.retry_attempts "5"
bd config set export.retry_backoff_ms "200"
# Skip individual issues that fail JSON encoding
bd config set export.skip_encoding_errors "true"
# Auto-export uses different policy (background operation)
bd config set auto_export.error_policy "best-effort"
Policy details:
-
strict(default) - Fail immediately on any error. Ensures complete exports but may block on transient issues like database locks. Best for critical exports and migrations. -
best-effort- Skip failed batches with warnings. Continues export even if labels or comments fail to load. Best for auto-exports and background sync where availability matters more than completeness. -
partial- Retry transient failures (3x by default), then skip with manifest file. Creates.manifest.jsonalongside JSONL documenting what succeeded/failed. Best for large databases with occasional corruption. -
required-core- Fail on core data (issues, dependencies), skip enrichments (labels, comments) with warnings. Best when metadata is secondary to issue tracking.
When to use each mode:
- Use
strict(default) for production backups and critical exports - Use
best-effortfor auto-exports (default viaauto_export.error_policy) - Use
partialwhen you need visibility into export completeness - Use
required-corewhen labels/comments are optional
Context-specific behavior:
User-initiated exports (bd dolt push, manual export commands) use export.error_policy (default: strict).
Auto-exports (git hook sync) use auto_export.error_policy (default: best-effort), falling back to export.error_policy if not set.
Example: Different policies for different contexts:
# Critical project: strict everywhere
bd config set export.error_policy "strict"
# Development project: strict user exports, permissive auto-exports
bd config set export.error_policy "strict"
bd config set auto_export.error_policy "best-effort"
# Large database with occasional corruption
bd config set export.error_policy "partial"
bd config set export.write_manifest "true"
bd config set export.retry_attempts "5"
Example: Import Orphan Handling
Controls how imports handle hierarchical child issues when their parent is missing from the database:
# Strictest: Fail import if parent is missing (safest, prevents orphans)
bd config set import.orphan_handling "strict"
# Auto-resurrect: Search JSONL history and recreate missing parents as tombstones
bd config set import.orphan_handling "resurrect"
# Skip: Skip orphaned issues with warning (partial import)
bd config set import.orphan_handling "skip"
# Allow: Import orphans without validation (default, most permissive)
bd config set import.orphan_handling "allow"
Mode details:
strict- Fails immediately if a child's parent is missing. Use when database integrity is critical.resurrect- Searches for missing parents and recreates them as tombstones (Status=Closed, Priority=4). Preserves hierarchy with minimal data. Dependencies are also resurrected on best-effort basis.skip- Skips orphaned children with a warning. Partial import succeeds but some issues are excluded.allow- Imports orphans without parent validation. Most permissive. This is the default because it ensures all data is imported even if hierarchy is temporarily broken.
These modes apply when bootstrapping a database with bd init --from-jsonl or when bd dolt pull merges remote data:
# Override config for a single pull
bd config set import.orphan_handling "resurrect"
bd dolt pull # Respects import.orphan_handling setting
When to use each mode:
- Use
allow(default) for daily sync - ensures no data loss - Use
resurrectwhen pulling from remotes that had parent deletions - Use
strictonly when you need to guarantee parent existence - Use
skiprarely - only when you want to selectively import a subset
Example: Sync Safety Options
Controls for the sync branch workflow (see docs/PROTECTED_BRANCHES.md):
# Configure sync branch (required for protected branch workflow)
bd config set sync.branch beads-sync
# Enable mass deletion protection (optional, default: false)
# When enabled, if >50% of issues vanish during a merge AND more than 5
# issues existed before the merge, bd dolt push will:
# 1. Show forensic info about vanished issues
# 2. Prompt for confirmation before pushing
bd config set sync.require_confirmation_on_mass_delete "true"
When to enable sync.require_confirmation_on_mass_delete:
- Multi-user workflows where accidental mass deletions could propagate
- Critical projects where data loss prevention is paramount
- When you want manual review before pushing large changes
When to keep it disabled (default):
- Single-user workflows where you trust your local changes
- CI/CD pipelines that need non-interactive sync
- When you want hands-free automation
Example: Jira Integration
# Configure Jira connection
bd config set jira.url "https://company.atlassian.net"
bd config set jira.project "PROJ"
bd config set jira.projects "PROJ1,PROJ2" # Multiple projects (comma-separated)
bd config set jira.api_token "YOUR_TOKEN"
# Map bd statuses to Jira statuses
bd config set jira.status_map.open "To Do"
bd config set jira.status_map.in_progress "In Progress"
bd config set jira.status_map.closed "Done"
# Map bd issue types to Jira issue types
bd config set jira.type_map.bug "Bug"
bd config set jira.type_map.feature "Story"
bd config set jira.type_map.task "Task"
# Set Jira custom fields on pushed issues
bd config set jira.custom_fields.customfield_10042 '{"value":"AI Platform"}'
bd config set jira.custom_fields.Story.customfield_10042 '{"value":"AI Platform"}'
jira.custom_fields.<field> applies to every issue pushed to Jira.
jira.custom_fields.<JiraType>.<field> applies only when the mapped Jira issue
type matches <JiraType>; per-type fields override global fields with the same
field key. Values beginning with { or [ are sent as JSON, which is useful
for select-like fields. Other values are sent as strings.
Example: Linear Integration
Linear integration provides bidirectional sync between bd and Linear via GraphQL API.
Required configuration:
# API Key (recommended: use environment variable to avoid git exposure)
export LINEAR_API_KEY="lin_api_YOUR_API_KEY" # add to ~/.secrets or ~/.zshrc
# Team ID (find in Linear team settings or URL)
bd config set linear.team_id "team-uuid-here"
# Multiple team IDs (comma-separated; can also use LINEAR_TEAM_IDS env var)
bd config set linear.team_ids "uuid-team-1,uuid-team-2"
When linear.team_ids is set, bd linear sync fetches issues from all listed
teams. For push operations with multiple teams, use the --team flag to specify
the target. The singular linear.team_id is still supported for backward
compatibility.
Getting your Linear credentials:
- API Key: Go to Linear → Settings → API → Personal API keys → Create key
- Team ID: Go to Linear → Settings → General → Team ID (or extract from URLs)
Priority mapping (Linear 0-4 → Beads 0-4):
Linear and Beads both use 0-4 priority scales, but with different semantics:
- Linear: 0=no priority, 1=urgent, 2=high, 3=medium, 4=low
- Beads: 0=critical, 1=high, 2=medium, 3=low, 4=backlog
Default mapping (configurable):
bd config set linear.priority_map.0 4 # No priority -> Backlog
bd config set linear.priority_map.1 0 # Urgent -> Critical
bd config set linear.priority_map.2 1 # High -> High
bd config set linear.priority_map.3 2 # Medium -> Medium
bd config set linear.priority_map.4 3 # Low -> Low
State mapping (Linear state types → Beads statuses):
Map Linear workflow state types to Beads statuses:
bd config set linear.state_map.backlog open
bd config set linear.state_map.unstarted open
bd config set linear.state_map.started in_progress
bd config set linear.state_map.completed closed
bd config set linear.state_map.canceled closed
# For custom workflow states, use lowercase state name:
bd config set linear.state_map.in_review in_progress
bd config set linear.state_map.blocked blocked
bd config set linear.state_map.on_hold blocked
Label to issue type mapping:
Infer bd issue type from Linear labels:
bd config set linear.label_type_map.bug bug
bd config set linear.label_type_map.defect bug
bd config set linear.label_type_map.feature feature
bd config set linear.label_type_map.enhancement feature
bd config set linear.label_type_map.epic epic
bd config set linear.label_type_map.chore chore
bd config set linear.label_type_map.maintenance chore
bd config set linear.label_type_map.task task
Relation type mapping (Linear relations → Beads dependencies):
bd config set linear.relation_map.blocks blocks
bd config set linear.relation_map.blockedBy blocks
bd config set linear.relation_map.duplicate duplicates
bd config set linear.relation_map.related related
Relation import is opt-in when pulling:
bd linear sync --pull --relations
Sync commands:
# Bidirectional sync (pull then push, with conflict resolution)
bd linear sync
# Pull only (import from Linear)
bd linear sync --pull
# Pull only if data is stale (skip if fresh)
bd linear sync --pull-if-stale
# Pull with custom staleness threshold (default 20m)
bd linear sync --pull-if-stale --threshold 5m
# Pull issues and Linear relations as bd dependencies
bd linear sync --pull --relations
# Pull and rebuild Linear project milestones as local epic parents
bd linear sync --pull --milestones
# Push only (export to Linear)
bd linear sync --push
# Dry run (preview without changes)
bd linear sync --dry-run
# Conflict resolution options
bd linear sync --prefer-local # Local version wins on conflicts
bd linear sync --prefer-linear # Linear version wins on conflicts
# Default: newer timestamp wins
# Check sync status
bd linear status
Staleness detection:
After each successful pull, bd writes the current timestamp to .beads/last_pull. This enables ambient staleness detection:
--pull-if-stale: Only pull if data is older than the threshold (default 20m). When data is fresh, prints "Linear data is fresh" and exits. In--jsonmode, includes"is_fresh": true/false.--threshold: Override the default 20-minute staleness threshold (e.g.,--threshold 5m).- Debounce: A 5-minute debounce prevents agent loops — if a pull completed within the last 5 minutes, data is always treated as fresh regardless of the threshold.
bd primeauto-pull: WhenLINEAR_API_KEYis set and data is stale,bd primeautomatically pulls from Linear before emitting orientation output.- Per-session warning: On any
bdcommand, if data is stale, a one-time warning is emitted to stderr:⚠ Linear data is 45m stale — run 'bd linear sync --pull' to refresh. Suppressed in subsequent commands within the same shell session.
Automatic sync tracking:
The linear.last_sync config key is automatically updated after each sync, enabling incremental sync (only fetch issues updated since last sync).
Example: GitHub Integration
# Configure GitHub connection
bd config set github.org "myorg"
bd config set github.repo "myrepo"
bd config set github.token "YOUR_TOKEN"
# Map bd labels to GitHub labels
bd config set github.label_map.bug "bug"
bd config set github.label_map.feature "enhancement"
Example: Azure DevOps (ADO) Integration
Azure DevOps integration provides bidirectional sync between bd and ADO work items.
Required configuration:
# Personal access token (can also use AZURE_DEVOPS_PAT environment variable)
bd config set ado.pat "YOUR_PAT"
# Organization name (can also use AZURE_DEVOPS_ORG environment variable)
bd config set ado.org "myorg"
# Project name (can also use AZURE_DEVOPS_PROJECT environment variable)
bd config set ado.project "MyProject"
# Multiple projects (comma-separated; can also use AZURE_DEVOPS_PROJECTS env var)
bd config set ado.projects "Project1,Project2"
When ado.projects is set, bd ado sync fetches work items from all listed
projects in a single WIQL query. The singular ado.project is still supported
for backward compatibility.
Optional configuration:
# Custom base URL for Azure DevOps Server (on-prem) instances
# (can also use AZURE_DEVOPS_URL environment variable)
# When set, ado.org is not required — the URL replaces the default dev.azure.com base.
bd config set ado.url "https://ado.internal.example.com/DefaultCollection"
Getting your Azure DevOps PAT:
- Go to Azure DevOps → User Settings (top-right icon) → Personal access tokens
- Click "New Token"
- Select the organization and set an expiration
- Grant Work Items: Read & Write scope (minimum for sync)
- Copy the token — it is only shown once
State mapping (ADO Agile template defaults → Beads statuses):
ADO uses process-template-specific states (Agile, Scrum, CMMI). The defaults
use the Agile template. Override with ado.state_map.* for your process:
# Default Agile mapping (built-in, no config needed):
# New → open
# Active → in_progress
# Resolved → closed
# Closed → closed
# Removed → deferred
# Override for Scrum template:
bd config set ado.state_map.open "New"
bd config set ado.state_map.in_progress "Committed"
bd config set ado.state_map.blocked "Committed"
bd config set ado.state_map.deferred "Removed"
bd config set ado.state_map.closed "Done"
Type mapping (ADO work item types ↔ Beads issue types):
# Default mapping (built-in, no config needed):
# Bug → bug
# User Story → feature
# Product Backlog Item → feature
# Task → task
# Epic → epic
# Override for your process template:
bd config set ado.type_map.bug "Bug"
bd config set ado.type_map.feature "Feature"
bd config set ado.type_map.task "Task"
bd config set ado.type_map.epic "Epic"
bd config set ado.type_map.chore "Task"
Priority mapping (ADO 1-4 → Beads 0-4):
ADO uses a 1-4 scale; Beads uses 0-4. The mapping is:
- ADO 1 (Critical) → Beads 0 (Critical)
- ADO 2 (High) → Beads 1 (High)
- ADO 3 (Medium) → Beads 2 (Medium)
- ADO 4 (Low) → Beads 3 (Low)
- Beads 4 (Backlog) → ADO 4 (lossy: backlog collapses to low)
Priority mapping is not configurable — it is handled automatically.
Environment variables:
All ADO config keys have environment variable equivalents:
| Config Key | Environment Variable |
|---|---|
ado.pat | AZURE_DEVOPS_PAT |
ado.org | AZURE_DEVOPS_ORG |
ado.project | AZURE_DEVOPS_PROJECT |
ado.projects | AZURE_DEVOPS_PROJECTS |
ado.url | AZURE_DEVOPS_URL |
Environment variables take effect when the corresponding bd config key is not set.
Sync commands:
# Bidirectional sync (pull then push, with conflict resolution)
bd ado sync
# Pull only (import from Azure DevOps)
bd ado sync --pull-only
# Push only (export to Azure DevOps)
bd ado sync --push-only
# Dry run (preview without changes)
bd ado sync --dry-run
# Conflict resolution options
bd ado sync --prefer-local # Local version wins on conflicts
bd ado sync --prefer-ado # Azure DevOps version wins on conflicts
bd ado sync --prefer-newer # Most recent version wins (default)
# Check sync status and configuration
bd ado status
# List accessible projects (useful for finding your project name)
bd ado projects --json
Automatic sync tracking:
The ado.last_sync config key is automatically updated after each sync, enabling incremental sync (only fetch work items updated since last sync).
Use in Scripts
Configuration is designed for scripting. Use --json for machine-readable output:
#!/bin/bash
# Get Jira URL
JIRA_URL=$(bd config get --json jira.url | jq -r '.value')
# Get all config and extract multiple values
bd config list --json | jq -r '.["jira.project"]'
Example Python script:
import json
import subprocess
def get_config(key):
result = subprocess.run(
["bd", "config", "get", "--json", key],
capture_output=True,
text=True
)
data = json.loads(result.stdout)
return data["value"]
def list_config():
result = subprocess.run(
["bd", "config", "list", "--json"],
capture_output=True,
text=True
)
return json.loads(result.stdout)
# Use in integration
jira_url = get_config("jira.url")
jira_project = get_config("jira.project")
Best Practices
- Use namespaces: Prefix keys with integration name (e.g.,
jira.*,linear.*) - Hierarchical keys: Use dots for structure (e.g.,
jira.status_map.open) - Document your keys: Add comments in integration scripts
- Security: Store tokens in config, but ensure
.beads/dolt/and.beads/*.dbare in.gitignore(bd does this automatically) - Per-project: Configuration is project-specific, so each repo can have different settings
Integration with bd Commands
Some bd commands automatically use configuration:
bd admin compactusescompact_tier1_days,compact_tier1_dep_levels, etc.bd initsetsissue_prefix
External integration scripts can read configuration to sync with Jira, Linear, GitHub, etc.
See Also
- README.md - Main documentation
- ADVANCED.md - Extensible Database section and other advanced topics