Skip to content

Beads

Beads are LoopTroop's execution units. They are the bridge between an approved PRD and an actual coding run.

The current model lives in server/phases/beads/types.ts.

What A Bead Is

A bead is small enough to execute in focused context, but rich enough to encode:

  • what must be changed
  • what depends on what
  • how to verify completion
  • what happened in prior attempts

LoopTroop plans features as a bead graph and executes the graph in dependency order.

Current Bead Shape

FieldTypeMeaning
idstringStable bead identifier
titlestringShort execution title
prdRefsstring[]PRD references that justify the bead
descriptionstringFull execution task description
contextGuidance{ patterns: string[]; anti_patterns: string[] }Local implementation guidance
acceptanceCriteriastring[]Completion requirements
testsstring[]What should be verified
testCommandsstring[]Concrete commands to run
prioritynumberExecution order
status`'pending''in_progress'
issueTypestringTask, bug, chore, or similar
externalRefstringParent ticket reference
labelsstring[]PRD or planning labels
dependencies{ blocked_by: string[]; blocks: string[] }Execution graph edges
targetFilesstring[]Expected file touch set
notesstringDurable notes string carried across attempts
iterationnumberCurrent attempt count for the bead
createdAtstringISO timestamp
updatedAtstringISO timestamp
completedAtstringCompletion timestamp
startedAtstringStart timestamp
beadStartCommitstring | nullGit snapshot used for reset and retry

Example Bead

This example matches the current stored shape.

json
{
  "id": "auth-refresh-token-rotation",
  "title": "Implement refresh-token rotation",
  "prdRefs": ["EPIC-AUTH", "STORY-SESSION-2"],
  "description": "Add refresh-token rotation and invalidation on reuse.",
  "contextGuidance": {
    "patterns": ["Reuse the existing session repository abstraction"],
    "anti_patterns": ["Do not introduce a second token storage format"]
  },
  "acceptanceCriteria": [
    "Refresh tokens rotate on successful refresh",
    "Reused refresh tokens invalidate the session family"
  ],
  "tests": [
    "Cover normal refresh flow",
    "Cover reused refresh token invalidation"
  ],
  "testCommands": [
    "npm run test:server"
  ],
  "priority": 3,
  "status": "pending",
  "issueType": "task",
  "externalRef": "AUTH-12",
  "labels": ["epic:auth", "story:sessions"],
  "dependencies": {
    "blocked_by": ["session-store-foundation"],
    "blocks": ["api-refresh-endpoint"]
  },
  "targetFiles": [
    "server/auth/sessionStore.ts",
    "server/routes/auth.ts"
  ],
  "notes": "",
  "iteration": 1,
  "createdAt": "2026-04-23T09:00:00.000Z",
  "updatedAt": "2026-04-23T09:00:00.000Z",
  "completedAt": "",
  "startedAt": "",
  "beadStartCommit": null
}

Storage Model

The editable bead plan for a ticket is stored under:

text
.ticket/beads/<flow>/.beads/issues.jsonl

Important details:

  • flow defaults to the ticket base branch when not provided
  • the file is line-oriented JSONL
  • PUT /api/tickets/:id/beads rewrites the full file atomically
  • the server also refreshes the approval snapshot and clears execution-setup state after updates

So issues.jsonl is durable and canonical, but it is not append-only in the event-log sense.

Lifecycle

Beads move through a small local lifecycle even while the ticket moves through a much larger workflow lifecycle.

Bead statusMeaning
pendingPlanned but not yet started
in_progressCurrently selected by the execution loop
doneSuccessfully implemented and accepted by the executor
errorLast attempt failed and needs retry or manual recovery

The scheduler decides which pending bead becomes active based on dependency satisfaction.

Scheduler Rules

The scheduler logic is intentionally simple and deterministic:

  • getRunnable(beads) returns dependency-unblocked pending work
  • getNextBead(beads) picks the next runnable bead
  • isAllComplete(beads) decides whether the execution stage can advance

This prevents the coding model from deciding its own work order.

Notes And Iteration

Two fields matter for retry behavior:

FieldWhy it matters
notesCarries durable execution commentary across attempts
iterationRecords how many times the bead has been attempted

The stored bead model uses a single notes string. Some runtime context assembly logic may split or project note material into prompt slices, but the canonical bead object itself stores one notes field.

Diffs And Review

Execution writes bead diff artifacts with artifact types like:

text
bead_diff:<beadId>

Those diffs are exposed through:

text
GET /api/tickets/:id/beads/:beadId/diff

This is how the UI can show what changed for a specific bead without treating the whole ticket as one opaque patch.

Why Beads Matter Architecturally

Beads are more than tasks:

  • they limit coding context
  • they provide retry boundaries
  • they preserve execution memory
  • they create inspectable diffs
  • they allow the scheduler to enforce dependencies outside the model

Without beads, LoopTroop would collapse back into a single long-running coding chat with weaker recovery and weaker auditability.

LoopTroop documentation for the current runtime.