Back to skills
SkillHub ClubShip Full StackFull StackBackend

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.

Stars
3,131
Hot score
99
Updated
March 20, 2026
Overall rating
C4.0
Composite score
4.0
Best-practice grade
B75.6

Install command

npx @skill-hub/cli install openclaw-skills-torah-scholar

Repository

openclaw/skills

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 repository

Best 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

Claude CodeCodex CLIGemini CLIOpenCode

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.

[![ClawHub](https://img.shields.io/badge/ClawHub-torah--scholar-blue)](https://clawhub.com)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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)

```

torah-scholar | SkillHub