What Is Semantic Compaction and Memory Decay in Beads?

Semantic compaction is Beads' automated process for summarizing aged, closed issues to reduce database size and LLM context consumption, while memory decay refers to the intentional "forgetting" of granular details by agents once full issue text is replaced with concise summaries.

Beads is an issue tracker built on a Dolt-backed SQL database that stores every issue, comment, and metadata as versioned relational data. As projects age, closed issues accumulate and threaten to overwhelm both storage capacity and the limited context windows of LLM-driven agents. To solve this, the gastownhall/beads repository implements semantic compaction and memory decay, a tiered summarization system that preserves historical knowledge while discarding verbose content that agents no longer need immediate access to.

How Semantic Compaction Works

The compaction engine follows a strict seven-step pipeline defined in internal/compact/compactor.go. This process ensures only eligible issues are processed, verifies that compression actually occurs, and maintains a complete audit trail.

Eligibility and Tier-Based Processing

Compaction begins with an eligibility check. Only closed issues older than a configurable threshold—typically 30 days for Tier 1—are considered candidates.

In internal/compact/compactor.go lines 92-102, the Compactor.CheckEligibility method validates the issue status and age before any processing occurs:

// Simplified logic from Compactor.CompactTier1
if eligible, reason := c.store.CheckEligibility(ctx, issueID); !eligible {
    return fmt.Errorf("issue not eligible: %s", reason)
}

This fail-fast guard prevents active or recently closed issues from being prematurely summarized.

Size Calculation and Summarization

Once eligibility is confirmed, the system calculates the original byte size of the issue content. At lines 109-111, the compactor measures the cumulative length of description, design, notes, and acceptance_criteria fields:

originalSize := len(issue.Description) + len(issue.Design) + 
                len(issue.Notes) + len(issue.AcceptanceCriteria)

An LLM-based summarizer then generates a concise textual summary. Lines 116-119 invoke the summarization service:

summary, err := c.summarizer.SummarizeTier1(ctx, issue)
if err != nil {
    return fmt.Errorf("summarization failed: %w", err)
}

Safety Guards and Storage

Beads enforces a size-reduction guard to prevent bloating the database with verbose summaries. At lines 124-130, the compactor compares the compacted size against the original. If the summary fails to reduce the byte count, compaction is aborted and a warning comment is attached instead:

if compactedSize >= originalSize {
    // Skip compaction, add warning comment
    c.store.AddComment(ctx, issueID, "Compaction skipped: no size reduction")
    return nil
}

When compression is verified, lines 132-138 overwrite the issue fields with the summary and clear auxiliary data:

updates := map[string]interface{}{
    "description": summary,
    "design":      "",
    "notes":       "",
    // ... clear other fields
}

Metadata and Audit Trail

Finally, the system records compaction metadata and adds an audit comment. Lines 143-146 in internal/compact/compactor.go persist the compaction level, timestamp, Git commit hash, and original size:

c.store.ApplyCompaction(ctx, issueID, &CompactionRecord{
    Level:        1, // Tier 1
    CompactedAt:  time.Now(),
    CommitHash:   currentCommit,
    OriginalSize: originalSize,
})

An audit comment noting the byte savings is added at lines 149-152 via c.store.AddComment.

The Data Model for Compaction Metadata

The metadata attached to compacted issues is defined in internal/types/types.go lines 61-66. These fields track the decay state without altering the relational schema:

// internal/types/types.go
type Issue struct {
    // ... other fields ...
    CompactionLevel   int        `json:"compaction_level,omitempty"`   // 0: none, 1: tier-1, 2: tier-2
    CompactedAt       *time.Time `json:"compacted_at,omitempty"`       // when compaction occurred
    CompactedAtCommit *string    `json:"compacted_at_commit,omitempty"`// Git commit that performed compaction
    OriginalSize      int        `json:"original_size,omitempty"`      // bytes before compaction
}

These fields enable the system to distinguish between fully detailed issues (CompactionLevel: 0) and those that have undergone semantic decay (CompactionLevel: 1 or 2).

Memory Decay and LLM Context Management

The term memory decay describes the conceptual effect of compaction on LLM agents operating within Beads. Agents construct a mental model of the project by reading issues from the database, but LLM context windows are finite—often around 8,000 tokens. By replacing verbose closed-issue text with compact summaries, the system forces agents to "forget" granular implementation details while retaining the semantic knowledge that work was completed.

This decay is graceful rather than destructive. The original full-text content remains recoverable via Git history using the bd restore <id> command. As noted in the README, semantic memory decay "summarizes old closed tasks to save context window," allowing agents to focus on active work while maintaining historical awareness without token bankruptcy.

CLI Administration of Compaction

Administrators trigger and analyze compaction through the bd admin compact command suite documented in docs/CLI_REFERENCE.md:


# Analyze candidates without making changes (dry run)

bd admin compact --analyze --json

# Apply compaction to a specific issue

bd admin compact --apply --id bd-42 --summary summary.txt

# Display aggregate compaction statistics

bd admin compact --stats --json

These commands wrap the internal Compactor API and provide visibility into which issues are eligible for memory decay.

Programmatic Compaction Using the Go API

For custom workflows, the internal/compact package exposes a programmatic interface. Below is a complete example that initializes the Dolt-backed storage and compacts a single issue:

package main

import (
	"context"
	"log"

	"github.com/gastownhall/beads/internal/compact"
	"github.com/gastownhall/beads/internal/storage"
)

func main() {
	ctx := context.Background()

	// 1️⃣ Initialize the storage backend (Embedded Dolt)
	store, err := storage.NewEmbeddedDoltStore("./.beads/embeddeddolt")
	if err != nil {
		log.Fatalf("store init: %v", err)
	}

	// 2️⃣ Build a compactor with default configuration
	c, err := compact.NewCompactor(store, compact.DefaultConfig())
	if err != nil {
		log.Fatalf("compactor init: %v", err)
	}

	// 3️⃣ Compact issue "bd-1234" using Tier 1 rules
	if err = c.CompactTier1(ctx, "bd-1234"); err != nil {
		log.Printf("Compaction failed: %v", err)
	} else {
		log.Println("Issue bd-1234 compacted successfully")
	}
}

Executing this program performs the full eligibility check, LLM summarization, and metadata recording pipeline described in the implementation section.

Summary

  • Semantic compaction in gastownhall/beads automatically summarizes closed issues older than a configured threshold (e.g., 30 days) to reduce storage and LLM context usage.
  • The process is implemented in internal/compact/compactor.go with strict guards: eligibility checks, size calculations, and verification that summaries actually reduce byte count.
  • Memory decay refers to the intentional loss of granular detail from an agent's working context, allowing LLMs to retain historical awareness without exceeding token limits.
  • Compaction metadata—including CompactionLevel, CompactedAt, and OriginalSize—is stored in the Issue struct defined in internal/types/types.go.
  • Original content remains recoverable via bd restore <id> because Beads versions all data in Dolt/Git history.
  • Administrators control compaction via bd admin compact CLI commands, while developers can invoke the Compactor type directly in Go applications.

Frequently Asked Questions

What is the difference between semantic compaction and memory decay in Beads?

Semantic compaction is the technical process of overwriting issue fields with LLM-generated summaries to reduce byte size. Memory decay is the conceptual model describing how agents "forget" detailed content once it has been compacted, freeing up limited LLM context windows while maintaining semantic awareness of historical work.

How does Beads prevent accidental compaction of active issues?

The system enforces eligibility criteria in internal/compact/compactor.go lines 92-102 via CheckEligibility. Only issues with a "closed" status and age exceeding the configured threshold—typically 30 days for Tier 1—are processed. This ensures active or recent work is never subjected to semantic decay.

Can I recover the original full text of a compacted issue?

Yes. Beads stores all data in a Dolt-backed database with full Git versioning. The original uncompressed content remains in the Git history and can be retrieved using the bd restore <id> command, making memory decay a reversible operation rather than permanent data loss.

What happens if the LLM summary is longer than the original issue?

The compactor implements a size-reduction guard at lines 124-130 of internal/compact/compactor.go. If compactedSize >= originalSize, the system skips the update and adds a warning comment to the issue instead, preventing the database from growing due to ineffective summarization.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →