ravel-lite run ~/Development/ravel-tutorial-example/LLM_STATE/main
With the plan created, you can run a cycle. This chapter walks through ravel-lite run against the reading-list-manager plan from the previous chapter — the work-phase prompt, the headless phases that follow, and what the audit-trail commits look like in git log afterwards.
Starting the loop
ravel-lite run is the phase-loop entry point. It reads <plan-dir>/phase.md to decide which phase runs next, dispatches to the matching handler, and on completion advances phase.md to the successor. Single-plan mode (one directory) loops continuously, prompting between cycles. Multi-plan mode (two or more) prioritises across plans via an LLM survey and runs one cycle at a time on the chosen plan.
For now we run a single plan:
The TUI takes over the terminal. A banner identifies the plan and the agent backend; the first phase.md read picks up work, and the work phase begins.
|
Note
|
The first time |
The work phase
The work phase is the only interactive phase in the cycle. The agent reads four sources of context — <project>/README.md, the backlog, distilled memory, and declared peer-project relationships — then asks you to steer task selection. Below is an illustrative session.
[work] reading-list-manager / main
Backlog (3 not-started, 0 in-progress, 0 done, 0 blocked):
## reading-list
| title | status |
|-------------------------------------------------------------|-------------|
| Add first ten distributed-systems entries | not_started |
| Add five type-theory entries on dependent typing | not_started |
| Cross-link entries that cite each other | not_started |
Any input on which task to work on next? If yes, name it; otherwise
I'll pick the best next task.
Three tasks, none blocked, no momentum from a prior cycle. Pick the first:
> the distributed-systems entries
Working on: Add first ten distributed-systems entries.
[edits reading-list.md, creates notes/lamport-clocks.md, ...]
Done. Set status to done, recorded results.
Behind the scenes the agent is calling ravel-lite state backlog set-status to flip the task to done and ravel-lite state backlog set-results to record what it did. The source-file edits to reading-list.md and the new files under notes/ are not committed by the work phase — they are left dirty for analyse-work, the next phase, to see and commit-message from the actual diff. This split is deliberate: the work phase records what was decided, the analyse-work phase records what was changed in the tree, and a commit message authored from the tree is more reliable than a commit message authored from a self-report.
When the work phase finishes, it writes analyse-work to phase.md and exits. The TUI advances and the next phase starts.
The headless phases
From here, the cycle runs unattended through analyse-work, git-commit-work, reflect, git-commit-reflect, (optionally dream and git-commit-dream), triage, and finally git-commit-triage. The TUI banners each phase as it starts, streams the agent output, and shows the per-phase exit status. Each runs in its own subprocess with its own prompt; nothing is shared between them except the plan-state files on disk.
A few things are worth watching for as the cycle progresses.
Analyse-work. The phase examines the actual git diff and writes two artifacts: a session-log entry (overwriting latest-session.yaml) and commits.yaml, which describes how to partition the diff into commits. Default is one commit per cycle; the phase splits only when the diff genuinely spans independent concerns. For a small reading-list update, expect a single commit.
Git-commit-work. A pure Rust handler — no LLM. It reads commits.yaml, applies each entry as git reset HEAD — . then git add — <paths> then git commit -m <message>, then appends latest-session.yaml to session-log.yaml and captures the next baseline. Two to three commits land: the work commit(s), and a save-reflect-baseline follow-on commit recording the SHA the reflect phase will diff against.
Reflect. Distils the latest session’s learnings into durable memory. Reflect is the only lossy phase — it can sharpen, contradict, and prune memory entries based on what the session uncovered. For a first cycle the agent typically adds zero or one new entries; reflection is more interesting from cycle 3 onward when patterns start to emerge.
Dream. Conditional. Runs only when memory has grown past baseline + headroom words (default 1500 from defaults/config.yaml). On a first cycle, memory is well within the threshold and dream is skipped — the TUI shows a DREAM banner: skipped — memory within headroom line so the absence is as legible as the work that ran.
Triage. Reviews the backlog, mines completed tasks for hand-offs, and reprioritises. Two things triage does even on a first cycle: it removes the completed task from the backlog (the audit trail of the work it did lives in the git history and the session log, not in the open backlog), and it tightens dependency edges between remaining tasks when the work just done makes a dependency newly visible. From cycle 2 onward, triage’s narrative starts to carry [REPRIORITISED], [PROMOTED], and [ARCHIVED] labels alongside its actions.
Git-commit-triage. Lands the triage mutations, captures work-baseline, and exits the inner phase loop. The cycle is over. The TUI prints "Proceed to next work phase?" and waits.
Inspecting what landed
Stop here for a moment and look at the audit trail. git log --oneline after one full cycle is the complete record of what landed:
$ git log --oneline -10
4f5807d run-plan: save-work-baseline (main)
f7f1715 run-plan: triage (main)
1739944 run-plan: save-triage-baseline (main)
d852fbc run-plan: reflect (main)
5d3be6a run-plan: save-reflect-baseline (main)
97c724e Add ten distributed-systems reading-list entries
5ef24da Initial scaffold
Reading bottom-up: the initial scaffold from chapter 02; the work commit, whose message is authored by analyse-work from the actual diff (so it reads like a normal feature commit, not a templated run-plan: work); the save-reflect-baseline capturing the SHA reflect will diff against; the reflect commit (memory mutations); save-triage-baseline; the triage commit; and the closing save-work-baseline ready for cycle 2. A reader can scrub through a cycle the same way they would scrub through a video.
The first cycle is a special case in one respect: there is no leading save-work-baseline between Initial scaffold and the work commit. The scaffold itself is the baseline ravel-lite diffs against; the first explicit save-work-baseline lands at the end of cycle 1 in preparation for cycle 2.
|
Note
|
The "no magic" principle cashes out here. There is no shadow state in memory between phases — every state transition is a file write or a commit. A crash mid-cycle is recoverable from |
Inspect the session log to see what reflect saw:
$ ravel-lite state session-log show-latest \
~/Development/ravel-tutorial-example/LLM_STATE/main
id: session-1
timestamp: 2026-04-28T06:06:30Z
phase: work
body: |
### Session 1 (2026-04-28T06:06:30Z) — Add ten distributed-systems reading-list entries
- Attempted: add the first ten distributed-systems entries as specified in the backlog task.
- What worked: all ten entries added to `reading-list.md` as a markdown table; ten companion `notes/<slug>.md` files created. The README was extended with a full entry-format specification (the original was a one-line stub with no format defined), which was necessary for this task and the two follow-on tasks to have a shared source of truth.
- Tags established: `time-and-order`, `consensus`, `replication`, `storage`, `failure-modes`, `paper`, `book` — covering the four areas the task specified (time/order, consensus, replication, failure modes).
- What this suggests next: the type-theory task is unblocked (format documented, tag conventions established); the cross-link task is most productive once both batches exist but has natural clusters available now (FLP/Paxos/Raft/Viewstamped Replication; Lamport/Dynamo/Spanner; Bigtable/Spanner).
The body is the attempted / what worked / what this suggests next shape that analyse-work distils from the diff. The "What this suggests next" line is what triage will read in the next phase to decide whether dependencies between backlog tasks should be tightened.
And the memory after reflect:
$ ravel-lite state memory list ~/Development/ravel-tutorial-example/LLM_STATE/main
entries:
- id: annotations-are-one-liners-depth-goes-in-notes-slug-md
title: Annotations are one-liners; depth goes in notes/<slug>.md
body: |
[seeded in chapter 03 — three-line spec; full body elided here]
- id: slugs-are-lower-kebab-case-derived-from-the-title
title: Slugs are lower-kebab-case derived from the title
body: |
[seeded in chapter 03 — full body elided here]
- id: reuse-existing-tags-before-inventing-new-ones
title: Reuse existing tags before inventing new ones
body: |
[seeded in chapter 03 — full body elided here]
- id: readme-md-is-the-authoritative-entry-format-specification
title: README.md is the authoritative entry-format specification
body: |
`README.md` is the **authoritative specification for the entry format** — columns, annotation rules, slug convention, tag vocabulary. Read it before adding or editing entries.
**Why:** The original README was a one-line stub with no format defined. After the first batch of entries, it was extended with a complete spec so that all sessions work from the same source of truth. The per-entry rules in memory (annotations, slugs, tags) are derived from it; if they conflict, README wins.
**How to apply:** Before adding any new entry, read `README.md` to confirm the current format, column order, and any constraints. Do not infer format from existing table rows alone — the README may contain rules not visible from examples.
A new memory entry — "README.md is the authoritative entry-format specification" — distilled from the session. Reflect added it because the work-phase agent extended the README during the cycle (the original was a one-line stub) and that extension established a precedence rule between the README and the per-entry memories: when they conflict, README wins. Reflect noticed and made the rule durable.
The four-entry shape is also worth noting. Three of the entries are the seeds from chapter 03; the fourth is the cycle-1 distillation. Memory grows by accumulation, not replacement — the seeds stay until a future reflect or dream phase decides to consolidate them.
And the backlog after triage:
$ ravel-lite state backlog list \
~/Development/ravel-tutorial-example/LLM_STATE/main --format markdown
## reading-list
| title | status | deps |
|---|---|---|
| Add five type-theory entries focused on dependent-typing introductions | not_started | — |
| Cross-link entries that cite each other | not_started | add-five-type-theory-entries-focused-on-dependent-typing-introductions |
The completed task is gone — triage removed it; its trail lives in the work commit and the session log entry above. The cross-link task gained a dependency on the type-theory task: it is most productive once both batches of entries exist, and triage saw that constraint in the "What this suggests next" line of the session log and made it explicit. Cycle 2’s work phase will see only the type-theory task as actionable.
Continuing or stopping
After git-commit-triage exits, the TUI prompts:
Proceed to next work phase? [y/N]
Answer y to start cycle 2. Answer n to exit the loop cleanly. The plan directory is left in a fully consistent state either way — phase.md reads work, ready for the next invocation. There is no "save and quit" step: every transition has already been written to disk and committed.
The next chapter runs cycles 2 and 3, watches memory accumulate, and demonstrates the dream trigger and a hand-off being mined by triage.