Installs into .claude/skills of the current project.
Are you the author of Prd?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/mehdiforoozandeh-prd-crux)
# PRD: the literature-search scoping skill
- **Kind:** feature · **Spec:** [.spec/17-openalex.md](../../.spec/17-openalex.md) (slice 17.3)
## Problem / motivation
`crux lit crawl` seeded itself from *every* `raw/` source carrying a work id. That is wrong
for any vault with more than one line of enquiry: a `raw/` holding chromatin-segmentation
papers **and** optimiser papers produces a subgraph about neither. The seed set is the
load-bearing input — [the spec's](../../.spec/17-openalex.md) own reframe — and nothing let
the PI choose it deliberately.
## Design decision
A new skill, `skills/crux-litsearch/`, mirroring `crux-autopilot`'s shape at proportionate
ceremony: **two asks and one approval**, ending in a written file rather than in chat.
1. *Ask* — what is this search for? One paragraph, the PI's own words.
2. *Ask* — which papers do you already trust? Target 3–8. Where the PI names a paper rather
than a DOI, the agent resolves it and reads the title back before it enters the file; a
wrong seed is invisible in the output and poisons every rank. Where the PI has no seeds,
the agent proposes candidates **by name** from its own knowledge and says so plainly — no
keyword-search verb is added, because naming papers needs no new engine surface.
3. *Approve* — write `wiki/lit/<slug>/scope.md`, run `crux lit lint <slug>`, show the PI, stop.
**The skill writes; the engine checks.** Same split as PRD 05.5: the setup skill is not
unit-tested, the grammar it writes against is. That is what makes a conversation testable.
`crux lit crawl <slug>` uses the scope's seeds when a scope file exists and the whole registry
when it does not — a one-topic vault should not have to hold a conversation before it can
search. This resolves the PI's third open question from 17.2.
`candidates.tsv` stays **complete and sorted**; the skill presents the top 30 and offers to go
deeper. Truncating the file destroys evidence that costs a whole budget to recover. This
resolves the second open question.
## Scope — what this does not do
No PDF download and no auto-ingest (17.4). No keyword or vector search verb. No year window
and no topic filter — still waiting for a real crawl to show they are needed. The skill never
runs the crawl and never writes to `raw/`: [crux-wiki](../../skills/crux-wiki/SKILL.md)'s rule
that the PI alone curates sources is untouched; the PI just curates from a computed list
instead of memory.
## Acceptance criteria
- [x] A well-formed `scope.md` lints clean; each of the five findings fires on its own minimal
fixture under a stable slug (`scope-slug`, `scope-seed-count`, `scope-seed-duplicate`,
`scope-seed-unknown`, `scope-problem-empty`, `scope-problem-long`).
- [x] Lint reports every problem a scope carries in one pass, not just the first.
- [x] `crux lit crawl` uses the scope's seeds when the file exists and the full registry when
it does not, asserted by the queries actually issued against a stubbed boundary.
- [x] A seed that is neither a work id nor a DOI is a lint finding, not a crash.
- [x] A seed given as a **DOI** is resolved to a work id before the crawl. (Found by the
manual criterion: `_bare()` sheared `10.1038/nmeth.1906` to `nmeth.1906` and queried for
a work that does not exist.)
- [x] The skill ships, stays under `crux-autopilot/SKILL.md`'s size, names `scope.md` as its
only output and states that the PI curates `raw/`.
- [x] `engine.py` imports no `urllib`; `crux lit lint` never loads the network module at all.
- [x] selftest green and offline from a fresh clone with no key (2067 → 2083).
- [x] (manual) Ran the whole thing against the chromatin vault: a hand-written scope with
three DOI seeds lints clean, a broken seed reports as one finding with exit 1, and the
scope-driven crawl reproduces the 17.2 list exactly — 3,584 candidates, same top 5.
## Also fixed, found by the manual criterion
An HTTP **400** — a malformed query, which is a crux bug — was reported with the "register a
free key, your budget may be spent" message, sending the PI to fix something that was not
wrong. Status codes are now told apart: 400 says it is a crux bug, 401/403 names the key, 429
mentions the daily reset, and only a genuine network failure gets the original text.
## Backward-compat / migration
None. New files under `wiki/lit/<slug>/`; no format change, no verdict change.
`ENGINE_VERSION` stays 3.4.