An automated pipeline of one-shot LLM agents reads a Talmudic sugya and
distills it into a property graph of atomic knowledge units and typed
edges — a knowledge model in which a claim about a claim is a
first-class citizen — under mechanical checks and a human review gate.
The graph — not the model — is the system's memory. This engine is
stage one of a RAG system of a different kind: retrieval grounded in an
approved, addressed knowledge graph rather than similarity search over
raw text — an answer layer over a self-refining, status-graded store,
where every answer carries addresses in the sources.
Status: the first sugya has passed the pipeline end to end, and the
candidate graph behind this site is now under human review.
The problem
Why this corpus breaks conventional RAG
The decisive knowledge in a Talmudic sugya is relational structure that
is written in no sentence of it: who transmits in whose name, which
challenge lands on which resolution, what an okimta narrows a dispute
down to, what is rejected and what stands. A single Mishnaic ruling
carries a whole unwritten storey of claims about claims.
Similarity retrieval returns what is written — and here the question is
decided by what is not. Two passages nearly identical in wording can be
entirely different in status, so embedding distance is the wrong
instrument. And the failure region of model memory is exactly this
unwritten part: tested on this sugya, a model returned transmitters
swapped with each other and a quotation that was never written — both
fluent, both confident.
Architecture
What runs where, and why
Solid boxes are built and running; dashed boxes are designed, not yet
built. The published snapshot on this site is exported from
staging.
Storage — a property graph, physically split
Neo4j 5 Community, as two separate containers on one host:
main on its own port for approved knowledge only, and
staging for the candidate graph plus review-state properties
that are stripped when it merges. Why a graph: the knowledge is a
graph — claims hanging on claims — and similarity search cannot represent
precise, directed, composable relations. Why two containers rather than a
policy flag: the split is a structural guarantee — no query can mix
approved with pending knowledge, because no connection reaches both.
Stated flat: main currently holds nothing. The snapshot on
this site is the first end-to-end candidate, exported from
staging, now under human review — the store's first approved
entry will come from it.
Processing — one-shot agents under an enforced schema
A Python pipeline (Python 3.14, dependencies locked with uv) runs every
step as a single closed model call through the Claude Agent SDK, with no
tools and no conversation. The model used for the run behind this site is
recorded in the run's frozen config, alongside the frozen text and edge
dictionary. Output is enforced twice: the API is given a flattened JSON
schema, and the full schema — complete branches, no extra properties
anywhere — is re-validated in process with jsonschema; a
reply that fails is discarded with its agent, and a fresh agent retries
the step. Why one-shot: an agent with no private memory accumulates no
shadow store — everything it knows lives in the graph, where it has an
address and a review. The set of legal edge types is not a code list; it
is built at runtime from the edge dictionary, so the contract and the
data cannot drift apart.
Serving — a static export with no backdoor
One VPS. Caddy is the only public entry point; every data service is
bound to localhost, and the public site is static files with no process
behind them at all — the block that serves it has no reverse proxy. A
publish pipeline exports the site with per-file sha256
checksums, and the export is an allowlist, not a filter: only named
properties are copied, so anything a future round adds has no path out by
default. Minification strips internal commentary, and a scanner fails the
publish if any survives. Why: hard separation between the live system and
the public face.
Front end — vendored, no egress
vis-network renders the graph canvas; Heebo and Frank Ruhl Libre are the
two typefaces. Everything is vendored — the site makes no external
request at runtime, sets no cookies, and runs no analytics.
The run pipeline
From text to candidate graph
A violation triggers one focused correction round; an agent that fails
is discarded and a fresh one retries the same step.
Entity-registry pre-pass
A model proposes the sugya's canonical entities — sages, sources,
concepts, measures — and a person approves the registry before intake
begins. Approved entities carry a normalized merge key, and the
normalization is written in code rather than asked of the model.
Skeleton
One agent reads the whole sugya and lays down the concept skeleton —
the backbone of concepts the units will hang on — and a map of its
sub-sugyot. Every boundary is anchored to a quote the machinery can
locate mechanically.
Routing
A classification layer assigns each piece of text its move types from
a catalog of sixteen move schemas — typed patterns of Talmudic
argumentation: challenge, resolution, derivation, transmission,
dispute and the rest. It is deterministic first — a table of opening
formulas decides most pieces — and asks a model only when the table
cannot decide. Each worker agent then gets a minimal-sufficient
mandate: the relevant schemas, the piece, its graph neighbourhood,
and a compact briefing. A piece that fits no schema gets an explicit
fallback classification, never a silent generic bucket.
Ingest steps
Each step is a single closed model call, carrying a letter — the
complete written mandate the agent works from. The agent returns one
write decision as JSON under the enforced schema. The text is consumed
by a front-anchored cursor: the piece the agent declares must match
the front of the not-yet-marked text, so coverage is a mechanical
guarantee rather than a matter of agent diligence.
Mechanical checks on every write
Transitive-shortcut ban, direction invariants from the edge
dictionary, cycle detection, reference integrity, quote matching under
deterministic normalization, transaction scope. A violation triggers
one focused correction round whose scope is enforced mechanically —
the correction may change only what the violation names.
The debts ledger
Work an agent intends but cannot do in the current step is recorded as
a structured debt — target, requirement, redemption trigger — kept in
run state and shown in every later letter. It has to be redeemed or
explicitly waived at the sub-sugya summary. A promise is not
knowledge, so it does not live in the graph — but it is not allowed
to evaporate either.
Summaries and a final audit
Node-led consolidation per sub-sugya, then whole-graph checks:
coverage crosschecked against the text, skeleton remnants, unanchored
units, dispute mediators left without sides.
Delta, staging, gate, main
The run exports a delta — the candidate graph as one reviewable
unit — the delta is loaded into staging, a person reviews it on the
graph with each source quote shown against its converted unit, and
only an approved review merges it into the store.
Where the figures come from
Everything below is rendered from the published snapshot. Node and edge
counts come from the export itself, and test counts are collected from
the repository's suites at publish time. Nothing on this site is a
typed-in number.
How quality is made
An evolutionary loop, with evidence instead of reports
Every generation runs under review
The system improves by generations. Every graph generation runs under
the full automated suites and a human review of its products; review
findings do not patch the output — they change the architecture, and
the next generation runs under the improved contract. A failure family
found once becomes a mechanical check that makes it impossible twice.
A report is not evidence
A claim that a test passed is not accepted; the command output is
shown. The same rule holds inside the system: agent self-report is
never used as verification — a model asked "did you understand?"
confirms that it did even when the input was nonsense, and that is a
measured finding here, not a worry. Every check is a test against the
product.
Two implementations, one truth
Where a claim matters, two independent implementations must agree on
it. The graph-apply logic exists twice — in Python, and as a
deliberate JavaScript re-implementation used by the run viewer — and a
seam test holds them byte-identical over every recorded run. That
test has already caught a real divergence: the first run to exercise a
newly-added field showed every affected unit differing between the two
ports. One implementation reporting on itself would never have seen it.
Replay and audit — two implementations that must agree
Every run writes a journal as a write-ahead log: each event is flushed to
disk before the action it describes touches state, and a torn
final line is discarded on read. Any step — and the run's final delta —
can be reconstructed from the journal with no model call. The run viewer
runs a separate JavaScript implementation of the same graph-apply logic,
and a browser-based seam test requires exact equality with the Python
output over every recorded run. Why: two independent implementations that
agree are evidence; one implementation reporting on itself is not.
Evidence discipline
Every run directory keeps a frozen copy of its inputs, full transcripts of
every agent call and reply including the attempts that failed, the
journal as the source of truth, and per-call cost telemetry.
The site checks itself
This page lives under the same discipline. A battery of automated checks
runs against the built site and again against the live one: every source
anchor on the home page must match a quote in the published graph, layout
shift and contrast are measured on every page, and every guided-tour step
must frame its subject on the canvas. Publishing is gated on the battery
being green.
Design principles
What this is built on, and what was rejected
When in doubt, split fine
Principle
A unit is atomic when no part of its content could be pointed at by
another edge — a test against the graph, not against the agent's
feeling about its own phrasing. Where the boundary falls is set by the
questions the corpus actually gets asked: who disputes what, what a
law rests on, which challenges hang on this text.
Why
Three independent grounds. Empirically, an agent held "one sentence,
one claim" to its own satisfaction while review found mixed nodes,
duplicated content and missing nodes — a rule measured from the inside
is not a mechanism. Structurally, this is first normal form in graph
language, and a graph gives it neither for free nor enforced. And the
risk is asymmetric: with no general join, an unsplit relation is not
slow, it is silent — the graph looks healthy. A companion rule follows:
identical content appearing in two units is not a phrasing flaw but a
missing-node detector — had the node existed, both would point at it.
Rejected
"One sentence stating one thing" as the operative test, because it
measures from inside. Splitting by potential hangability, because it
has no stopping point. Splitting only when an edge in the current
material demands it, because it is blind to omission. The real cost of
splitting fine is review load at the gate, accepted knowingly.
One-shot agents: the graph is the only memory
Principle
Every pipeline agent is a single closed model call. All of its
knowledge arrives in its letter; all of its output is recorded in the
graph and the journal. No persistent agents, no agent memory, no
hidden state between steps.
Why
Two reasons that are really one. Knowledge accumulated in an agent's
private memory is a shadow store: it influences decisions with no
address, no gate and no review — precisely what this project exists
to prevent. And reproducibility: a closed call is a pure function, so
when a step goes wrong, the letter and the reply are the complete
evidence. Discard-and-retry works operationally because
memory is zero — the agent that did not fail is not committed to the
failure.
Rejected
A standing expert team with persistent memory. Specialization as agent
identity — if step types need specialization, its form is different
templates for the same one-shot agents. And solving letter-size limits
with agent memory: that problem belongs to the feeding layer — at
scale, what changes is how the agent is fed, never the principle.
A promise is not knowledge — and it may not evaporate
Principle
Work an agent intends but cannot do now must live somewhere
mechanical. A pattern whose second storey is already known at ingest
is written in both storeys in a single step; anything else becomes a
structured debt — filed in the agent's reply, kept in run state,
shown in every later letter, and closed at the sub-sugya summary by
redemption or a recorded waiver. Silent deferral is not a legal move.
Why
A measured architecture failure: an intention written into a free-text
rationale field does not travel to the next agent. Making the graph
the only memory left a promise with no home — so it evaporated. The
measured cost in one full run was zero transmission edges and a dead
classification axis: the second storey of the text, the very thing the
system exists to capture, lost silently.
Rejected
Relaying free prose between agents, which reintroduces through the
back door the framing-alignment that one-shot agents exist to prevent.
Monitoring agents that scan transcripts, which buys dearly what a
state file carries for free. And recording debts as graph nodes, which
pollutes the knowledge store with process entities.
Honest limits
What you cannot check from here — and the route onward
There is an honest gap in all of this, and it is worth naming rather than
papering over. The system itself is private by design — the corpus, both
databases, and the pipeline that fills them are not exposed, and no run
artifact is published. So the numbers above cannot be independently
reproduced by a reader of this page.
What is offered instead is narrower and checkable. The site is fed by a
dated snapshot, and meta.json publishes a sha256 for every
file in it, so what arrived is verifiably what was written — an integrity
check, not a signature, and not a claim that anyone has vouched for the
contents. The snapshot comes from a system in calibration: it is the
first end-to-end candidate, and it has not yet passed its human review.
During calibration a human gate reviews every product in full. The exit
from the gate is a bar written in advance — consecutive clean runs on
unseen sugyot, zero surviving violations, zero retrieval failures, a
converged cross-sugya identity layer — never a felt sense of readiness.
The route onward is deliberate: more sugyot through the same pipeline
first; then the commentators' storey, built on the approved base; then
the world of psak, ruling across both. Each storey inherits the
precision of the one beneath it.
Author
What I'd value feedback on
Identity resolution across sugyot: when the
same sage or concept surfaces in a second sugya, what should
"same entity" mean mechanically — and how would you converge a
cross-sugya identity layer without polluting the store?
The exit from the human gate: is consecutive
clean runs on unseen sugyot the right bar for trusting the
pipeline without per-item review — and what is missing from it?
Retrieval over a typed graph: when the store
is addressed claims and typed edges rather than embeddings, what
should the retrieval layer look like — graph walks, subgraph
extraction, a hybrid with vectors?