$ mkdir -p ~/Development/ravel-tutorial-example
$ cd ~/Development/ravel-tutorial-example
$ git init
Initialized empty Git repository in /Users/admin/Development/ravel-tutorial-example/.git/
Before creating a plan, you need a project — the subtree ravel-lite will read, write, and commit against during a cycle. This chapter introduces what a project is in ravel-lite’s vocabulary, scaffolds a worked example we will use for the rest of the tutorial, and registers it in the per-user projects catalog.
What ravel-lite means by "project"
A project is the subtree the orchestrator controls during a cycle. It is not derived from where .git sits — a single repository can host many projects as nested subtrees. It is derived from where the plan lives: given a plan directory at <project>/<state-dir>/<plan>/ (typically <project>/LLM_STATE/<plan>/), ravel-lite computes the project as <plan_dir>/../.. and treats that subtree as everything it is allowed to read, write, and commit.
The decoupling matters in two situations. The common one is a single-purpose repository where the project root is the repository root — the path math just happens to coincide. The interesting one is a monorepo, where the project is a subtree like monorepo/services/billing/ and ravel-lite needs to stay out of sibling subtrees. In both cases the orchestrator scopes its git operations using a pathspec on the project subtree, so dirty-tree checks, baseline diffs, and the analyse-work snapshot all see only the project’s files.
For this tutorial the project will be a standalone directory under ~/Development/ — no monorepo concerns — but the path math is the same.
A non-code worked example
Throughout this tutorial we will operate on a small reading-list-manager: a curated list of articles and books to read, with notes and tags. There is no code; the project is purely a Markdown file and a YAML catalog. That is on purpose. A non-code project keeps the focus on the cycle — task selection, the headless phases, memory growth, the dream trigger — without diff-resolution gymnastics.
Bootstrap the project directory:
git init is recommended even for a non-code project. The audit-trail commits ravel-lite produces (run-plan: work, run-plan: reflect, the per-phase baseline commits) need somewhere to land. Without a git repository, the git-commit-* audit-trail phases will fail loudly the first time they run.
Now seed two files. A README the work phase will read, and a placeholder reading list:
cat > README.md <<'EOF'
# Reading list
A curated list of articles and books I want to read, with notes and tags.
## Files
- `reading-list.md` — the list, organised by tag.
- `notes/` — per-entry notes, one Markdown file per item.
## Conventions
- Each entry has: title, author, source URL, status (`queued`, `reading`, `done`, `dropped`),
one or more tags, and an optional one-line annotation.
- Notes for an entry live at `notes/<slug>.md`. The slug is the lower-kebab-case title.
- Tags are free-form lower-kebab-case.
EOF
mkdir notes
touch reading-list.md
git add .
git commit -m "Initial scaffold"
You now have a project. Two files, one directory, one commit. Ravel-Lite will treat ~/Development/ravel-tutorial-example/ as the project root once we point a plan at it.
|
Note
|
The README is not optional. The work phase reads |
Registering the project
Ravel-Lite maintains a per-user projects catalog at <config-dir>/projects.yaml. The catalog maps human-friendly component names to absolute paths on disk. Component names are the shared currency of the cross-plan graph (related-components.yaml); the catalog is the per-user resolver from name to path.
You do not have to populate the catalog manually — ravel-lite run auto-registers a project the first time it sees one. But it is instructive to do it by hand once. The add subcommand is silent on success:
$ ravel-lite state projects add --path ~/Development/ravel-tutorial-example
$ ravel-lite state projects list
schema_version: 1
projects:
- name: ravel-tutorial-example
path: ../../Development/ravel-tutorial-example
The path stored in the catalog is relative to the config directory, not absolute — pathdiff::diff_paths normalises every entry against <config-dir> so the catalog stays portable: copying the config directory and the project directory together to another machine continues to resolve correctly without an edit. The relative form here (../../Development/ravel-tutorial-example) climbs out of ~/.config/ravel-lite/ to ~/, then descends into the project. At runtime the binary re-resolves to an absolute path before doing anything with it.
If --name is omitted, the basename of the path is used. The catalog rejects duplicate names and duplicate paths so two entries cannot disagree about the same project. To rename later — say, after refactoring or moving the directory — use state projects rename; the rename cascades into related-components.yaml and the discover-cache so cross-references stay consistent. The full surface is documented on the State commands reference.
The shape of a plan directory
A plan is a directory of state files representing an in-flight body of work. Conventionally it sits at <project>/LLM_STATE/<plan-name>/, though the state-directory name is configurable. We will create ~/Development/ravel-tutorial-example/LLM_STATE/main/ in the next chapter.
Inside a freshly-created plan, four files exist — the minimum scaffold ravel-lite create writes before the bootstrap conversation runs:
LLM_STATE/main/
├── phase.md # one-line file naming the phase to run next ("work\n")
├── backlog.yaml # tasks, statuses, dependencies, results, hand-offs
├── memory.yaml # distilled learnings carried across cycles
└── dream-word-count # word-count tracking for the dream trigger
backlog.yaml and memory.yaml start as empty shells (tasks: [] and entries: []) and are populated by the create conversation through ravel-lite state backlog add / state memory add calls. The bootstrap LLM never writes YAML directly — every mutation routes through the schemas in src/state/<name>/schema.rs, so a malformed entry never lands on disk.
As the cycle runs, a few more files appear in the same directory:
-
session-log.yamlandlatest-session.yaml— the analyse-work phase appends one record per completed phase to the log and overwrites the latest-session pointer each cycle. -
work-baseline,reflect-baseline,dream-baseline,triage-baseline— per-phase baseline SHAs captured so each phase has something to diff against. -
commits.yamlandsubagent-dispatch.yaml— written by triage when committing or when dispatching cross-plan subagents.
A project can host multiple plans. Each is its own directory under LLM_STATE/ and runs its own cycle independently. For this tutorial we will run a single plan called main. The full schema for each file lives on the State files reference; the current chapter only needs the high-level shape so the next chapter’s create command makes sense.
With the project directory in place and registered, you are ready to bootstrap the plan — the next chapter walks through ravel-lite create.