Structural verification
Turning on the Lumen code index, what each structural hint proves, querying the index, and Pyxis retrieval.
zurdo v1.36.0
A [grep:] hint proves a string exists, not that it's code: it passes on a comment as happily as on a real call. Structural hints check facts about named code symbols (a definition exists, a symbol is referenced, a function is actually called) by static analysis of the working tree. They resolve against Lumen, Zurdo's code index at .zurdo/lumen/.
Turning it on
[lumen]
enabled = true # build the index, and allow [symbol:] / [references:] / [callers:]
It's off by default, and it's the only switch. A structural hint while Lumen is off is a validation error naming this key, in validate, analyze, run and --resume alike. The other [lumen] keys are on Configuration.
Lumen indexes Rust, Python, Go, TypeScript and JavaScript (TSX and JSX included).
What each hint proves
- [ ] limiter type is defined [symbol: struct RateLimiter in src/middleware/rate_limit.rs]
- [ ] app wires the limiter [callers: method RateLimiter::layer in src/middleware/rate_limit.rs within function build_router in src/app.rs]
- [ ] config reaches the limiter [references: struct AppConfig in src/config.rs within struct RateLimiter in src/middleware/rate_limit.rs]
| Hint | Passes when | Doesn't count |
|---|---|---|
[symbol:] | A definition of that kind and name exists in exactly that file | Imports, use sites |
[references:] | An occurrence inside the within symbol binds to the target through scope and static imports | A same-named symbol from another module |
[callers:] | As [references:], and the occurrence is the callee of a call | Passing the function as a value |
Here a stub agent claims the wiring is done. The grep passes on a // TODO: comment; the [callers:] hint holds out until the real call lands:
─── task-wire: Wire the rate limiter ─── effort=low, deps=[]
→ iteration 1 of 3
✓ agent completed: exit=0, 272ms
✓ symbol: struct RateLimiter in src/middleware/rate_limit.rs
already passed at pre-flight — proves nothing about this run
✓ grep: install_limiter\(&cfg\) in src/app.rs
already passed at pre-flight — proves nothing about this run
✗ callers: function install_limiter in src/middleware/rate_limit.rs within function build_router in src/app.rs
stderr tail: unbound: no call occurrence of `install_limiter` in `build_router` (in src/app.rs) binds to `install_limiter` in src/middleware/rate_limit.rs
…
→ iteration 3 of 3
✓ agent completed: exit=0, 56ms
✓ callers: function install_limiter in src/middleware/rate_limit.rs within function build_router in src/app.rs
evidence file modified by agent
✓ task-wire: passed in 3 iterations (464ms)
A failure is typed (symbol_unresolved or binding_unresolved) with a diagnostic (not found, wrong kind, ambiguous with every candidate listed), and the diagnostic goes into the agent's next prompt. A pass records the resolved symbol and its source span in prd.json.
Note
False negatives over false greens. What can't be bound deterministically (dynamic dispatch, trait objects, macro-generated names, method calls that need the receiver's type) fails rather than guesses. A structural hint can be strict; it can't be wrong in your favour.
The index during a run
- Lazy. A PRD with no structural hints never builds or reads the index.
- Current. The index is repaired before each verification pass, so code the agent just wrote resolves at once.
- Fails closed. No usable index means the hint fails, never passes.
- Repo-scoped. One index serves every PRD.
zurdo run --resetleaves it alone;zurdo lumen cleardeletes it.
An optional watcher, Vela, can keep the index warm between runs. It never changes a verdict. Vela, and which constructs resolve in each language, are on Internals.
Asking the index a question
Structural hints assert; zurdo lumen query asks. Pass exactly one selector:
$ zurdo lumen query --name load
segment method AppConfig::load src/config.rs:6:5
$ zurdo lumen query --outline src/middleware/rate_limit.rs
module rate_limit src/middleware/rate_limit.rs:1:1
struct RateLimiter src/middleware/rate_limit.rs:3:1
field RateLimiter::per_second src/middleware/rate_limit.rs:4:5
method RateLimiter::new src/middleware/rate_limit.rs:8:5
method RateLimiter::layer src/middleware/rate_limit.rs:11:5
$ zurdo lumen query --callers new
RateLimiter::new build_router src/app.rs:6:19
$ zurdo lumen query --references AppConfig
AppConfig build_router src/app.rs:5:15
AppConfig config src/config.rs:5:6
AppConfig RateLimiter::new src/middleware/rate_limit.rs:8:22
| Selector | Row |
|---|---|
--name | rank kind qualified-name file:line:col |
--outline | kind qualified-name file:line:col, in source order |
--callers | callee enclosing-symbol file:line:col |
--references | identifier enclosing-symbol file:line:col |
Results stop at 20 rows; --limit 0 lifts the cap. The query repairs the index first and writes nothing. Use --name before writing a hint: it prints the exact kind and qualified name the hint needs. The same four questions are served to agents by zurdo mcp serve.
| Command | What it does |
|---|---|
zurdo lumen status | Record counts, languages and the last publish time |
zurdo lumen rebuild | Rebuild the index from scratch. The fix for a non-ready index. |
zurdo lumen clear | Delete .zurdo/lumen/ (--yes skips the prompt) |
Pyxis: finding code by meaning
zurdo lumen query needs an exact name, kind or path. Pyxis (since 1.26.0) answers a free-text question such as "the code that loads the config". It indexes one unit per Lumen definition and one per markdown section, and ranks them.
[lumen]
enabled = true # required: symbol units come from Lumen
[pyxis]
enabled = true
zurdo pyxis query "the code that loads the config"
zurdo pyxis status
- Lexical always. With no model, ranking is BM25: no network and nothing to download.
- Hybrid with a model.
zurdo pyxis installfetches the pinned embedding model and checks its digests. Rankings then fuse BM25 with embedding similarity, and each row sayslexicalorhybrid. - Retrieval, not proof. A row points at a file, never a line, and never satisfies a criterion. Use it to find where to look, then pin a structural hint.
With [pyxis] enabled = true, zurdo mcp serve also publishes find_related, the same query for agents.
Authoring with structural hints
- Wiring criteria. "The middleware is installed" is exactly
[callers:]. A grep for the registration line passes on commented-out code. - Existence with teeth. Prefer
[symbol:]over grep when it must be a real definition in the right file. - Cost. Pricier to write than grep, cheaper than building
[shell:]test infrastructure to prove a relationship.
| Symptom | Fix |
|---|---|
structural hint requires lumen.enabled = true | Set [lumen] enabled = true. |
| Pre-flight fails with a non-ready index | zurdo lumen rebuild, then re-run. |
| "wrong kind" | Use the kind the diagnostic names (struct vs type is the usual one). |
unknown symbol kind naming field, enum-variant, macro or alias | Those are recorded but not hint kinds. Target the enclosing type. |
[callers:] fails binding_unresolved though the call is there | The call site doesn't import the target, or the call needs receiver-type inference. Import it directly, or use [shell:]. |