Skip to content

Schemas and prompts

Extraction is driven by schema + prompt pairs under extraction.schemas. LitCurate ships worked examples you can copy and adapt.

Shipped examples

Role Path
Example schema (JSON Schema) schemas/example/record.json
Example schema (declarative YAML) schemas/example/record.yaml
Example prompt prompts/example/prompt.md
Bibliographic source schema (JSON) schemas/example/source.json
Bibliographic source schema (YAML) schemas/example/source.yaml

The default dry-run config wires the example record schema:

extraction:
  schemas:
    - name: record
      path: schemas/example/record.json
      prompt: prompts/example/prompt.md
      version: "2.1"
      empty_list_field: eos_entries

Why EOS fields?

The example schema is a concrete equation-of-state extraction shape (eos_entries with V0 / K0 / Kp). Treat it as a template for list-shaped scientific records, not a package dependency on mineral physics. See the full configuration example for how schemas and prompts are connected.

Example prompt

prompts/example/prompt.md
Extract STATIC equation-of-state (EOS) parameters for lower-mantle-relevant phases
into the flat schema. Priority fields: **V0, K0, and Kp (K′)**. Values and units
must be copied exactly as reported.

Target phases (keep these; skip unrelated crustal/transition-zone-only phases unless
explicitly framed as lower-mantle):
- bridgmanite / (Mg,Fe)SiO3 or MgSiO3 perovskite (Pv)
- ferropericlase / magnesiowüstite / periclase / (Mg,Fe)O / MgO
- post-perovskite (PPv)
- CaSiO3 perovskite (CaPv)
- closely related deep-mantle SiO2 or hydrous phases only when discussed with EOS numbers

For each distinct phase + composition + sample/table row + EOS model, return one entry.

Promote when present:
- `V0` (+ `V0_unit`, `V0_name`, `V0_basis`, `V0_determination`)
- `K0` (+ `K0_unit`, `K0_name`, `K0_type`, `K0_determination`)
- `Kp` for K′ / K0′ / K_T′ (+ `Kp_name`, `Kp_determination`)

Determination enums:
- `V0_determination`: `measured` | `fitted` | `assumed` | `unknown`
- `K0_determination`: `fitted` | `measured` | `assumed` | `unknown`
- `Kp_determination`: `fitted` | `fixed` | `assumed` | `unknown`

Ambient / Table zero-pressure unit-cell volumes used with an EOS fit → fill `V0`
with `V0_determination: measured` even if the text only quotes fitted K0 and fixed
K′. Do not park those volumes only in `extra_info`.

Also set: `eos_model`, `method`, `T_ref`/`P_ref` (+ units), `origin`
(`this_study` | `cited` | `unknown`).

INCLUDE literature-tabulated V0/K0/K′ when reported numerically (`origin: cited`).
Other parameters (γ0, θ0, q, α, …) → `extra_info` only.
`evidence` is one string. Do not invent values or convert units.
If no relevant static EOS parameters appear, return `{ "eos_entries": [] }`.

Return JSON matching the schema: `{ "eos_entries": [ ... ] }`.

Example schema

Choose either JSON Schema or declarative YAML — same extraction shape, different file formats. Do not configure both in the same extraction.schemas list.

- name: record
  path: schemas/example/record.json
  prompt: prompts/example/prompt.md
  version: "2.1"
  empty_list_field: eos_entries
schemas/example/record.json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "eos_entries": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "phase": {
            "type": "string"
          },
          "composition": {
            "type": "string"
          },
          "structure": {
            "type": "string"
          },
          "sample": {
            "type": "string"
          },
          "eos_model": {
            "type": "string"
          },
          "method": {
            "type": "string"
          },
          "V0": {
            "type": [
              "string",
              "number"
            ]
          },
          "V0_unit": {
            "type": "string"
          },
          "V0_name": {
            "type": "string"
          },
          "V0_basis": {
            "type": "string",
            "enum": [
              "unit_cell",
              "molar",
              "unknown"
            ]
          },
          "V0_determination": {
            "type": "string",
            "enum": [
              "measured",
              "fitted",
              "assumed",
              "unknown"
            ]
          },
          "K0": {
            "type": [
              "string",
              "number"
            ]
          },
          "K0_unit": {
            "type": "string"
          },
          "K0_name": {
            "type": "string"
          },
          "K0_type": {
            "type": "string",
            "enum": [
              "isothermal",
              "adiabatic",
              "unknown"
            ]
          },
          "K0_determination": {
            "type": "string",
            "enum": [
              "fitted",
              "measured",
              "assumed",
              "unknown"
            ]
          },
          "Kp": {
            "type": [
              "string",
              "number"
            ]
          },
          "Kp_unit": {
            "type": "string"
          },
          "Kp_name": {
            "type": "string"
          },
          "Kp_determination": {
            "type": "string",
            "enum": [
              "fitted",
              "fixed",
              "assumed",
              "unknown"
            ]
          },
          "T_ref": {
            "type": [
              "string",
              "number"
            ]
          },
          "T_ref_unit": {
            "type": "string"
          },
          "P_ref": {
            "type": [
              "string",
              "number"
            ]
          },
          "P_ref_unit": {
            "type": "string"
          },
          "origin": {
            "type": "string",
            "enum": [
              "this_study",
              "cited",
              "unknown"
            ]
          },
          "evidence": {
            "type": "string"
          },
          "confidence": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "optional": true
          },
          "extra_info": {
            "type": "object",
            "additionalProperties": true,
            "optional": true
          }
        },
        "required": [
          "phase",
          "eos_model",
          "evidence"
        ],
        "additionalProperties": false
      }
    }
  },
  "required": [
    "eos_entries"
  ],
  "additionalProperties": false,
  "title": "RecordList",
  "version": "2.1",
  "$id": "litcurate://schemas/example/record/2.1",
  "description": "Example extraction schema (equation-of-state parameters: V0, K0, Kp). Copy and adapt for your domain. Values and units are verbatim from the paper.\n"
}
- name: record
  format: declarative_yaml
  path: schemas/example/record.yaml
  prompt: prompts/example/prompt.md
  version: "2.1"
  empty_list_field: eos_entries
schemas/example/record.yaml
title: RecordList
version: "2.1"
$id: litcurate://schemas/example/record/2.1
description: >
  Example extraction schema for static V0, K0, and Kp (K') equation-of-state
  parameters. Values and units are verbatim from the paper.

fields:
  eos_entries:
    array:
      required: [phase, eos_model, evidence]
      fields:
        phase: string
        composition: string?
        structure: string?
        sample: string?

        eos_model: string
        method: string?

        V0: string|number?
        V0_unit: string?
        V0_name: string?
        V0_basis: enum(unit_cell, molar, unknown)?
        V0_determination: enum(measured, fitted, assumed, unknown)?

        K0: string|number?
        K0_unit: string?
        K0_name: string?
        K0_type: enum(isothermal, adiabatic, unknown)?
        K0_determination: enum(fitted, measured, assumed, unknown)?

        Kp: string|number?
        Kp_unit: string?
        Kp_name: string?
        Kp_determination: enum(fitted, fixed, assumed, unknown)?

        T_ref: string|number?
        T_ref_unit: string?
        P_ref: string|number?
        P_ref_unit: string?

        origin: enum(this_study, cited, unknown)?

        evidence: string
        confidence:
          type: number
          minimum: 0
          maximum: 1
          optional: true

        extra_info:
          type: object
          additionalProperties: true
          optional: true

Warning

Do not configure both record schemas in the same extraction list. They represent the same schema in two file formats; choose either JSON or YAML.

Valid payload shape

Top-level object with an eos_entries array. Each entry requires at least phase, eos_model, and evidence:

{
  "eos_entries": [
    {
      "phase": "ExamplePhase",
      "composition": "ABO3",
      "eos_model": "3rd-order Birch-Murnaghan",
      "method": "XRD",
      "V0": "46.23",
      "V0_unit": "Å^3",
      "V0_determination": "measured",
      "K0": "106 (2)",
      "K0_unit": "GPa",
      "K0_determination": "fitted",
      "Kp": "4",
      "Kp_determination": "fixed",
      "origin": "this_study",
      "evidence": "Table 2 reports K0 = 106 (2) GPa with K′ fixed at 4."
    }
  ]
}

If the paper has nothing extractable, return { "eos_entries": [] }.

Optional source schema

Bibliographic source metadata is filled from OpenAlex / parquet, not extracted by an LLM. Set fill_from: papers_meta; do not provide a prompt:

extraction:
  schemas:
    - name: record
      path: schemas/example/record.json
      prompt: prompts/example/prompt.md
      empty_list_field: eos_entries
    - name: source
      path: schemas/example/source.json
      fill_from: papers_meta
      skip_when_prior_empty: record

With fill_from set:

  1. LitCurate reads bibliographic fields from the best available paper metadata (papers_filtered.parquet, then papers_ranked.parquet).
  2. It does not call an LLM and does not read a prompt.
  3. It validates the generated payload against the configured source schema.
  4. It writes the normal extraction envelope as <paper_id>/source.json.

The schema is therefore required even though a prompt is not.

- name: source
  path: schemas/example/source.json
  fill_from: papers_meta
schemas/example/source.json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Source",
  "type": "object",
  "required": ["doi", "title", "year", "source_type"],
  "properties": {
    "doi": { "type": "string" },
    "title": { "type": "string" },
    "authors": { "type": "array", "items": { "type": "string" } },
    "journal": { "type": "string" },
    "year": { "type": "integer" },
    "source_type": {
      "type": "string",
      "enum": ["journal", "database", "book", "thesis", "other"]
    },
    "evidence_text": { "type": "string" },
    "confidence": { "type": "number", "minimum": 0, "maximum": 1 }
  },
  "additionalProperties": false
}
- name: source
  format: yaml_schema
  path: schemas/example/source.yaml
  fill_from: papers_meta
schemas/example/source.yaml
$schema: https://json-schema.org/draft/2020-12/schema
title: Source
type: object
required:
  - doi
  - title
  - year
  - source_type
properties:
  doi:
    type: string
  title:
    type: string
  authors:
    type: array
    items:
      type: string
  journal:
    type: string
  year:
    type: integer
  source_type:
    type: string
    enum:
      - journal
      - database
      - book
      - thesis
      - other
  evidence_text:
    type: string
  confidence:
    type: number
    minimum: 0
    maximum: 1
additionalProperties: false

Warning

Do not configure both source schemas in the same extraction list. They represent the same schema in two file formats; choose either JSON or YAML.

There is intentionally no source prompt because this workflow does not use an LLM for source metadata.

Example source payload
{
  "doi": "10.1000/example",
  "title": "Example paper",
  "authors": ["A. Author", "B. Author"],
  "journal": "Example Journal",
  "year": 2026,
  "source_type": "journal",
  "evidence_text": "Bibliographic metadata supplied by the paper index.",
  "confidence": 1.0
}

Schema entry fields

extraction:
  schemas:
    - name: record
      path: schemas/example/record.json
      prompt: prompts/example/prompt.md
      version: "2.1"
      empty_list_field: eos_entries
Field Meaning
name Schema id; output filename stem
path JSON Schema, declarative YAML, or related format
prompt Instructions for the LLM (required unless fill_from is set)
format json_schema (default), yaml_schema, declarative_yaml, or pydantic
version Optional schema version recorded in envelopes
fill_from e.g. papers_meta — fill from paper metadata instead of calling an LLM
skip_when_prior_empty Skip if a prior schema’s empty_list_field is empty
empty_list_field List field used for empty checks / export counts

Declarative YAML format

format: declarative_yaml is a shorter authoring style (string, string?, enum(...), nested fields / array). The example record schema above shows the full file; configure it with:

- name: record
  format: declarative_yaml
  path: schemas/example/record.yaml
  prompt: prompts/example/prompt.md
  empty_list_field: eos_entries

Output location

runs/<RUN_ID>/artifacts/extractions/<paper_id>/<schema_name>.json

Each file is an envelope (metadata + payload). See Export format.

Adapting for your domain

  1. Copy schemas/example/record.jsonschemas/my_domain/...
  2. Copy prompts/example/prompt.mdprompts/my_domain/...
  3. Rename fields / instructions to match what you extract
  4. Point extraction.schemas at the new paths
  5. Keep empty_list_field aligned with your top-level list property

See Custom domains.