Skip to content

API reference

The CLI is the primary user interface, but the underlying Python package is also importable for programmatic use. This page is a module-by-module reference for what’s in each file and what’s part of the public API.

For the source: home/collabs/elife/claim-trees/extract/elife_extract/. ~1200 lines of Python across 9 modules.

The argparse-based command-line interface. ~400 lines.

Entry points:

  • main(argv: list[str] | None = None) -> int — the elife-extract console script
  • build_parser() -> argparse.ArgumentParser — build the full parser; useful for embedding the CLI in another tool

Subcommand handlers:

  • cmd_extract(args) — Steps 1-4 (prepare → reconcile)
  • cmd_write(args) — Steps 5-7 (review → write)
  • cmd_verify_refs(args) — CrossRef DOI resolution
  • cmd_run(args) — composed shorthand
  • cmd_evaluate(args) — round-trip scoring

Each handler resolves a Config from the args, runs its phase, and returns an exit code.

Configuration resolution. ~120 lines.

Class:

  • Config — dataclass holding resolved configuration. Constructed via Config.from_args(args) which falls through CLI args → env vars → defaults.

Module constants:

  • DEFAULT_MODEL_RESULTS = "claude-sonnet-4-6"
  • DEFAULT_MODEL_CAPTION = "claude-sonnet-4-6"
  • DEFAULT_MODEL_STRUCTURE = "claude-sonnet-4-6"
  • DEFAULT_MODEL_RECONCILE = "claude-opus-4-6"
  • DEFAULT_VERTEX_PROJECT = "cr-mainen"
  • DEFAULT_VERTEX_REGION = "europe-west1"
  • DEFAULT_PROMPT_VARIANT = "default"

Methods:

  • Config.from_args(args) -> Config — build from argparse Namespace
  • Config.prompt_path(agent: str) -> Path — resolve the prompt file for a given agent in the active variant
  • Config.validate() -> list[str] — return error messages if config is incomplete

Pydantic models for the wire format between pipeline steps. ~80 lines.

Type aliases:

  • ClaimType = Literal[...] — the 5 (or 9, in extended schema) claim-type values
  • Role = Literal[...] — the 9 role values
  • AgentName = Literal["results", "caption", "structure", "reviewer"] — agent identifiers
  • AgentConfidence = Literal["high", "tentative"]
  • ReconciledConfidence = Literal["high", "contested", "single-source"]

Classes:

  • CandidateClaim — one claim as emitted by a single extraction agent
  • AgentExtraction — the output of one extraction agent on one paper (paper_slug + claims list)
  • ReconciledClaim — a claim after the reconciliation step (with confidence, sources, evidence_by_agent)
  • DraftClaimTable — the output of Step 4, the input to Step 5

All models inherit from pydantic.BaseModel; instantiate from dicts (validated) and serialize via .model_dump_json().

Step 1: paper fetch, slice, figure mapping. ~200 lines.

Class:

  • PreparedPaper — dataclass with doi, paper_slug, title, authors, abstract, results_text, captions_text, methods_text, extraction_path, figure_captions

Functions:

  • prepare(doi: str, ...) -> PreparedPaper — top-level: fetch, slice, return prepared paper
  • fetch_pdf(article_id: str, cache_dir: Path | None = None) -> Path — fetch from eLife CDN with disk cache
  • extract_text(pdf_path: Path) -> str — pdfplumber wrapper
  • slice_sections(text: str) -> dict[str, str] — regex-based section detection
  • extract_figure_captions(text: str) -> list[FigureCaption] — caption parser
  • derive_slug(authors, year, title) -> str — slug derivation from metadata
  • article_id_from_doi(doi: str) -> str — extract article ID from eLife DOI

Steps 2-3: extraction agents. ~150 lines.

Functions:

  • run_agent(agent: AgentName, paper: PreparedPaper, cfg: Config) -> AgentExtraction — run one agent
  • run_all_agents(paper, cfg) -> tuple[AgentExtraction, AgentExtraction, AgentExtraction] — run all three sequentially
  • slice_for_agent(agent: AgentName, paper: PreparedPaper) -> str — what each agent reads
  • load_prompt(agent: AgentName, cfg: Config) -> str — load the role-specific prompt
  • parse_json_response(raw: str) -> list[dict] | dict — JSON parsing with code-fence tolerance
  • get_vertex_client(cfg: Config) -> AnthropicVertex — cached Vertex client

Step 4: reconciliation. ~120 lines.

Function:

  • reconcile(results, caption, structure, cfg, paper_doi, paper_title) -> DraftClaimTable — the Opus reconciliation call

Step 4.5: external Opus reviewer pass. ~110 lines.

Function:

  • external_review(paper: PreparedPaper, draft: DraftClaimTable, cfg: Config) -> DraftClaimTable — runs the Opus reviewer pass on a reconciled draft, returns a revised DraftClaimTable

Step 5: human review gate. ~110 lines.

Function:

  • review(draft: DraftClaimTable, cfg: Config) -> DraftClaimTable | None — invoke the configured review mode (interactive / auto-approve / dry-run); external mode is invoked from cmd_write directly

Steps 6-7: dependency mapping (scaffolded) + claim file emission. ~200 lines.

Functions:

  • write_claim_files(draft: DraftClaimTable, cfg: Config) -> list[Path] — emit claim files; returns paths written
  • derive_claim_slug(claim_text: str, panel: str | None) -> str — slug derivation from claim text
  • map_dependencies(draft, cfg) -> DraftClaimTable — Step 6 (currently a no-op; raises NotImplementedError)

CrossRef DOI resolution for literature-context claims. ~250 lines.

Class:

  • VerifyResult — per-claim resolution outcome

Functions:

  • verify_refs(paper_slug, cfg, dry_run) -> list[VerifyResult] — top-level walk
  • verify_claim(fm, body, paper_slug, claim_path, dry_run) -> VerifyResult — verify one claim
  • crossref_lookup(query, rows=3) -> list[CrossrefMatch] — CrossRef /works query
  • crossref_resolve_doi(doi) -> CrossrefMatch | None — confirm a DOI resolves
  • extract_reference_hints(slug, claim_text, body_text) -> list[str] — hint extraction for un-DOI’d claims

Round-trip scoring. ~300 lines.

Class:

  • PaperScorecard — per-paper scoring result
  • Claim — per-claim representation for the matcher

Functions:

  • evaluate_paper(ref_paper_dir, work_dir, cfg, review_mode) -> PaperScorecard — full pipeline + scoring on one paper
  • score_against_reference(ref_dir, cli_dir, paper_slug, paper_doi, review_mode, cfg) -> PaperScorecard — score one CLI output against a reference
  • aggregate_report(cards, out_path, reference_dir, work_root, review_mode) — render multi-paper scorecard
  • run_matcher(ref_claims, cli_claims, cfg) -> dict — Opus matcher call
  • load_claims(claim_dir, source) -> list[Claim] — read claim files from a paper directory
from elife_extract.config import Config
from elife_extract.prepare import prepare
from elife_extract.agents import run_all_agents
from elife_extract.reconcile import reconcile
from elife_extract.external_review import external_review
from elife_extract.write import write_claim_files
# Build a Config (without going through argparse)
import argparse
ns = argparse.Namespace(corpus_dir="/tmp/corpus", review_mode="external")
cfg = Config.from_args(ns)
# Run the pipeline programmatically
paper = prepare("10.7554/eLife.95562")
results, caption, structure = run_all_agents(paper, cfg)
draft = reconcile(results, caption, structure, cfg, paper_doi=paper.doi, paper_title=paper.title)
revised = external_review(paper, draft, cfg)
written = write_claim_files(revised, cfg)
print(f"wrote {len(written)} claim files")

This bypasses the CLI’s user-facing logging but uses the same modules. Useful for embedding the pipeline in larger systems or for testing.

  • home/collabs/elife/claim-trees/extract/elife_extract/ — the source
  • pyproject.toml — package metadata and entry point declaration