CLI & API Reference

Complete documentation for developers and AI agents

CLI Usage

research-agent [query] [--flags]

Options

FlagTypeDefaultDescription
querystringResearch query (positional, optional)
--evalflagfalseRun evaluation suite
--eval-runsint2Runs per eval task
--gepaflagfalseRun GEPA self-improvement loop
--gepa-generationsint3Number of GEPA generations
--gepa-poolint4Candidates per generation
--dogfoodflagfalseFull pipeline: eval + GEPA + self-patch
--searx-instancestringSearXNG instance URL (e.g. http://localhost:8888)
--self-updateflagfalseUpdate research-agent.py from GitHub latest release
--statestringresearch_state.jsonPath to state file
--forceflagfalseRe-run even if completed
--clearflagfalseClear saved state and exit
--reportflagfalsePrint last report and exit

Examples

# Basic research
research-agent "Latest developments in RAG"

# Run eval suite (3 tasks × 4 checks each)
research-agent --eval --eval-runs 1

# Self-improvement loop (5 generations, 6 candidates each)
research-agent --gepa --gepa-generations 5 --gepa-pool 6

# Full dogfood pipeline
research-agent --dogfood

# Use custom SearXNG instance
research-agent --searx-instance http://searxng.local:8888 "latest AI papers"

# Update to latest version
research-agent --self-update

# View last report
research-agent --report

Programmatic API

Import and use research-agent as a Python module:

ResearchAgent

from research_agent import ResearchAgent
import asyncio

agent = ResearchAgent("Impact of AI on healthcare?")
state = asyncio.run(agent.run())
print(state.report[:500])
print(f"Status: {state.status}")

EvaluationRunner

from research_agent import EvaluationRunner

runner = EvaluationRunner(n_runs=2)
results = asyncio.run(runner.run_all())
for task in results["tasks"]:
    errors = sum(r["errors"] for r in task["runs"])
    print(f"{task['title']}: {'PASS' if errors == 0 else 'FAIL'}")

GEPALoop

from research_agent import GEPALoop, EvaluationRunner

gepa = GEPALoop(pool_size=4, max_generations=3)
eval_runner = EvaluationRunner(n_runs=1)
results = asyncio.run(gepa.run_self_improvement(eval_runner))
print(gepa.format_report(results))

Eval Suite

The evaluation suite tests research quality across 3 tasks with 4 deterministic checks each:

IDTaskChecks
eval-001Ambiguous Health Claim — coffee & heart healthExecutive summary, findings with sources, bibliography, contradictions
eval-002Emerging Technology Impact — quantum computing & cryptographyExecutive summary, findings with sources, bibliography, contradictions
eval-003Historical Revisionism — fall of the Roman EmpireExecutive summary, findings with sources, bibliography, contradictions

Each check is a keyword-based heuristic scan of the generated report. All checks are deterministic and complete in ~ms. Adding new eval tasks is straightforward:

EVAL_TASKS.append({
    "title": "Your Task",
    "query": "Your research question",
    "checks": [
        lambda r: ("keyword" in r.lower()),
        lambda r: (r.count("###") >= 3),
    ],
})

Grading System

GraderMethodDependencies
HeuristicGraderKeyword-based report quality analysisNone (built-in)
OllamaGraderLocal LLM inference via Ollama APIOllama installed + model pulled

The heuristic grader checks 4 dimensions: synthesis quality (conclusion language), thoroughness (analysis terms), balance (contrastive language), and specificity (citations, numbers). Each dimension is scored 0-0.25 for a total score of 0.0-1.0.

Self-Patching

After a GEPA run, the best candidate's prompts are written to _self_patch.py:

research-agent --gepa --gepa-generations 3
python _self_patch.py
# Patched to v2.X.X with N prompt updates

The patch script modifies research_agent.py in-place using re.sub for surgical replacements. It updates SCRIPT_VERSION and modifies the BASE_PROMPTS dictionary.

GEPA Internals

PromptCandidate

@dataclass
class PromptCandidate:
    id: str                     # e.g. "gen0-3"
    parent_id: str | None       # e.g. "gen0-0"
    prompt_template: dict[str, str]  # one prompt per module
    accuracy: float = 0.0
    speed_ms: float = 0.0
    token_efficiency: float = 0.0
    generation: int = 0
    pareto_front: bool = False

Lesson

Reflections produce structured lessons that drive targeted mutations:

@dataclass
class Lesson:
    module: str       # Which module needs improvement
    failure: str      # Which check failed (with task ID)
    suggestion: str   # What to change in the prompt

Mutation Strategy

Version History

VersionChanges
2.0.0Full GEPA loop, Ollama grading, self-patching, Rich CLI
2.0.1SearXNG support, --self-update, bug fixes, CI/CD, Docs site