From a971762b0ed370d178bc9e2bdc65701692e73a04 Mon Sep 17 00:00:00 2001 From: Steve Yegge Date: Fri, 17 Oct 2025 10:56:52 -0700 Subject: [PATCH] Remove ~/.beads fallback behavior - Remove ~/.beads/default.db fallback from FindDatabasePath() - Update daemon to error if no database found instead of falling back - Update main.go to require explicit database initialization - Add help/version/quickstart to commands that don't need database - Add MCP client debug logging for database routing Amp-Thread-ID: https://ampcode.com/threads/T-2b757a14-cf10-400e-a83c-30349182dd82 Co-authored-by: Amp --- beads.go | 13 ++----------- cmd/bd/daemon.go | 18 ++++++------------ cmd/bd/main.go | 12 +++++++----- .../beads-mcp/src/beads_mcp/bd_client.py | 10 +++++++++- 4 files changed, 24 insertions(+), 29 deletions(-) diff --git a/beads.go b/beads.go index 6b78c33a..811ff025 100644 --- a/beads.go +++ b/beads.go @@ -53,9 +53,8 @@ func NewSQLiteStorage(dbPath string) (Storage, error) { // FindDatabasePath discovers the bd database path using bd's standard search order: // 1. $BEADS_DB environment variable // 2. .beads/*.db in current directory or ancestors -// 3. ~/.beads/default.db (fallback) // -// Returns empty string if no database is found at (1) or (2) and (3) doesn't exist. +// Returns empty string if no database is found. func FindDatabasePath() string { // 1. Check environment variable if envDB := os.Getenv("BEADS_DB"); envDB != "" { @@ -67,15 +66,7 @@ func FindDatabasePath() string { return foundDB } - // 3. Try home directory default - if home, err := os.UserHomeDir(); err == nil { - defaultDB := filepath.Join(home, ".beads", "default.db") - // Only return if it exists - if _, err := os.Stat(defaultDB); err == nil { - return defaultDB - } - } - + // No fallback to ~/.beads - return empty string return "" } diff --git a/cmd/bd/daemon.go b/cmd/bd/daemon.go index 53a60a30..07feb291 100644 --- a/cmd/bd/daemon.go +++ b/cmd/bd/daemon.go @@ -115,11 +115,8 @@ func ensureBeadsDir() (string, error) { if dbPath != "" { beadsDir = filepath.Dir(dbPath) } else { - home, err := os.UserHomeDir() - if err != nil { - return "", fmt.Errorf("cannot resolve home directory: %w", err) - } - beadsDir = filepath.Join(home, ".beads") + // No database path - error out instead of falling back to ~/.beads + return "", fmt.Errorf("no database path configured (run 'bd init' or set BEADS_DB)") } if err := os.MkdirAll(beadsDir, 0700); err != nil { @@ -446,13 +443,10 @@ func runDaemonLoop(interval time.Duration, autoCommit, autoPush bool, logPath, p if foundDB := beads.FindDatabasePath(); foundDB != "" { daemonDBPath = foundDB } else { - // Fallback to default location - home, err := os.UserHomeDir() - if err != nil { - log("Error: cannot resolve home directory: %v", err) - os.Exit(1) - } - daemonDBPath = filepath.Join(home, ".beads", "default.db") + // No database found - error out instead of falling back to ~/.beads + log("Error: no beads database found") + log("Hint: run 'bd init' to create a database or set BEADS_DB environment variable") + os.Exit(1) } } diff --git a/cmd/bd/main.go b/cmd/bd/main.go index fb48c499..89cc3ce4 100644 --- a/cmd/bd/main.go +++ b/cmd/bd/main.go @@ -55,8 +55,8 @@ var rootCmd = &cobra.Command{ Short: "bd - Dependency-aware issue tracker", Long: `Issues chained together like beads. A lightweight issue tracker with first-class dependency support.`, PersistentPreRun: func(cmd *cobra.Command, args []string) { - // Skip database initialization for init and daemon commands - if cmd.Name() == "init" || cmd.Name() == "daemon" { + // Skip database initialization for commands that don't need a database + if cmd.Name() == "init" || cmd.Name() == "daemon" || cmd.Name() == "help" || cmd.Name() == "version" || cmd.Name() == "quickstart" { return } @@ -72,9 +72,11 @@ var rootCmd = &cobra.Command{ if foundDB := beads.FindDatabasePath(); foundDB != "" { dbPath = foundDB } else { - // Fallback to default location (will be created by init command) - home, _ := os.UserHomeDir() - dbPath = filepath.Join(home, ".beads", "default.db") + // No database found - error out instead of falling back to ~/.beads + fmt.Fprintf(os.Stderr, "Error: no beads database found\n") + fmt.Fprintf(os.Stderr, "Hint: run 'bd init' to create a database in the current directory\n") + fmt.Fprintf(os.Stderr, " or set BEADS_DB environment variable to specify a database\n") + os.Exit(1) } } diff --git a/integrations/beads-mcp/src/beads_mcp/bd_client.py b/integrations/beads-mcp/src/beads_mcp/bd_client.py index b0e46d85..ccc0146c 100644 --- a/integrations/beads-mcp/src/beads_mcp/bd_client.py +++ b/integrations/beads-mcp/src/beads_mcp/bd_client.py @@ -149,12 +149,20 @@ class BdClient: """ cmd = [self.bd_path, *args, *self._global_flags(), "--json"] + # Log database routing for debugging + import sys + working_dir = self._get_working_dir() + db_info = self.beads_db if self.beads_db else "auto-discover" + print(f"[beads-mcp] Running bd command: {' '.join(args)}", file=sys.stderr) + print(f"[beads-mcp] Database: {db_info}", file=sys.stderr) + print(f"[beads-mcp] Working dir: {working_dir}", file=sys.stderr) + try: process = await asyncio.create_subprocess_exec( *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, - cwd=self._get_working_dir(), + cwd=working_dir, ) stdout, stderr = await process.communicate() except FileNotFoundError as e: