Building Apps with AI: Deep Dive into beads Workflow
Part 2 of 2: JSONL Memory, Real Examples, and Honest Drawbacks
Recap
In that described:
- core user flows
- data sources (e.g. NAPLAN, Google Maps)
- output expectations (comparison metrics, charts)
I then asked Claude Code (with beads installed) to:
- Read requirements.md
- Propose epics, features, and tasks
- Encode them directly into beads issues with explicit dependencies
In other words, requirements existed, but they were treated as input, not as a continuously consulted execution artifact.
Once the task graph existed, beads became the primary source of truth.
Scope and Assumptions
This post reflects a solo, AI-assisted development workflow on a small but non-trivial codebase (dozens of tasks, explicit dependencies, multiple external APIs).
Assumptions:
- The AI agent has read access to the full issue graph
- Execution efficiency matters more than prolonged design deliberation
For ambiguous product discovery, multi-team coordination, or regulated environments, spec-driven approaches may be a better first step.
The JSONL Advantage: Compact and Queryable
Every beads issue is stored as a single line of JSON in .beads/issues.jsonl:
{"id":"mission-house-ogp","title":"Implement myschool.edu.au scraper","description":"Create Puppeteer-based scraper...","status":"closed","priority":1,"close_reason":"NAPLAN scraper implemented in server.js","dependencies":[{"depends_on_id":"mission-house-5mv"}]}
Compare this to a typical markdown task file that might span dozens of lines with headers, descriptions, and nested checklists for the same information.
Why Compact Matters
flowchart LR
subgraph "Verbose MD Files"
A1[Read file 1] --> A2[Read file 2]
A2 --> A3[Read file 3...]
A3 --> A4[Parse all prose]
A4 --> A5[Build mental model]
A5 --> A6[Tokens consumed: 📈]
end
subgraph "Single JSONL"
B1[Read issues.jsonl] --> B2[Parse structured data]
B2 --> B3[Query with bd commands]
B3 --> B4[Tokens consumed: 📉]
end
style A6 fill:#ff6b6b,color:#fff
style B4 fill:#4ade80,color:#000
The AI gets structured data it can query, not prose it must interpret:
bd ready- What's unblocked and highest priority?
bd blocked- What's waiting on other work?
bd show <id>- Full details on one issue
bd stats- Project health at a glance
Close Reasons: Implementation Memory
When you close an issue, you document what was actually built:
bd close mission-house-ogp --reason="NAPLAN scraper implemented in server.js, handles terms acceptance and score extraction"
This is not just status — it’s ground truth.
Specs capture intent.
Close reasons capture reality.
Real Example: Session Continuity
Here's what happened when I resumed work on NAPLAN scoring after a break:
Session 1 (ended with):
bd close mission-house-ogp --reason="NAPLAN scores integration complete: scraper implemented in server.js"
Session 2 (started with):
> bd ready
mission-house-6t1 [P2] [task] open - Display NAPLAN scores in UI
└─ Blocked by: mission-house-ogp (closed), mission-house-0ch (closed)
└─ All blockers resolved - ready to work!
Claude immediately knew:
- The scraper was done (from ogp's close reason)
- The schema was updated (from 0ch's close reason)
- The next logical step was UI display
No manual context re-establishment was needed, because dependencies and implementation details were already encoded.
The Hierarchy: Epics → Features → Tasks
We organized Mission House using a three-level hierarchy:
flowchart TB
subgraph Epics["Epics (Strategic Goals)"]
E1["House Comparison App<br/>mission-house-1ow"]
E2["Data Comparison Page<br/>mission-house-tfz"]
end
subgraph Features["Features (User-Facing)"]
F1["Data Entry Page<br/>mission-house-a6u"]
F2["Data View Page<br/>mission-house-ng2"]
F3["JSON Database<br/>mission-house-2e6"]
F4["Radar Chart<br/>mission-house-xsq"]
F5["NAPLAN Integration<br/>mission-house-9d1"]
end
subgraph Tasks["Tasks (Implementation)"]
T1["Frontend Setup"]
T2["URL Form"]
T3["Web Scraper"]
T4["Google Maps API"]
T5["School Lookups"]
T6["Train Station Finder"]
T7["Chart Library Setup"]
T8["NAPLAN Scraper"]
end
E1 --> F1
E1 --> F2
E1 --> F3
E2 --> F4
F5 --> T8
F1 --> T1
F1 --> T2
F1 --> T3
F2 --> T4
F2 --> T5
F2 --> T6
F4 --> T7
style Epics fill:#7c3aed,color:#fff
style Features fill:#2563eb,color:#fff
style Tasks fill:#059669,color:#fff
Why This Structure Works
| Level | Purpose | Typical Count | Lifetime |
|---|---|---|---|
| Epic | Strategic goal, multiple sessions | 2-5 per project | Weeks |
| Feature | User-facing capability | 5-15 per epic | Days |
| Task | Single implementation unit | 3-10 per feature | Hours |
The AI works at the task level but understands the feature and epic context.
Real Issues from Mission House
Let me show you actual issues from our project to illustrate different patterns:
Pattern 1: Task with Clear Dependencies
{
"id": "mission-house-73p",
"title": "Calculate Flinders Street Station travel time",
"description": "Calculate travel time to Flinders Street Station during peak hours on a working day from: (a) the nearest train station, (b) the property address directly.",
"status": "closed",
"priority": 2,
"issue_type": "task",
"close_reason": "Implemented MapsService.getTravelToFlinders() with peak hour scheduling. Calculates transit, driving, walking routes from property and via nearest station",
"dependencies": [
{
"depends_on_id": "mission-house-utk",
"type": "blocks"
}
]
}
What the AI learned from this:
- Can't calculate commute until "Find nearest train station" (utk) is done
- Implementation went into
MapsService.getTravelToFlinders()
- Peak hour scheduling was added
- Multiple route types were implemented
Pattern 2: Bug with Acceptance Criteria
{
"id": "mission-house-v4e",
"title": "Fix naplan score web scraping logic",
"description": "Naplan score web scraping not working as expected. Check the requirements document",
"acceptance_criteria": "Naplan score written in json file as in the requirements document",
"status": "closed",
"priority": 0,
"issue_type": "bug",
"close_reason": "Implemented naplan_quality metric: added benchmark constants, quality calculation function, and UI display in both hub-spoke view and compare page radar chart"
}
Priority 0 (P0) is the highest priority level. The AI knew to work on this first.
Pattern 3: Tombstone (Deleted Issue)
{
"id": "mission-house-ck6",
"title": "Implement spider/radar chart visualization",
"status": "tombstone",
"deleted_at": "2026-01-17T23:15:21.909135+11:00",
"deleted_by": "batch delete",
"delete_reason": "batch delete",
"original_type": "task"
}
Tombstones preserve history while removing clutter. The AI knows this was deleted and won't try to work on it.
beads vs. agent-os (an SDD Framework)
Spec-Driven Development (SDD) is a methodology - different tools implement it differently. Let's compare beads to
Thanks for reading! If you try beads on your next AI-assisted project, I'd love to hear how it goes.
SOCIAL SHARE CARD GENERATOR