# Custom agents

Drive the pipeline from your own harness using the skill files and the run-directory interface.

Nothing about Research Scan assumes Claude Code. The interface is a run directory
of JSON and a CLI with stable exit codes, so any harness that can run a subprocess
and read a file can drive the pipeline — including fifty lines of Python.

There are two ways in.

## Option 1 — speak MCP

If your harness already speaks MCP, launch `research-scan mcp` over stdio and use
[the four tools](/reference/mcp-tools/). You supply the judgement at each
decision point; the adapter drives the CLI and manages the run directory for you.

This is the lower-effort route, and it is the one to prefer if MCP is available to
you.

## Option 2 — drive the CLI directly

The stages are ordinary commands. Your harness runs them in order and writes the
three agent-owned files between them.

```bash
research-scan init "your question" --profile quick --json
# → write queries.json
research-scan retrieve --json
# → score every batch in screen-batches/, write screen.json
research-scan expand --json
# → score the expansion batches, append to screen.json
research-scan coverage --json
# → optionally: write round-2 queries, then
#   research-scan retrieve --round 2 && research-scan expand --round 2
research-scan shortlist --json
# → write ranked.json
research-scan verify --json
research-scan emit --json
```

Every stage takes `--json` for machine-readable stdout and `--quiet` to silence
the stderr log. Exit codes are stable: `0` success, `2` a validation or usage
failure with every offending path listed, `3` a mandatory readiness check failed.

### What your harness must write

| File | What goes in it |
|---|---|
| `queries.json` | The query plan: 6–8 queries, 3–6 sub-criteria, `must_not`, `anchors`. |
| `screen.json` | A 0–3 score per candidate, with a reason and the criteria hit. |
| `ranked.json` | Per-criterion and overall scores, `relation`, `evidence_level`, `key_finding`, `why_it_matters`, limitations, flags. |

Do not write anything else. The CLI owns `candidates.json`, `shortlist.json`,
`manifest.json` and `evidence.*`, and the two halves never edit each other's
files.

### Get the contracts

`schema.py` in the package is the source of truth, and it will print itself:

```bash
research-scan schema --name Queries        # one model, as JSON Schema
research-scan schema --md                  # every model, as Markdown
```

Validate against those rather than against examples. Unknown keys are rejected
everywhere, so a field your harness invents will surface as an exit-2 error rather
than being ignored.

## Bring the rubrics with you

The judgement your harness supplies should be made against the same rubrics the
skill uses, or against rubrics you have deliberately changed. They ship as plain
Markdown in the main repo under `skills/research-scan/references/`:

| File | Governs |
|---|---|
| `plan-rubric.md` | Query shape, the mandatory query types, sub-criteria derivation. |
| `screen-rubric.md` | The 0–3 scale and its boundary rules. |
| `rerank-rubric.md` | Per-criterion and overall scoring, `relation`, the off-domain cap. |
| `schemas.md` | The generated data contracts. |

`SKILL.md` itself is the procedure: the stage order, what to do at each decision
point, and the rules that hold throughout. Reading it is the fastest way to
understand what a correct harness does.

The two rules it opens with are the ones to carry into any implementation:

> Never cite a paper that is not in the run's files; never edit paper metadata from
> memory.

## Worth knowing before you build

**Screening dominates.** It is the agent reading the pool, and it is most of both
the wall clock and the token cost. Batch it, and expect roughly 3.8 seconds per
candidate at frontier-model speeds.

**Do not show the screener citation counts or venues.** The rubric withholds them
deliberately; a harness that helpfully adds them changes what the scale means.

**Abstracts are truncated to 600 characters** for screening. That is the input the
scale was calibrated against.

**A second round adds, never subtracts.** If you implement the gap round, round
one's scores stay.

**Re-runs should be byte-identical.** The engine's clocks are injectable so that
this holds. If your harness injects a timestamp into a file it writes, you lose
the ability to diff two runs — which is the main way you will evaluate your own
changes.

## Related

- [Artifacts and schemas](/concepts/artifacts-and-schemas/) — the run directory in detail.
- [The agent layer](/architecture/agent-layer/) — what each rubric says.
- [File formats](/reference/file-formats/) — every file, in order.
