* fix(routing): auto-enable hydration and flush JSONL after routed create Fixes split-brain bug where issues routed to different repos (via routing.mode=auto) weren't visible in bd list because JSONL wasn't updated and hydration wasn't configured. **Problem**: When routing.mode=auto routes issues to a separate repo (e.g., ~/.beads-planning), those issues don't appear in 'bd list' because: 1. Target repo's JSONL isn't flushed after create 2. Multi-repo hydration (repos.additional) not configured automatically 3. No doctor warnings about the misconfiguration **Changes**: 1. **Auto-flush JSONL after routed create** (cmd/bd/create.go) - After routing issue to target repo, immediately flush to JSONL - Tries target daemon's export RPC first (if daemon running) - Falls back to direct JSONL export if no daemon - Ensures hydration can read the new issue immediately 2. **Enable hydration in bd init --contributor** (cmd/bd/init_contributor.go) - Wizard now automatically adds planning repo to repos.additional - Users no longer need to manually run 'bd repo add' - Routed issues appear in bd list immediately after setup 3. **Add doctor check for hydrated repo daemons** (cmd/bd/doctor/daemon.go) - New CheckHydratedRepoDaemons() warns if daemons not running - Without daemons, JSONL becomes stale and hydration breaks - Suggests: cd <repo> && bd daemon start --local 4. **Add doctor check for routing+hydration mismatch** (cmd/bd/doctor/config_values.go) - Validates routing targets are in repos.additional - Catches split-brain configuration before users encounter it - Suggests: bd repo add <routing-target> **Testing**: Builds successfully. Unit/integration tests pending. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * test(routing): add comprehensive tests for routing fixes Add unit tests for all 4 routing/hydration fixes: 1. **create_routing_flush_test.go** - Test JSONL flush after routing - TestFlushRoutedRepo_DirectExport: Verify direct JSONL export - TestPerformAtomicExport: Test atomic file operations - TestFlushRoutedRepo_PathExpansion: Test path handling - TestRoutingWithHydrationIntegration: E2E routing+hydration test 2. **daemon_test.go** - Test hydrated repo daemon check - TestCheckHydratedRepoDaemons: Test with/without daemons running - Covers no repos, daemons running, daemons missing scenarios 3. **config_values_test.go** - Test routing+hydration validation - Test routing without hydration (should warn) - Test routing with correct hydration (should pass) - Test routing target not in hydration list (should warn) - Test maintainer="." edge case (should pass) All tests follow existing patterns and use t.TempDir() for isolation. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * fix(tests): fix test failures and refine routing validation logic Fixes test failures and improves validation accuracy: 1. **Fix routing+hydration validation** (config_values.go) - Exclude "." from hasRoutingTargets check (current repo doesn't need hydration) - Prevents false warnings when maintainer="." or contributor="." 2. **Fix test ID generation** (create_routing_flush_test.go) - Use auto-generated IDs instead of hard-coded "beads-test1" - Respects test store prefix configuration (test-) - Fixed json.NewDecoder usage (file handle, not os.Open result) 3. **Fix config validation tests** (config_values_test.go) - Create actual directories for routing paths to pass path validation - Tests now verify both routing+hydration AND path existence checks 4. **Fix daemon test expectations** (daemon_test.go) - When database unavailable, check returns "No additional repos" not error - This is correct behavior (graceful degradation) All tests now pass: - TestFlushRoutedRepo* (3 tests) - TestPerformAtomicExport - TestCheckHydratedRepoDaemons (3 subtests) - TestCheckConfigValues routing tests (5 subtests) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * docs: clarify when git config beads.role maintainer is needed Clarify that maintainer role config is only needed in edge case: - Using GitHub HTTPS URL without credentials - But you have write access (are a maintainer) In most cases, beads auto-detects correctly via: - SSH URLs (git@github.com:owner/repo.git) - HTTPS with credentials This prevents confusion - users with SSH or credential-based HTTPS don't need to manually configure their role. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * fix(lint): address linter warnings in routing flush code - Add missing sqlite import in daemon.go - Fix unchecked client.Close() error return - Fix unchecked tempFile.Close() error returns - Mark unused parameters with _ prefix - Add nolint:gosec for safe tempPath construction Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Roland Tritsch <roland@ailtir.com> Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
6.4 KiB
Multi-Repo Auto-Routing
This document describes the auto-routing feature that intelligently directs new issues to the appropriate repository based on user role.
Overview
Auto-routing solves the OSS contributor problem: contributors want to plan work locally without polluting upstream PRs with planning issues. The routing layer automatically detects whether you're a maintainer or contributor and routes bd create to the appropriate repository.
User Role Detection
Strategy
The routing system detects user role via:
-
Explicit git config (highest priority):
git config beads.role maintainer # or git config beads.role contributor -
Push URL inspection (automatic):
- SSH URLs (
git@github.com:user/repo.git) → Maintainer - HTTPS with credentials → Maintainer
- HTTPS without credentials → Contributor
- No remote → Contributor (fallback)
- SSH URLs (
Examples
# Maintainer (SSH access)
git remote add origin git@github.com:owner/repo.git
bd create "Fix bug" -p 1
# → Creates in current repo (.)
# Contributor (HTTPS fork)
git remote add origin https://github.com/fork/repo.git
git remote add upstream https://github.com/owner/repo.git
bd create "Fix bug" -p 1
# → Creates in planning repo (~/.beads-planning by default)
Configuration
Routing is configured via the database config:
# Auto-routing is disabled by default (routing.mode="")
# Enable with:
bd init --contributor
# OR manually:
bd config set routing.mode auto
# Set default planning repo
bd config set routing.default "~/.beads-planning"
# Set repo for maintainers (in auto mode)
bd config set routing.maintainer "."
# Set repo for contributors (in auto mode)
bd config set routing.contributor "~/.beads-planning"
CLI Usage
Auto-Routing
# Let bd decide based on role
bd create "Fix authentication bug" -p 1
# Maintainer: creates in current repo (.)
# Contributor: creates in ~/.beads-planning
Explicit Override
# Force creation in specific repo (overrides auto-routing)
bd create "Fix bug" -p 1 --repo /path/to/repo
bd create "Add feature" -p 1 --repo ~/my-planning
Discovered Issue Inheritance
Issues created with discovered-from dependencies automatically inherit the parent's source_repo:
# Parent in current repo
bd create "Implement auth" -p 1
# → Created as bd-abc (source_repo = ".")
# Discovered issue inherits parent's repo
bd create "Found bug in auth" -p 1 --deps discovered-from:bd-abc
# → Created with source_repo = "." (same as parent)
This ensures discovered work stays in the same repository as the parent task.
Multi-Repo Hydration
⚠️ Critical: When using routing to separate repos, you must enable multi-repo hydration or routed issues won't appear in bd list.
The Problem
Auto-routing writes issues to a separate repository (e.g., ~/.beads-planning), but by default, bd list only shows issues from the current repository's database. Without hydration, routed issues are "invisible" even though they exist.
The Solution
Add routing targets to repos.additional in config.yaml:
routing:
mode: auto
contributor: ~/.beads-planning
repos:
primary: "."
additional:
- ~/.beads-planning
Automatic Setup
bd init --contributor now automatically configures both routing AND hydration:
cd ~/my-forked-repo
bd init --contributor
# This sets up:
# 1. routing.mode=auto
# 2. routing.contributor=~/.beads-planning
# 3. repos.additional=[~/.beads-planning]
Manual Setup (Advanced)
If you configured routing before this feature, add hydration manually:
# Add planning repo to hydration list
bd repo add ~/.beads-planning
# Verify configuration
bd repo list
How It Works
Multi-repo hydration imports issues from all configured repos into the current database:
- JSONL as source of truth: Each repo maintains its own
issues.jsonl - Periodic import: Daemon imports from
repos.additionalevery sync cycle - Source tracking: Each issue tagged with
source_repofield - Unified view:
bd listshows issues from all repos
Requirements
For optimal hydration, run daemons in all repos:
# In main repo
bd daemon start
# In planning repo
cd ~/.beads-planning
bd daemon start --local
Without daemons, JSONL files become stale and hydration only sees old data.
Troubleshooting
Run bd doctor to check for configuration issues:
bd doctor
# Checks:
# - routing.mode=auto with routing targets but repos.additional not configured
# - Routing targets not in repos.additional list
# - Daemons not running in hydrated repos
Common Issues:
-
Routed issues not appearing in bd list
- Cause:
repos.additionalnot configured - Fix:
bd repo add <routing-target>
- Cause:
-
Issues appear but data is stale
- Cause: Daemon not running in target repo
- Fix:
cd <target-repo> && bd daemon start --local
-
After upgrading, routed issues missing
- Cause: Upgraded before hydration was automatic
- Fix:
bd repo add <routing-target>to enable hydration manually
Backward Compatibility
- Single-repo workflows unchanged: If no multi-repo config exists, all issues go to current repo
- Explicit --repo always wins:
--repoflag overrides any auto-routing - No schema changes: Routing is pure config-based, no database migrations
Implementation
Key Files:
internal/routing/routing.go- Role detection and routing logicinternal/routing/routing_test.go- Unit testscmd/bd/create.go- Integration with create commandrouting_integration_test.go- End-to-end tests
API:
// Detect user role based on git configuration
func DetectUserRole(repoPath string) (UserRole, error)
// Determine target repo based on config and role
func DetermineTargetRepo(config *RoutingConfig, userRole UserRole, repoPath string) string
Testing
# Run routing tests
go test -v -run TestRouting
# Tests cover:
# - Maintainer detection (git config)
# - Contributor detection (fork remotes)
# - SSH vs HTTPS remote detection
# - Explicit --repo override
# - End-to-end multi-repo workflow
Future Enhancements
See bd-k58 for proposal workflow:
bd propose <id>- Move issue from planning to upstreambd withdraw <id>- Un-proposebd accept <id>- Maintainer accepts proposal