# template_search_project — Agent Guide
## Purpose
Exemplar project demonstrating end-to-end use of the
`infrastructure/search/`, `infrastructure/reference/`, and
`infrastructure/llm/` modules. Mirrors the structure of
`projects/templates/template_code_project/` so the pipeline runner discovers
and executes both projects with the same code.
Decision memory and verifier hardening follow [`docs/rules/memory_and_decision_records.md`](../../../docs/rules/memory_and_decision_records.md): use nearby `WHY:` comments only for surprising local choices, keep volatile counts generated, and add negative controls for verifier-like gates.
Subfolder documentation: [`docs/AGENTS.md`](docs/AGENTS.md), [`manuscript/AGENTS.md`](manuscript/AGENTS.md), [`src/AGENTS.md`](src/AGENTS.md), [`tests/AGENTS.md`](tests/AGENTS.md), [`scripts/AGENTS.md`](scripts/AGENTS.md) (each with a [`README.md`](README.md) in the same directory).
## Layout
```mermaid
flowchart TB
ROOT[/projects/templates/template_search_project/]
ROOT --> SRC_DIR[/src
domain logic/]
ROOT --> TESTS_DIR[/tests
real-data tests/]
ROOT --> SCR_DIR[/scripts
thin orchestrators/]
ROOT --> MAN_DIR[/manuscript/]
ROOT --> DATA_DIR[/data
committed corpus/]
ROOT --> DOCS_DIR[/docs/]
ROOT --> OUT_DIR[/output
regeneratable/]
ROOT --> META[pyproject.toml
README.md · AGENTS.md · .gitignore]
SRC_DIR --> S_CFG[config.py
typed YAML loader]
SRC_DIR --> S_PIPE[pipeline.py
search → enrich → BibTeX]
SRC_DIR --> S_DEEP[deep_search.py
multi-keyword fan-out]
SRC_DIR --> S_SYN[synthesis.py
prompts · LLM callable]
SRC_DIR --> S_FIG[figures.py
matplotlib plots]
SRC_DIR --> S_MV[manuscript_variables.py
substitution]
SRC_DIR --> S_REP[report.py
markdown assembly]
SRC_DIR --> S_AN[analysis.py
review-stage helpers]
SRC_DIR --> S_DOT[dotenv.py
.env loader]
TESTS_DIR --> T_LIST[test_config · test_pipeline · test_analysis ·
test_scripts · …]
SCR_DIR --> SC0[run_deep_search.py]
SCR_DIR --> SC1[run_search_pipeline.py]
SCR_DIR --> SCS[s_compose_literature_review.py]
SCR_DIR --> SC2[y_generate_search_figures.py]
SCR_DIR --> SC3[z_generate_manuscript_variables.py]
SCR_DIR --> SC4[zz_generate_review_report.py]
SCR_DIR --> SC5[zzz_build_dashboard.py]
SCR_DIR --> SCR_REV[review
configurable gate]
MAN_DIR --> M_CFG[config.yaml
single source of truth]
MAN_DIR --> M_PRE[preamble.md]
MAN_DIR --> M_SECTIONS[00_abstract.md … 07_deep_search.md ·
S01_literature_review.md · 99_references.md]
MAN_DIR --> M_BIB[references.bib · references_deep.bib
auto-generated where applicable]
DATA_DIR --> D_CORPUS[corpus.json
offline default]
DOCS_DIR --> D_FILES[quickstart.md ·
architecture.md ·
output_conventions.md ·
troubleshooting.md]
classDef dir fill:#0f172a,stroke:#0f172a,color:#fff
classDef code fill:#1e3a8a,stroke:#0f172a,color:#fff
classDef doc fill:#0f766e,stroke:#0f172a,color:#fff
classDef gen fill:#7c2d12,stroke:#0f172a,color:#fff
class ROOT,SRC_DIR,TESTS_DIR,SCR_DIR,MAN_DIR,DATA_DIR,DOCS_DIR,OUT_DIR dir
class S_CFG,S_PIPE,S_DEEP,S_SYN,S_FIG,S_MV,S_REP,S_AN,S_DOT,SC0,SC1,SCS,SC2,SC3,SC4,SC5,SCR_REV,T_LIST code
class M_CFG,M_PRE,M_SECTIONS,D_CORPUS,D_FILES,META doc
class M_BIB gen
```
## Key contracts
* `src/config.py::ProjectConfig` — every knob is here. Adding a new flag
means: add a field to the dataclass, add YAML parsing in
`from_dict`, add a default in `manuscript/config.yaml`. Tests live in
`tests/test_config.py`.
* `src/pipeline.py::run_literature_pipeline` — the only function that
touches `infrastructure.search.*`. Returns a
:class:`LiteratureRunArtifacts` so the script knows where every
artefact landed without re-deriving paths.
* `src/synthesis.py` — duck-typed `llm: (str) -> str` callable lets
tests pass deterministic local functions and runtime callers pass an
Ollama-backed adapter. Prompts are module-level constants.
* `src/report.py::write_reading_report` — single function; takes a
`SearchResult` + citation-key map + optional synthesis records.
## Run modes
### Standard pipeline (`run_search_pipeline.py`)
| Command | Behaviour |
|---|---|
| `python scripts/run_search_pipeline.py` | Default config, hits live arXiv + Crossref, runs LLM if Ollama is reachable, writes everything. |
| `… --no-llm` | Skip the LLM stage; produce reading report without synthesis. |
| `… --no-cache` | Bypass cache reads (writes still happen). |
| `… --corpus path.json` | Required when `project_config.search.sources` includes `local`. |
| `… --config other.yaml` | Use an alternative config file. |
### Deep search (`run_deep_search.py`)
Reads the `deep_search:` block of `config.yaml`. Each keyword runs its
own `SearchQuery` (capped at `max_results_per_keyword`, default 100),
every paper is fully enriched (abstract + fulltext), and each paper
gets a multi-section markdown reading note (LLM-generated when enabled).
See [`src/deep_search.py`](src/deep_search.py) and
[`manuscript/07_deep_search.md`](manuscript/07_deep_search.md).
| Command | Behaviour |
|---|---|
| `python scripts/run_deep_search.py` | Honours `project_config.deep_search.enabled`; exits 2 if disabled. |
| `… --enable` | Force-enable regardless of config. |
| `… --keyword "X" --keyword "Y"` | Override the keyword list at the CLI. |
| `… --no-llm` | Skip per-paper LLM summaries even when config enables them. |
| `… --no-cache` | Bypass `SearchCache` reads. |
| `… --corpus path.json` | Use a local JSON corpus instead of network backends. |
## Testing
```bash
uv run pytest projects/templates/template_search_project/tests/ -v
```
All tests run offline: `LocalBackend` against real temp files,
deterministic LLM callable, real subprocess where needed. The committed
`data/corpus.json` is a deterministic fixture, not empirical evidence; the
standard report writes a fixture-scope notice and rejects high-confidence
empirical assertion language in fixture-backed synthesis.
## How this project differs from `template_code_project`
* `template_code_project` has its **own algorithm** (`src/optimizer.py`) and
generates figures from numerical experiments.
* `template_search_project` has **no algorithm** — its `src/` is pure
orchestration over `infrastructure/`. The "experiment" is the
pipeline itself.
* Both projects emit a Pandoc-ready `references.bib`; this project
populates it from a query, while `template_code_project` ships a hand-curated
one.
* Both projects produce a manuscript PDF via the standard pipeline.
## Extending
To target a different topic:
1. Edit `manuscript/config.yaml` → `project_config.search.query`.
2. Adjust `project_config.search.year_min` / `year_max` / `sources` as needed.
3. Re-run `scripts/run_search_pipeline.py`.
To swap LLM models:
1. Change `llm.model` (must be available locally via `ollama pull `).
2. Optionally change `llm.seed` / `llm.temperature`.
To use only a curated corpus (offline reproducibility):
1. Generate one once via `infrastructure.search.literature.write_corpus`.
2. Set `project_config.search.sources: [local]` in `config.yaml`.
3. Pass `--corpus path/to/corpus.json` to the script.
## Review phase
Configurable gate via [`scripts/review`](scripts/review) and [`review_config.yaml`](review_config.yaml). The project-analysis stage runs [`scripts/zz_generate_review_report.py`](scripts/zz_generate_review_report.py) last; if `output/review/summary.json` is absent it invokes `scripts/review` subprocess before writing `output/review/REVIEW_REPORT.md`.
List stages:
```bash
cd projects/templates/template_search_project && uv run python scripts/review --list
```
Run all enabled stages (from repo root):
```bash
uv run python projects/templates/template_search_project/scripts/review \
--project-root "$(pwd)/projects/templates/template_search_project"
```
### Available stages
| Name | Validates | Backend |
|------|-----------|---------|
| `prerender_validation` | Source markdown gate | `infrastructure.validation.cli prerender` (`--repo-root` is `.` with project `cwd`) |
| `markdown_links` | Repo link scan | `infrastructure.validation.cli links` |
| `bibtex_validation` | BibTeX strict | `infrastructure.reference.citation.cli validate` |
| `bibliography_completeness` | `[@key]` ↔ `.bib` | `src.analysis` (subprocess) |
| `variables_resolved` | `{{TOKENS}}` | `src.analysis` |
| `output_integrity` | `output/` | `infrastructure.validation.cli integrity` |
| `test_suite_health` | pytest + coverage | subprocess |
| `infrastructure_usage` | `infrastructure.*` imports | `src.analysis` |
| `determinism_check` | cache / seed / temperature | `src.analysis` |
Disable a stage with `enabled: false` in `review_config.yaml`.
### Custom stages
Add `stage_type: custom` and wire the subprocess in `scripts/review` to `src.analysis` (see that file’s `run_custom_stage`).
## Related Capabilities
This project's full-text acquisition is the narrow `FulltextFetcher` in
`infrastructure/search/literature/fulltext.py` — arXiv-derived or
`paper.pdf_url` PDF download only, with no Unpaywall/OA resolution across
arbitrary DOIs — and `src/` has no workflow-graph decomposition or composite
reproducibility score over that text.
[`template_literature_meta_analysis`](../template_literature_meta_analysis/)
is a candidate pattern to adopt here if this project's acquisition step
grows to match: its `src/literature/fulltext_download.py` resolves full text
via Unpaywall/OA/direct-PDF with graceful degradation, feeding
`src/reproducibility/` — an LLM-populated workflow-graph model (`models.py`)
scored by a no-compensation composite (`scoring.py`: `R = sqrt(Rc * Rs)` over
content and structural sub-scores). Porting the workflow-graph/scoring
approach here would first require a comparable multi-source full-text
resolver, since the sibling project's reproducibility runner assumes richer
full-text coverage than a single-source arXiv fetch provides. Not planned
work — noted for future reference only.
## See also
* [`README.md`](README.md) — quick reference.
* [`docs/README.md`](docs/README.md) — project docs index.
* [`docs/modules/literature-search-and-references.md`](../../../docs/modules/literature-search-and-references.md) — module overview.
* [`docs/guides/literature-workflow-guide.md`](../../../docs/guides/literature-workflow-guide.md) — narrative tutorial.
* [`infrastructure/search/AGENTS.md`](../../../infrastructure/search/AGENTS.md) and [`infrastructure/reference/AGENTS.md`](../../../infrastructure/reference/AGENTS.md) — infrastructure guides.