Early benchmarks: 135/135 trace-seeded replay cells matched across three model families
v0.6 · Now content-addressed →

Scholialang — Reasoning you can read, validate, and graph.

Scholialang is a small markup language for the reasoning itself. Agents emit goals, hypotheses, evidence, and decisions as typed atoms, linked by logical relations into a graph that a reviewer, a validator, or another model can parse, diff, and replay.

Scholialang helps agentic systems preserve reasoning state, use tools without quality loss, and reduce context cost across long-horizon work. Like HTML made the web legible, Scholialang makes reasoning legible.

pip install scholialang

Python 3.11+ · parser, validator, registry, serializers · source on GitHub

Scholialang Live
emitting

The problem

Chain-of-thought is opaque, ungraphable, untestable.

An agent that reasons in unstructured prose leaves no trace a second party can parse. You cannot diff two runs that disagree. You cannot point at the step where a hypothesis got conflated with a finding. You cannot graph references. You cannot lint for retractions that vanish silently. The reasoning is locked inside the agent's monologue — and so is every regression.

What changes

From monologue to artifact.

The same reasoning, twice. On the left, the way agents think today. On the right, a Scholialang trace — validated by the same linter that runs in the playground.

Prose

what the transcript holds

Okay — I want to swap datetime.utcnow() for datetime.now(timezone.utc) in utc_iso_now. Both should come out as the same ISO string, so callers probably won't notice.

Looking at dates.py, the helper just returns isoformat(), and events.py calls it too. Both call-sites only consume the returned string, so the format doesn't change. Seems safe — calling it done.

Readable — and nothing else. You can't cite the file check, diff two runs, or lint the leap from "probably" to "done".

Scholialang

the same reasoning, typed
<Step id="Step_a3f17b21" name="Refactor utc_iso_now to UTC-strict">
  <Hypothesis id="Hypothesis_4c9d8e02">
    "Replacing datetime.utcnow() with datetime.now(timezone.utc)
     preserves callers since both return naïve-equivalent ISO strings."
  </Hypothesis>
  <Observation id="Observation_8b2a1f06" location="src/harness/util/dates.py:14:21" confidence="1.0">
    Exports utc_iso_now: returns datetime.now(timezone.utc).isoformat().
    <Edge type="depends" target="datetime"/>
    <Edge type="calls" target="src/harness/kb/events.py"/>
  </Observation>
  <Evidence for="Hypothesis_4c9d8e02" polarity="supports">
    "Both call-sites only consume the returned ISO string; format unchanged."
    REFER:Observation_8b2a1f06
  </Evidence>
  <Finding id="Finding_91ce0a44" for_hyp="Hypothesis_4c9d8e02">
    "Hypothesis_4c9d8e02 SUPPORTED. Refactor safe across 2 known callers."
  </Finding>
</Step>

Open this trace — and eight more — in the gallery, or paste your own into the playground.

Typed steps.

The hunch becomes a <Hypothesis>, the file check an <Observation> with a location, the verdict a <Finding> — each with a stable, citable id.

Linked evidence.

<Evidence> declares what it supports and what it rests on. REFER makes every citation explicit — and graphable.

Machine-checkable.

18 validity rules lint this trace in the browser: no orphan hypotheses, no dangling references, no conclusions without cited support.

What Scholialang gives you

Three things prose can't.

Quick start

Four steps.

  1. 01

    Install the reference implementation.

    pip install scholialang
  2. 02

    Write a .srml trace.

    <Step name="my-first-trace">
      <Hypothesis id="H_01">...</Hypothesis>
      <Finding id="F_01" for_hyp="H_01">...</Finding>
    </Step>
  3. 03

    Validate it.

    from scholialang.parser import parse
    from scholialang.validator import validate
    
    result = validate(parse(source))
    if not result.ok:
        print(result.errors)
  4. 04

    Wire it into your agent.

    Claude Code and Codex plugins, an MCP server, and host recipes ship in scholialang-mcp — agents emit validated traces as they work. Plugin setup →

New to Scholialang? Read why reasoning needs a protocol layer, skim the quick reference, or go straight to the full v0.6 spec.

Current specification

v0.6: reasoning, content-addressed.

The v0.6 release defines a 32-atom catalog, 11 typed operators, three equivalent serializations, and 18 validity rules. New in this release: every atom can carry a SHA-256 canonical_id, turning a trace into a portable, deduplicating knowledge graph that a later session — or a different model — can reference by hash instead of re-deriving. What's new in v0.6 →

Repository split

Three public packages, one language.

Scholialang now has separate homes for the language contract, the Python implementation, and protocol tooling. The split keeps the spec portable while letting host integrations move independently.

For agent hosts

Scholialang is the reasoning layer for auditable agent work.

The validator, gallery, playground, MCP server, and LSP are built around the same trace grammar. Host tools can keep their own runtime concerns while sharing one readable surface for decisions, evidence, references, and review.