Import reports misleading '0 created, 0 updated' when actually importing all issues

When running 'bd import' on a fresh database (no existing issues), the command reports 'Import complete: 0 created, 0 updated' even though it successfully imported all issues from the JSONL file.

**Steps to reproduce:**
1. Delete .beads/beads.db
2. Run: bd import .beads/issues.jsonl
3. Observe output: 'Import complete: 0 created, 0 updated'
4. Run: bd list
5. Confirm: All issues are actually present in the database

**Expected behavior:**
Report the actual number of issues imported, e.g., 'Import complete: 523 created, 0 updated'

**Actual behavior:**
'Import complete: 0 created, 0 updated' (misleading - makes user think import failed)

**Impact:**
- Users think import failed when it succeeded
- Confusing during database sync operations (e.g., after git pull)
- Makes debugging harder (can't tell if import actually worked)

**Context:**
Discovered during VC session when syncing database after git pull. The misleading message caused confusion about whether the database was properly synced with the canonical JSONL file.


Update info.go versionChanges

Add entry to versionChanges in cmd/bd/info.go with agent-actionable changes for {{version}}


Tier 2: Basic bd mol squash command

Add bd mol squash command for basic molecule execution compression.

## Command

bd mol squash <molecule-id> [flags]
  --dry-run         Preview what would be squashed
  --keep-children   Don't delete ephemeral children after squash
  --json            JSON output

## Implementation

1. Find all ephemeral children of molecule (parent-child deps)
2. Concatenate child descriptions/notes into digest
3. Create digest issue in main repo with:
   - Title: 'Molecule Execution Summary: <original-title>'
   - digest_of: [list of squashed child IDs]
   - ephemeral: false (digest is permanent)
4. Delete ephemeral children (unless --keep-children)
5. Link digest to parent work item

## Schema Changes

Add to Issue struct:
- SquashedAt *time.Time
- SquashDigest string (ID of digest)
- DigestOf []string (IDs of squashed children)

## Acceptance Criteria

- bd mol squash <id> creates digest, removes children
- --dry-run shows preview
- Digest has proper metadata linking


Version Bump: {{version}}

Release checklist for version {{version}}. This molecule ensures all release steps are completed properly.


Update version to {{version}} in version.go

Edit cmd/bd/version.go line 17:

```go
Version = "{{version}}"
```

Verify with: `grep 'Version =' cmd/bd/version.go`


wish: list & ready show issues as hierarchy tree

`bd ready` and `bd list` just show a flat list, and it's up to the reader to parse which ones are dependent or sub-issues of others. It would be much easier to understand if they were shown in a tree format


Phase 1.2: Separate bdt executable - Initial structure

Create minimal bdt command structure completely separate from bd. Must not share code, config, or database.

## Subtasks
1. Create cmd/bdt/ directory with main.go
2. Implement bdt version, help, and status commands
3. Configure separate database location: $HOME/.bdt/ (not $HOME/.beads/)
4. Create separate issues file: issues.toon (not issues.jsonl)
5. Update build system:
   - Makefile: Add bdt target
   - .goreleaser.yml: Add bdt binary config

## Files to Create
- cmd/bdt/main.go - Entry point
- cmd/bdt/version.go - Version handling
- cmd/bdt/help.go - Help text (separate from bd)

## Success Criteria
- `make build` produces both `bd` and `bdt` executables
- `bdt version` shows distinct version output from bd
- `bdt --help` shows distinct help text
- bdt uses $HOME/.bdt/ directory (verify with `bdt info`)
- bd and bdt completely isolated (no shared imports beyond stdlib)


> bd sync --no-daemon
→ Exporting pending changes to JSONL...
→ Committing changes to sync branch 'beads-sync'...
Error committing to sync branch: failed to create worktree: failed to create worktree parent directory: mkdir /var/home/matt/dev/beads/fix-ci/.git: not a directory

**Problem Diagnosed**: The `bd sync` command was failing with "mkdir /var/home/matt/dev/beads/fix-ci/.git: not a directory" because it was being executed from the wrong directory.

**Root Cause**: The command was run from `/var/home/matt/dev/beads` (where the `fix-ci` worktree exists) instead of the main repository directory `/var/home/matt/dev/beads/main`. Since `fix-ci` is a git worktree with a `.git` file (not directory), the worktree creation logic failed when trying to create `<current_dir>/.git/beads-worktrees/<branch>`.

**Solution Verified**: Execute `bd sync` from the main repository directory:
```bash
cd main && bd sync --dry-run
```


Spawn-time bonding: --attach flag

Add --attach flag to bd mol spawn for on-the-fly composition.

COMMAND: bd mol spawn proto-feature --attach proto-docs --attach proto-testing

BEHAVIOR:
- Spawn the primary proto as normal
- For each --attach: spawn that proto and wire to primary
- Attachments become children of primary's root epic
- Dependencies wired based on bond type (default: sequential)

FLAGS:
- --attach PROTO: Attach a proto (can repeat)
- --attach-type TYPE: sequential (default) or parallel for all attachments
- --after ISSUE: Attachment point for attached protos

VARIABLE HANDLING:
- All attached protos share variable namespace
- Warn on variable name conflicts
- All --var flags apply to all protos

DESIGN NOTE: This is syntactic sugar. Equivalent to:
  bd mol spawn proto-A
  bd mol bond $new_epic_id proto-B

Keeping as separate task because it's a common UX pattern worth optimizing.


GH#692: Code quality and refactoring improvements

Epic for implementing refactoring suggestions from GitHub issue #692 (rsnodgrass). These are code quality improvements that don't change functionality but improve maintainability, type safety, and performance.

Original issue: https://github.com/steveyegge/beads/issues/692

High priority items:
1. Replace map[string]interface{} with typed structs for JSON output
2. Adopt slices.SortFunc instead of sort.Slice (Go 1.21+)
3. Split large files (sync.go, init.go, show.go)
4. Introduce slog for structured logging in daemon

Lower priority:
5. Further CLI helper extraction
6. Preallocate slices in hot paths
7. Polish items (error wrapping, table-driven parsing)


Fix unparam unused parameter in cmd/bd/doctor.go:1879

Linting issue: checkGitHooks - path is unused (unparam) at cmd/bd/doctor.go:1879:20. Error: func checkGitHooks(path string) doctorCheck {


Unify template.go and mol.go under bd mol

Consolidate the two DAG-template systems into one under the mol command. mol.go (on rictus branch) has the right UX (catalog/show/bond), template.go has the mechanics. Merge them, deprecate bd template commands.


Add date and priority filters to bd search for parity with bd list.

## Current State
bd search supports: --status, --type, --assignee, --label, --limit
bd list supports: all of the above PLUS date ranges and priority filters

## Filters to Add

### Priority Filters
```bash
bd search "query" --priority 1           # Exact priority
bd search "query" --priority-min 0       # P0 and above (higher priority)
bd search "query" --priority-max 2       # P2 and below (lower priority)
```

### Date Filters
```bash
bd search "query" --created-after 2025-01-01
bd search "query" --created-before 2025-12-31
bd search "query" --updated-after 2025-01-01
bd search "query" --closed-after 2025-01-01
```

### Content Filters
```bash
bd search "query" --desc-contains "bug"
bd search "query" --notes-contains "todo"
bd search "query" --empty-description    # Issues with no description
bd search "query" --no-assignee          # Unassigned issues
bd search "query" --no-labels            # Issues without labels
```

## Files to Modify

### 1. cmd/bd/search.go
Add flag definitions in init():
```go
searchCmd.Flags().IntP("priority", "p", -1, "Filter by exact priority (0-4)")
searchCmd.Flags().Int("priority-min", -1, "Filter by minimum priority")
searchCmd.Flags().Int("priority-max", -1, "Filter by maximum priority")
searchCmd.Flags().String("created-after", "", "Filter by creation date (YYYY-MM-DD)")
searchCmd.Flags().String("created-before", "", "Filter by creation date")
searchCmd.Flags().String("updated-after", "", "Filter by update date")
searchCmd.Flags().String("updated-before", "", "Filter by update date")
searchCmd.Flags().String("closed-after", "", "Filter by close date")
searchCmd.Flags().String("closed-before", "", "Filter by close date")
searchCmd.Flags().String("desc-contains", "", "Filter by description content")
searchCmd.Flags().String("notes-contains", "", "Filter by notes content")
searchCmd.Flags().Bool("empty-description", false, "Filter issues with empty description")
searchCmd.Flags().Bool("no-assignee", false, "Filter unassigned issues")
searchCmd.Flags().Bool("no-labels", false, "Filter issues without labels")
```

### 2. internal/rpc/protocol.go
Update SearchArgs struct:
```go
type SearchArgs struct {
    Query             string
    Filter            types.IssueFilter
    // Already has most fields via IssueFilter
}
```

Note: types.IssueFilter already has these fields - just need to wire them up!

### 3. cmd/bd/search.go Run function
Parse flags and populate filter:
```go
if priority, _ := cmd.Flags().GetInt("priority"); priority >= 0 {
    filter.Priority = &priority
}
if createdAfter, _ := cmd.Flags().GetString("created-after"); createdAfter != "" {
    t, err := time.Parse("2006-01-02", createdAfter)
    if err != nil {
        FatalError("invalid date format for --created-after: %v", err)
    }
    filter.CreatedAfter = &t
}
// ... similar for other flags
```

## Implementation Steps

1. **Check types.IssueFilter** - verify all needed fields exist
2. **Add flags to search.go** init()
3. **Parse flags** in Run function
4. **Pass to SearchIssues** via filter
5. **Test all combinations**

## Testing
```bash
# Create test issues
bd create "Test P1" -p 1
bd create "Test P2" -p 2 --description "Has description"

# Test filters
bd search "" --priority 1
bd search "" --priority-min 0 --priority-max 1
bd search "" --empty-description
bd search "" --desc-contains "description"
```

## Success Criteria
- All filters work in both direct and daemon mode
- Date parsing handles YYYY-MM-DD format
- --json output includes filtered results
- Help text documents all new flags


bd mail uses git user.name for sender instead of BEADS_AGENT_NAME

When sending mail via `bd mail send`, the sender field in the stored issue uses git config user.name instead of the BEADS_AGENT_NAME environment variable.

Reproduction:
1. Set BEADS_AGENT_NAME=gastown-alpha
2. Run: bd mail send mayor/ -s 'Test' -m 'Body'
3. Check the issue.jsonl: sender is 'Steve Yegge' (git user.name) not 'gastown-alpha'

Expected: The sender field should use BEADS_AGENT_NAME when set.

This breaks the mail system for multi-agent workflows where agents need to identify themselves by their role (polecat, refinery, etc.) rather than the human user's git identity.

Related: gt mail routing integration with Gas Town


Simplify bd onboard to minimal AGENTS.md snippet pointing to bd prime

## Context
GH#604 raised concerns about bd onboard bloating AGENTS.md with ~100+ lines of static instructions that:
- Load every session whether beads is being used or not
- Get stale when bd upgrades
- Waste tokens

## Solution
Simplify `bd onboard` to output a minimal snippet (~2 lines) that points to `bd prime`:

```markdown
## Issue Tracking
This project uses beads (`bd`) for issue tracking.
Run `bd prime` for workflow context, or hooks auto-inject it.
```

## Rationale
- `bd prime` is dynamic, concise (~80 lines), and always matches installed bd version
- Hooks already auto-inject `bd prime` at session start when .beads/ detected
- AGENTS.md only needs to mention beads exists, not contain full instructions

## Implementation
1. Update `cmd/bd/onboard.go` to output minimal snippet
2. Keep `--output` flag for BD_GUIDE.md generation (may still be useful)
3. Update help text to explain the new approach


Fix G104 errors unhandled in internal/storage/sqlite/queries.go:1181

Linting issue: G104: Errors unhandled (gosec) at internal/storage/sqlite/queries.go:1181:4. Error: rows.Close()


Add integration tests for bd reset command

End-to-end integration tests for the reset command.

## Test Scenarios

### Basic reset
1. Init beads, create some issues
2. Run bd reset --force
3. Verify .beads/ is fresh, issues gone

### Hard reset
1. Init beads, create issues, commit
2. Run bd reset --hard --force
3. Verify git history has reset commits

### Backup functionality
1. Init beads, create issues
2. Run bd reset --backup --force
3. Verify backup exists with correct contents
4. Verify main .beads/ is reset

### Dry run
1. Init beads, create issues
2. Run bd reset --dry-run
3. Verify nothing changed

### Confirmation prompt
1. Init beads
2. Run bd reset (no --force)
3. Verify prompts for confirmation
4. Test both y and n responses

## Location
tests/integration/reset_test.go or similar


wish: a 'continue' or similar cmd/flag which means alter last issue

so many time I create an issue and then have another thought: 'oh, before I did X and it crashed there was ZZZ happening' or 'actually that is P4 not P2'. It would be nice if when `bd {cmd}` is used without a {title} or {id} it just adds or updates the most recently touched issue.


Command Set Standardization & Flag Consistency

Comprehensive improvements to bd command set based on 2025 audit findings.

## Background
See docs/command-audit-2025.md for detailed analysis.

## Goals
1. Standardize flag naming and behavior across all commands
2. Add missing flags for feature parity
3. Fix naming confusion
4. Improve consistency in JSON output

## Success Criteria
- All mutating commands support --dry-run (no --preview variants)
- bd update supports label operations
- bd search has filter parity with bd list
- Priority flags accept both int and P0-P4 format everywhere
- JSON output is consistent across all commands


Deferred HOP schema additions (P2/P3)

Deferred from bd-7pwh after review. Add when semantics are clearer and actually needed:

- assignee_ref: Structured EntityRef alongside string assignee
- work_type: 'mutex' vs 'open_competition' (everything is mutex in v0.1)
- crystallizes: bool for work that compounds vs evaporates (can derive from issue_type)
- cross_refs: URIs to beads in other repos (needs federation first)
- skill_vector: []float32 embeddings placeholder (YAGNI)

These can be added later without breaking changes (all optional fields).


Merge: bd-4qfb

branch: polecat/Polish
target: main
source_issue: bd-4qfb
rig: beads


Integration test: agent waits for CI via gate

End-to-end test of the gate workflow.

## Test Scenario
1. Agent creates gate: bd gate create --await gh:run:123 --timeout 5m --notify beads/dave
2. Agent writes handoff and exits
3. Deacon patrol checks gate condition
4. (Mock) GitHub run completes
5. Deacon notifies waiter and closes gate
6. New agent session reads mail and resumes

## Test Requirements
- Mock GitHub API responses
- Test timeout path
- Test multiple waiters
- Verify mail notifications sent


Test body-file

This is a test description from a file.

It has multiple lines.


Restart running daemons

Kill and restart any running bd daemons to pick up new version: pkill -f 'bd daemon' && bd daemon --start


Update Homebrew formula

Update the Homebrew tap with new version:

```bash
./scripts/update-homebrew.sh 0.33.2
```

This script waits for GitHub Actions to complete (~5 min), then updates the formula with new SHA256 hashes.


Review and document rarely-used commands

Document use cases or consider deprecation for infrequently-used commands.

**Commands to review:**
1. bd rename-prefix - How often is this used? Document use cases
2. bd detect-pollution - Consider integrating into bd validate
3. bd migrate-hash-ids - One-time migration, keep but document as legacy

**For each command:**
- Document typical use cases
- Add examples to help text
- Consider if it should be a subcommand instead
- Add deprecation warning if appropriate

**Not changing:**
- duplicates ✓ (useful for data quality)
- repair-deps ✓ (useful for fixing broken refs)
- restore ✓ (critical for compacted issues)
- compact ✓ (performance feature)

**Deliverable:**
- Updated help text
- Documentation in ADVANCED.md
- Deprecation plan if needed


Merge: bd-n386

branch: polecat/immortan
target: main
source_issue: bd-n386
rig: beads


Remove all deletions.jsonl code except migration

There's deletions manifest code spread across the entire codebase that should have been removed after tombstone migration:

Files with deletions code (non-migration):
- internal/deletions/ - entire package
- cmd/bd/sync.go - 25+ references, auto-compact, sanitize
- cmd/bd/delete.go - dual-writes to deletions.jsonl
- internal/importer/importer.go - checks deletions manifest
- internal/syncbranch/worktree.go - merges deletions.jsonl
- cmd/bd/doctor/fix/sync.go - cleanupDeletionsManifest
- cmd/bd/doctor/fix/deletions.go - HydrateDeletionsManifest
- cmd/bd/integrity.go - checks deletions for data loss
- cmd/bd/deleted.go - entire command
- cmd/bd/compact.go - pruneDeletionsManifest
- cmd/bd/doctor.go - checkDeletionsManifest
- Plus many more

Action: Aggressively remove all non-migration deletions code. Tombstones are the only deletion mechanism now.


Commit release v{{version}}

Stage and commit the version bump:

```bash
git add cmd/bd/version.go cmd/bd/info.go CHANGELOG.md
git commit -m "release: v{{version}}"
```

Do NOT push yet - tag first.


Create git tag v0.33.2

Create the release tag:

```bash
git tag v0.33.2
```

Verify: `git tag | grep 0.33.2`


Time-dependent tests may be flaky near TTL boundary

Several tombstone merge tests use time.Now() to create test data: time.Now().Add(-24 * time.Hour), time.Now().Add(-60 * 24 * time.Hour), etc. While these work reliably in practice (24h vs 30d TTL has large margin), they could theoretically be flaky if: 1) Tests run slowly, 2) System clock changes during test, 3) TTL constants change. Recommendation: Consider using a fixed reference time or time injection for deterministic tests. Lower priority since current margin is large. Files: internal/merge/merge_test.go:1337-1338, 1352-1353, 1548-1549, 1590-1591


Auto-recovery mode (bd sync --auto-recover)

Add bd sync --auto-recover flag that: detects problematic sync state, backs up .beads/issues.db with timestamp, rebuilds DB from JSONL atomically, verifies consistency, reports what was fixed. Provides safety valve when sync integrity fails.


Fix TestRunSync_Timeout failing on macOS

The hooks timeout test fails because exec.CommandContext doesn't properly terminate child processes of shell scripts on macOS. The test creates a hook that runs 'sleep 60' with a 500ms timeout, but it waits the full 60 seconds.

Options to fix:
- Use SysProcAttr{Setpgid: true} to create process group and kill the group
- Skip test on darwin with build tag
- Use a different approach for timeout testing

Location: internal/hooks/hooks_test.go:220-253


Bump version in all files

Run ./scripts/bump-version.sh 0.33.2 to update 10 version files. Then run with --commit after info.go is updated.


bd sync --from-main fails: unknown flag --no-git-history


Update CHANGELOG.md for {{version}}

In CHANGELOG.md:

1. Change `## [Unreleased]` section header to `## [{{version}}] - {{date}}`
2. Add new empty `## [Unreleased]` section above it
3. Review and clean up the changes list

Format:
```markdown
## [Unreleased]

## [{{version}}] - {{date}}

### Added
- ...

### Changed
- ...

### Fixed
- ...
```


Implement bd gate create/show/list/close/wait commands

Implement the gate CLI commands.

## Commands
```bash
# Create gate (returns gate ID)
bd gate create --await <type>:<id> --timeout <duration> --notify <addr>

# Check gate status
bd gate show <id>

# List open gates
bd gate list

# Close gate (usually done by Deacon)
bd gate close <id> --reason "completed"

# Add waiter to existing gate
bd gate wait <id> --notify <addr>
```

## Implementation
- Add cmd/bd/gate.go with subcommands
- Gate create creates wisp issue of type gate
- Gate list filters for open gates
- Gate wait adds to waiters[] array
- All support --json output