A study companion for Jewish texts. Ask it what the tradition says about a subject and it finds the sources, fetches them with their editions and licences, and teaches from what it fetched: how the argument is built, who disagrees, and what turns on the disagreement. Underneath the teaching sits a careful instrument: retrieval that names its edition every time, romanization under eight published standards, comparison of editions, recorded cantillation, and the Jewish calendar.
A meturgaman is the person who stood beside the reader and rendered the text for the congregation. This does that job, in both senses: it renders the letters, and it renders the meaning, without ever supplying a text from memory.
Asked "is there Jewish wisdom about limited liability?", the agent built on this tool answered from fetched sources: the default of expansive liability, the apotiki formula of Shulchan Arukh Choshen Mishpat 117:1 quoted from the Lemberg 1898 printing, the Nehardean iska from Bava Metzia 104b:14, the debtor protections of Deuteronomy 24 and Mishneh Torah Creditor and Debtor 1:7, and the modern dispute over whether halakhah recognizes the corporate veil, reported as a dispute. An independent checker then fetched every one of those citations and confirmed all six.
That is the standard the project holds itself to, and it is measured rather than claimed: six real questions were put to the agent, every answer was saved verbatim, and every citation-bearing claim was handed to a separate verification agent told to fetch it and try to refute it. The transcripts, the hostile verification reports, and an honest account of what still goes wrong (counts and reference anchors remain the weak spot) are in notes/agent-evaluation.md.
git clone https://github.com/Oranburg/meturgaman.git
cd meturgaman
python3 -m venv .venv && .venv/bin/pip install -e ".[dev]"
.venv/bin/python -m tools.fetch_sources # the source documents, verified by hash
.venv/bin/python -m pytest -m "not network"
Python 3.11 or later. The core has no dependencies at all: both services are
keyless JSON over HTTPS, and urllib does that.
meturgaman topics charity # find a subject's slug
meturgaman sources tzedakah --text # what the tradition says about it
meturgaman text "Berakhot 2a" # a passage, in every edition
meturgaman chain "Mishnah Bava Metzia 5:11" # what the tradition built on it
meturgaman romanize "כָּל־הָאָרֶץ" # kol-ha-’arets
meturgaman audio "Genesis 1:1" # chanted, by a person
The same instrument, pointed at the statute book. In the classical library the risk is a Hebrew text supplied from memory. In Israeli legislation the Hebrew is usually the easy part and the English is the trap: an unattributed copy of a statute on the open web is complete, fluent, right about the section numbering, and not the authorized translation, and nothing on its face says so.
meturgaman law statutes # the registry
meturgaman law tiers # the authority ladder
meturgaman law sources remedies-1970 # where an English text can be had
meturgaman law hebrew remedies-1970 # consolidated Hebrew, with its revision id
meturgaman law parse delivery.txt --json # split a delivered English text into sections
meturgaman law align --hebrew numbers.txt --english delivery.txt
meturgaman law reconcile --witness lsi=authorized:a.txt --witness web=unattributed:b.txt
It does not translate. It locates, fetches, parses, aligns and reconciles,
and every artifact carries the tier of what it came from. The tiers, best first,
are enacted (the English is law, or authentic treaty text), authorized
(Laws of the State of Israel, the Ministry of Justice's own translation,
authorized and not binding), government, commercial, scholarly,
unattributed, and assistant. Only the first two print as the law. A
translation a model produced is tier assistant, says so wherever it appears,
and never stands as the text.
Three facts the registry knows so that nobody has to remember them. L.S.I. runs to volume 45 and stops around 1989, so a later statute has no authorized English at all and the registry says so rather than sending anyone to a volume that does not exist. L.S.I. prints the law as enacted, so setting it beside a consolidated Hebrew text can print two different laws and call one a translation of the other. And a section's marginal heading is typeset in its own column, so every flattening of the columns puts it somewhere a naive read will misfile it; the parser reports it as a candidate and refuses to attach it.
Pairing is on the section number and never on position. align exits non-zero
on any section without a counterpart, because a bilingual page built over a gap
prints one column beside the wrong other column and shows nothing.
A halakhic question runs Torah, Mishnah, Gemara, the Rishonim, the codes, then responsa. Sefaria's link graph knows the actual path for any passage, and three commands walk it:
$ meturgaman chain "Mishnah Bava Metzia 5:11"
Mishnah Bava Metzia 5:11: what the tradition built on this passage
Tanakh (5)
Exodus Exodus 22:24
Leviticus Leviticus 25:36 and 2 more
Deuteronomy Deuteronomy 23:20
Tosefta (2)
Talmud (3)
Bava Metzia Bava Metzia 75a:11-75b:4
Commentary (43)
Quoting Commentary (6)
Halakhah (1)
The work lists are trimmed here; the command prints every work and its refs.
meturgaman links gives the same graph filtered and flat (--category Commentary, --refs-only for piping), and meturgaman related summarizes
everything Sefaria attaches to a passage, topics included. Reading the chain
down from a Gemara shows where its law lands in the Shulchan Arukh; reading
up from a code shows where its ruling began. Every ref in the output can be
fetched with meturgaman text.
meturgaman sugya maps a Talmud reference to the passage boundary it belongs
to, which regularly crosses the printed page. meturgaman word fetches
dictionary entries, with Jastrow's citations back into the corpus.
Every romanization table lives in schemes/, as markdown, one file per
standard. No table is written in Python anywhere in this repository.
That is not a stylistic preference. A table written in code is a table nobody proofreads: it gets edited to make a test pass, it drifts from the standard it claims to implement, and the drift is invisible because checking it means reading code. This project shipped a set of spirant characters that appear nowhere in the SBL Handbook, and they survived a rewrite because a second file had quietly copied them. They were caught by someone opening the PDF.
So the tables are documents. Each one carries its citation, its grid, and a section recording every place it departs from what its source prints and why. A test re-extracts each source and checks every character against it. When the output looks wrong, you read one page.
| Scheme | Source | Use it when |
|---|---|---|
sbl-general |
SBL Handbook 2nd ed. §5.1.2 | general scholarly writing. The default. |
sbl-academic |
SBL Handbook 2nd ed. §5.1.1 | the romanization must be reversible |
ala-lc |
ALA-LC, Library of Congress | the result must match a catalogue record |
bgn-pcgn |
BGN/PCGN 2018 Agreement | Israeli place names, or anything official |
encyclopaedia-judaica-general |
EJ 2nd ed. vol. 1 p. 197 | matching how a Jewish Studies reader expects a word to look |
encyclopaedia-judaica-scientific |
EJ 2nd ed. vol. 1 p. 197 | comparative Semitics. Check its output |
yivo |
YIVO Institute | Yiddish, and the closest published thing to Ashkenazi Hebrew |
ala-lc-yiddish |
ALA-LC, Yiddish column | Yiddish for a catalogue record |
meturgaman schemes # all eight with their sources
meturgaman schemes --name yivo # one in full, table and reasoning
There is no published romanization table for Ashkenazi Hebrew. Not one that could not be found: one that does not exist. ArtScroll and Feldheim have house practices and publish no tables, and the Library of Congress's Hebraica Cataloging manual mentions Ashkenaz only as the surname of a lexicographer.
What exists is Yiddish. YIVO's treatment of the loshn-koydesh layer, the
words of Hebrew and Aramaic origin, is Ashkenazi Hebrew pronunciation: תּ is
t and bare ת is s, which is what gives Shabbos rather than Shabbat. That
is real, published, and in schemes/yivo.md.
What the tool will not do is rewrite your Ashkenazi spelling into Sephardi. It refuses and shows its evidence:
$ meturgaman romanize "Shabbos and halachah and Sukkos and mitzvos"
refused: This text is written in Ashkenazi register (ashkenazi 14, sephardi 0),
and sbl-general would rewrite it as Sephardi. That is a change of the author's
usage rather than a correction.
Hebrew orthography is genuinely ambiguous in four places, and each of them has one mark doing two jobs: a dagesh is lene or forte, a sheva is vocal or silent, a qamats is long or short, a vav is a consonant or half a vowel.
The engine decides these in a pass of their own, in the open. Where the
rules cannot settle a question, it raises a flag rather than picking a default
and staying quiet. Output goes to stdout, flags to stderr, and under
--json the flags travel inside the document so a pipeline cannot lose them.
$ meturgaman romanize "קָנְיָא"
qaneya
[qamats-may-be-short] (קָנְיָא) read long (a), which is the commoner reading
of this shape. A few words take a short qamats (o) here and are listed in
rules/qamats-qatan.md; check the word if it matters
[sheva-after-qamats] (קָנְיָא) read as vocal, which is the commoner reading
after a long qamats. Some words take a silent sheva here and the spelling
does not say which; check if it matters
The Library of Congress reaches the same conclusion from the cataloguing side: its manual sends cataloguers to a dictionary "primarily to distinguish schwa naʻ from schwa nah, a matter which has significant impact on romanization." Code that answers from orthography alone should say when it is unsure.
$ meturgaman text "Genesis 1:1" --version all
Genesis 1:1
8 editions, 5 independent witnesses
providers: he.wikisource.org, tanach.us, jps.org, sefaria.org, chabad.org
Five witnesses from eight editions, because three of them came from the same
digitization. An edition's provider is derived from its own stated source
rather than from the fact that Sefaria served it, so two rows that came from
one place do not count as two. meturgaman compare then reports where
editions actually differ, on the consonantal skeleton, with vocalization
recorded as apparatus rather than as disagreement.
$ meturgaman verify chapter.md
resolved 'Genesis 1:1' -> Genesis 1:1
found בראשית ברא אלהים את השמים ואת... in Genesis 1:1
NOT FOUND בראשית ברא משה את הארץ ואת... checked against Genesis 1:2
verify finds every citation in a manuscript with Sefaria's own reference
finder, validates each one, and checks every Hebrew quotation of three words
or more against the fetched text of the passages cited in its paragraph.
Matching runs on the consonantal skeleton, so pointing and cantillation
differences do not defeat a genuine quotation while a reworded one still
fails. A miss arrives as a diagnosis: the closest passage, the run of words
that does match, and the first word where the draft parts from the edition:
matches Genesis 1:1 through 'בראשית ברא', then the draft has
'משה' where the edition has 'אֱלֹהִ֑ים'
Exit code 0 means everything resolved and every quotation was found; "not found" is a flag to check, never proof of fabrication.
$ meturgaman anchors "Hasagot HaRaavad on Mishneh Torah, Repentance"
Hasagot HaRa'avad on Mishneh Torah, Repentance
10 chapters, 12 populated anchors, 13 segments
2:5 1 segment
3:7 2 segments
...
A sentence like "Ravad glosses this book in nine places" is a census, and a
census written from memory is how careful answers go wrong. anchors prints
every populated anchor of a work with its segment count, straight from the
service's shape record, so counting means reading rather than remembering.
meturgaman daf # today's daf yomi, fetched
meturgaman daf --cycle "Daily Mishnah"
meturgaman study "Bava Metzia 75b:11" --sugya --tier block
meturgaman study "Genesis 1" --tier file --output ~/notes/
daf fetches any learning cycle's reading directly. study --sugya expands
a Talmud reference to its mapped passage before rendering, and --output
writes the file, named from the normalized reference when given a directory.
Two further study options:
--pairedappends companion passages:rules/pairings.mdnames the pairs (Mishneh Torah with the Guide, Shulchan Arukh and the Tur with the Beit Yosef, each with its reason), and the passage-level connections come from Sefaria's link graph at run time. Where the graph records no companion passage, the file says so instead of guessing; the graph is genuinely sparse there.--vocalizepoints unvocalized Hebrew with Dicta's model, run locally (pip install 'meturgaman[dicta]'), and stamps the output as a model's reading rather than an edition's. Editions that carry their own pointing are left alone.
Every command that talks to a service takes --json and --no-cache, limits
are bounded, refusals exit non-zero with a reason on stderr, and
meturgaman clear-cache empties the response cache. The engine romanizes
about 60,000 words per second and the CLI starts in about 50 milliseconds, so
driving it one call at a time from an agent costs nothing worth engineering
around.
meturgaman text "Genesis 1:1" --json | jq '.editions[0].segments[0].text'
meturgaman links "Bava Metzia 75b:2" --refs-only | while read ref; do ...
For MCP clients such as Claude Desktop and Claude Code, an optional server wraps the same library:
pip install 'meturgaman[mcp]'
meturgaman-mcp
Thirteen tools over stdio, structured results, flags inside the payload. The SDK stays behind the extra so the core keeps its zero dependencies.
Recorded cantillation. Sefaria carries PocketTorah's recordings: a person
chanting, with the trope, CC-BY-SA, timestamped to the verse. Torah only.
Synthetic speech through the macOS Carmit voice covers the rest, and
the tool always says which one you are getting.
meturgaman audio "Genesis 1:1" # the recording
meturgaman audio "Berakhot 2a" --synth # nobody has recorded the Talmud
meturgaman day --date 2026-08-08 --register a
meturgaman calendars # daf yomi and the learning cycles
meturgaman leyning --triennial
meturgaman yahrzeit 2020-03-15
meturgaman zmanim --zip 20902 --elevation 150
--register a keeps holiday names in Ashkenazi register; Hebcal publishes
twenty-two locales and six of them are Ashkenazi.
Sefaria, for texts, editions, links, topics, search, dictionaries, commentaries, sugya boundaries and the learning calendar. No key, no registration.
Hebcal, for the calendar, Torah readings, halachic times and yahrzeits.
Dicta, optionally and locally, for adding vowel points. Their models are on HuggingFace under a permissive licence and run on your own machine. They publish no API contract, so this project does not call one.
Both APIs' contracts are committed under docs/api/, so the code is written
against a recorded spec rather than against anyone's memory of one: Sefaria's
OpenAPI document with all sixty of its paths, Sefaria's index of the prose about
them, and Hebcal's OpenAPI document, which sources/hebcal.py reads at import
time to validate its own parameter names. Provenance and hashes are in
docs/api/README.md, and python -m tools.fetch_contracts
verifies every one of them against the bytes the services serve.
The same capability, packaged for wherever Claude happens to be running. All of them are written around teaching from fetched sources, and all of them carry the four disciplines that came out of the evaluation: no census without an enumeration, no dressing a reading in the tool's authority, references copied exactly as fetched, and search snippets treated as leads rather than sources.
| Where | What to use |
|---|---|
| Claude Code, workstation | agents/meturgaman.md and skills/meturgaman/SKILL.md, with the tool on the path |
| Claude Code on the web | .claude/agents/meturgaman.md, which installs from the checkout and needs nothing else |
| claude.ai | claude-ai/: build the zip, upload it, allow the sandbox three hosts. claude-ai/INSTALL.md |
| Claude Cowork | the skill, plus claude-ai/agents/cowork-instructions.md as folder instructions |
| Claude Desktop | desktop-skill/, the complete package the claude.ai build is an overlay on |
Both packaged builds come out of python tools/build_skill.py, which vendors the
library whole, standard library only and no install step, because a sandbox may
have no package index in reach. They also
carry both API contracts and a script that queries them, so a question about a
parameter is answered from what the service publishes rather than from
recollection, and answering it costs a few hundred tokens rather than the
megabyte the spec occupies.
The evidence for what the agent can and cannot do is in notes/agent-evaluation.md.
The code and documentation here are MIT. The rest is not ours to license:
- The texts carry their own licences per edition. The tool reports each one rather than assuming.
- Hebcal is CC-BY-4.0 and the tool prints its attribution.
- PocketTorah is CC-BY-SA and the tool prints its attribution.
- The romanization standards in
sources/are not committed. Two of the six are copyrighted commercial publications, sosources/is gitignored and only provenance lives in the repository.sources/manifest.mdrecords every URL and SHA-256, andpython -m tools.fetch_sourcesretrieves and verifies them.
What is committed is the extracted table data in schemes/, because a
table of correspondences between two writing systems is a set of facts.
The tanach.us reader, translation beyond retrieval of published
translations, and a web interface. Sefaria also runs hosted MCP servers at
https://mcp.sefaria.org/sse and https://developers.sefaria.org/mcp; they
need a paid account, which is why this tool does not depend on them.