fix: improve JSONL-only mode detection and error messages (GH #534)
- Add JSONL-only mode detection in ensureStoreActive() with context-aware error messages that suggest correct actions based on project state - Improve error messages in main.go to detect JSONL presence and suggest appropriate solutions (bd init, --no-db flag, or config.yaml setting) - Update documentation to use issues.jsonl as canonical filename: - AGENT_INSTRUCTIONS.md, README.md, resolve-beads-conflict.md - docs/GIT_INTEGRATION.md - Update hook template comments to clarify issues.jsonl is canonical while maintaining backward compatibility for beads.jsonl Fixes #534 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
---
|
||||
description: How to resolve merge conflicts in .beads/beads.jsonl
|
||||
description: How to resolve merge conflicts in .beads/issues.jsonl
|
||||
---
|
||||
|
||||
# Resolving `beads.jsonl` Merge Conflicts
|
||||
# Resolving `issues.jsonl` Merge Conflicts
|
||||
|
||||
If you encounter a merge conflict in `.beads/beads.jsonl` that doesn't have standard git conflict markers (or if `bd merge` failed automatically), follow this procedure.
|
||||
If you encounter a merge conflict in `.beads/issues.jsonl` that doesn't have standard git conflict markers (or if `bd merge` failed automatically), follow this procedure.
|
||||
|
||||
## 1. Identify the Conflict
|
||||
Check if `beads.jsonl` is in conflict:
|
||||
Check if `issues.jsonl` is in conflict:
|
||||
```powershell
|
||||
git status
|
||||
```
|
||||
@@ -20,9 +20,9 @@ Git stores three versions of conflicted files in its index:
|
||||
|
||||
Extract them to temporary files:
|
||||
```powershell
|
||||
git show :1:.beads/beads.jsonl > beads.base.jsonl
|
||||
git show :2:.beads/beads.jsonl > beads.ours.jsonl
|
||||
git show :3:.beads/beads.jsonl > beads.theirs.jsonl
|
||||
git show :1:.beads/issues.jsonl > beads.base.jsonl
|
||||
git show :2:.beads/issues.jsonl > beads.ours.jsonl
|
||||
git show :3:.beads/issues.jsonl > beads.theirs.jsonl
|
||||
```
|
||||
|
||||
## 3. Run `bd merge` Manually
|
||||
@@ -43,13 +43,13 @@ Optionally, verify the content (e.g., check for missing IDs if you suspect data
|
||||
## 5. Apply the Merge
|
||||
Overwrite the conflicted file with the resolved version:
|
||||
```powershell
|
||||
cp beads.merged.jsonl .beads/beads.jsonl
|
||||
cp beads.merged.jsonl .beads/issues.jsonl
|
||||
```
|
||||
|
||||
## 6. Cleanup and Continue
|
||||
Stage the resolved file and continue the merge:
|
||||
```powershell
|
||||
git add .beads/beads.jsonl
|
||||
git add .beads/issues.jsonl
|
||||
git merge --continue
|
||||
```
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# bd (beads) pre-commit hook
|
||||
#
|
||||
# This hook ensures that any pending bd issue changes are flushed to
|
||||
# .beads/beads.jsonl before the commit is created, preventing the
|
||||
# .beads/issues.jsonl before the commit is created, preventing the
|
||||
# race condition where daemon auto-flush fires after the commit.
|
||||
#
|
||||
# Installation:
|
||||
@@ -35,7 +35,7 @@ if ! bd sync --flush-only >/dev/null 2>&1; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Stage all tracked JSONL files (beads.jsonl, issues.jsonl for backward compat, deletions.jsonl for deletion propagation)
|
||||
# Stage all tracked JSONL files (issues.jsonl is canonical, beads.jsonl for backward compat, deletions.jsonl for deletion propagation)
|
||||
# git add is harmless if file doesn't exist
|
||||
for f in .beads/beads.jsonl .beads/issues.jsonl .beads/deletions.jsonl; do
|
||||
[ -f "$f" ] && git add "$f" 2>/dev/null || true
|
||||
|
||||
1534
.beads/issues.jsonl
1534
.beads/issues.jsonl
File diff suppressed because one or more lines are too long
@@ -79,7 +79,7 @@ The 30-second debounce provides a **transaction window** for batch operations -
|
||||
|
||||
**Git worktrees**: Enhanced support with shared database architecture. Use `bd --no-daemon` if daemon warnings appear. See [docs/GIT_INTEGRATION.md](docs/GIT_INTEGRATION.md).
|
||||
|
||||
**Merge conflicts**: Rare with hash IDs. If conflicts occur, use `git checkout --theirs/.beads/beads.jsonl` and `bd import`. See [docs/GIT_INTEGRATION.md](docs/GIT_INTEGRATION.md).
|
||||
**Merge conflicts**: Rare with hash IDs. If conflicts occur, use `git checkout --theirs/.beads/issues.jsonl` and `bd import`. See [docs/GIT_INTEGRATION.md](docs/GIT_INTEGRATION.md).
|
||||
|
||||
## Landing the Plane
|
||||
|
||||
@@ -95,9 +95,9 @@ The 30-second debounce provides a **transaction window** for batch operations -
|
||||
# Pull first to catch any remote changes
|
||||
git pull --rebase
|
||||
|
||||
# If conflicts in .beads/beads.jsonl, resolve thoughtfully:
|
||||
# - git checkout --theirs .beads/beads.jsonl (accept remote)
|
||||
# - bd import -i .beads/beads.jsonl (re-import)
|
||||
# If conflicts in .beads/issues.jsonl, resolve thoughtfully:
|
||||
# - git checkout --theirs .beads/issues.jsonl (accept remote)
|
||||
# - bd import -i .beads/issues.jsonl (re-import)
|
||||
# - Or manual merge, then import
|
||||
|
||||
# Sync the database (exports to JSONL, commits)
|
||||
@@ -145,9 +145,9 @@ bd close bd-42 bd-43 --reason "Completed" --json
|
||||
|
||||
# 4. PUSH TO REMOTE - MANDATORY, NO STOPPING BEFORE THIS IS DONE
|
||||
git pull --rebase
|
||||
# If conflicts in .beads/beads.jsonl, resolve thoughtfully:
|
||||
# - git checkout --theirs .beads/beads.jsonl (accept remote)
|
||||
# - bd import -i .beads/beads.jsonl (re-import)
|
||||
# If conflicts in .beads/issues.jsonl, resolve thoughtfully:
|
||||
# - git checkout --theirs .beads/issues.jsonl (accept remote)
|
||||
# - bd import -i .beads/issues.jsonl (re-import)
|
||||
# - Or manual merge, then import
|
||||
bd sync # Export/import/commit
|
||||
git push # MANDATORY - THE PLANE IS STILL IN THE AIR UNTIL THIS SUCCEEDS
|
||||
|
||||
@@ -166,7 +166,7 @@ echo -e "\nBEFORE ANYTHING ELSE: run 'bd onboard' and follow the instructions" >
|
||||
```bash
|
||||
git config merge.beads.driver "bd merge %A %O %A %B"
|
||||
git config merge.beads.name "bd JSONL merge driver"
|
||||
echo ".beads/beads.jsonl merge=beads" >> .gitattributes
|
||||
echo ".beads/issues.jsonl merge=beads" >> .gitattributes
|
||||
```
|
||||
|
||||
### Files Created by `bd init`
|
||||
@@ -175,7 +175,7 @@ echo ".beads/beads.jsonl merge=beads" >> .gitattributes
|
||||
|
||||
**Should be committed to git:**
|
||||
- `.gitattributes` - Configures git merge driver for intelligent JSONL merging (critical for team collaboration)
|
||||
- `.beads/beads.jsonl` - Issue data in JSONL format (source of truth, synced via git)
|
||||
- `.beads/issues.jsonl` - Issue data in JSONL format (source of truth, synced via git)
|
||||
- `.beads/deletions.jsonl` - Deletion manifest for cross-clone propagation (tracks deleted issues)
|
||||
- `.beads/config.yaml` - Repository configuration template
|
||||
- `.beads/README.md` - Documentation about beads for repository visitors
|
||||
|
||||
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/steveyegge/beads/internal/beads"
|
||||
@@ -62,7 +63,25 @@ func ensureStoreActive() error {
|
||||
if found := beads.FindDatabasePath(); found != "" {
|
||||
dbPath = found
|
||||
} else {
|
||||
return fmt.Errorf("no beads database found. Hint: run 'bd init' in this directory")
|
||||
// Check if this is a JSONL-only project (bd-534)
|
||||
beadsDir := beads.FindBeadsDir()
|
||||
if beadsDir != "" {
|
||||
jsonlPath := filepath.Join(beadsDir, "issues.jsonl")
|
||||
if _, err := os.Stat(jsonlPath); err == nil {
|
||||
// JSONL exists - check if no-db mode is configured
|
||||
if isNoDbModeConfigured(beadsDir) {
|
||||
return fmt.Errorf("this project uses JSONL-only mode (no SQLite database).\n" +
|
||||
"Hint: use 'bd --no-db <command>' or set 'no-db: true' in config.yaml")
|
||||
}
|
||||
// JSONL exists but no-db not configured - fresh clone scenario
|
||||
return fmt.Errorf("found JSONL file but no database: %s\n"+
|
||||
"Hint: run 'bd init' to create the database and import issues,\n"+
|
||||
" or use 'bd --no-db' for JSONL-only mode", jsonlPath)
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("no beads database found.\n" +
|
||||
"Hint: run 'bd init' to create a database in the current directory,\n" +
|
||||
" or use 'bd --no-db' for JSONL-only mode")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -329,8 +329,25 @@ var rootCmd = &cobra.Command{
|
||||
// - import: auto-initializes database if missing
|
||||
// - setup: creates editor integration files (no DB needed)
|
||||
if cmd.Name() != "import" && cmd.Name() != "setup" {
|
||||
// No database found - error out instead of falling back to ~/.beads
|
||||
// No database found - provide context-aware error message (bd-534)
|
||||
fmt.Fprintf(os.Stderr, "Error: no beads database found\n")
|
||||
|
||||
// Check if JSONL exists without no-db mode configured
|
||||
if beadsDir != "" {
|
||||
jsonlPath := filepath.Join(beadsDir, "issues.jsonl")
|
||||
if _, err := os.Stat(jsonlPath); err == nil {
|
||||
// JSONL exists but no-db mode not configured
|
||||
fmt.Fprintf(os.Stderr, "\nFound JSONL file: %s\n", jsonlPath)
|
||||
fmt.Fprintf(os.Stderr, "This looks like a fresh clone or JSONL-only project.\n\n")
|
||||
fmt.Fprintf(os.Stderr, "Options:\n")
|
||||
fmt.Fprintf(os.Stderr, " • Run 'bd init' to create database and import issues\n")
|
||||
fmt.Fprintf(os.Stderr, " • Use 'bd --no-db %s' for JSONL-only mode\n", cmd.Name())
|
||||
fmt.Fprintf(os.Stderr, " • Add 'no-db: true' to .beads/config.yaml for permanent JSONL-only mode\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// Generic error - no beads directory or JSONL found
|
||||
fmt.Fprintf(os.Stderr, "Hint: run 'bd init' to create a database in the current directory\n")
|
||||
fmt.Fprintf(os.Stderr, " or use 'bd --no-db' to work with JSONL only (no SQLite)\n")
|
||||
fmt.Fprintf(os.Stderr, " or set BEADS_DIR to point to your .beads directory\n")
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# bd (beads) pre-commit hook
|
||||
#
|
||||
# This hook ensures that any pending bd issue changes are flushed to
|
||||
# .beads/beads.jsonl before the commit is created, preventing the
|
||||
# .beads/issues.jsonl before the commit is created, preventing the
|
||||
# race condition where daemon auto-flush fires after the commit.
|
||||
#
|
||||
# When sync-branch is configured in config.yaml, .beads changes are committed
|
||||
@@ -52,7 +52,7 @@ if ! bd sync --flush-only >/dev/null 2>&1; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Stage all tracked JSONL files (beads.jsonl, issues.jsonl for backward compat, deletions.jsonl for deletion propagation)
|
||||
# Stage all tracked JSONL files (issues.jsonl is canonical, beads.jsonl for backward compat, deletions.jsonl for deletion propagation)
|
||||
# For worktrees, .beads is in the main repo's working tree, not the worktree,
|
||||
# so we can't use git add. Skip staging for worktrees.
|
||||
if [ "$(git rev-parse --git-dir)" = "$(git rev-parse --git-common-dir)" ]; then
|
||||
|
||||
@@ -100,7 +100,7 @@ bd automatically detects worktrees and shows prominent warnings if daemon mode i
|
||||
|
||||
### When Conflicts Occur
|
||||
|
||||
Git conflicts in `.beads/beads.jsonl` happen when:
|
||||
Git conflicts in `.beads/issues.jsonl` happen when:
|
||||
- **Same issue modified on both branches** (different timestamps/fields)
|
||||
- This is a **same-issue update conflict**, not an ID collision
|
||||
- Conflicts are rare in practice since hash IDs prevent structural collisions
|
||||
@@ -111,9 +111,9 @@ bd automatically detects conflict markers and shows clear resolution steps:
|
||||
|
||||
```bash
|
||||
# bd import rejects files with conflict markers
|
||||
bd import -i .beads/beads.jsonl
|
||||
bd import -i .beads/issues.jsonl
|
||||
# Error: JSONL file contains git conflict markers
|
||||
# Resolve with: git checkout --theirs .beads/beads.jsonl
|
||||
# Resolve with: git checkout --theirs .beads/issues.jsonl
|
||||
|
||||
# Validate for conflicts
|
||||
bd validate --checks=conflicts
|
||||
@@ -124,22 +124,22 @@ Conflict markers detected: `<<<<<<<`, `=======`, `>>>>>>>`
|
||||
### Resolution Workflow
|
||||
|
||||
```bash
|
||||
# After git merge creates conflict in .beads/beads.jsonl
|
||||
# After git merge creates conflict in .beads/issues.jsonl
|
||||
|
||||
# Option 1: Accept their version (remote)
|
||||
git checkout --theirs .beads/beads.jsonl
|
||||
bd import -i .beads/beads.jsonl
|
||||
git checkout --theirs .beads/issues.jsonl
|
||||
bd import -i .beads/issues.jsonl
|
||||
|
||||
# Option 2: Keep our version (local)
|
||||
git checkout --ours .beads/beads.jsonl
|
||||
bd import -i .beads/beads.jsonl
|
||||
git checkout --ours .beads/issues.jsonl
|
||||
bd import -i .beads/issues.jsonl
|
||||
|
||||
# Option 3: Manual resolution in editor
|
||||
# Edit .beads/beads.jsonl to remove conflict markers
|
||||
bd import -i .beads/beads.jsonl
|
||||
# Edit .beads/issues.jsonl to remove conflict markers
|
||||
bd import -i .beads/issues.jsonl
|
||||
|
||||
# Commit the merge
|
||||
git add .beads/beads.jsonl
|
||||
git add .beads/issues.jsonl
|
||||
git commit
|
||||
```
|
||||
|
||||
@@ -170,7 +170,7 @@ git config merge.beads.driver "bd merge %A %O %A %B"
|
||||
git config merge.beads.name "bd JSONL merge driver"
|
||||
|
||||
# .gitattributes entry added:
|
||||
# .beads/beads.jsonl merge=beads
|
||||
# .beads/issues.jsonl merge=beads
|
||||
```
|
||||
|
||||
### Manual Setup
|
||||
@@ -180,7 +180,7 @@ git config merge.beads.name "bd JSONL merge driver"
|
||||
```bash
|
||||
git config merge.beads.driver "bd merge %A %O %A %B"
|
||||
git config merge.beads.name "bd JSONL merge driver"
|
||||
echo ".beads/beads.jsonl merge=beads" >> .gitattributes
|
||||
echo ".beads/issues.jsonl merge=beads" >> .gitattributes
|
||||
```
|
||||
|
||||
### How It Works
|
||||
@@ -532,20 +532,20 @@ export BEADS_NO_DAEMON=1 # Direct mode
|
||||
|
||||
```
|
||||
# Intelligent merge driver for JSONL (auto-configured by bd init)
|
||||
.beads/beads.jsonl merge=beads
|
||||
.beads/issues.jsonl merge=beads
|
||||
|
||||
# Treat JSONL as text for diffs
|
||||
.beads/*.jsonl text diff
|
||||
```
|
||||
|
||||
This file is automatically created by `bd init` and is essential for:
|
||||
- Preventing spurious merge conflicts in `.beads/beads.jsonl`
|
||||
- Preventing spurious merge conflicts in `.beads/issues.jsonl`
|
||||
- Enabling field-level 3-way merging instead of line-by-line
|
||||
- Ensuring all team members get intelligent JSONL merging
|
||||
|
||||
### Git LFS Considerations
|
||||
|
||||
**Do NOT use Git LFS for `.beads/beads.jsonl`:**
|
||||
**Do NOT use Git LFS for `.beads/issues.jsonl`:**
|
||||
- JSONL needs intelligent merge (doesn't work with LFS)
|
||||
- File size stays reasonable (<1MB per 10K issues)
|
||||
- Text diffs are valuable for review
|
||||
@@ -563,7 +563,7 @@ WARN Database timestamp older than JSONL, importing...
|
||||
```bash
|
||||
# Normal after git pull - auto-import handles it
|
||||
# If stuck, force import:
|
||||
bd import -i .beads/beads.jsonl
|
||||
bd import -i .beads/issues.jsonl
|
||||
```
|
||||
|
||||
### Issue: "Database is ahead of JSONL"
|
||||
@@ -583,7 +583,7 @@ bd sync
|
||||
### Issue: Merge conflicts every time
|
||||
|
||||
**Symptoms:**
|
||||
- Git merge always creates conflicts in `.beads/beads.jsonl`
|
||||
- Git merge always creates conflicts in `.beads/issues.jsonl`
|
||||
- Merge driver not being used
|
||||
|
||||
**Solutions:**
|
||||
@@ -596,7 +596,7 @@ bd init --skip-db # Only reconfigure git, don't touch database
|
||||
|
||||
# Verify .gitattributes
|
||||
grep "beads.jsonl" .gitattributes
|
||||
# Expected: .beads/beads.jsonl merge=beads
|
||||
# Expected: .beads/issues.jsonl merge=beads
|
||||
```
|
||||
|
||||
### Issue: Changes not syncing to other workspaces
|
||||
@@ -613,7 +613,7 @@ git push
|
||||
|
||||
# Agent B: Force import
|
||||
git pull
|
||||
bd import -i .beads/beads.jsonl
|
||||
bd import -i .beads/issues.jsonl
|
||||
|
||||
# Check git hooks installed (prevent future issues)
|
||||
./examples/git-hooks/install.sh
|
||||
|
||||
Reference in New Issue
Block a user