- Add GetOrphanHandling() helper to SQLiteStorage (reads from config table) - Add --orphan-handling flag to 'bd import' command - Wire OrphanHandling through ImportOptions -> importer.Options - Auto-read config if flag not provided (default: 'allow') - Document in CONFIG.md with detailed mode explanations Modes: - strict: Fail on missing parent (safest) - resurrect: Auto-create parent tombstones from JSONL - skip: Skip orphans with warning - allow: Import without validation (default, most permissive) Closes bd-8072, bd-b92a Amp-Thread-ID: https://ampcode.com/threads/T-fd18d4a5-06b3-4400-9073-194d570846d8 Co-authored-by: Amp <amp@ampcode.com>
10 KiB
Configuration System
bd has two complementary configuration systems:
- Tool-level configuration (Viper): User preferences for tool behavior (flags, output format)
- Project-level configuration (
bd config): Integration data and project-specific settings
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,--no-daemon, etc.) - Environment variables (
BD_JSON,BD_NO_DAEMON, etc.) - Config file (
~/.config/bd/config.yamlor.beads/config.yaml) - Defaults
Config File Locations
Viper searches for config.yaml in these locations (in order):
.beads/config.yaml- Project-specific tool settings (version-controlled)~/.config/bd/config.yaml- User-specific tool settings~/.beads/config.yaml- Legacy user settings
Supported Settings
Tool-level settings you can configure:
| Setting | Flag | Environment Variable | Default | Description |
|---|---|---|---|---|
json |
--json |
BD_JSON |
false |
Output in JSON format |
no-daemon |
--no-daemon |
BD_NO_DAEMON |
false |
Force direct mode, bypass daemon |
no-auto-flush |
--no-auto-flush |
BD_NO_AUTO_FLUSH |
false |
Disable auto JSONL export |
no-auto-import |
--no-auto-import |
BD_NO_AUTO_IMPORT |
false |
Disable auto JSONL import |
db |
--db |
BD_DB |
(auto-discover) | Database path |
actor |
--actor |
BD_ACTOR |
$USER |
Actor name for audit trail |
flush-debounce |
- | BEADS_FLUSH_DEBOUNCE |
5s |
Debounce time for auto-flush |
auto-start-daemon |
- | BEADS_AUTO_START_DAEMON |
true |
Auto-start daemon if not running |
Example Config File
~/.config/bd/config.yaml:
# Default to JSON output for scripting
json: true
# Disable daemon for single-user workflows
no-daemon: true
# Custom debounce for auto-flush (default 5s)
flush-debounce: 10s
# Auto-start daemon (default true)
auto-start-daemon: true
.beads/config.yaml (project-specific):
# Project team prefers longer flush delay
flush-debounce: 15s
Why Two Systems?
Tool settings (Viper) are user preferences:
- How should I see output? (
--json) - Should I use the daemon? (
--no-daemon) - 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/*.dbdatabase - Version-control-friendly: Stored in SQLite, 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 (see EXTENDING.md)issue_prefix- Issue ID prefix (managed bybd init)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)
Integration Namespaces
Use these namespaces for external integrations:
jira.*- Jira integration settingslinear.*- Linear integration settingsgithub.*- GitHub integration settingscustom.*- Custom integration settings
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 docs/ADAPTIVE_IDS.md for detailed documentation.
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- Import fails immediately if a child's parent is missing. Use when database integrity is critical.resurrect- Searches the full JSONL file 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, works around import bugs. This is the default because it ensures all data is imported even if hierarchy is temporarily broken.
Override per command:
# Override config for a single import
bd import -i issues.jsonl --orphan-handling strict
# Auto-import (sync) uses config value
bd sync # Respects import.orphan_handling setting
When to use each mode:
- Use
allow(default) for daily imports and auto-sync - ensures no data loss - Use
resurrectwhen importing from another database that had parent deletions - Use
strictonly for controlled imports where you need to guarantee parent existence - Use
skiprarely - only when you want to selectively import a subset
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.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"
Example: Linear Integration
# Configure Linear connection
bd config set linear.api_token "YOUR_TOKEN"
bd config set linear.team_id "team-123"
# Map statuses
bd config set linear.status_map.open "Backlog"
bd config set linear.status_map.in_progress "In Progress"
bd config set linear.status_map.closed "Done"
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"
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 add
.beads/*.dbto.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 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
- EXTENDING.md - Database schema and compaction config
- examples/integrations/ - Integration examples