When `bd dep add` fails to resolve the dependency ID locally, it now
checks routes.jsonl for a matching prefix and auto-converts to an
external reference format (external:<project>:<id>).
This allows simpler syntax like:
bd dep add gt-xyz bd-abc
Instead of the verbose:
bd dep add gt-xyz external:beads:bd-abc
New functions in routing package:
- ExtractProjectFromPath: Gets project name from route path
- ResolveToExternalRef: Converts foreign ID to external ref using routes
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The verb 'wisp' fits the chemistry metaphor (pour, bond, burn, squash)
while 'ephemeral' is an adjective. The internal API field remains
'Ephemeral' but the CLI command is now 'bd mol wisp'.
Commands:
bd mol wisp <proto> - create ephemeral wisp
bd mol wisp list - list wisps
bd mol wisp gc - garbage collect old wisps
For consistency, all molecule operations are now under bd mol:
- bd mol pour <proto> - create persistent mol
- bd mol ephemeral <proto> - create ephemeral mol
- bd mol ephemeral list - list ephemeral issues
- bd mol ephemeral gc - garbage collect old ephemeral issues
This aligns with existing mol subcommands: bond, squash, burn, etc.
The --resolution flag was accidentally removed by a bd sync commit.
This restores the hidden alias for --reason, following Jira CLI convention.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Writes activity.json to ~/gt/daemon/ when bd runs inside a Gas Town
workspace. This enables the daemon to detect bd usage and adjust its
polling frequency with exponential backoff.
Best-effort: silently skips if not in Gas Town or on any error.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
created_by was recently added in c3ef1c3f38 but was missing support for passing in the CreatedBy through the RPC path so a create that was using the daemon was never having the created_by field set.
The defer-in-loop pattern was causing all routed storage connections
to accumulate until function exit. This could lead to resource leaks
when showing multiple routed issues. Now explicitly close each
connection after processing each issue.
(bd-uu8p)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When an ID needs routing to a different beads directory, the daemon
cannot resolve it. Now we check needsRouting() before daemon resolution
and handle routed IDs via direct mode with routing.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Enables cross-repo issue lookups via routes.jsonl configuration.
Running `bd show gt-xyz` from ~/gt now routes to the correct beads
directory based on the issue ID prefix.
- Add internal/routing/routes.go with routing logic
- Add cmd/bd/routed.go with routed storage helpers
- Update show command to use routed resolution in direct mode
- Support redirect files for canonical database locations
- Debug output available via BD_DEBUG_ROUTING=1
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add a created_by field to track who created each issue, similar to how
comments have an author field.
- Add CreatedBy string field to Issue struct
- Add migration 029 to add created_by column to issues table
- Update all SELECT/INSERT/Scan statements across storage layer
- Populate created_by in bd create from actor chain
- Display created_by in bd show output
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The CheckChildParentDependencies detection and ChildParentDependencies fix
were flagging ALL child→parent dependencies, including legitimate
'parent-child' type structural hierarchy relationships.
Now only blocking types (blocks, conditional-blocks, waits-for) are
detected as anti-patterns. The 'parent-child' type is a legitimate
hierarchy marker used for:
- Tracking parent-child relationships
- Transitive block propagation (if parent blocked, children blocked)
- Hierarchy visualization in external tools
Changes:
- Add type filter to SELECT queries (only blocking types)
- Add type filter to DELETE statement (preserve parent-child)
- Add regression test TestChildParentDependencies_PreservesParentChildType
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Mail gates check for messages matching the pattern (await_id):
- Case-insensitive substring match on message subjects
- If waiters specified, only matches messages to those recipients
- Closes gate when matching message found
Note: Full testing blocked by bd-70c4 (await fields being cleared).
The code is correct but gate fields get corrupted by auto-import.
Also adds context and storage imports for mail gate function.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Human gates now have proper workflow:
- Create with: bd gate create --await human:approve-deploy
- Approve with: bd gate approve <gate-id> [--comment "reason"]
- bd gate eval now reports human gates as "awaiting approval"
- Rejects non-human gates with clear error message
Also added mail gate placeholder in eval (awaiting mail: ...).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The merged field does not exist in gh pr view output. The actual
fields are:
- state: OPEN, CLOSED, or MERGED
- mergedAt: timestamp string (empty if not merged)
Also simplified the switch statement since state already distinguishes
merged vs closed-without-merge PRs.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements evaluation for GitHub-related gate types:
- gh:run: Checks if a GitHub Actions run has completed using
`gh run view <id> --json status,conclusion`
- gh:pr: Checks if a PR has been merged/closed using
`gh pr view <id> --json state,merged`
Both gate types require the gh CLI to be installed and authenticated.
If gh fails (not installed, network issues, invalid IDs), the gate is
skipped rather than erroneously closed.
Refactors the eval loop to use a switch statement for cleaner
gate type dispatch.
(gt-twjr5.3)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- New `bd gate eval` command evaluates all open gates and closes elapsed ones
- Timer gates: closes when elapsed time exceeds timeout duration
- For timer gates, parse duration from await_id if --timeout not explicitly set
- Supports --dry-run and --json output modes
- Idempotent and safe to run repeatedly (e.g., in Deacon patrol)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add TOML parsing using BurntSushi/toml
- Update formula loader to try .toml first, fall back to .json
- Add `bd formula convert` command for JSON→TOML migration
- Multi-line string support for readable descriptions
- Cache git worktree/reporoot checks for performance
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When bd init runs in a forked repo (detected via upstream remote), prompt
the user to configure .git/info/exclude to keep beads files local.
- Add --setup-exclude flag for manual trigger
- Add fork detection to init flow (reuses detectForkSetup)
- Add setupForkExclude() to configure .git/info/exclude with:
.beads/, **/RECOVERY*.md, **/SESSION*.md
- Add promptForkExclude() with Y/n prompt (default yes)
- Add containsExactPattern() helper for precise pattern matching
🤖 Generated with Claude Code
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(ready,blocked): Add --parent flag for scoping by epic/bead descendants
Add --parent flag to `bd ready` and `bd blocked` CLI commands and MCP tools
to filter results to all descendants of a specific epic or bead.
## Backward Compatibility
- CLI: New optional --parent flag; existing usage unchanged
- RPC: New `blocked` operation added (was missing); existing operations unchanged
- MCP: New optional `parent` parameter; existing calls work as before
- Storage interface: GetBlockedIssues signature changed to accept WorkFilter
- All callers updated to pass empty filter for existing behavior
- Empty WorkFilter{} returns identical results to previous implementation
## Implementation Details
SQLite uses recursive CTE to traverse parent-child hierarchy:
WITH RECURSIVE descendants AS (
SELECT issue_id FROM dependencies
WHERE type = 'parent-child' AND depends_on_id = ?
UNION ALL
SELECT d.issue_id FROM dependencies d
JOIN descendants dt ON d.depends_on_id = dt.issue_id
WHERE d.type = 'parent-child'
)
SELECT issue_id FROM descendants
MemoryStorage implements equivalent recursive traversal with visited-set
cycle protection via collectDescendants helper.
Parent filter composes with existing filters (priority, labels, assignee, etc.)
as an additional WHERE clause - all filters are AND'd together.
## RPC Blocked Support
MCP beads_blocked() existed but daemon client raised NotImplementedError.
Added OpBlocked and handleBlocked to enable daemon RPC path, which was
previously broken. Now both CLI and daemon clients work for blocked queries.
## Changes
- internal/types/types.go: Add ParentID *string to WorkFilter
- internal/storage/sqlite/ready.go: Add recursive CTE for parent filtering
- internal/storage/memory/memory.go: Add getAllDescendants/collectDescendants
- internal/storage/storage.go: Update GetBlockedIssues interface signature
- cmd/bd/ready.go: Add --parent flag to ready and blocked commands
- internal/rpc/protocol.go: Add OpBlocked constant and BlockedArgs type
- internal/rpc/server_issues_epics.go: Add handleBlocked RPC handler
- internal/rpc/client.go: Add Blocked client method
- integrations/beads-mcp/: Add BlockedParams model and parent parameter
## Usage
bd ready --parent bd-abc # All ready descendants
bd ready --parent bd-abc --priority 1 # Combined with other filters
bd blocked --parent bd-abc # All blocked descendants
## Testing
Added 4 test cases for parent filtering:
- TestParentIDFilterDescendants: Verifies recursive traversal (grandchildren)
- TestParentIDWithOtherFilters: Verifies composition with priority filter
- TestParentIDWithBlockedDescendants: Verifies blocked issues excluded from ready
- TestParentIDEmptyParent: Verifies empty result for childless parent
* fix: Correct blockedCmd indentation and suppress gosec false positive
- Fix syntax error from incorrect indentation in blockedCmd Run function
- Add nolint:gosec comment for GetBlockedIssues SQL formatting (G201)
The filterSQL variable contains only parameterized WHERE clauses with
? placeholders, not user input
Steps can now declare their own expansion using the Expand field:
steps:
- id: design
expand: rule-of-five
expand_vars:
iterations: 3
This is more convenient than compose.expand for single-step expansions.
The step is replaced by the expansion template with variables substituted.
Reuses existing expandStep() and mergeVars() from gt-8tmz.34.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When closing an issue, the new --suggest-next flag returns a list of
issues that became unblocked (ready to work on) as a result of the close.
This helps agents and users quickly identify what work is now available
after completing a blocker.
Example:
$ bd close bd-5 --suggest-next
✓ Closed bd-5: Completed
Newly unblocked:
• bd-7 "Implement feature X" (P1)
• bd-8 "Write tests for X" (P2)
Implementation:
- Added GetNewlyUnblockedByClose to storage interface
- Implemented efficient single-query for SQLite using blocked_issues_cache
- Added SuggestNext field to CloseArgs in RPC protocol
- Added CloseResult type for structured response
- CLI handles both daemon and direct modes
Thanks to @kraitsura for the detailed feature request and design.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update help text to clarify mol/wisp/epic support (not just epics)
- Add daemon support (no longer requires --no-daemon)
- Add -o shorthand for --output flag
- Update use cases to match new architecture
Part of bd-1dez.1
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix YAML → JSON references in formula.go and types.go
- Update MOLECULES.md with ephemeral proto architecture
- Add Distillation section: extract formulas from completed work
- Add Sharing section: Mol Mall formula marketplace
- Update Layer Cake diagram to show ephemeral proto flow
Related: bd-1dez (Mol Mall epic)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add --mode flag (compile/runtime) and --var flag to bd cook command.
Compile-time mode (default):
- Keeps {{variable}} placeholders intact
- Use for: modeling, estimation, contractor handoff
Runtime mode (triggered by --var or --mode=runtime):
- Substitutes variables with provided values
- Validates all required variables have values
- Use for: final validation before pour
Also updates --dry-run output to clearly show which mode is active
and display substituted values in runtime mode.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The ephemeral proto path (collectDependenciesToSubgraph) was missing
waits_for handling that was already implemented in collectDependencies
for persisted protos. This ensures fanout gate dependencies are created
correctly for both ephemeral and persisted formula cooking.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add children-of(step-id) syntax for explicit spawner reference
- Add WaitsForSpec type and ParseWaitsFor() helper
- Update cook.go to create DepWaitsFor dependencies with metadata
- Infer spawner from first needs entry when using all-children
- Add validation tests for children-of() syntax
- Add unit tests for ParseWaitsFor()
This completes the Christmas Ornament aggregation pattern:
- survey-workers does for-each → creates N children
- aggregate waits-for children-of(survey-workers)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Major refactor of molecular chemistry to make protos ephemeral:
- Formulas are now cooked directly to in-memory TemplateSubgraph
- No more proto beads stored in the database
Changes:
- cook.go: Add cookFormulaToSubgraph() and resolveAndCookFormula()
for in-memory formula cooking
- template.go: Add VarDefs field to TemplateSubgraph for default
value handling, add extractRequiredVariables() and
applyVariableDefaults() helpers
- pour.go: Try formula loading first for any name (not just mol-)
- wisp.go: Same pattern as pour
- mol_bond.go: Use resolveOrCookToSubgraph() for in-memory subgraphs
- mol_catalog.go: List formulas from disk instead of DB proto beads
- mol_distill.go: Output .formula.json files instead of proto beads
Flow: Formula (.formula.json) -> pour/wisp (cook inline) -> Mol/Wisp
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove resolvePartialIDDirect function and context import that became
dead code after switching to resolveOrCookFormula in bd-rciw.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changes:
- bd cook: outputs proto JSON to stdout by default, add --persist flag
for legacy behavior (write to database)
- bd pour: accepts formula names, cooks inline as ephemeral proto,
spawns mol, then cleans up temporary proto
- bd wisp create: accepts formula names, cooks inline as ephemeral proto,
creates wisp, then cleans up temporary proto
- bd mol bond: already supported ephemeral protos (gt-8tmz.25)
The ephemeral proto pattern avoids persisting templates in the database.
Protos are only needed temporarily during spawn operations - the spawned
mol/wisp is what gets persisted.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fixes from review of gt-8tmz.25 implementation:
1. Dry-run no longer cooks formulas - added resolveOrDescribe() for
dry-run mode that checks if operand exists without cooking
2. Ephemeral protos now cleaned up after successful bond, not just
on error
3. Unique proto IDs to avoid collision - ephemeral protos use format
"_ephemeral-<formula>-<timestamp>" instead of formula name
4. Removed unused vars parameter from resolveOrCookFormula
5. Added informative output showing formulas will be cooked and
cleaned up
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Bond command now accepts formula names (e.g., mol-polecat-arm) in addition
to issue IDs. When a formula name is given:
1. Looks up the formula using formula.Parser
2. Resolves inheritance and applies transformations (control flow, advice,
expansions, aspects)
3. Cooks the formula inline to create an ephemeral proto
4. Uses the cooked proto for bonding
This eliminates the need for pre-cooked proto beads in the database,
enabling more dynamic workflow composition.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add SourceFormula and SourceLocation fields to track where each step
came from during the cooking process. This enables debugging of complex
compositions with inheritance, expansion, and advice.
Changes:
- Added SourceFormula and SourceLocation fields to Step struct (formula/types.go)
- Added same fields to Issue struct (types/types.go)
- Added SetSourceInfo() to parser.go - sets source on all steps after parsing
- Updated cook.go to copy source fields from Step to Issue
- Updated dry-run output to display source info: [from: formula@location]
- Updated advice.go to set source on advice-generated steps
- Updated controlflow.go to preserve source on loop-expanded steps
- Updated expand.go to preserve source on template-expanded steps
The source location format is:
- steps[N] - regular step at index N
- steps[N].children[M] - child step
- steps[N].loop.body[M] - loop body step
- template[N] - expansion template step
- advice - step inserted by advice transformation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Claude Code's installed_plugins.json changed from v1 (plugins as structs)
to v2 (plugins as arrays). Update GetClaudePluginVersion() to handle both.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>