Adds closed_by_session tracking for entity CV building per Gas Town decision 009-session-events-architecture.md. Changes: - Add ClosedBySession field to Issue struct - Add closed_by_session column to issues table (migration 034) - Add --session flag to bd close command - Support CLAUDE_SESSION_ID env var as fallback - Add --session flag to bd update for status=closed - Display closed_by_session in bd show output - Update Storage interface to include session parameter in CloseIssue 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> Executed-By: beads/crew/dave Rig: beads Role: crew
Beads Library Usage Example
This example demonstrates using Beads as a Go library in external projects (like VC).
Why Use Beads as a Library?
Instead of spawning bd CLI processes:
- ✅ Direct API access - Call functions directly instead of parsing JSON output
- ✅ Type safety - Compile-time checking of types and interfaces
- ✅ Performance - No process spawn overhead
- ✅ Transactions - Access to database transactions for complex operations
- ✅ Shared database - Multiple components can use same database connection
- ✅ Error handling - Proper Go error types instead of parsing stderr
Installation
In your Go project:
go get github.com/steveyegge/beads@latest
Basic Usage
package main
import (
"context"
"log"
"github.com/steveyegge/beads"
)
func main() {
ctx := context.Background()
// Find and open database
dbPath := beads.FindDatabasePath()
store, err := beads.NewSQLiteStorage(dbPath)
if err != nil {
log.Fatal(err)
}
defer store.Close()
// Get ready work
ready, err := store.GetReadyWork(ctx, beads.WorkFilter{
Status: beads.StatusOpen,
Limit: 10,
})
if err != nil {
log.Fatal(err)
}
// Process ready issues...
}
Running This Example
# From this directory
cd examples/library-usage
# Make sure there's a Beads database
bd init --prefix demo
# Run the example
go run main.go
Available Operations
The beads.Storage interface provides:
Issues
CreateIssue(ctx, issue, actor)- Create a new issueCreateIssues(ctx, issues, actor)- Batch create issuesGetIssue(ctx, id)- Get issue by IDUpdateIssue(ctx, id, updates, actor)- Update issue fieldsCloseIssue(ctx, id, reason, actor)- Close an issueSearchIssues(ctx, query, filter)- Search with filters
Dependencies
AddDependency(ctx, dep, actor)- Add dependency between issuesRemoveDependency(ctx, issueID, dependsOnID, actor)- Remove dependencyGetDependencies(ctx, issueID)- Get what this issue depends onGetDependents(ctx, issueID)- Get what depends on this issueGetDependencyTree(ctx, issueID, maxDepth, showAllPaths)- Visualize tree
Labels
AddLabel(ctx, issueID, label, actor)- Add label to issueRemoveLabel(ctx, issueID, label, actor)- Remove labelGetLabels(ctx, issueID)- Get all labels for an issueGetIssuesByLabel(ctx, label)- Find issues with label
Ready Work & Blocking
GetReadyWork(ctx, filter)- Find issues with no blockersGetBlockedIssues(ctx)- Find blocked issues with blocker infoGetEpicsEligibleForClosure(ctx)- Find completable epics
Comments & Events
AddIssueComment(ctx, issueID, author, text)- Add commentGetIssueComments(ctx, issueID)- Get all commentsGetEvents(ctx, issueID, limit)- Get audit trail
Statistics
GetStatistics(ctx)- Get aggregate metrics
Types
All types are exported via the beads package:
// Core types
beads.Issue
beads.Status (Open, InProgress, Closed, Blocked)
beads.IssueType (Bug, Feature, Task, Epic, Chore)
beads.Priority (0-4)
// Relationships
beads.Dependency
beads.DependencyType (Blocks, Related, ParentChild, DiscoveredFrom)
// Metadata
beads.Label
beads.Comment
beads.Event
// Queries
beads.IssueFilter
beads.WorkFilter
beads.BlockedIssue
beads.EpicStatus
beads.Statistics
VC Integration Example
For VC (VibeCoder), the integration would look like:
// In VC's storage layer
type VCStorage struct {
beads beads.Storage
}
func NewVCStorage(dbPath string) (*VCStorage, error) {
store, err := beads.NewSQLiteStorage(dbPath)
if err != nil {
return nil, err
}
return &VCStorage{beads: store}, nil
}
// Claim ready work for executor
func (s *VCStorage) ClaimWork(ctx context.Context, executorID string) (*beads.Issue, error) {
ready, err := s.beads.GetReadyWork(ctx, beads.WorkFilter{
Status: beads.StatusOpen,
Limit: 1,
})
if err != nil {
return nil, err
}
if len(ready) == 0 {
return nil, nil // No work available
}
issue := ready[0]
// Claim it
updates := map[string]interface{}{
"status": beads.StatusInProgress,
"assignee": executorID,
}
if err := s.beads.UpdateIssue(ctx, issue.ID, updates, executorID); err != nil {
return nil, err
}
return issue, nil
}
Best Practices
- Context - Always pass
context.Contextfor cancellation support - Actor - Provide meaningful actor strings for audit trail
- Error handling - Check all errors; database operations can fail
- Close - Always
defer store.Close()after opening - Transactions - For complex multi-step operations, consider using the underlying database connection directly
See Also
- EXTENDING.md - Detailed extension guide
- beads.go - Public API source
- internal/storage/storage.go - Storage interface