beads

package
v0.1.0-alpha.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 31, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Index

Constants

View Source
const (
	StatusOpen       = "open"        // Default status for new issues
	StatusInProgress = "in_progress" // Issue is being actively worked on
	StatusBlocked    = "blocked"     // Issue cannot proceed due to dependencies
	StatusDeferred   = "deferred"    // Issue is postponed (not actively worked on)
	StatusClosed     = "closed"      // Issue is completed or resolved
)

Bead status constants. These are the canonical status values used by the beads issue tracker.

Variables

This section is empty.

Functions

func AddComment

func AddComment(ctx context.Context, beadID, comment, beadsDir string) error

AddComment adds a comment to a bead.

func AddDependency

func AddDependency(ctx context.Context, beadID, dependsOnID, beadsDir string) error

AddDependency adds a dependency between two beads. The bead identified by beadID will depend on the bead identified by dependsOnID.

func AddLabels

func AddLabels(ctx context.Context, beadID, beadsDir string, labels []string) error

AddLabels adds labels to a bead.

func Close

func Close(ctx context.Context, beadID, beadsDir string) error

Close closes a bead.

func Create

func Create(ctx context.Context, beadsDir string, opts CreateOptions) (string, error)

Create creates a new bead and returns its ID.

func EditCommand

func EditCommand(ctx context.Context, beadID, beadsDir string) *exec.Cmd

EditCommand returns an exec.Cmd for opening a bead in an editor. This is meant to be used with tea.ExecProcess for interactive editing.

func Init

func Init(_ context.Context, beadsDir, prefix string) error

Init initializes beads in the specified directory. beadsDir should be the path where .beads/ should be created (e.g., /path/to/.beads). prefix is the issue ID prefix (e.g., "myproject" for myproject-1, myproject-2). bd init runs in the parent directory and creates .beads/ there. Uses mise exec to run bd commands since mise-managed tools may not be in PATH.

func InstallHooks

func InstallHooks(_ context.Context, repoDir string) error

InstallHooks installs beads hooks in the specified directory. repoDir should be the path to the git repository (e.g., /path/to/repo). Uses mise exec to run bd commands since mise-managed tools may not be in PATH.

func IsWorkableStatus

func IsWorkableStatus(status string) bool

IsWorkableStatus returns true if the status indicates the bead can be worked on. This includes open and in_progress statuses (not blocked or deferred).

func Reinit

func Reinit(_ context.Context, repoDir string) error

Reinit regenerates the beads database from existing JSONL files. repoDir should be the path to the repository containing .beads/ directory. This is used when the .beads directory already exists and we just need to rebuild the database. Uses mise exec to run bd commands since mise-managed tools may not be in PATH.

func Reopen

func Reopen(ctx context.Context, beadID, beadsDir string) error

Reopen reopens a closed bead.

func SetExternalRef

func SetExternalRef(ctx context.Context, beadID, externalRef, beadsDir string) error

SetExternalRef sets the external reference for a bead.

func Update

func Update(ctx context.Context, beadID, beadsDir string, opts UpdateOptions) error

Update updates a bead's fields.

Types

type Bead

type Bead struct {
	ID                 string
	Title              string
	Description        string
	Design             string
	AcceptanceCriteria string
	Notes              string
	Status             string
	Priority           int
	Type               string // issue_type in the database
	Assignee           string
	EstimatedMinutes   int
	CreatedAt          time.Time
	CreatedBy          string
	Owner              string
	UpdatedAt          time.Time
	ClosedAt           time.Time
	CloseReason        string
	ExternalRef        string
	IsEpic             bool // derived from issue_type == "epic"
}

Bead is a clean wrapper around queries.Issue without SQL null types.

func BeadFromIssue

func BeadFromIssue(issue queries.Issue) Bead

BeadFromIssue converts a queries.Issue to a clean Bead.

type BeadWithDeps

type BeadWithDeps struct {
	*Bead
	Dependencies []Dependency
	Dependents   []Dependent
}

BeadWithDeps bundles a bead with its dependencies and dependents.

type BeadsCLIMock

type BeadsCLIMock struct {
	// AddCommentFunc mocks the AddComment method.
	AddCommentFunc func(ctx context.Context, beadID string, comment string) error

	// AddDependencyFunc mocks the AddDependency method.
	AddDependencyFunc func(ctx context.Context, beadID string, dependsOnID string) error

	// AddLabelsFunc mocks the AddLabels method.
	AddLabelsFunc func(ctx context.Context, beadID string, labels []string) error

	// CloseFunc mocks the Close method.
	CloseFunc func(ctx context.Context, beadID string) error

	// CreateFunc mocks the Create method.
	CreateFunc func(ctx context.Context, opts CreateOptions) (string, error)

	// ReopenFunc mocks the Reopen method.
	ReopenFunc func(ctx context.Context, beadID string) error

	// SetExternalRefFunc mocks the SetExternalRef method.
	SetExternalRefFunc func(ctx context.Context, beadID string, externalRef string) error

	// UpdateFunc mocks the Update method.
	UpdateFunc func(ctx context.Context, beadID string, opts UpdateOptions) error
	// contains filtered or unexported fields
}

BeadsCLIMock is a mock implementation of CLI.

func TestSomethingThatUsesCLI(t *testing.T) {

	// make and configure a mocked CLI
	mockedCLI := &BeadsCLIMock{
		AddCommentFunc: func(ctx context.Context, beadID string, comment string) error {
			panic("mock out the AddComment method")
		},
		AddDependencyFunc: func(ctx context.Context, beadID string, dependsOnID string) error {
			panic("mock out the AddDependency method")
		},
		AddLabelsFunc: func(ctx context.Context, beadID string, labels []string) error {
			panic("mock out the AddLabels method")
		},
		CloseFunc: func(ctx context.Context, beadID string) error {
			panic("mock out the Close method")
		},
		CreateFunc: func(ctx context.Context, opts CreateOptions) (string, error) {
			panic("mock out the Create method")
		},
		ReopenFunc: func(ctx context.Context, beadID string) error {
			panic("mock out the Reopen method")
		},
		SetExternalRefFunc: func(ctx context.Context, beadID string, externalRef string) error {
			panic("mock out the SetExternalRef method")
		},
		UpdateFunc: func(ctx context.Context, beadID string, opts UpdateOptions) error {
			panic("mock out the Update method")
		},
	}

	// use mockedCLI in code that requires CLI
	// and then make assertions.

}

func (*BeadsCLIMock) AddComment

func (mock *BeadsCLIMock) AddComment(ctx context.Context, beadID string, comment string) error

AddComment calls AddCommentFunc.

func (*BeadsCLIMock) AddCommentCalls

func (mock *BeadsCLIMock) AddCommentCalls() []struct {
	Ctx     context.Context
	BeadID  string
	Comment string
}

AddCommentCalls gets all the calls that were made to AddComment. Check the length with:

len(mockedCLI.AddCommentCalls())

func (*BeadsCLIMock) AddDependency

func (mock *BeadsCLIMock) AddDependency(ctx context.Context, beadID string, dependsOnID string) error

AddDependency calls AddDependencyFunc.

func (*BeadsCLIMock) AddDependencyCalls

func (mock *BeadsCLIMock) AddDependencyCalls() []struct {
	Ctx         context.Context
	BeadID      string
	DependsOnID string
}

AddDependencyCalls gets all the calls that were made to AddDependency. Check the length with:

len(mockedCLI.AddDependencyCalls())

func (*BeadsCLIMock) AddLabels

func (mock *BeadsCLIMock) AddLabels(ctx context.Context, beadID string, labels []string) error

AddLabels calls AddLabelsFunc.

func (*BeadsCLIMock) AddLabelsCalls

func (mock *BeadsCLIMock) AddLabelsCalls() []struct {
	Ctx    context.Context
	BeadID string
	Labels []string
}

AddLabelsCalls gets all the calls that were made to AddLabels. Check the length with:

len(mockedCLI.AddLabelsCalls())

func (*BeadsCLIMock) Close

func (mock *BeadsCLIMock) Close(ctx context.Context, beadID string) error

Close calls CloseFunc.

func (*BeadsCLIMock) CloseCalls

func (mock *BeadsCLIMock) CloseCalls() []struct {
	Ctx    context.Context
	BeadID string
}

CloseCalls gets all the calls that were made to Close. Check the length with:

len(mockedCLI.CloseCalls())

func (*BeadsCLIMock) Create

func (mock *BeadsCLIMock) Create(ctx context.Context, opts CreateOptions) (string, error)

Create calls CreateFunc.

func (*BeadsCLIMock) CreateCalls

func (mock *BeadsCLIMock) CreateCalls() []struct {
	Ctx  context.Context
	Opts CreateOptions
}

CreateCalls gets all the calls that were made to Create. Check the length with:

len(mockedCLI.CreateCalls())

func (*BeadsCLIMock) Reopen

func (mock *BeadsCLIMock) Reopen(ctx context.Context, beadID string) error

Reopen calls ReopenFunc.

func (*BeadsCLIMock) ReopenCalls

func (mock *BeadsCLIMock) ReopenCalls() []struct {
	Ctx    context.Context
	BeadID string
}

ReopenCalls gets all the calls that were made to Reopen. Check the length with:

len(mockedCLI.ReopenCalls())

func (*BeadsCLIMock) SetExternalRef

func (mock *BeadsCLIMock) SetExternalRef(ctx context.Context, beadID string, externalRef string) error

SetExternalRef calls SetExternalRefFunc.

func (*BeadsCLIMock) SetExternalRefCalls

func (mock *BeadsCLIMock) SetExternalRefCalls() []struct {
	Ctx         context.Context
	BeadID      string
	ExternalRef string
}

SetExternalRefCalls gets all the calls that were made to SetExternalRef. Check the length with:

len(mockedCLI.SetExternalRefCalls())

func (*BeadsCLIMock) Update

func (mock *BeadsCLIMock) Update(ctx context.Context, beadID string, opts UpdateOptions) error

Update calls UpdateFunc.

func (*BeadsCLIMock) UpdateCalls

func (mock *BeadsCLIMock) UpdateCalls() []struct {
	Ctx    context.Context
	BeadID string
	Opts   UpdateOptions
}

UpdateCalls gets all the calls that were made to Update. Check the length with:

len(mockedCLI.UpdateCalls())

type BeadsReaderMock

type BeadsReaderMock struct {
	// GetBeadFunc mocks the GetBead method.
	GetBeadFunc func(ctx context.Context, id string) (*BeadWithDeps, error)

	// GetBeadWithChildrenFunc mocks the GetBeadWithChildren method.
	GetBeadWithChildrenFunc func(ctx context.Context, id string) ([]Bead, error)

	// GetBeadsWithDepsFunc mocks the GetBeadsWithDeps method.
	GetBeadsWithDepsFunc func(ctx context.Context, beadIDs []string) (*BeadsWithDepsResult, error)

	// GetReadyBeadsFunc mocks the GetReadyBeads method.
	GetReadyBeadsFunc func(ctx context.Context) ([]Bead, error)

	// GetTransitiveDependenciesFunc mocks the GetTransitiveDependencies method.
	GetTransitiveDependenciesFunc func(ctx context.Context, id string) ([]Bead, error)

	// ListBeadsFunc mocks the ListBeads method.
	ListBeadsFunc func(ctx context.Context, status string) ([]Bead, error)
	// contains filtered or unexported fields
}

BeadsReaderMock is a mock implementation of Reader.

func TestSomethingThatUsesReader(t *testing.T) {

	// make and configure a mocked Reader
	mockedReader := &BeadsReaderMock{
		GetBeadFunc: func(ctx context.Context, id string) (*BeadWithDeps, error) {
			panic("mock out the GetBead method")
		},
		GetBeadWithChildrenFunc: func(ctx context.Context, id string) ([]Bead, error) {
			panic("mock out the GetBeadWithChildren method")
		},
		GetBeadsWithDepsFunc: func(ctx context.Context, beadIDs []string) (*BeadsWithDepsResult, error) {
			panic("mock out the GetBeadsWithDeps method")
		},
		GetReadyBeadsFunc: func(ctx context.Context) ([]Bead, error) {
			panic("mock out the GetReadyBeads method")
		},
		GetTransitiveDependenciesFunc: func(ctx context.Context, id string) ([]Bead, error) {
			panic("mock out the GetTransitiveDependencies method")
		},
		ListBeadsFunc: func(ctx context.Context, status string) ([]Bead, error) {
			panic("mock out the ListBeads method")
		},
	}

	// use mockedReader in code that requires Reader
	// and then make assertions.

}

func (*BeadsReaderMock) GetBead

func (mock *BeadsReaderMock) GetBead(ctx context.Context, id string) (*BeadWithDeps, error)

GetBead calls GetBeadFunc.

func (*BeadsReaderMock) GetBeadCalls

func (mock *BeadsReaderMock) GetBeadCalls() []struct {
	Ctx context.Context
	ID  string
}

GetBeadCalls gets all the calls that were made to GetBead. Check the length with:

len(mockedReader.GetBeadCalls())

func (*BeadsReaderMock) GetBeadWithChildren

func (mock *BeadsReaderMock) GetBeadWithChildren(ctx context.Context, id string) ([]Bead, error)

GetBeadWithChildren calls GetBeadWithChildrenFunc.

func (*BeadsReaderMock) GetBeadWithChildrenCalls

func (mock *BeadsReaderMock) GetBeadWithChildrenCalls() []struct {
	Ctx context.Context
	ID  string
}

GetBeadWithChildrenCalls gets all the calls that were made to GetBeadWithChildren. Check the length with:

len(mockedReader.GetBeadWithChildrenCalls())

func (*BeadsReaderMock) GetBeadsWithDeps

func (mock *BeadsReaderMock) GetBeadsWithDeps(ctx context.Context, beadIDs []string) (*BeadsWithDepsResult, error)

GetBeadsWithDeps calls GetBeadsWithDepsFunc.

func (*BeadsReaderMock) GetBeadsWithDepsCalls

func (mock *BeadsReaderMock) GetBeadsWithDepsCalls() []struct {
	Ctx     context.Context
	BeadIDs []string
}

GetBeadsWithDepsCalls gets all the calls that were made to GetBeadsWithDeps. Check the length with:

len(mockedReader.GetBeadsWithDepsCalls())

func (*BeadsReaderMock) GetReadyBeads

func (mock *BeadsReaderMock) GetReadyBeads(ctx context.Context) ([]Bead, error)

GetReadyBeads calls GetReadyBeadsFunc.

func (*BeadsReaderMock) GetReadyBeadsCalls

func (mock *BeadsReaderMock) GetReadyBeadsCalls() []struct {
	Ctx context.Context
}

GetReadyBeadsCalls gets all the calls that were made to GetReadyBeads. Check the length with:

len(mockedReader.GetReadyBeadsCalls())

func (*BeadsReaderMock) GetTransitiveDependencies

func (mock *BeadsReaderMock) GetTransitiveDependencies(ctx context.Context, id string) ([]Bead, error)

GetTransitiveDependencies calls GetTransitiveDependenciesFunc.

func (*BeadsReaderMock) GetTransitiveDependenciesCalls

func (mock *BeadsReaderMock) GetTransitiveDependenciesCalls() []struct {
	Ctx context.Context
	ID  string
}

GetTransitiveDependenciesCalls gets all the calls that were made to GetTransitiveDependencies. Check the length with:

len(mockedReader.GetTransitiveDependenciesCalls())

func (*BeadsReaderMock) ListBeads

func (mock *BeadsReaderMock) ListBeads(ctx context.Context, status string) ([]Bead, error)

ListBeads calls ListBeadsFunc.

func (*BeadsReaderMock) ListBeadsCalls

func (mock *BeadsReaderMock) ListBeadsCalls() []struct {
	Ctx    context.Context
	Status string
}

ListBeadsCalls gets all the calls that were made to ListBeads. Check the length with:

len(mockedReader.ListBeadsCalls())

type BeadsWithDepsResult

type BeadsWithDepsResult struct {
	Beads        map[string]Bead
	Dependencies map[string][]Dependency
	Dependents   map[string][]Dependent
}

BeadsWithDepsResult holds the result of GetBeadsWithDeps.

func (*BeadsWithDepsResult) GetBead

func (r *BeadsWithDepsResult) GetBead(id string) *BeadWithDeps

GetBead returns a single BeadWithDeps from the result, or nil if not found.

type CLI

type CLI interface {
	// Create creates a new bead and returns its ID.
	Create(ctx context.Context, opts CreateOptions) (string, error)
	// Close closes a bead.
	Close(ctx context.Context, beadID string) error
	// Reopen reopens a closed bead.
	Reopen(ctx context.Context, beadID string) error
	// Update updates a bead's fields.
	Update(ctx context.Context, beadID string, opts UpdateOptions) error
	// AddComment adds a comment to a bead.
	AddComment(ctx context.Context, beadID, comment string) error
	// AddLabels adds labels to a bead.
	AddLabels(ctx context.Context, beadID string, labels []string) error
	// SetExternalRef sets the external reference for a bead.
	SetExternalRef(ctx context.Context, beadID, externalRef string) error
	// AddDependency adds a dependency between two beads.
	AddDependency(ctx context.Context, beadID, dependsOnID string) error
}

CLI defines the interface for bd command operations. This abstraction enables testing without actual bd CLI calls. Each CLI instance is bound to a specific beads directory.

Note: Init and InstallHooks are package-level functions, not part of this interface, since they are setup operations that run before a CLI is created.

func NewCLI

func NewCLI(beadsDir string) CLI

NewCLI creates a new CLI instance bound to the specified beads directory.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client provides database access to beads with caching.

func NewClient

func NewClient(ctx context.Context, cfg ClientConfig) (*Client, error)

NewClient creates a new beads database client.

func (*Client) Close

func (c *Client) Close() error

Close closes the database connection.

func (*Client) CloseEligibleParents

func (c *Client) CloseEligibleParents(ctx context.Context, beadsDir string) error

CloseEligibleParents closes any parent beads where all children are complete. Uses cached bead data to find eligible parents, then closes them via bd CLI. Works for any parent-child relationship, not just epics.

func (*Client) FlushCache

func (c *Client) FlushCache(ctx context.Context) error

FlushCache flushes the cache.

func (*Client) GetBead

func (c *Client) GetBead(ctx context.Context, id string) (*BeadWithDeps, error)

GetBead retrieves a single bead by ID with its dependencies/dependents. Returns nil if the bead is not found.

func (*Client) GetBeadWithChildren

func (c *Client) GetBeadWithChildren(ctx context.Context, id string) ([]Bead, error)

GetBeadWithChildren retrieves a bead and all its child beads recursively. This is useful for epic beads that have sub-beads (parent-child relationship).

func (*Client) GetBeadsWithDeps

func (c *Client) GetBeadsWithDeps(ctx context.Context, beadIDs []string) (*BeadsWithDepsResult, error)

GetBeadsWithDeps retrieves beads and their dependencies/dependents. Results are cached based on sorted bead IDs.

func (*Client) GetReadyBeads

func (c *Client) GetReadyBeads(ctx context.Context) ([]Bead, error)

GetReadyBeads returns all open beads where all dependencies are satisfied.

func (*Client) GetTransitiveDependencies

func (c *Client) GetTransitiveDependencies(ctx context.Context, id string) ([]Bead, error)

GetTransitiveDependencies collects all transitive dependencies for a bead. Returns beads in dependency order (dependencies before dependents).

func (*Client) ListBeads

func (c *Client) ListBeads(ctx context.Context, status string) ([]Bead, error)

ListBeads lists all beads with optional status filter. Pass empty string for status to get all beads.

type ClientConfig

type ClientConfig struct {
	DBPath           string
	CacheEnabled     bool
	CacheExpiration  time.Duration
	CacheCleanupTime time.Duration
}

ClientConfig holds configuration for the Client.

func DefaultClientConfig

func DefaultClientConfig(dbPath string) ClientConfig

DefaultClientConfig returns default configuration for the Client.

type CreateOptions

type CreateOptions struct {
	Title       string
	Type        string // "task", "bug", "feature"
	Priority    int
	IsEpic      bool
	Description string
	Parent      string   // Parent bead ID for hierarchical child
	Labels      []string // Optional labels for the bead
	ExternalRef string   // Optional external reference (e.g., GitHub comment ID)
}

CreateOptions specifies options for creating a bead.

type Dependency

type Dependency struct {
	IssueID     string
	DependsOnID string
	Type        string // "blocks", "blocked_by", "parent-child", "relates-to"
	Status      string // status of the depended-on issue
	Title       string // title of the depended-on issue
}

Dependency represents a dependency relationship between beads.

type Dependent

type Dependent struct {
	IssueID     string // the issue that depends on us
	DependsOnID string
	Type        string
	Status      string // status of the dependent issue
	Title       string // title of the dependent issue
}

Dependent represents a bead that depends on another bead.

type Reader

type Reader interface {
	// GetBead retrieves a single bead by ID with its dependencies/dependents.
	GetBead(ctx context.Context, id string) (*BeadWithDeps, error)
	// GetBeadsWithDeps retrieves beads and their dependencies/dependents.
	GetBeadsWithDeps(ctx context.Context, beadIDs []string) (*BeadsWithDepsResult, error)
	// ListBeads lists all beads with optional status filter.
	ListBeads(ctx context.Context, status string) ([]Bead, error)
	// GetReadyBeads returns all open beads where all dependencies are satisfied.
	GetReadyBeads(ctx context.Context) ([]Bead, error)
	// GetTransitiveDependencies collects all transitive dependencies for a bead.
	GetTransitiveDependencies(ctx context.Context, id string) ([]Bead, error)
	// GetBeadWithChildren retrieves a bead and all its child beads recursively.
	GetBeadWithChildren(ctx context.Context, id string) ([]Bead, error)
}

Reader defines the interface for reading beads from the database. This abstraction enables testing without actual database access.

type UpdateOptions

type UpdateOptions struct {
	Title       string
	Type        string
	Description string
	Assignee    string
	Priority    *int // nil means don't update
	Status      string
}

UpdateOptions specifies options for updating a bead.

Directories

Path Synopsis
Package pubsub provides a generic publish/subscribe event system.
Package pubsub provides a generic publish/subscribe event system.
Package watcher provides file system watching with debouncing for the beads database.
Package watcher provides file system watching with debouncing for the beads database.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL