torah-scholar
Search and explore Jewish texts (Torah, Tanach, Talmud, Midrash, commentaries) via Sefaria API. Use when researching Torah sources, looking up verses, finding commentaries, cross-references, or preparing divrei Torah. Supports Hebrew and English. Handles references like "Genesis 1:1", "Berakhot 2a", "Mishnah Avot 1:1".
Packaged view
This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.
Install command
npx @skill-hub/cli install openclaw-skills-torah-scholar
Repository
Skill path: skills/abeperl/torah-scholar
Search and explore Jewish texts (Torah, Tanach, Talmud, Midrash, commentaries) via Sefaria API. Use when researching Torah sources, looking up verses, finding commentaries, cross-references, or preparing divrei Torah. Supports Hebrew and English. Handles references like "Genesis 1:1", "Berakhot 2a", "Mishnah Avot 1:1".
Open repositoryBest for
Primary workflow: Ship Full Stack.
Technical facets: Full Stack, Backend.
Target audience: everyone.
License: Unknown.
Original source
Catalog source: SkillHub Club.
Repository owner: openclaw.
This is still a mirrored public skill entry. Review the repository before installing into production workflows.
What it helps with
- Install torah-scholar into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
- Review https://github.com/openclaw/skills before adding torah-scholar to shared team environments
- Use torah-scholar for development workflows
Works across
Favorites: 0.
Sub-skills: 0.
Aggregator: No.
Original source / Raw SKILL.md
---
name: torah-scholar
description: Search and explore Jewish texts (Torah, Tanach, Talmud, Midrash, commentaries) via Sefaria API. Use when researching Torah sources, looking up verses, finding commentaries, cross-references, or preparing divrei Torah. Supports Hebrew and English. Handles references like "Genesis 1:1", "Berakhot 2a", "Mishnah Avot 1:1".
keywords:
- torah
- jewish
- judaism
- sefaria
- talmud
- bible
- hebrew
- tanach
- mishnah
- midrash
- dvar torah
- parsha
- rabbi
- yeshiva
- study
- religious
- scripture
---
# Torah Scholar
Research Jewish texts with full access to the Sefaria library: Tanach, Talmud Bavli/Yerushalmi, Mishnah, Midrash, Zohar, and thousands of commentaries.
## Quick Start
```bash
# Search across all texts
torah search "love your neighbor"
# Get specific verse with Hebrew + English
torah verse "Leviticus 19:18"
# Find commentaries on a verse
torah links "Genesis 1:1"
# This week's parsha
torah parsha
# Today's learning schedule (Daf Yomi, etc.)
torah today
```
## Commands
| Command | Description | Example |
|---------|-------------|---------|
| `torah search <query>` | Full-text search | `torah search "tikkun olam"` |
| `torah verse <ref>` | Get text + translation | `torah verse "Psalms 23"` |
| `torah links <ref>` | Commentaries & cross-refs | `torah links "Exodus 20:1"` |
| `torah related <ref>` | Related texts & topics | `torah related "Deuteronomy 6:4"` |
| `torah parsha` | This week's portion | `torah parsha` |
| `torah today` | Daily learning schedule | `torah today` |
| `torah dvar` | Generate dvar Torah | `torah dvar` |
| `torah dvar ref <ref>` | Dvar on specific verse | `torah dvar ref "Genesis 12:1"` |
| `torah dvar theme <theme>` | Dvar with theme focus | `torah dvar theme "leadership"` |
## Reference Formats
### Tanach (Hebrew Bible)
- Books: Genesis, Exodus, Leviticus, Numbers, Deuteronomy (Torah)
- Nevi'im: Joshua, Judges, Samuel, Kings, Isaiah, Jeremiah, Ezekiel, etc.
- Ketuvim: Psalms, Proverbs, Job, Song of Songs, Ruth, Ecclesiastes, etc.
- Format: `Book Chapter:Verse` or `Book Chapter:Start-End`
- Examples: `Genesis 1:1`, `Psalms 23`, `Isaiah 40:1-5`
### Talmud
- Bavli (Babylonian): `Tractate DafNumber` + `a` or `b`
- Examples: `Berakhot 2a`, `Shabbat 31a`, `Bava Metzia 59b`
- Major tractates: Berakhot, Shabbat, Eruvin, Pesachim, Yoma, Sukkah, Beitzah, Rosh Hashanah, Taanit, Megillah, Moed Katan, Chagigah, Yevamot, Ketubot, Nedarim, Nazir, Sotah, Gittin, Kiddushin, Bava Kamma, Bava Metzia, Bava Batra, Sanhedrin, Makkot, Shevuot, Avodah Zarah, Horayot, Zevachim, Menachot, Chullin, Bekhorot, Arakhin, Temurah, Keritot, Meilah, Tamid, Niddah
### Mishnah
- Format: `Mishnah Tractate Chapter:Mishnah`
- Examples: `Mishnah Avot 1:1`, `Mishnah Berakhot 1:1`
### Midrash
- Midrash Rabbah: `Genesis Rabbah 1:1`, `Exodus Rabbah 1:1`
- Midrash Tanchuma: `Tanchuma Bereshit 1`
- Other: `Pirkei DeRabbi Eliezer 1`
### Commentaries
- Access via `torah links <ref>` to see Rashi, Ramban, Ibn Ezra, Sforno, etc.
## Research Workflows
### Find Sources on a Topic
```bash
# 1. Search for topic
torah search "repentance teshuvah"
# 2. Get full text of relevant result
torah verse "Maimonides Hilchot Teshuvah 2:1"
# 3. Find related commentaries
torah links "Maimonides Hilchot Teshuvah 2:1"
```
### Prepare a Dvar Torah
```bash
# 1. Get this week's parsha
torah parsha
# 2. Read the opening verses
torah verse "Genesis 12:1-5" # (adjust to actual parsha)
# 3. Find commentaries for insights
torah links "Genesis 12:1"
# 4. Search for thematic connections
torah search "lech lecha journey"
```
### Study Daf Yomi
```bash
# 1. Check today's daf
torah today
# 2. Get the text
torah verse "Berakhot 2a" # (from calendar)
# 3. See what it connects to
torah links "Berakhot 2a"
```
### Generate a Dvar Torah
```bash
# Quick dvar for this week's parsha
torah dvar
# Focus on specific verse
torah dvar ref "Exodus 28:1"
# Explore a theme across sources
torah dvar theme "holiness and service"
```
The dvar generator outputs:
- Opening verses with Hebrew + English
- Key commentaries (Rashi, Ramban, Sforno, etc.)
- Related sources across the library
- Suggested structure (hook → problem → sources → resolution → application)
- Themes to explore further
## Python API
For advanced usage, import directly:
```python
from scripts.sefaria import get_text, search, get_links, get_parsha
# Get verse
result = get_text("Genesis 1:1")
print(result.get("he")) # Hebrew
print(result.get("text")) # English
# Search
results = search("golden rule", limit=5)
# Get commentaries
links = get_links("Leviticus 19:18")
```
## Tips
- **Hebrew search**: Sefaria supports Hebrew queries: `torah search "ואהבת לרעך כמוך"`
- **Partial refs**: `torah verse "Psalms 23"` returns entire chapter
- **Ranges**: `torah verse "Genesis 1:1-5"` for multiple verses
- **Talmud context**: Daf refs include both amud a and b context
## Limitations
- Rate-limited by Sefaria (be respectful of their free API)
- Some texts may have Hebrew only (no English translation)
- Search is full-text, not semantic (exact/stemmed matches)
## Source
Powered by [Sefaria](https://www.sefaria.org) — the free, open-source library of Jewish texts.
---
## Skill Companion Files
> Additional files collected from the skill directory layout.
### README.md
```markdown
# Torah Scholar 📜
**Search and explore Jewish texts with AI agents** — powered by the Sefaria API.
[](https://clawhub.com)
[](https://opensource.org/licenses/MIT)
<a href="https://www.sefaria.org"><img src="assets/powered-by-sefaria-dark.png" alt="Powered by Sefaria" width="200"></a>
## Overview
Torah Scholar is an OpenClaw/MCP skill that gives AI agents access to the world's largest open-source library of Jewish texts:
- **Tanach** (Torah, Nevi'im, Ketuvim)
- **Talmud** (Bavli & Yerushalmi)
- **Mishnah & Midrash**
- **Commentaries** (Rashi, Ramban, Ibn Ezra, Sforno, and hundreds more)
- **Kabbalah** (Zohar)
- **Halacha** (Shulchan Aruch, Mishneh Torah)
All texts available in **Hebrew and English**.
## Features
| Command | Description |
|---------|-------------|
| `torah search <query>` | Full-text search across all texts |
| `torah verse <ref>` | Get text with Hebrew + English translation |
| `torah links <ref>` | Find commentaries and cross-references |
| `torah related <ref>` | Discover related texts and topics |
| `torah parsha` | This week's Torah portion |
| `torah today` | Daily learning schedule (Daf Yomi, etc.) |
| `torah dvar` | Generate dvar Torah outlines with sources |
## Quick Start
### Installation
```bash
# Via ClawHub
clawhub install torah-scholar
# Or copy to OpenClaw skills directory
cp -r torah-scholar ~/.openclaw/skills/
```
### Usage Examples
```bash
# Search for a concept
torah search "love your neighbor"
# Get a specific verse
torah verse "Genesis 1:1"
torah verse "Berakhot 2a"
# Find commentaries
torah links "Leviticus 19:18"
# This week's parsha
torah parsha
# Generate a dvar Torah
torah dvar
torah dvar ref "Esther 4:14"
torah dvar theme "faith"
```
## Reference Formats
| Text Type | Format | Example |
|-----------|--------|---------|
| Torah | Book Chapter:Verse | `Genesis 1:1` |
| Prophets | Book Chapter:Verse | `Isaiah 40:1` |
| Writings | Book Chapter:Verse | `Psalms 23` |
| Talmud Bavli | Tractate Daf+Side | `Berakhot 2a` |
| Mishnah | Mishnah Tractate Ch:M | `Mishnah Avot 1:1` |
| Midrash | Midrash Name Section | `Genesis Rabbah 1:1` |
## Dvar Torah Generator
Generate structured Torah insights with sources:
```bash
torah dvar
```
**Output includes:**
- Opening verses (Hebrew + English)
- Key commentaries (Rashi, Ramban, etc.)
- Related sources across the library
- Suggested dvar structure
- Themes to explore
## API
For programmatic access:
```python
from scripts.sefaria import get_text, search, get_links
# Get verse
result = get_text("Genesis 1:1")
print(result["he"]) # Hebrew
print(result["text"]) # English
# Search
results = search("golden rule", limit=10)
# Get commentaries
links = get_links("Exodus 20:1")
```
## Use Cases
- **Torah Study** — Quick access to texts and commentaries
- **Dvar Torah Prep** — Generate outlines with sources
- **Research** — Cross-reference and explore connections
- **Education** — Build Torah learning tools
- **Content Creation** — Source-backed Jewish content
## Requirements
- Python 3.8+
- Internet connection (Sefaria API)
- No API key required
## Credits
- **Sefaria** — The incredible open-source Jewish library
- **OpenClaw** — AI agent framework
## License
MIT License — Use freely, contribute back!
## Links
- [Sefaria](https://www.sefaria.org)
- [Sefaria API Docs](https://developers.sefaria.org)
- [ClawHub](https://clawhub.com)
- [OpenClaw](https://github.com/openclaw/openclaw)
---
**Built with ❤️ for the Jewish community**
*"The study of Torah is equal to all the other commandments." — Mishnah Peah 1:1*
```
### _meta.json
```json
{
"owner": "abeperl",
"slug": "torah-scholar",
"displayName": "Torah Scholar",
"latest": {
"version": "1.0.1",
"publishedAt": 1771953500345,
"commit": "https://github.com/openclaw/skills/commit/413249399a660bce5ca156cca9d654e32da1268d"
},
"history": [
{
"version": "1.0.0",
"publishedAt": 1771883468839,
"commit": "https://github.com/openclaw/skills/commit/b043e40ab625963da7ff799a7a38713b3528be2d"
}
]
}
```
### references/common-refs.md
```markdown
# Common Torah References
Quick reference for frequently cited texts.
## Famous Verses
| Topic | Reference | Text |
|-------|-----------|------|
| Creation | Genesis 1:1 | "In the beginning God created..." |
| Love neighbor | Leviticus 19:18 | "Love your neighbor as yourself" |
| Shema | Deuteronomy 6:4 | "Hear O Israel, the Lord is our God..." |
| Golden Rule | Shabbat 31a | "What is hateful to you, do not do..." |
| Tikkun Olam | Mishnah Avot 2:16 | "You are not required to finish..." |
| Torah study | Mishnah Avot 1:1 | "Moses received Torah from Sinai..." |
## Parsha List (Weekly Torah Portions)
### Bereishit (Genesis)
1. Bereishit - Genesis 1:1-6:8
2. Noach - Genesis 6:9-11:32
3. Lech Lecha - Genesis 12:1-17:27
4. Vayera - Genesis 18:1-22:24
5. Chayei Sarah - Genesis 23:1-25:18
6. Toldot - Genesis 25:19-28:9
7. Vayetzei - Genesis 28:10-32:3
8. Vayishlach - Genesis 32:4-36:43
9. Vayeshev - Genesis 37:1-40:23
10. Miketz - Genesis 41:1-44:17
11. Vayigash - Genesis 44:18-47:27
12. Vayechi - Genesis 47:28-50:26
### Shemot (Exodus)
13. Shemot - Exodus 1:1-6:1
14. Vaera - Exodus 6:2-9:35
15. Bo - Exodus 10:1-13:16
16. Beshalach - Exodus 13:17-17:16
17. Yitro - Exodus 18:1-20:23
18. Mishpatim - Exodus 21:1-24:18
19. Terumah - Exodus 25:1-27:19
20. Tetzaveh - Exodus 27:20-30:10
21. Ki Tisa - Exodus 30:11-34:35
22. Vayakhel - Exodus 35:1-38:20
23. Pekudei - Exodus 38:21-40:38
### Vayikra (Leviticus)
24. Vayikra - Leviticus 1:1-5:26
25. Tzav - Leviticus 6:1-8:36
26. Shemini - Leviticus 9:1-11:47
27. Tazria - Leviticus 12:1-13:59
28. Metzora - Leviticus 14:1-15:33
29. Acharei Mot - Leviticus 16:1-18:30
30. Kedoshim - Leviticus 19:1-20:27
31. Emor - Leviticus 21:1-24:23
32. Behar - Leviticus 25:1-26:2
33. Bechukotai - Leviticus 26:3-27:34
### Bamidbar (Numbers)
34. Bamidbar - Numbers 1:1-4:20
35. Naso - Numbers 4:21-7:89
36. Behaalotecha - Numbers 8:1-12:16
37. Shelach - Numbers 13:1-15:41
38. Korach - Numbers 16:1-18:32
39. Chukat - Numbers 19:1-22:1
40. Balak - Numbers 22:2-25:9
41. Pinchas - Numbers 25:10-30:1
42. Matot - Numbers 30:2-32:42
43. Masei - Numbers 33:1-36:13
### Devarim (Deuteronomy)
44. Devarim - Deuteronomy 1:1-3:22
45. Vaetchanan - Deuteronomy 3:23-7:11
46. Eikev - Deuteronomy 7:12-11:25
47. Re'eh - Deuteronomy 11:26-16:17
48. Shoftim - Deuteronomy 16:18-21:9
49. Ki Teitzei - Deuteronomy 21:10-25:19
50. Ki Tavo - Deuteronomy 26:1-29:8
51. Nitzavim - Deuteronomy 29:9-30:20
52. Vayelech - Deuteronomy 31:1-31:30
53. Haazinu - Deuteronomy 32:1-32:52
54. V'Zot HaBracha - Deuteronomy 33:1-34:12
## Talmud Tractates by Order
### Zeraim (Seeds)
Berakhot
### Moed (Festivals)
Shabbat, Eruvin, Pesachim, Shekalim, Yoma, Sukkah, Beitzah, Rosh Hashanah, Taanit, Megillah, Moed Katan, Chagigah
### Nashim (Women)
Yevamot, Ketubot, Nedarim, Nazir, Sotah, Gittin, Kiddushin
### Nezikin (Damages)
Bava Kamma, Bava Metzia, Bava Batra, Sanhedrin, Makkot, Shevuot, Avodah Zarah, Horayot
### Kodashim (Holy Things)
Zevachim, Menachot, Chullin, Bekhorot, Arakhin, Temurah, Keritot, Meilah, Tamid
### Taharot (Purities)
Niddah
## Major Commentators
| Name | Hebrew | Era | Known For |
|------|--------|-----|-----------|
| Rashi | רש"י | 1040-1105 | Primary commentary on Torah & Talmud |
| Ramban | רמב"ן | 1194-1270 | Mystical/philosophical commentary |
| Ibn Ezra | אבן עזרא | 1089-1167 | Grammatical/linguistic analysis |
| Sforno | ספורנו | 1475-1550 | Philosophical interpretation |
| Or HaChaim | אור החיים | 1696-1743 | Kabbalistic insights |
| Rambam | רמב"ם | 1138-1204 | Mishneh Torah, Guide for Perplexed |
```
### scripts/dvar.py
```python
#!/usr/bin/env python3
"""
Dvar Torah Generator - AI-assisted Torah insights
Pulls sources from Sefaria and structures a dvar Torah.
"""
import json
import sys
import os
# Import sefaria module from same directory
script_dir = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, script_dir)
from sefaria import get_text, get_links, get_parsha, search, format_text, strip_html
def get_parsha_info():
"""Get this week's parsha details."""
parsha = get_parsha()
if "error" in parsha:
return None
return parsha
def get_parsha_opening(ref: str, verses: int = 5) -> dict:
"""Get the opening verses of a parsha."""
# Extract book and starting chapter:verse from ref like "Exodus 27:20-30:10"
parts = ref.split("-")[0] # Get "Exodus 27:20"
# Get the text
result = get_text(parts)
return result
def get_key_commentaries(ref: str) -> list:
"""Get key commentaries on a verse."""
links = get_links(ref)
if isinstance(links, dict) and "error" in links:
return []
# Filter for main commentaries
key_commentators = ["Rashi", "Ramban", "Sforno", "Or HaChaim", "Ibn Ezra", "Kli Yakar"]
commentaries = []
for link in links:
ref_text = link.get("ref", "")
for commentator in key_commentators:
if commentator in ref_text:
commentaries.append({
"commentator": commentator,
"ref": ref_text,
"he": link.get("he", ""),
"text": link.get("text", "")
})
break
return commentaries[:5] # Limit to 5 commentaries
def find_related_sources(query: str, limit: int = 3) -> list:
"""Find related sources on a theme."""
results = search(query, limit=limit)
if "error" in results:
return []
hits = results.get("hits", {}).get("hits", [])
sources = []
for hit in hits[:limit]:
ref_id = hit.get("_id", "")
ref = ref_id.split(" (")[0] if " (" in ref_id else ref_id
highlight = hit.get("highlight", {})
snippets = highlight.get("naive_lemmatizer", [])
sources.append({
"ref": ref,
"snippet": snippets[0] if snippets else ""
})
return sources
def generate_dvar_structure(parsha_name: str = None, ref: str = None, theme: str = None) -> str:
"""
Generate a structured dvar Torah outline with sources.
Args:
parsha_name: Name of parsha (e.g., "Tetzaveh")
ref: Specific verse reference to focus on
theme: Optional theme to explore
Returns:
Markdown-formatted dvar Torah structure with sources
"""
output = []
# Get parsha info if not provided
if not parsha_name and not ref:
parsha_info = get_parsha_info()
if parsha_info:
parsha_name = parsha_info.get("parsha")
ref = parsha_info.get("ref")
hebrew_name = parsha_info.get("hebrew", "")
else:
return "Error: Could not get parsha information"
else:
hebrew_name = ""
output.append(f"# Dvar Torah: Parashat {parsha_name}")
if hebrew_name:
output.append(f"## פרשת {hebrew_name}")
output.append("")
# Get opening verses
if ref:
output.append("## Opening Verses")
output.append(f"**Source:** {ref}")
output.append("")
# Get the actual text
opening_ref = ref.split("-")[0] # Get first part
text_data = get_text(opening_ref)
if "error" not in text_data:
he_text = text_data.get("he", [])
en_text = text_data.get("text", [])
# Show first 3 verses
for i in range(min(3, len(he_text) if isinstance(he_text, list) else 1)):
if isinstance(he_text, list) and i < len(he_text):
clean_he = strip_html(str(he_text[i]))
output.append(f"**{i+1}.** {clean_he}")
if isinstance(en_text, list) and i < len(en_text):
clean_en = strip_html(str(en_text[i]))
output.append(f" *{clean_en}*")
output.append("")
# Get commentaries on the opening verse
if ref:
opening_verse = ref.split("-")[0]
output.append("## Classical Commentaries")
output.append("")
commentaries = get_key_commentaries(opening_verse)
if commentaries:
for comm in commentaries:
output.append(f"### {comm['commentator']}")
output.append(f"**{comm['ref']}**")
if comm.get("text"):
clean_text = strip_html(str(comm["text"]))[:300]
output.append(f"> {clean_text}...")
elif comm.get("he"):
clean_he = strip_html(str(comm["he"]))[:200]
output.append(f"> {clean_he}...")
output.append("")
else:
output.append("*No commentaries found for this reference*")
output.append("")
# Find thematic connections if theme provided
if theme:
output.append(f"## Related Sources: {theme}")
output.append("")
related = find_related_sources(theme)
if related:
for source in related:
output.append(f"- **{source['ref']}**")
if source.get("snippet"):
clean_snippet = source["snippet"].replace("<b>", "**").replace("</b>", "**")
output.append(f" > {clean_snippet}")
output.append("")
# Add structure suggestions
output.append("## Suggested Structure")
output.append("")
output.append("1. **Hook**: Start with a question or observation from the opening verses")
output.append("2. **Problem**: What difficulty or tension exists in the text?")
output.append("3. **Sources**: Bring the commentaries above to explore answers")
output.append("4. **Resolution**: Synthesize insights from the sources")
output.append("5. **Application**: Connect to modern life or personal growth")
output.append("")
# Add key themes to explore
output.append("## Key Themes to Explore")
output.append("")
if parsha_name:
# Search for themes related to this parsha
themes = find_related_sources(parsha_name, limit=5)
if themes:
for t in themes:
output.append(f"- {t['ref']}")
output.append("")
output.append("---")
output.append("*Sources powered by Sefaria. Customize and expand with your own insights.*")
return "\n".join(output)
def main():
"""CLI entry point."""
if len(sys.argv) < 2:
# Default: generate for this week's parsha
print(generate_dvar_structure())
return
command = sys.argv[1]
if command == "parsha":
# Generate for this week's parsha
print(generate_dvar_structure())
elif command == "ref" and len(sys.argv) >= 3:
# Generate for specific reference
ref = " ".join(sys.argv[2:])
print(generate_dvar_structure(ref=ref))
elif command == "theme" and len(sys.argv) >= 3:
# Generate with specific theme
theme = " ".join(sys.argv[2:])
print(generate_dvar_structure(theme=theme))
elif command == "help" or command == "-h":
print("""
Dvar Torah Generator
Usage:
dvar.py Generate for this week's parsha
dvar.py parsha Generate for this week's parsha
dvar.py ref <reference> Generate for specific verse/section
dvar.py theme <theme> Generate with specific theme focus
Examples:
dvar.py
dvar.py ref "Genesis 12:1"
dvar.py theme "faith and trust"
""")
else:
# Treat as parsha name or ref
ref = " ".join(sys.argv[1:])
print(generate_dvar_structure(ref=ref))
if __name__ == "__main__":
main()
```
### scripts/sefaria.py
```python
#!/usr/bin/env python3
"""
Sefaria API wrapper for Torah Scholar skill.
Provides access to Jewish texts, search, and cross-references.
"""
import json
import sys
import urllib.request
import urllib.parse
import urllib.error
from typing import Optional
BASE_URL = "https://www.sefaria.org/api"
def api_request(endpoint: str, params: dict = None, method: str = "GET", json_body: dict = None) -> dict:
"""Make a request to the Sefaria API."""
url = f"{BASE_URL}/{endpoint}"
if params and method == "GET":
url += "?" + urllib.parse.urlencode(params)
try:
headers = {"User-Agent": "TorahScholar/1.0"}
data = None
if json_body:
headers["Content-Type"] = "application/json"
data = json.dumps(json_body).encode('utf-8')
req = urllib.request.Request(url, data=data, headers=headers, method=method)
with urllib.request.urlopen(req, timeout=30) as response:
return json.loads(response.read().decode())
except urllib.error.HTTPError as e:
return {"error": f"HTTP {e.code}: {e.reason}"}
except urllib.error.URLError as e:
return {"error": f"Connection failed: {e.reason}"}
except json.JSONDecodeError:
return {"error": "Invalid JSON response"}
def get_text(ref: str, lang: str = "all", with_context: bool = False) -> dict:
"""
Get text by reference (e.g., "Genesis 1:1", "Berakhot 2a").
Args:
ref: Sefaria reference string
lang: "he" (Hebrew), "en" (English), or "all"
with_context: Include surrounding context
Returns:
dict with text, translations, and metadata
"""
# Normalize reference format: "Genesis 1:1" -> "Genesis.1.1"
# But keep Talmud refs like "Berakhot 2a" as-is
normalized_ref = ref.replace(":", ".").replace(" ", "_")
encoded_ref = urllib.parse.quote(normalized_ref)
# Use v2 API (more reliable for text content)
endpoint = f"texts/{encoded_ref}"
params = {}
if with_context:
params["context"] = "1"
return api_request(endpoint, params if params else None)
def search(query: str, filters: dict = None, limit: int = 10) -> dict:
"""
Search across all texts.
Args:
query: Search query
filters: Optional filters (e.g., {"book": "Genesis"})
limit: Max results to return
Returns:
dict with search results
"""
body = {
"query": query,
"size": limit,
"type": "text",
"field": "naive_lemmatizer", # Better for English searches
"sort_type": "relevance"
}
if filters:
if "book" in filters:
body["filters"] = [filters["book"]]
return api_request("search-wrapper/es6", method="POST", json_body=body)
def get_links(ref: str) -> dict:
"""
Get all texts linked to a reference.
Args:
ref: Sefaria reference string
Returns:
dict with linked texts (commentaries, cross-references)
"""
encoded_ref = urllib.parse.quote(ref.replace(" ", "_"))
return api_request(f"links/{encoded_ref}")
def get_related(ref: str) -> dict:
"""
Get related texts and topics for a reference.
Args:
ref: Sefaria reference string
Returns:
dict with related content
"""
encoded_ref = urllib.parse.quote(ref.replace(" ", "_"))
return api_request(f"related/{encoded_ref}")
def get_index(title: str) -> dict:
"""
Get metadata about a book/text.
Args:
title: Book title (e.g., "Genesis", "Berakhot")
Returns:
dict with book metadata
"""
encoded_title = urllib.parse.quote(title.replace(" ", "_"))
return api_request(f"v2/index/{encoded_title}")
def get_calendars() -> dict:
"""
Get today's learning schedule (Daf Yomi, Parsha, etc.).
Returns:
dict with calendar items
"""
return api_request("calendars")
def get_parsha() -> dict:
"""
Get this week's Torah portion.
Returns:
dict with parsha information
"""
calendars = get_calendars()
if "error" in calendars:
return calendars
for item in calendars.get("calendar_items", []):
if item.get("title", {}).get("en") == "Parashat Hashavua":
return {
"parsha": item.get("displayValue", {}).get("en"),
"ref": item.get("ref"),
"hebrew": item.get("displayValue", {}).get("he")
}
return {"error": "Parsha not found"}
def strip_html(text: str) -> str:
"""Remove HTML tags from text."""
import re
# Remove HTML tags but keep content
clean = re.sub(r'<[^>]+>', '', text)
# Clean up extra whitespace
clean = re.sub(r'\s+', ' ', clean).strip()
return clean
def format_text(data: dict, format_type: str = "markdown") -> str:
"""
Format API response as readable text.
Args:
data: API response dict
format_type: "markdown", "plain", or "json"
Returns:
Formatted string
"""
if "error" in data:
return f"Error: {data['error']}"
if format_type == "json":
return json.dumps(data, indent=2, ensure_ascii=False)
output = []
# Title/Reference
ref = data.get("ref") or data.get("sectionRef", "")
if ref:
output.append(f"## {ref}\n")
# Hebrew text
he_text = data.get("he")
if he_text:
if isinstance(he_text, list):
# Join verses with numbers
formatted_he = []
for i, verse in enumerate(he_text, 1):
if isinstance(verse, str):
clean_verse = strip_html(verse)
formatted_he.append(f"{i}. {clean_verse}")
he_text = "\n".join(formatted_he)
else:
he_text = strip_html(str(he_text))
output.append(f"**Hebrew:**\n{he_text}\n")
# English text
en_text = data.get("text")
if en_text:
if isinstance(en_text, list):
# Join verses with numbers
formatted_en = []
for i, verse in enumerate(en_text, 1):
if isinstance(verse, str):
clean_verse = strip_html(verse)
formatted_en.append(f"{i}. {clean_verse}")
en_text = "\n".join(formatted_en)
else:
en_text = strip_html(str(en_text))
output.append(f"**English:**\n{en_text}\n")
return "\n".join(output) if output else json.dumps(data, indent=2, ensure_ascii=False)
def format_search_results(data: dict) -> str:
"""Format search results as markdown."""
if "error" in data:
return f"Error: {data['error']}"
hits = data.get("hits", {}).get("hits", [])
total = data.get("hits", {}).get("total", 0)
if not hits:
return "No results found."
output = [f"## Search Results ({total} total, showing {len(hits)})\n"]
for i, hit in enumerate(hits[:10], 1):
# Extract ref from _id (format: "Book, Section (version [lang])")
ref_id = hit.get("_id", "Unknown")
# Try to extract just the reference part before the version info
ref = ref_id.split(" (")[0] if " (" in ref_id else ref_id
# Get highlighted text
highlight = hit.get("highlight", {})
text_snippets = highlight.get("naive_lemmatizer", []) or highlight.get("exact", [])
output.append(f"### {i}. {ref}")
if text_snippets:
# Clean up HTML bold tags and join snippets
for snippet in text_snippets[:2]: # Show first 2 snippets
clean_snippet = snippet.replace("<b>", "**").replace("</b>", "**")
output.append(f"> {clean_snippet}")
output.append("")
return "\n".join(output)
def format_links(data: list) -> str:
"""Format links as markdown."""
if isinstance(data, dict) and "error" in data:
return f"Error: {data['error']}"
if not data:
return "No linked texts found."
# Group by category
categories = {}
for link in data:
cat = link.get("category", "Other")
if cat not in categories:
categories[cat] = []
categories[cat].append(link)
output = ["## Linked Texts\n"]
for cat, links in categories.items():
output.append(f"### {cat}")
for link in links[:5]: # Limit per category
ref = link.get("ref", "Unknown")
text = link.get("he", "") or link.get("text", "")
if isinstance(text, str) and text:
text = text[:150] + "..." if len(text) > 150 else text
output.append(f"- **{ref}**: {text}")
output.append("")
return "\n".join(output)
if __name__ == "__main__":
# CLI interface
if len(sys.argv) < 2:
print("Usage: sefaria.py <command> [args]")
print("Commands: text, search, links, related, parsha, calendars")
sys.exit(1)
command = sys.argv[1]
if command == "text" and len(sys.argv) >= 3:
ref = " ".join(sys.argv[2:])
result = get_text(ref)
print(format_text(result))
elif command == "search" and len(sys.argv) >= 3:
query = " ".join(sys.argv[2:])
result = search(query)
print(format_search_results(result))
elif command == "links" and len(sys.argv) >= 3:
ref = " ".join(sys.argv[2:])
result = get_links(ref)
print(format_links(result))
elif command == "related" and len(sys.argv) >= 3:
ref = " ".join(sys.argv[2:])
result = get_related(ref)
print(json.dumps(result, indent=2, ensure_ascii=False))
elif command == "parsha":
result = get_parsha()
print(json.dumps(result, indent=2, ensure_ascii=False))
elif command == "calendars":
result = get_calendars()
print(json.dumps(result, indent=2, ensure_ascii=False))
else:
print(f"Unknown command: {command}")
sys.exit(1)
```