# How Hierarchical Grouping of Tasks (Epics) Works in Beads

> Discover how Beads uses an Epic issue type for hierarchical task grouping. Learn how parent-child dependencies work without blocking the queue, ensuring efficient workflow.

- Repository: [Gas Town Hall/beads](https://github.com/gastownhall/beads)
- Tags: deep-dive
- Published: 2026-04-27

---

**TLDR:** Beads implements hierarchical task grouping through a first-class Epic issue type that establishes parent-child dependencies without blocking the ready queue, enforcing closure only when all child issues are resolved.

The gastownhall/beads project manages complex work through **hierarchical grouping of tasks** using Epics, which function as containers for child issues while maintaining distinct rules from blocking dependencies. Unlike hard `blocks` relationships that prevent work from entering the ready queue, parent-child links serve purely for organizational tracking and progress calculation.

## Epic Data Model and Type System

In [`internal/types/types.go`](https://github.com/gastownhall/beads/blob/main/internal/types/types.go), the **IssueType** enum includes `"epic"` as a distinct classification alongside tasks and bugs. The `Issue` struct defines three optional fields populated exclusively for epics containing children: **EpicTotalChildren**, **EpicClosedChildren**, and **EpicCloseable** (lines 527-528 and 762-765).

These fields enable real-time progress tracking by counting total descendants and completed items. The `EpicCloseable` boolean specifically indicates whether an epic meets closure criteria, though this status depends on validation rules enforced elsewhere in the codebase.

## Creating Epic Hierarchies

Creating an epic requires the `-t epic` flag with the `bd create` command. The CLI automatically assigns a top-level identifier, such as `bd-a3f8e9`, stored in the underlying **Dolt** database.

Adding children to an existing epic uses the `--parent` flag documented in [`website/docs/core-concepts/issues.md`](https://github.com/gastownhall/beads/blob/main/website/docs/core-concepts/issues.md) (lines 96-99). The system automatically appends dotted numeric suffixes to child IDs, reflecting their positional hierarchy:

```bash

# Create an epic

bd create "Auth System" -t epic -p 1

# Returns: bd-a3f8e9

# Add child tasks with automatic ID numbering

bd create "Design login UI" --parent bd-a3f8e9    # Returns: bd-a3f8e9.1

bd create "Backend validation" --parent bd-a3f8e9 # Returns: bd-a3f8e9.2

```

This numbering scheme persists across the epic lifecycle and remains consistent during export and import operations.

## Visualizing Epic Relationships

To inspect the complete hierarchy of an epic, use the `bd dep tree` command followed by the epic ID. This renders a tree view showing the parent and all descendants:

```bash
bd dep tree bd-a3f8e9

#   bd-a3f8e9 (Epic)

#   ├─ bd-a3f8e9.1

#   ├─ bd-a3f8e9.2

#   └─ bd-a3f8e9.3

```

The visualization draws from the same parent-child metadata stored in the issue records, providing immediate context for dependency mapping.

## Closure Validation and Lifecycle Rules

An epic enforces strict completion semantics: it cannot close while any child remains open. The **EpicHasOpenChildren** validation function in [`internal/validation/issue.go`](https://github.com/gastownhall/beads/blob/main/internal/validation/issue.go) (lines 20-34) checks this constraint during the `bd close` operation.

If attempted prematurely, the operation fails with an error indicating open children remain. Users can bypass this validation using the `--force` flag, though this overrides the standard lifecycle protections:

```bash

# Attempting to close with open children fails

bd close bd-a3f8e9

# Error: epic has open children (validation)

# Force closure bypasses validation

bd close bd-a3f8e9 --force

```

## Impact on Ready Queue Calculation

Parent-child relationships explicitly **do not** affect the ready queue calculation. While hard `blocks` dependencies prevent work from entering the ready state, epic hierarchies serve organizational purposes only. This distinction allows teams to structure large bodies of work without artificial workflow blockers, while still maintaining clear ownership and progress tracking.

## Preserving Hierarchies Across Exports

Epic trees remain intact during `bd export` and `bd import` operations because parent-child edges exist as standard issue metadata within the Dolt schema. When importing issues, the system reconstructs the hierarchical relationships automatically, preserving dotted ID notation and dependency structures.

## Summary

- **Epic Structure**: Defined in [`internal/types/types.go`](https://github.com/gastownhall/beads/blob/main/internal/types/types.go) with dedicated progress fields (`EpicTotalChildren`, `EpicClosedChildren`, `EpicCloseable`).
- **Hierarchy Creation**: Use `-t epic` to create parents and `--parent` to link children, generating dotted numeric IDs like `bd-a3f8e9.1`.
- **Validation**: The `EpicHasOpenChildren` function prevents closure until all children resolve, bypassable with `--force`.
- **Queue Impact**: Parent-child relationships organize work without blocking the ready queue, unlike hard `blocks` dependencies.
- **Data Portability**: Hierarchies persist through export/import cycles via metadata preservation in Dolt.

## Frequently Asked Questions

### Can I close an epic while child issues remain open?

No, the `EpicHasOpenChildren` validation in [`internal/validation/issue.go`](https://github.com/gastownhall/beads/blob/main/internal/validation/issue.go) blocks closure unless all descendants are resolved. You must either close the children first or use the `--force` flag to override this protection, though forced closure bypasses standard lifecycle safeguards.

### Do parent-child epic relationships block the ready queue?

No, parent-child dependencies explicitly do not impact ready queue calculations according to the dependency table specifications. Only hard `blocks` dependencies prevent work from entering the ready state, allowing epic hierarchies to organize work without creating artificial workflow blockers.

### How are child issue IDs generated when adding them to epics?

Child issues receive automatic dotted numeric suffixes reflecting their position in the tree. For example, the first child of epic `bd-a3f8e9` becomes `bd-a3f8e9.1`, the second becomes `bd-a3f8e9.2`, and so on. This numbering system is handled by the CLI argument parsing logic in [`cmd/bd/bootstrap.go`](https://github.com/gastownhall/beads/blob/main/cmd/bd/bootstrap.go) and persists across data exports.

### Are epic hierarchies preserved during data export and import?

Yes, because parent-child edges are stored as standard issue metadata in the underlying Dolt database, epic trees survive `bd export` and `bd import` operations intact. The system reconstructs hierarchical relationships automatically during import, maintaining the original dotted ID notation and dependency structures.