citum-server 0.64.0

Citum JSON-RPC server for citation and bibliography processing
Documentation

citum-server

citum-server exposes Citum citation rendering through JSON-RPC. Use it when a client should talk to a long-running process instead of linking citum-engine directly.

The same dispatcher is available over two transports:

  • stdin/stdout: newline-delimited JSON-RPC, enabled in every build
  • HTTP: POST /rpc, enabled by the default http feature

The document-level RPC method is format_document. The single-citation and bibliography methods are convenience methods for smaller workflows. The session API (open_session and friends) supports stateful incremental editing and is enabled by the default session feature.

Install

cargo install citum-server --locked

Run It

Start stdio mode (reads one JSON object per line from stdin, writes one per line to stdout):

citum-server

For HTTP mode:

citum-server --http --port 9000

From the workspace root (development / contributing):

cargo run -p citum-server -- --http --port 9000

The examples below assume they are run from the Citum repository root so the relative style path styles/embedded/apa-7th.yaml resolves. Outside the repository, replace that value with an absolute path to a Citum YAML style.

JSON-RPC Envelope

Every request has this shape:

{
  "id": 1,
  "method": "render_citation",
  "params": {}
}

Successful responses echo the request ID and include result:

{
  "id": 1,
  "result": "..."
}

Errors echo the request ID when available and include error:

{
  "id": 1,
  "error": "missing required field: style_path"
}

refs in render_citation and render_bibliography is an inline JSON map of reference objects. refs in format_document accepts a tagged input object — see the refs input section below. Reference data uses native Citum schema. Dates are EDTF strings such as "1988", not CSL-JSON date-parts objects.

Method Summary

Method Required params Optional params Result
render_citation style_path, refs, citation output_format, inject_ast_indices rendered citation string
render_bibliography style_path, refs output_format, inject_ast_indices {format, content, entries}
validate_style style_path none {valid, warnings}
format_document style, refs, citations output_format, locale, document_options {formatted_citations, bibliography, warnings}
open_session ¹ style style_overrides, locale, output_format, document_options {session_id}
put_references ¹ refs session_id {}
insert_citations_batch ¹ citations session_id session mutation result
insert_citation ¹ citation session_id, position session mutation result
update_citation ¹ citation_id, citation session_id, position session mutation result
delete_citation ¹ citation_id session_id session mutation result
preview_citation ¹ items session_id, position preview result
get_citations ¹ session_id {formatted_citations}
get_bibliography ¹ session_id {bibliography}
close_session ¹ session_id {}

¹ Requires the session feature (default-on). session_id is optional in stdio (omit it or pass "default") and required in HTTP. See Session API.

Supported output_format values are plain (default), html, djot, latex, and typst.

render_citation, render_bibliography, and validate_style use style_path, a string path to a local Citum YAML style. format_document uses the richer style object:

{ "kind": "path", "value": "styles/embedded/apa-7th.yaml" }

Other style.kind values are id, uri, and yaml.

Stdio Example: render_citation

The stdio transport expects each request on a single line:

printf '%s\n' '{"id":1,"method":"render_citation","params":{"style_path":"styles/embedded/apa-7th.yaml","refs":{"hawking1988":{"id":"hawking1988","class":"monograph","type":"book","title":"A Brief History of Time","author":[{"family":"Hawking","given":"Stephen"}],"issued":"1988"}},"citation":{"id":"cite-1","items":[{"id":"hawking1988"}]}}}' \
  | citum-server

The response is a JSON object whose result is the rendered citation string.

HTTP Example: render_bibliography

Start the server in another terminal:

citum-server --http --port 9000

Then send a request:

curl -s http://localhost:9000/rpc \
  -H 'Content-Type: application/json' \
  -d '{
    "id": 2,
    "method": "render_bibliography",
    "params": {
      "style_path": "styles/embedded/apa-7th.yaml",
      "output_format": "html",
      "refs": {
        "hawking1988": {
          "id": "hawking1988",
          "class": "monograph",
          "type": "book",
          "title": "A Brief History of Time",
          "author": [{ "family": "Hawking", "given": "Stephen" }],
          "issued": "1988"
        }
      }
    }
  }'

The response result contains:

  • format: the selected output format
  • content: the rendered bibliography
  • entries: optional plain-text entry strings when the renderer supplies them

Full Document Example: format_document

Use format_document when the client has the whole document citation order. This is the preferred editor and word-processor integration method because it lets the engine render document-sensitive citation state and bibliography output in one call.

HTTP format_document

Use this form when the server is running with --http:

curl -s http://localhost:9000/rpc \
  -H 'Content-Type: application/json' \
  -d '{
    "id": 3,
    "method": "format_document",
    "params": {
      "style": { "kind": "path", "value": "styles/embedded/apa-7th.yaml" },
      "output_format": "html",
      "refs": {
        "smith2010": {
          "id": "smith2010",
          "class": "monograph",
          "type": "book",
          "title": "Nationalism: Theory, Ideology, History",
          "author": [{ "family": "Smith", "given": "Anthony D." }],
          "issued": "2010",
          "publisher": { "name": "Polity" }
        }
      },
      "citations": [
        {
          "id": "cite-1",
          "items": [
            {
              "id": "smith2010",
              "locator": { "label": "page", "value": "10" }
            }
          ]
        }
      ],
      "document_options": {
        "show_semantics": true
      }
    }
  }'

Stdio JSON-RPC format_document

Use this form when the server is running in its default stdin/stdout mode. The request must be one JSON object on one line:

printf '%s\n' '{"id":3,"method":"format_document","params":{"style":{"kind":"path","value":"styles/embedded/apa-7th.yaml"},"output_format":"html","refs":{"smith2010":{"id":"smith2010","class":"monograph","type":"book","title":"Nationalism: Theory, Ideology, History","author":[{"family":"Smith","given":"Anthony D."}],"issued":"2010","publisher":{"name":"Polity"}}},"citations":[{"id":"cite-1","items":[{"id":"smith2010","locator":{"label":"page","value":"10"}}]}],"document_options":{"show_semantics":true}}}' \
  | citum-server

The response result has the same top-level shape over HTTP and stdio:

{
  "id": 3,
  "result": {
    "formatted_citations": [
      {
        "id": "cite-1",
        "text": "(<span class=\"citum-citation\" data-ref=\"smith2010\">Smith, <span class=\"citum-issued\">2010</span>, <span class=\"citum-variable\">p. 10</span></span>)",
        "ref_ids": ["smith2010"]
      }
    ],
    "bibliography": {
      "format": "html",
      "content": "<div class=\"citum-bibliography\">...</div>",
      "entries": [
        {
          "id": "smith2010",
          "text": "<div class=\"citum-bibliography\">...</div>",
          "metadata": {
            "author": "Smith",
            "year": "2010",
            "title": "Nationalism: Theory, Ideology, History"
          }
        }
      ]
    },
    "warnings": []
  }
}

Clients should read bibliography output from result.bibliography, not from result.formatted_citations.

refs Input for format_document

The refs field in format_document accepts a tagged input object, mirroring the style field. These are alternative shapes, not one combined JSON value:

{ "kind": "path",  "value": "/abs/path/to/refs.yaml" }
{ "kind": "yaml",  "value": "hawking1988:\n  id: hawking1988\n  ..." }
{ "kind": "json",  "value": { "hawking1988": { ... } } }

A bare JSON object (no kind key) is also accepted as {"kind": "json"} for backward compatibility.

path and yaml have the server read and parse the bibliography file; json passes inline reference data directly. Use path when the server and client share a filesystem (e.g., when called via pipe from a LuaLaTeX document).

Loading Local Files

Style and bibliography files on the same filesystem can be referenced by path in both style and refs:

printf '%s\n' '{
  "id": 4,
  "method": "format_document",
  "params": {
    "style":        { "kind": "path", "value": "styles/embedded/apa-7th.yaml" },
    "refs":         { "kind": "path", "value": "examples/document-refs-native.json" },
    "output_format": "html",
    "citations":    [{ "id": "cite-1", "items": [{ "id": "kuhn1962" }] }]
  }
}' | citum-server

For HTTP clients that prefer inline data, assemble the request with jq:

jq -n \
  --arg style_path "styles/embedded/apa-7th.yaml" \
  --slurpfile refs examples/document-refs-native.json \
  --slurpfile citations examples/document-citations.json \
  '{
    id: 4,
    method: "format_document",
    params: {
      style: { kind: "path", value: $style_path },
      refs:  { kind: "json", value: $refs[0] },
      citations: $citations[0],
      output_format: "html"
    }
  }' | curl -s http://localhost:9000/rpc \
    -H 'Content-Type: application/json' \
    -d @-

Session API

The session API is for editor and word-processor integrations where the reference list and citation order evolve as the user edits. Instead of re-sending the entire document on every change, a session holds state between calls so you can insert, update, or delete individual citations incrementally.

Session model

Stdio transport: one implicit session per process. open_session returns session_id: "default". Pass session_id or omit it — both work.

HTTP transport: multiple concurrent named sessions, each identified by the session_id returned from open_session. Sessions expire after 30 minutes of inactivity. Always pass the session_id you received.

Session mutation result

insert_citation, update_citation, delete_citation, and insert_citations_batch all return the same shape:

{
  "formatted_citations": [{ "id": "cite-1", "text": "...", "ref_ids": ["..."] }],
  "bibliography": { "format": "html", "content": "...", "entries": [...] },
  "warnings": []
}

Lifecycle

open_session  →  put_references  →  insert_citation(s)
                                        ↕ update_citation / delete_citation
                                    get_citations / get_bibliography
                                    close_session

style_overrides

open_session accepts an optional style_overrides field: a partial YAML or JSON fragment merged over the resolved base style using the same null-aware typed-merge semantics as extends inheritance. The base style is never mutated, so overrides are scoped to the session.

Stdio session example

# open a session
printf '%s\n' '{"id":1,"method":"open_session","params":{"style":{"kind":"path","value":"styles/embedded/apa-7th.yaml"},"output_format":"html"}}' \
  | citum-server

# put references (session_id optional in stdio — defaults to "default")
printf '%s\n' '{"id":2,"method":"put_references","params":{"refs":{"hawking1988":{"id":"hawking1988","class":"monograph","type":"book","title":"A Brief History of Time","author":[{"family":"Hawking","given":"Stephen"}],"issued":"1988"}}}}' \
  | citum-server

# insert a citation
printf '%s\n' '{"id":3,"method":"insert_citation","params":{"citation":{"id":"cite-1","items":[{"id":"hawking1988"}]}}}' \
  | citum-server

HTTP session example

# open a session
SESSION=$(curl -s http://localhost:9000/rpc \
  -H 'Content-Type: application/json' \
  -d '{"id":1,"method":"open_session","params":{"style":{"kind":"path","value":"styles/embedded/apa-7th.yaml"},"output_format":"html"}}' \
  | jq -r '.result.session_id')

# put references
curl -s http://localhost:9000/rpc \
  -H 'Content-Type: application/json' \
  -d "{\"id\":2,\"method\":\"put_references\",\"params\":{\"session_id\":\"$SESSION\",\"refs\":{\"hawking1988\":{\"id\":\"hawking1988\",\"class\":\"monograph\",\"type\":\"book\",\"title\":\"A Brief History of Time\",\"author\":[{\"family\":\"Hawking\",\"given\":\"Stephen\"}],\"issued\":\"1988\"}}}}"

# insert a citation and receive updated formatted output
curl -s http://localhost:9000/rpc \
  -H 'Content-Type: application/json' \
  -d "{\"id\":3,\"method\":\"insert_citation\",\"params\":{\"session_id\":\"$SESSION\",\"citation\":{\"id\":\"cite-1\",\"items\":[{\"id\":\"hawking1988\"}]}}}"

# close the session
curl -s http://localhost:9000/rpc \
  -H 'Content-Type: application/json' \
  -d "{\"id\":4,\"method\":\"close_session\",\"params\":{\"session_id\":\"$SESSION\"}}"

Discovery

HTTP mode exposes read-only discovery endpoints:

curl http://localhost:9000/rpc/methods

GET /rpc/methods returns supported methods, required fields, and optional fields.

curl http://localhost:9000/rpc/schema

GET /rpc/schema returns JSON Schemas for method parameters when the binary is built with the schema feature. Sending GET /rpc returns 405 Method Not Allowed with a JSON hint explaining that /rpc expects POST.

Features

Feature Default Description
session on Enables the stateful session API (open_session, insert_citation, etc.)
async on through http Enables the Tokio runtime dependency used by HTTP transport
http on Enables the axum HTTP server and implies async
schema off Enables /rpc/schema and implies http plus schema type support
schema-types off Enables schema derivations without the HTTP schema endpoint

Build a stdio-only binary with:

cargo build -p citum-server --no-default-features
cargo install citum-server --no-default-features

Performance

A simulation script benchmarks a server-backed word-processor workflow:

cargo build --release -p citum-server
node scripts/benchmark-rpc-workflow.js

Dependencies

citum-server depends on citum-engine, citum-schema, and citum_store for rendering and the standard resolver chain. It does not depend on citum-migrate.