Commit Graph

666 Commits

Author SHA1 Message Date
Charles P. Cross
03f5afb605 feat(daemon): add auto_pull config parameter for periodic remote sync
Add --auto-pull flag to control whether the daemon periodically pulls from
remote to check for updates from other clones.

Configuration precedence:
1. --auto-pull CLI flag (highest)
2. BEADS_AUTO_PULL environment variable
3. daemon.auto_pull in database config
4. Default: true when sync.branch is configured

When auto_pull is enabled, the daemon creates a remoteSyncTicker that
periodically calls doAutoImport() to pull remote changes. When disabled,
users must manually run 'git pull' to sync remote changes.

Changes:
- cmd/bd/daemon.go: Add --auto-pull flag and config reading logic
- cmd/bd/daemon_event_loop.go: Gate remoteSyncTicker on autoPull parameter
- cmd/bd/daemon_lifecycle.go: Add auto-pull to status output and spawn args
- internal/rpc/protocol.go: Add AutoPull field to StatusResponse
- internal/rpc/server_core.go: Add autoPull to Server struct and SetConfig
- internal/rpc/server_routing_validation_diagnostics.go: Include in status
- Tests updated to pass autoPull parameter

Closes #TBD
2025-12-22 18:47:18 -05:00
Charles P. Cross
737e65afbd fix(daemon): add periodic remote sync to event-driven mode (#698)
* fix(daemon): add periodic remote sync to event-driven mode

The event-driven daemon mode only triggered imports when the local JSONL
file changed (via file watcher) or when the fallback ticker fired (only
if watcher failed). This meant the daemon wouldn't see updates pushed
by other clones until something triggered a local file change.

Bug scenario:
1. Clone A creates an issue and daemon pushes to sync branch
2. Clone B's daemon only watched local file changes
3. Clone B would not see the new issue until something triggered local change
4. With this fix: Clone B's daemon periodically calls doAutoImport

This fix adds a 30-second periodic remote sync ticker that calls
doAutoImport(), which includes syncBranchPull() to fetch and import
updates from the remote sync branch.

This is essential for multi-clone workflows where:
- Clone A creates an issue and daemon pushes to sync branch
- Clone B's daemon needs to periodically pull to see the new issue
- Without periodic sync, Clone B would only see updates if its local
  JSONL file happened to change

The 30-second interval balances responsiveness with network overhead.

Adds integration test TestEventDrivenLoop_PeriodicRemoteSync that
verifies the event-driven loop starts with periodic sync support.

* feat(daemon): add configurable interval for periodic remote sync

- Add BEADS_REMOTE_SYNC_INTERVAL environment variable to configure
  the interval for periodic remote sync (default: 30s)
- Add getRemoteSyncInterval() function to parse the env var
- Minimum interval is 5s to prevent excessive load
- Setting to 0 disables periodic sync (not recommended)
- Add comprehensive integration tests for the configuration

Valid duration formats:
- "30s" (30 seconds)
- "1m" (1 minute)
- "5m" (5 minutes)

Tests added:
- TestEventDrivenLoop_HasRemoteSyncTicker
- TestGetRemoteSyncInterval_Default
- TestGetRemoteSyncInterval_CustomValue
- TestGetRemoteSyncInterval_MinimumEnforced
- TestGetRemoteSyncInterval_InvalidValue
- TestGetRemoteSyncInterval_Zero
- TestSyncBranchPull_FetchesRemoteUpdates

* fix: resolve all golangci-lint errors (cherry-pick from fix/linting-errors)

Cherry-picked linting fixes to ensure CI passes.

* feat(daemon): add config.yaml support for remote-sync-interval

- Add remote-sync-interval to .beads/config.yaml as alternative to
  BEADS_REMOTE_SYNC_INTERVAL environment variable
- Environment variable takes precedence over config.yaml (follows
  existing pattern for flush-debounce)
- Add config binding in internal/config/config.go
- Update getRemoteSyncInterval() to use config.GetDuration()
- Add doctor validation for remote-sync-interval in config.yaml

Configuration sources (in order of precedence):
1. BEADS_REMOTE_SYNC_INTERVAL environment variable
2. remote-sync-interval in .beads/config.yaml
3. DefaultRemoteSyncInterval (30s)

Example config.yaml:
  remote-sync-interval: "1m"

---------

Co-authored-by: Charles P. Cross <cpdata@users.noreply.github.com>
2025-12-22 14:15:33 -08:00
Charles P. Cross
e360a74b61 fix: resolve all golangci-lint errors (#699)
Fix 12 linting issues that were causing CI failures:

errcheck (8 fixes):
- cmd/bd/mol_burn.go: wrap wispStore.Close() in defer func
- cmd/bd/mol_burn.go: handle fmt.Scanln() return value
- cmd/bd/mol_squash.go: wrap wispStore.Close() in defer func (2 locations)
- cmd/bd/wisp.go: wrap wispStore.Close() in defer func (3 locations)
- internal/beads/beads.go: wrap mainStore.Close() and wispStore.Close()

gosec G104 (2 fixes):
- internal/storage/sqlite/multirepo.go: handle rows.Close() errors

misspell (1 fix):
- cmd/bd/mol_burn.go: change "Cancelled" to "Canceled"

unparam (1 fix):
- cmd/bd/mol_squash.go: use blank identifier for unused cmd parameter

All fixes follow existing patterns in the codebase:
- defer func() { _ = store.Close() }() for deferred closes
- _ = rows.Close() for explicit closes with ignored errors
- _, _ = fmt.Scanln() for ignored return values

Co-authored-by: Charles P. Cross <cpdata@users.noreply.github.com>
2025-12-22 14:06:45 -08:00
Steve Yegge
199def9fed release: v0.34.0
## Added
- Wisp commands - bd wisp create/list/gc for ephemeral molecule management
- Chemistry UX - bd pour, bd mol bond --wisp/--pour for phase control
- Cross-project deps - external:<repo>:<id> syntax, bd ship command
- Orphan detection in bd doctor

## Changed
- Multi-repo config uses YAML - bd repo add/remove writes to .beads/config.yaml

## Fixed
- Wisp storage auto-copies issue_prefix from main database
- Prefix validation in multi-repo mode
- Remove orphaned repo_test.go
- Update version tests for 0.34.0 thresholds

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-22 03:18:55 -08:00
Steve Yegge
8f8e9516df fix: bd repo commands write to YAML and cleanup on remove (#683)
- bd repo add/remove now writes to .beads/config.yaml instead of database
- bd repo remove deletes hydrated issues from the removed repo
- Added internal/config/repos.go for YAML config manipulation
- Added DeleteIssuesBySourceRepo for cleanup on remove

Fixes config disconnect where bd repo add wrote to DB but hydration read from YAML.

Breaking change: bd repo add no longer accepts optional alias argument.

Co-authored-by: Dylan Conlin <dylan.conlin@gmail.com>

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-22 01:26:45 -08:00
Ryan
a11b20960a fix(doctor): UX improvements for diagnostics and daemon (#687)
* fix(doctor): UX improvements for diagnostics and daemon

- Add Repo Fingerprint check to detect when database belongs to a
  different repository (copied .beads dir or git remote URL change)
- Add interactive fix for repo fingerprint with options: update repo ID,
  reinitialize database, or skip
- Add visible warning when daemon takes >5s to start, recommending
  'bd doctor' for diagnosis
- Detect install method (Homebrew vs script) and show only relevant
  upgrade command
- Improve WARNINGS section:
  - Add icons (⚠ or ✖) next to each item
  - Color numbers by severity (yellow for warnings, red for errors)
  - Render entire error lines in red
  - Sort by severity (errors first)
  - Fix alignment with checkmarks above
- Use heavier fail icon (✖) for better visibility
- Add integration and validation tests for doctor fixes

* fix(lint): address errcheck and gosec warnings

- mol_bond.go: explicitly ignore ephStore.Close() error
- beads.go: add nosec for .gitignore file permissions (0644 is standard)
2025-12-22 01:25:23 -08:00
Gero Hillebrandt
9d30e80fdf fix: skip prefix validation in multi-repo mode (GH#686) (#688)
Issues from additional repos have their own prefixes, which is expected.
Skip validation when multi-repo config is present.
2025-12-22 01:25:19 -08:00
Steve Yegge
69911070f0 feat: add cross-store wisp→digest squash (bd-kwjh.4)
- Add wisp detection in mol squash: checks wisp storage if not in main
- squashWispToPermanent: creates digest in permanent, deletes from wisp
- Fix directory naming: .beads-wisps → .beads-wisp (singular, matches doc)
- Add comprehensive tests for wisp squash scenarios

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-22 00:54:35 -08:00
Steve Yegge
a49b924794 refactor: rename ephemeral → wisp throughout (bd-ldb0)
Standardize terminology for ephemeral molecule storage:
- .beads-ephemeral/ → .beads-wisps/
- --ephemeral flag → --wisp flag
- All Ephemeral* functions → Wisp*

Wisps are the "steam" in Gas Town's engine metaphor - ephemeral
molecules that evaporate after squash.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-22 00:32:18 -08:00
Steve Yegge
2d719b189d feat: add ephemeral storage backend for wisps (bd-kwjh.2)
Add .beads-ephemeral/ storage support for ephemeral molecule tracking:

- FindEphemeralDir: locate ephemeral directory (sibling to .beads/)
- FindEphemeralDatabasePath: get DB path, create directory if needed
- NewEphemeralStorage: open ephemeral SQLite database
- EnsureEphemeralGitignore: add .beads-ephemeral/ to .gitignore
- IsEphemeralDatabase: check if a path is ephemeral storage

Part of the wisp storage epic for Gas Town patrol cycles.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-22 00:19:18 -08:00
Steve Yegge
1cfb23487b feat: bd ready filters by external dep satisfaction (bd-zmmy)
GetReadyWork now lazily resolves external dependencies at query time:
- External refs (external:project:capability) checked against target DB
- Issues with unsatisfied external deps are filtered from ready list
- Satisfaction = closed issue with provides:<capability> label in target

Key changes:
- Remove FK constraint on depends_on_id to allow external refs
- Add migration 025 to drop FK and recreate views
- Filter external deps in GetReadyWork, not in blocked_issues_cache
- Add application-level validation for orphaned local deps
- Comprehensive tests for external dep resolution

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 23:41:44 -08:00
Steve Yegge
a9bfce7f6e wip: external dep resolution helper (bd-zmmy) 2025-12-21 23:13:50 -08:00
Steve Yegge
e7f09660c0 feat: add cross-project dependency support - config and external: prefix (bd-66w1, bd-om4a)
Config (bd-66w1):
- Add external_projects config for mapping project names to paths
- Add GetExternalProjects() and ResolveExternalProjectPath() functions
- Add config documentation and tests

External deps (bd-om4a):
- bd dep add accepts external:project:capability syntax
- External refs stored as-is in dependencies table
- GetBlockedIssues includes external deps in blocked_by list
- blocked_issues_cache includes external dependencies
- Add validation and parsing helpers for external refs

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 23:08:00 -08:00
Steve Yegge
240a4e2dbc feat: add bd doctor check for orphaned issues (bd-5hrq)
- Add CheckOrphanedIssues to detect issues referenced in commits but still open
- Pattern matches (prefix-xxx) in git log against open issues in database
- Reports warning with issue IDs and commit hashes
- Add 8 comprehensive tests for the new check

Also:
- Add tests for mol spawn --attach functionality (bd-f7p1)
- Document commit message convention in AGENT_INSTRUCTIONS.md
- Fix CheckpointWAL to use wrapDBError for consistency

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 22:05:14 -08:00
Steve Yegge
8b87c556c7 fix: priority:0 omitempty and markdown nil pointer (GH#671, GH#674)
- Remove omitempty from Priority field so P0 issues preserve priority:0
- Add nil check for store in createIssuesFromMarkdown

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 15:41:22 -08:00
Steve Yegge
358d076fde refactor: rename Ephemeral → Wisp (Steam Engine metaphor)
Wisp = ephemeral vapor produced by the Steam Engine (Gas Town).
This aligns with the metaphor:
- Claude = Fire
- Claude Code = Steam
- Gas Town = Steam Engine
- Wisps = ephemeral vapor it produces

Changes:
- types.Issue.Ephemeral → types.Issue.Wisp
- types.IssueFilter.Ephemeral → types.IssueFilter.Wisp
- JSON field: "ephemeral" → "wisp"
- CLI flag: --ephemeral → --wisp (bd cleanup)
- All tests updated

Note: SQLite column remains "ephemeral" (no migration needed).
This is a breaking change for JSON consumers using 0.33.0.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 15:22:45 -08:00
Steve Yegge
39f8461914 feat(mol): filter ephemeral issues from JSONL export (bd-687g)
Ephemeral issues should never be exported to issues.jsonl. They exist only
in SQLite and are shared via .beads/redirect pointers. This prevents
"zombie" issues from resurrecting after mol squash deletes them.

Changes:
- Filter ephemeral issues in autoflush, export, and multirepo_export
- Add --summary flag to bd mol squash for agent-provided summaries
- Fix DeleteIssue to also remove comments (missing cascade)
- Add tests for ephemeral filtering and comment deletion

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 14:37:22 -08:00
Steve Yegge
169684754d fix: clean goroutine exit in timeout message helpers
Add done channel to runGitCmdWithTimeoutMsg and runCmdWithTimeoutMessage
so goroutines exit immediately when command completes, rather than
waiting for the full timeout duration.

Follow-up to PR #678.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 12:43:18 -08:00
Steve Yegge
fd8b987189 Merge branch 'pr-678' 2025-12-21 12:42:29 -08:00
Steve Yegge
acba84ef7f fix(memory): exclude pinned issues from GetReadyWork
SQLite storage already excluded pinned issues from ready work
(bd-92u), but memory storage was missing this check. Pinned
issues are context markers, not actionable work items.

Closes bd-o9o.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 11:30:58 -08:00
matt wilkie
12e3809aef fix: correct misspelling 'cancelled' to 'canceled' 2025-12-21 12:15:14 -07:00
matt wilkie
5a2976b500 fix: remove unused channels in timeout message helpers
The timerChan and timeoutChan variables were created but never read from,
causing lint errors. Removed them since we don't need channel synchronization -
we only want the timeout to trigger a message, not block anything.
2025-12-21 12:13:39 -07:00
matt wilkie
03118e7226 feat(sync): add timeout message for long-running git operations (fixes #647)
When git push or other git operations hang waiting for credential/browser
auth, show a helpful message to the user after 5 seconds of inactivity
instead of appearing frozen.

Added:
- runCmdWithTimeoutMessage() in internal/syncbranch/worktree.go
- runGitCmdWithTimeoutMsg() in cmd/bd/sync.go
- Both functions print a message after timeout delay with advice
  to check for browser auth prompts

Fixes issue #647 (bd sync frozen waiting for browser auth)
2025-12-21 12:05:13 -07:00
Steve Yegge
466c606eb9 feat(mol): rename bond→spawn, add BondRef data model
Molecule evolution:
- Rename `bd mol bond` to `bd mol spawn` for instantiation
- Add BondRef type for tracking compound lineage
- Add `bonded_from` field to Issue for compound molecules
- Add BondType constants (sequential, parallel, conditional, root)
- Add IsCompound() and GetConstituents() helpers
- Add 'protomolecule' easter egg alias

Closes: bd-mh4w, bd-rnnr
Part of: bd-o5xe (Molecule bonding epic)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 01:20:25 -08:00
Steve Yegge
c195dc1874 Merge branch 'main' into subtle-ux-improvements
Resolved modify/delete conflict: cmd/bd/mail.go was deleted on main
(mail functionality moved to Gas Town), accepting deletion.
2025-12-20 23:26:35 -08:00
Steve Yegge
5d2daf2e1e fix(pin): add 'pinned' field to allowed update fields (gt-zr0a)
The 'bd pin' command was failing with "invalid field for update: pinned"
because the pinned field was missing from allowedUpdateFields.

Fixes:
- Add 'pinned' to allowedUpdateFields in queries.go
- Update importer to include pinned field in updates during import
- Add equalBool comparator for IssueDataChanged to detect pinned changes
- Fix stats query to count pinned=1 instead of status='pinned'
- Fix pinIndicator in list.go to check issue.Pinned instead of status

This unblocks gt mail --pinned functionality.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 19:57:16 -08:00
Steve Yegge
7ad2bbbcde Merge PR #665: fix(setup): preserve symlinks in atomicWriteFile
Add ResolveForWrite helper that resolves symlinks before writing, so
atomic writes go to the symlink target instead of replacing the symlink.

This prevents `bd setup claude` from overwriting nix/home-manager
managed ~/.claude/settings.json symlinks.

Closes #665

Co-authored-by: qmx <qmx@qmx.me>
2025-12-20 18:03:12 -08:00
Steve Yegge
4f504bdff8 fix(test): resolve target path in symlink test for macOS
On macOS, /var is a symlink to /private/var, so EvalSymlinks returns
the canonical path. The test needs to resolve the expected target path
before comparison.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 18:02:41 -08:00
Steve Yegge
4fa0866fcf refactor: remove bd mail commands - mail moves to Gas Town
Mail is orchestration, not data plane. The bd mail commands were just
sugar over bd create/list/show with type=message. Gas Town (gt) now
owns mail routing and delivery.

Removed:
- cmd/bd/mail.go - all mail subcommands (send, inbox, read, ack, reply)
- cmd/bd/mail_test.go - mail command tests
- docs/messaging.md - dedicated mail documentation
- EventMessage hook - no longer triggered

Kept (data plane):
- type=message as valid issue type
- Sender, Ephemeral fields on issues
- replies_to dependency type for threading

Coordination: gt-9xg implements native mail in Gas Town.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 17:56:46 -08:00
Ryan Snodgrass
84b4562fda Merge upstream/main into subtle-ux-improvements
Resolves conflicts and converts new defer/undefer commands from
fatih/color to the lipgloss semantic color system.

Key changes:
- Added StatusDeferred case in graph.go with ui.RenderAccent
- Converted status.go to use ui package for colorized output
- Converted defer.go/undefer.go to use ui package
- Merged GroupID and Aliases for status command
- Updated pre-commit hook version to 0.31.0
- Ran go mod tidy to remove fatih/color dependency
2025-12-20 17:22:43 -08:00
Doug Campos
c7615e4075 fix(setup): preserve symlinks in atomicWriteFile
Add ResolveForWrite helper that resolves symlinks before writing,
so atomic writes go to the symlink target instead of replacing
the symlink itself.
2025-12-20 20:15:55 -05:00
Ryan Snodgrass
6ca141712c refactor(ui): standardize on lipgloss semantic color system
Replace all fatih/color usages with internal/ui package that provides:
- Semantic color tokens (Pass, Warn, Fail, Accent, Muted)
- Adaptive light/dark mode support via Lipgloss AdaptiveColor
- Ayu theme colors for consistent, accessible output
- Tufte-inspired data-ink ratio principles

Files migrated: 35 command files in cmd/bd/

Add docs/ui-philosophy.md documenting:
- Semantic token usage guidelines
- Light/dark terminal optimization rationale
- Tufte and perceptual UI/UX theory application
- When to use (and not use) color in CLI output
2025-12-20 17:09:50 -08:00
Steve Yegge
e778b3f648 feat(status): add deferred status for icebox issues (bd-4jr)
Add 'deferred' as a valid issue status for issues that are deliberately
put on ice - not blocked by dependencies, just postponed for later.

Changes:
- Add StatusDeferred constant and update IsValid() validation
- Add DeferredIssues to Statistics struct with counting in both SQLite
  and memory storage
- Add 'bd defer' command to set status to deferred
- Add 'bd undefer' command to restore status to open
- Update help text across list, search, count, dep, stale, and config
- Update MCP server models and tools to accept deferred status
- Add deferred to blocker status checks (schema, cache, ready, compact)
- Add StatusDeferred to public API exports (beads.go, internal/beads)
- Add snowflake styling for deferred in dep tree and graph views

Semantics:
- deferred vs blocked: deferred is a choice, blocked is forced
- deferred vs closed: deferred will be revisited, closed is done
- Deferred issues excluded from 'bd ready' (already works since
  default filter only includes open/in_progress)
- Deferred issues still block dependents (they are not done!)
- Deferred issues visible in 'bd list' and 'bd stale'

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 14:24:48 -08:00
Steve Yegge
844e9ffc02 fix(deps): exclude relates-to from cycle detection (fixes #661)
relates-to dependencies are intentionally bidirectional ("see also" links)
and should not be reported as cycles by bd dep cycles. This matches the
existing behavior in AddDependency which already skips cycle prevention
for relates-to.

Changes:
- Filter relates-to edges in DetectCycles SQL query
- Add tests for relates-to exclusion from cycle detection
- Update existing test to reflect correct behavior

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:33:15 -08:00
Steve Yegge
f6392efd07 feat(molecules): Add molecules.jsonl as separate catalog file for templates
Implements gt-0ei3: Template molecules now live in a separate molecules.jsonl
file, distinct from work items in issues.jsonl.

Key changes:
- Add internal/molecules package for loading molecule catalogs
- Implement hierarchical loading: built-in → town → user → project
- Molecules use their own ID namespace (mol-*) with prefix validation skipped
- Templates are marked with is_template: true and are read-only
- bd list excludes templates by default (existing functionality)

The hierarchical loading allows:
- Built-in molecules shipped with bd binary (placeholder for future)
- Town-level: ~/gt/.beads/molecules.jsonl (Gas Town)
- User-level: ~/.beads/molecules.jsonl
- Project-level: .beads/molecules.jsonl

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 09:27:41 -08:00
Steve Yegge
244ba1471b feat(config): add directory-aware label scoping for monorepos (fixes #541)
Adds automatic label filtering based on current working directory:
- New config option: directory.labels (maps directory patterns to labels)
- bd ready and bd list auto-apply label filtering when in matching directory
- Uses --label-any semantics (shows issues with any of the matching labels)

Config example:
```yaml
directory:
  labels:
    packages/maverick: maverick
    packages/agency: agency
```

When running `bd ready` from `packages/maverick/`, issues labeled
"maverick" are automatically shown first, without needing --label-any.

Closes #541

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 03:41:09 -08:00
Steve Yegge
c988b171e8 feat(config): add git.author and git.no-gpg-sign options (fixes #600)
Adds configuration options for beads git commits:
- git.author: Override commit author (e.g., "beads-bot <beads@example.com>")
- git.no-gpg-sign: Disable GPG signing for beads commits

This is useful for users with Touch ID commit signing (like Secretive)
who get prompted for every beads auto-commit.

Config example:
```yaml
git:
  author: "beads-bot <beads@example.com>"
  no-gpg-sign: true
```

Environment variables: BD_GIT_AUTHOR, BD_GIT_NO_GPG_SIGN

Closes #600

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 03:36:41 -08:00
Steve Yegge
7b758271ed feat(audit): add append-only agent audit trail (.beads/interactions.jsonl)
Implements audit logging for agent interactions to support auditing and
dataset generation (fixes #649).

New features:
- .beads/interactions.jsonl (append-only audit log)
- bd audit record: log LLM calls, tool calls, or pipe JSON via stdin
- bd audit label <id>: append labels (good/bad) for dataset curation
- bd compact --audit: optionally log LLM prompt/response during compaction
- bd init: creates empty interactions.jsonl
- bd sync: includes interactions.jsonl in staging

Audit entries are append-only - labeling creates new entries that
reference parent entries by ID.

Closes #649

Co-authored-by: Dmitry Chichkov <dchichkov@nvidia.com>

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 03:24:51 -08:00
Ryan
3c08e5eb9d DOCTOR IMPROVEMENTS: visual improvements/grouping + add comprehensive tests + fix gosec warnings (#656)
* test(doctor): add comprehensive tests for fix and check functions

Add edge case tests, e2e tests, and improve test coverage for:
- database_test.go: database integrity and sync checks
- git_test.go: git hooks, merge driver, sync branch tests
- gitignore_test.go: gitignore validation
- prefix_test.go: ID prefix handling
- fix/fix_test.go: fix operations
- fix/e2e_test.go: end-to-end fix scenarios
- fix/fix_edge_cases_test.go: edge case handling

* docs: add testing philosophy and anti-patterns guide

- Create TESTING_PHILOSOPHY.md covering test pyramid, priority matrix,
  what NOT to test, and 5 anti-patterns with code examples
- Add cross-reference from README_TESTING.md
- Document beads-specific guidance (well-covered areas vs gaps)
- Include target metrics (test-to-code ratio, execution time targets)

* chore: revert .beads/ to upstream/main state

* refactor(doctor): add category grouping and Ayu theme colors

- Add Category field to DoctorCheck for organizing checks by type
- Define category constants: Core, Git, Runtime, Data, Integration, Metadata
- Update thanks command to use shared Ayu color palette from internal/ui
- Simplify test fixtures by removing redundant test cases

* fix(doctor): prevent test fork bomb and fix test failures

- Add ErrTestBinary guard in getBdBinary() to prevent tests from
  recursively executing the test binary when calling bd subcommands
- Update claude_test.go to use new check names (CLI Availability,
  Prime Documentation)
- Fix syncbranch test path comparison by resolving symlinks
  (/var vs /private/var on macOS)
- Fix permissions check to use exact comparison instead of bitmask
- Fix UntrackedJSONL to use git commit --only to preserve staged changes
- Fix MergeDriver edge case test by making both .git dir and config
  read-only
- Add skipIfTestBinary helper for E2E tests that need real bd binary

* test(doctor): skip read-only config test in CI environments

GitHub Actions containers may have CAP_DAC_OVERRIDE or similar
capabilities that allow writing to read-only files, causing
the test to fail. Skip the test when CI=true or GITHUB_ACTIONS=true.
2025-12-20 03:10:06 -08:00
Steve Yegge
b4bc682d93 feat(create): add require-description config option (GH#596)
Add create.require-description config option that enforces descriptions
when creating issues. When enabled, bd create will error if no
description is provided (except for test issues).

- Config in .beads/config.yaml or ~/.config/bd/config.yaml
- Also supports BD_CREATE_REQUIRE_DESCRIPTION env var
- Default: false (preserves current behavior with warning)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 02:38:56 -08:00
Steve Yegge
6c060461cb feat(jsonl): add omitempty to reduce JSONL bloat (beads-399)
Add omitempty JSON tags to Issue struct fields (Description, Status,
Priority, IssueType) and SetDefaults method to apply proper defaults
when importing JSONL with omitted fields.

This reduces JSONL file size for minimal issues like notifications
by not exporting empty/default values.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 23:18:11 -08:00
Steve Yegge
ad4e813e71 feat(molecules): add bd molecule commands and template protection (beads-1ra)
- Add `bd molecule list` to list template molecules
- Add `bd molecule show` to show molecule details
- Add `bd molecule instantiate` to create work items from templates
- Exclude templates from `bd list` by default (use --include-templates)
- Reject mutations (update/close/delete) to template issues
- Add IncludeTemplates to RPC ListArgs for daemon mode

Templates are marked with is_template=true and are read-only.
Use `bd molecule instantiate` to create editable work items.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 22:14:54 -08:00
Steve Yegge
52135d0370 feat(types): add template molecules infrastructure for beads-1ra
Add support for template molecules (is_template field and TypeMolecule type):

- Add IsTemplate field to Issue type with JSON support
- Add TypeMolecule constant to IssueType constants
- Add IsTemplate filter to IssueFilter for querying
- Update all SQL queries to include is_template column
- Add migration 024 for is_template column
- Add FindMoleculesJSONLInDir helper for molecules.jsonl path detection

This enables treating certain issues as read-only templates that can be
instantiated to create work items. The template flag allows separating
template molecules from regular work items in queries and exports.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 22:03:22 -08:00
Steve Yegge
567dd0a0c6 fix(schema): add pinned column to schema compatibility checks
The schema_probe.go and doctor/database.go had different column lists
for validating database schemas. Neither included the pinned column
added in migration 023, causing:
- Doctor to report "All required tables and columns present" on
  databases missing the pinned column
- Potential failures when using `gt mail send` on databases without
  the pinned column

Changes:
- Add pinned, sender, ephemeral to doctor's criticalChecks
- Add metadata, thread_id to dependencies check
- Add all missing columns to schema_probe.go's expectedSchema:
  source_repo, close_reason, deleted_at, deleted_by, delete_reason,
  original_type, sender, ephemeral, pinned

Fixes: beads-9yc

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 19:57:14 -08:00
Steve Yegge
46488d4f96 Add 'molecule' as valid issue type
Molecules are composable workflow templates used by Gas Town (gt) for
defining multi-step processes like bootstrap, engineer-in-box, etc.

Changes:
- Add TypeMolecule constant to internal/types/types.go
- Add molecule to IsValid() switch case
- Add molecule and merge-request to validation/bead.go validTypes map
- Update help text in create.go, show.go, list.go
- Add test cases for molecule and merge-request types

Closes gt-qn4l

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 18:31:33 -08:00
Steve Yegge
af432bee4e test(linear): add comprehensive tests for mapping and client functions
Added tests for:
- DefaultMappingConfig
- PriorityToBeads/PriorityToLinear
- StateToBeadsStatus/ParseBeadsStatus
- StatusToLinearStateType
- LabelToIssueType/ParseIssueType
- RelationToBeadsDep
- IssueToBeads (with parent/child handling)
- BuildLinearToLocalUpdates
- LoadMappingConfig
- BuildLinearDescription
- NewClient/WithEndpoint/WithHTTPClient
- ExtractLinearIdentifier
- IsLinearExternalRef

Linear package coverage improved from 14.3% to ~50%.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 18:30:03 -08:00
Steve Yegge
2a6e6a7054 fix(idgen): correct test vectors in hash_test.go
The test vectors in TestGenerateHashIDMatchesJiraVector did not match
the actual output of GenerateHashID. Updated to use the correct values
that the algorithm produces.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 18:13:56 -08:00
Justin Williams
df5ceb5d82 feat: Linear Integration (#655)
* Add Linear integration CLI with sync and status commands

- Add `bd linear sync` for bidirectional issue sync with Linear
- Add `bd linear status` to show configuration and sync state
- Stub pull/push functions pending GraphQL client (bd-b6b.2)

* Implement Linear GraphQL client with full sync support

- Add LinearClient with auth, fetch, create, update methods
- Implement pull/push operations with Beads type mapping
- Clean up redundant comments and remove unused code

* Add configurable data mapping and dependency sync for Linear

- Add LinearMappingConfig with configurable priority/state/label/relation maps
- Import parent-child and issue relations as Beads dependencies
- Support custom workflow states via linear.state_map.* config

* Add incremental sync support for Linear integration

- Add FetchIssuesSince() method using updatedAt filter in GraphQL
- Check linear.last_sync config to enable incremental pulls
- Track sync mode (incremental vs full) in LinearPullStats

* feat(linear): implement push updates for existing Linear issues

Add FetchIssueByIdentifier method to retrieve single issues by identifier
(e.g., "TEAM-123") for timestamp comparison during push.

Update doPushToLinear to:
- Fetch Linear issue to get internal ID and UpdatedAt timestamp
- Compare timestamps: only update if local is newer
- Build update payload with title, description, priority, and state
- Call UpdateIssue for issues where local has newer changes

Closes bd-b6b.5

* Implement Linear conflict resolution strategies

- Add true conflict detection by fetching Linear timestamps via API
- Implement --prefer-linear resolution (re-import from Linear)
- Implement timestamp-based resolution (newer wins as default)
- Fix linter issues: handle resp.Body.Close() and remove unused error return

* Add Linear integration tests and documentation

- Add comprehensive unit tests for Linear mapping (priority, state, labels, relations)
- Update docs/CONFIG.md with Linear configuration reference
- Add examples/linear-workflow guide for bidirectional sync
- Remove AI section header comments from tests

* Fix Linear GraphQL filter construction and improve test coverage

- Refactor filter handling to combine team ID into main filter object
- Add test for duplicate issue relation mapping
- Add HTTP round-trip helper for testing request payload validation

* Refactor Linear queries to use shared constant and add UUID validation

- Extract linearIssuesQuery to deduplicate FetchIssues/FetchIssuesSince
- Add linearMaxPageSize constant and UUID validation with regex
- Expand test coverage for new functionality

* Refactor Linear integration into internal/linear package

- Extract types, client, and mapping logic from cmd/bd/linear.go
- Create internal/linear/ package for better code organization
- Update tests to work with new package structure

* Add linear teams command to list available teams

- Add FetchTeams GraphQL query to Linear client
- Refactor config reading to support daemon mode
- Add tests for teams listing functionality

* Refactor Linear config to use getLinearConfig helper

- Consolidate config/env var lookup using getLinearConfig function
- Add LINEAR_TEAM_ID environment variable support
- Update error messages to include env var configuration options

* Add hash ID generation and improve Linear conflict detection

- Add configurable hash ID mode for Linear imports (matches bd/Jira)
- Improve conflict detection with content hash comparison
- Enhance conflict resolution with skip/force update tracking

* Fix test for updated doPushToLinear signature

- Add missing skipUpdateIDs parameter to test call
2025-12-19 17:58:24 -08:00
Charles P. Cross
a82f393e49 fix(storage): implement RenameDependencyPrefix to preserve dependencies (#642)
* fix(storage): implement RenameDependencyPrefix to update dependency records

RenameDependencyPrefix was previously a no-op that returned nil without
updating any records. This caused dependencies to break after using
bd rename-prefix, as the issue_id and depends_on_id columns in the
dependencies table still referenced the old prefix.

The fix updates both columns in the dependencies table to use the new
prefix, ensuring all dependency relationships are preserved.

Fixes #630

* test(storage): add regression tests for RenameDependencyPrefix

Add tests verifying that RenameDependencyPrefix:
- Executes without error when no dependencies exist
- Can be called with various prefix combinations

These tests ensure the fix for GH#630 doesn't regress.

---------

Co-authored-by: Charles P. Cross <cpdata@users.noreply.github.com>
2025-12-19 17:52:44 -08:00
Charles P. Cross
81aa301649 fix(syncbranch): support bare repos and worktrees with git-common-dir (#641)
* fix(syncbranch): support bare repos and worktrees with git-common-dir

Replace hardcoded .git/beads-worktrees/ path with dynamic detection using
git rev-parse --git-common-dir. This correctly handles:

- Regular repositories (.git is a directory)
- Git worktrees (.git is a file pointing elsewhere)
- Bare repositories (no .git directory, repo IS the git dir)
- Worktrees of bare repositories

The new getBeadsWorktreePath() helper uses git's native API to find the
shared git directory, ensuring beads worktrees are created in the correct
location regardless of repository structure.

Updated functions:
- CommitToSyncBranch
- PullFromSyncBranch
- CheckDivergence
- ResetToRemote

Fixes #639

* test(syncbranch): add regression tests for getBeadsWorktreePath

Add comprehensive tests for the worktree path calculation to ensure proper
handling of various repository structures:

- Regular repos: uses .git/beads-worktrees path
- Bare repos: uses <bare-repo>/beads-worktrees (no .git subdirectory)
- Worktrees: uses main repo's .git/beads-worktrees (git-common-dir)
- Fallback: legacy behavior when git command fails
- Relative paths: ensures absolute path conversion

These tests ensure the fix for GH#639 doesn't regress.

---------

Co-authored-by: Charles P. Cross <cpdata@users.noreply.github.com>
2025-12-19 17:52:40 -08:00