Bead Issue Tracking¶
Bead is a lightweight, git-native issue tracking system built into sase. It uses Rust-backed SQLite/query/mutation logic
through the required sase_core_rs extension, with JSONL export for git portability (inspired by
Fossil). Issues are organized into plan-like containers and executable child phases. Plan
beads can represent ordinary plans, executable epics, or legend-level roadmaps through their tier metadata.

Table of Contents¶
- Quick Start
- Data Model
- Issue Types
- Status Lifecycle
- Dependencies
- Storage
- Directory Structure
- SQLite + JSONL Dual Storage
- Sync Mechanism
- CLI Commands
- Rust Backend
- Multi-Workspace Support
- ACE TUI Integration
Quick Start¶
sase bead init # Initialize beads in current project
sase bead create -t "New feature" --type "plan(sdd/tales/202605/feature.md)" --tier plan
sase bead create -t "Epic" --type "plan(sdd/epics/202605/epic.md)" --tier epic
sase bead create -t "Roadmap" --type "plan(sdd/legends/202605/roadmap.md)" --tier legend --epic-count 3
sase bead create -t "Linked epic" --type "plan(sdd/epics/202605/epic.md,<legend-id>)" --tier epic
sase bead create -t "Sub-task" --type "phase(beads-001)" # Create a phase under a plan
sase bead list # List all issues
sase bead list --status=open # List open issues
sase bead ready # Show issues ready to work on
sase bead show beads-001 # View issue details
sase bead update beads-001.1 --status=in_progress # Claim an issue
sase bead open beads-001.1 # Reopen an issue
sase bead close beads-001.1 # Close an issue
sase bead dep add beads-001.2 beads-001.1 # Add dependency
sase bead blocked # Show blocked issues
sase bead sync # Commit JSONL to git
sase bead stats # Project statistics
sase bead doctor # Health check
sase bead work beads-001 # Launch agents for an epic or legend plan bead
Data Model¶
Issue Types¶
| Type | Description | ID Format |
|---|---|---|
| Plan | Plan-like container with a tier | {prefix}-{counter} |
| Phase | Executable task within an epic/plan bead | {parent_id}.{N} |
Plans are groupings that can optionally link to an SDD file via the design field. Phases always belong to a parent
plan and use hierarchical IDs (e.g., beads-001.1, beads-001.2).
Plan beads carry a tier:
| Tier | SDD Path | Behavior |
|---|---|---|
plan |
sdd/tales/{YYYYMM}/*.md |
Normal non-epic implementation plan |
epic |
sdd/epics/{YYYYMM}/*.md |
Executable multi-phase plan accepted by sase bead work |
legend |
sdd/legends/{YYYYMM}/*.md |
Higher-level coordination plan; launches epic-planning agents by epic_count |
Linked epics use the existing parented plan syntax:
sase bead create --title "Epic" --type plan(sdd/epics/202605/epic.md,<legend_bead_id>) --tier epic
Status Lifecycle¶
| Status | Icon | Description |
|---|---|---|
open |
○ |
Not started |
in_progress |
◐ |
Currently being worked on |
closed |
✓ |
Completed or abandoned |
Status can transition freely between any values via sase bead update --status=<status>. sase bead open <id> is a
shortcut for sase bead update <id> --status=open.
Dependencies¶
Dependencies are one-way relationships: issue A depends on issue B. An issue is:
- Ready if it is
openand all its dependencies areclosed. - Blocked if it has at least one dependency with status
openorin_progress.
Storage¶
Directory Structure¶
When version-controlled mode is enabled (sdd.version_controlled config):
sdd/beads/
beads.db # SQLite database (gitignored)
issues.jsonl # Git-tracked JSONL export
config.json # Configuration (issue prefix, counter, owner)
In non-version-controlled mode, the directory is .sase/sdd/beads/ with the same structure.
Read paths also recognize the older workspace-local .sase_beads/ directory while legacy projects are being migrated.
New bead stores should use sdd/beads/ in version-controlled mode or .sase/sdd/beads/ in local mode.
SQLite + JSONL Dual Storage¶
Rust owns the bead storage/query/mutation path. SQLite is the local query cache and mutation target; JSONL is the git-portable format that gets committed. The two are kept in sync:
- Writes run through Rust mutation transactions, update SQLite, then export the portable JSONL state.
- Reads run through Rust read APIs, rebuilding SQLite from JSONL first when the cache is missing or stale.
- Fresh clones rebuild the SQLite database automatically from
issues.jsonlon first access.
The .gitignore excludes beads.db* files so only issues.jsonl and config.json are tracked in git.
Sync Mechanism¶
sase bead sync exports the current SQLite state to issues.jsonl and commits it to git. The JSONL file contains one
JSON object per line, sorted by issue ID for clean diffs.
On project open, if the JSONL file is newer than the database (or the database is missing), the database is automatically rebuilt from JSONL. This handles fresh clones and manual JSONL edits transparently.
CLI Commands¶
sase bead init¶
Initialize the beads directory in the current project.
sase bead create¶
Create a new issue.
| Flag | Required | Description |
|---|---|---|
-t, --title |
yes | Issue title |
-T, --type |
yes | Bead type: plan(<file>), plan(<file>,<parent>), or phase(<parent_id>) |
-d, --description |
no | Issue description |
-a, --assignee |
no | Assignee name |
--tier |
no | Plan-bead tier: plan, epic, or legend |
-c, --changespec |
no | Attach a ChangeSpec name to a plan bead |
-b, --bug-id |
no | Bug ID for the attached ChangeSpec; requires --changespec |
-E, --epic-count |
no | Positive number of epics proposed by a legend plan bead |
ChangeSpec metadata is valid only on plan beads. It is used by the epic-approval and sase bead work flows to keep plan
beads linked to the ChangeSpec they are intended to produce.
sase bead list¶
List issues with optional filtering. Closed beads are excluded from the default output.
| Flag | Values | Description |
|---|---|---|
-s, --status |
open, in_progress, closed |
Filter by status (repeatable) |
-t, --type |
plan, phase |
Filter by type (repeatable) |
--tier |
plan, epic, legend |
Filter by plan-bead tier |
sase bead show <id>¶
Display complete details for an issue including status, type, tier, epic count, parent/children, dependencies, blockers, description, notes, ChangeSpec metadata, and linked plan path.
sase bead ready¶
Show issues that are ready to work on: open status with all dependencies closed.
sase bead open <id>¶
Reopen an issue by setting its status to open. This is equivalent to sase bead update <id> --status=open.
sase bead update <id>¶
Update one or more fields on an issue.
| Flag | Description |
|---|---|
-s, --status |
Change status |
-t, --title |
Change title |
-d, --description |
Change description |
-n, --notes |
Change notes |
-D, --design |
Change plan path |
-a, --assignee |
Change assignee |
--tier |
Change plan tier |
-E, --epic-count |
Change legend epic count |
sase bead close <id> [<id2> ...]¶
Close one or more issues.
| Flag | Description |
|---|---|
-r, --reason |
Optional close reason text |
sase bead rm <id>¶
Remove an issue and cascade-delete all its children. This is irreversible.
sase bead dep add <issue> <depends_on>¶
Add a dependency: <issue> depends on <depends_on>. The issue becomes blocked if the dependency is not yet closed.
sase bead blocked¶
Show all issues that have at least one active (non-closed) blocker.
sase bead sync¶
Export the SQLite database to JSONL and commit to git.
| Flag | Description |
|---|---|
-s, --status |
Check sync status without committing |
sase bead stats¶
Show project statistics: total, open, in-progress, and closed counts, plus plan and phase counts.
sase bead doctor¶
Run health checks on the beads database. Checks for:
- Missing
config.json,issues.jsonl, orbeads.db - Uncommitted JSONL changes
- Orphan children (phases whose parent plan is missing)
If bead commands fail before opening a store, run sase core health first. It verifies that the required sase_core_rs
extension is importable and exposes the representative bead CLI binding used by the fast path.
sase bead onboard¶
Display a quick-start guide with common command examples.
sase bead work <id>¶
Run an entire epic-tier plan end-to-end by launching one agent per phase plus a final land agent, or run a legend-tier
plan by launching one epic-planning agent per stored epic_count.
For epic-tier plans, the command:
- Validates that
<epic_id>resolves to an issue of typeplanwithtier=epic. If the plan is already markedis_ready_to_work, the command treats the run as a retry and schedules any remaining non-closed phases. - Scans the live agent registry for any visible agent already named
<epic_id>.<N>(for any open phase),<epic_id>(for the land agent), or the legacy<epic_id>.landland-agent name, and refuses to launch when a collision exists, listing the offending artifact directories so the user can wipe/delete or otherwise resolve the orphan first. (--dry-rundowngrades this to a warning and continues.) - Flips the epic plan bead's
is_ready_to_workflag toTruewhen it was not already ready. - Builds a Kahn-wave schedule from the epic's open phase children, respecting dependencies.
- Pre-claims each phase bead — sets
status=in_progressandassignee=<phase_bead_id>(i.e.<epic_id>.<N>). - Hands a single
----separated multi-prompt to the agent launcher. Each per-phase agent is spawned with name<epic_id>.<N>and references thework_phase_beadxprompt; a final land agent named<epic_id>references theland_epicxprompt. Phase dependencies become%wwaits on blocker phase-agent names, and the land agent waits on every launched phase agent. Because%wrequires a successfuldone.jsonoutcome, a failed or killed phase keeps dependent phases and the land agent parked until the phase name is retried successfully.
For legend-tier plans, the command:
- Validates that
<id>resolves to a plan bead withtier=legend, a positiveepic_count, and a linked legend plan path. - Scans the live agent registry for generated epic-planning agent names like
<legend_id>.1.0and refuses collisions. - Flips the legend plan bead's
is_ready_to_workflag toTruewhen launching. - Hands a single
----separated multi-prompt to the agent launcher. Each segment includes%approve,%epic, and%name:<legend_id>.<N>.0; epicN > 1also waits on%w:<legend_id>.<N-1>, so epic planning proceeds in order.
Legend work does not create phase beads directly. The spawned epic-planning agents create epic plans, and the existing
bd/new_epic automation handles the linked epic and phase beads after those plans are approved.
| Flag | Description |
|---|---|
-n, --dry-run |
Print the wave plan and rendered multi-prompt without mutating state or launching |
-y, --yes |
Skip the launch confirmation prompt |
Both xprompts are resolved by XPromptTag (tag-based lookup), so a project-local or user-defined xprompt with the
matching tag overrides the built-in. Each generated phase and land prompt also carries a %approve directive, so the
spawned agents can self-approve their own plans without a human-in-the-loop checkpoint between waves.
When the epic plan bead is attached to ChangeSpec metadata (--changespec / --bug-id), sase bead work preserves the
current project's VCS context in the generated prompt. The first phase segment targets the project reference and adds a
#pr reference for the ChangeSpec, while later phase and land segments target the ChangeSpec ref directly. For
non-ChangeSpec epics launched from a known SASE workspace, each segment is still prefixed with the detected VCS workflow
and project name (for example #git:sase or #gh:sase-org/sase). If the current directory is not associated with a
SASE project, the prompts are left unprefixed and run in the caller's normal launch context.
If launching the multi-prompt fails partway through, the launcher SIGTERMs any already-spawned children before rolling
back the pre-claims and the is_ready_to_work flag when this run set it (best-effort), so the epic can be retried
without leaving zombie agents behind.
Rust Backend¶
The bead data model, JSONL/config codecs, SQLite rebuild/query layer, mutation transactions, ID allocation, workspace
merge, deterministic work-plan DAG, and common CLI output planning are implemented in sase-core and exposed through
sase_core_rs. Python keeps the host logic that belongs in the application layer: locating the active bead stores,
relativizing plan paths, resolving VCS context and xprompts for sase bead work, prompting the user, launching agents,
rolling back failed launches, and incrementing telemetry counters.
Common sase bead commands dispatch through an early CLI fast path before the full top-level parser is built. Help text
and host-coupled commands still fall through to the normal Python parser/handlers where needed.
Use these checks when changing bead internals:
sase core health -j
pytest tests/test_bead tests/test_core_facade/test_bead_read.py tests/test_core_facade/test_bead_mutation.py
just rust-check
just bead-perf-smoke
Multi-Workspace Support¶
When running in version-controlled mode with multiple workspace variants (e.g., myproject/, myproject_2/,
myproject_3/), bead provides a merged read view across all workspaces:
- Reads (list, show, ready, blocked, stats) aggregate issues from all workspace variants using the Rust merged
workspace view. For duplicate IDs across workspaces, the version with the most recent
updated_atwins. The merged view includes canonicalsdd/beads/stores and legacy.sase_beads/stores. - Writes (create, update, close, rm, dep add) always go to the primary workspace only.
- ID allocation scans JSONL stores from all discovered workspace variants before assigning the next top-level or child ID, preventing agents in sibling workspaces from reusing IDs that have not yet been merged into the primary SQLite database.
This enables multiple agents working in different workspace clones to track their own issues while still providing a unified view of all work.
Agent-facing metadata lookups use the same workspace-aware read path. When an agent belongs to another known SASE project, bead display resolution checks that project first, then the current directory's project, then all known project bead stores. This is what lets ACE and completion notifications show phase/land bead titles even when the TUI is opened from a different project.
ACE TUI Integration¶
Plan File Linking¶
When creating a plan bead with --type plan(PATH), the file path is stored in the design field. The ACE TUI can
navigate from a bead to its linked SDD file.
For SDD-generated epics, PATH should be the shared plan reference emitted by the plan approval flow:
sdd/epics/YYYYMM/*.md when sdd.version_controlled: true, or .sase/sdd/epics/YYYYMM/*.md in local SDD mode. Both
references are relative to the primary workspace so phase agents launched from sibling workspaces can still locate the
plan.
Plan Approval Flow¶
The plan approval popup in ACE includes normal approval, E (Epic), and L (Legend) actions. Normal approval saves
to sdd/tales/, Epic saves to sdd/epics/ and launches the epic follow-up that creates an epic-tier plan bead plus
phase beads, and Legend saves to sdd/legends/ and launches a legend follow-up that records a legend-tier plan bead
with epic_count before starting the legend work chain.