Good spec — tight enough that phasing is mostly "respect the dependency graph." Here's how I'd sequence it so every phase leaves you with something runnable, not just partial code.

**Phase 1 — Skeleton & CI gate**
`pyproject.toml` with `requires-python>=3.9`, pinned deps, Typer CLI with the four commands stubbed (no-ops that print "not implemented"). Wire CI immediately: ruff → mypy → pytest, on the version matrix. Getting the fail-fast pipeline running on day one means every later phase has to pass it before merging — that's your production-readiness backbone, not an afterthought at the end.

**Phase 2 — Config**
`rylox.toml` schema + loader, `rylox init` / auto-write-defaults-on-first-run, loud validation at command start. Everything downstream (embedding model name, budget, ignore patterns) reads from here, so it needs to exist before indexing does.

**Phase 3 — Indexing core**
tree-sitter-python integration, chunking at function/method/class granularity, metadata (path, line range, containing class, docstring, content hash), `.rylox/` cache + gitignore write, incremental re-index via hash diff. This is the foundation everything else queries against — get chunk boundaries and hashing rock-solid here, since bugs here silently corrupt every later phase.

**Phase 4 — `doctor` (build incrementally, not last)**
Start it now with just the Python-version check, then add a check every time a new dependency lands (tree-sitter importable after Phase 3, FAISS round-trip after Phase 5, etc.). Shipping `doctor` piecemeal alongside its dependencies means it's actually trustworthy by v0.1.0 instead of a rushed afterthought.

**Phase 5 — Dense retrieval**
ONNX-runnable embedding model loading, embed chunks at index time, FAISS build/persist/search, query embedding path. No LLM anywhere — just embed-and-search.

**Phase 6 — Sparse retrieval + fusion**
BM25 over the same chunks, Reciprocal Rank Fusion combining the two rankings. Small, isolated, easy to unit-test against hand-built toy corpora before touching real repos.

**Phase 7 — Relationship graph**
Call graph + import graph from the AST (built once per index, in Phase 3's indexing pass or right after). One-hop expansion from fused top-k, with labels (`caller of X` / `callee of X` / `import of X`) attached at expansion time so §6/§7 output has the data it needs later.

**Phase 8 — Assembly & budget**
Deterministic ordering (entry point → execution flow → supporting symbols → related files → code), tokenizer-matched counting, greedy fill that never exceeds budget and never truncates mid-chunk, the "primary entry point doesn't fit" error path as an explicit test case, not a bug you find later.

**Phase 9 — Markdown renderer**
Fixed-section template, always-present-even-if-empty sections, writes `<task>_context.md`. Thin layer over Phase 8's assembled structure — should be almost mechanical if 8 is done right.

**Phase 10 — Hardening & release**
Golden-set regression suite (hand-labeled query→chunk pairs, recall@k/precision@k, CI fails on regression vs. last tag) — this is the phase that actually earns "production ready," since it's the only thing keeping "relevant" honest as retrieval logic evolves. Alongside it: security boundaries (symlink containment, binary sniffing, size ceilings, malformed-file isolation), full integration tests (empty repo, single-file repo, constants-only module, unparseable file), packaging for `pip install rylox`, README, and the v0.1.0 tag.

**Why this order, concretely:** phases 1–2 give you a safety net and config surface before there's anything to configure; 3 is the one thing everything else reads from, so it can't slip; 4 rides alongside 3–9 instead of being bolted on; 5–6 are independent and can be built/tested in parallel if you split work with contributors; 7 needs 3's AST output but not 5/6; 8 needs 5+6+7 together; 9 is nearly free once 8 is correct; 10 is where "it works on my machine" becomes "it's a real release."

Want me to turn this into a `ROADMAP.md` / tracking-issue set you can drop into the repo, or start scaffolding Phase 1 now?