---
name: tufte-press
description: Generate Tufte-inspired study card JSON from conversation, build PDF, and print
---

# Tufte Press Study Card Generator

Generate structured JSON study cards from conversation context, convert to beautifully typeset PDFs with Tufte-inspired layouts, and optionally send to printer.

## When to Use

Invoke this skill when the user requests:
- "Create a study card about [topic]"
- "Generate a tufte-press card for [subject]"
- "Make a printable study guide for [concept]"
- "Build a study card and print it"
- "Convert our conversation to a study card"

## Process

### Step 1: Extract Learning Content from Conversation

Review the conversation history to identify:
- **Topic**: Main subject matter
- **Key concepts**: Core ideas discussed
- **Prerequisites**: Background knowledge mentioned
- **Examples**: Concrete illustrations provided
- **Technical details**: Specific facts, equations, or procedures

Ask clarifying questions if needed:
- What depth level? (intro/intermediate/advanced)
- How many pages? (1-3 recommended)
- Include practice exercises?
- Any specific citations to include?
- Target audience?

### Step 2: Generate JSON Following Strict Schema

**You are now the educator-typesetter.** Generate valid JSON that compiles to LaTeX/PDF without edits.

**Core Principles:**
- Output must be valid JSON that compiles to LaTeX/PDF without edits
- Margin notes must be self-contained (restate the term being defined)
- Lists must use JSON arrays, not newline-separated strings
- Practice strips have prompts only (NO answers in practice_strip)
- Self-check questions DO include answers (correct_answer and why_it_matters)
- Use Unicode symbols (λ, →, ×) in content; LaTeX in equation_latex
- Cite real sources or mark "[NEEDS CLARIFICATION]"

**Required Schema:**
```json
{
  "metadata": {
    "title": "Study Card: [Topic]",
    "topic": "Brief description",
    "audience": "Target learners",
    "learner_focus": "Learning objectives",
    "estimated_read_time_minutes": 15,
    "prerequisites": ["prereq1", "prereq2"],
    "learning_objectives": ["objective1", "objective2"],
    "sources": [
      {
        "title": "Source Title",
        "author": "Author Name",
        "year": "2024",
        "citation": "Full citation",
        "link": "https://doi.org/..."
      }
    ],
    "provenance": {
      "model": "Claude 3.5 Sonnet",
      "date": "2025-11-10",
      "version": "1.0",
      "notes": "Generated from conversation context"
    }
  },
  "pages": [
    {
      "page_number": 1,
      "layout": "two-column",
      "main_flow": [
        {
          "type": "text",
          "content": "Opening paragraph with main concept.",
          "attributes": { "emphasis": "newthought" }
        },
        {
          "type": "list",
          "content": ["Item 1", "Item 2", "Item 3"],
          "attributes": { "list_style": "bullet" }
        },
        {
          "type": "equation",
          "content": "E = mc^2",
          "attributes": { "equation_latex": "E = mc^{2}" }
        },
        {
          "type": "callout",
          "content": "Important note or tip.",
          "attributes": { "callout_title": "Key Insight" }
        }
      ],
      "margin_notes": [
        {
          "anchor": "concept",
          "content": "Term — Definition that restates the term being defined",
          "note_type": "definition"
        }
      ],
      "full_width_assets": []
    }
  ],
  "drills": {
    "practice_strip": [
      {
        "prompt": "Practice question for active learning (NO answers here)"
      }
    ],
    "self_check": [
      {
        "question": "Self-assessment question",
        "correct_answer": "Expected answer",
        "why_it_matters": "Why this question is important"
      }
    ]
  },
  "glossary": [
    {
      "term": "Technical Term",
      "definition": "Clear definition",
      "page_reference": [1]
    }
  ]
}
```

**Block Types:**
- `text`: { `type`: "text", `content`: string, `attributes`? { `emphasis`?: "newthought"|"bold"|"summary" } }
- `list`: { `type`: "list", `content`: [array of strings], `attributes`? { `list_style`: "bullet"|"numbered" } }
  - **CRITICAL**: `content` MUST be JSON array, NOT newline-separated string
  - ✅ CORRECT: `"content": ["Item 1", "Item 2", "Item 3"]`
  - ❌ WRONG: `"content": "Item 1\nItem 2\nItem 3"`
- `equation`: { `type`: "equation", `content`: string, `attributes`: { `equation_latex`: string } }
- `callout`: { `type`: "callout", `content`: string, `attributes`? { `callout_title`: string } }
- `quote`: { `type`: "quote", `content`: string, `attributes`? { `quote_citation`: string } }

**Margin Notes:**
- { `anchor`: string, `content`: string, `note_type`: "definition"|"syntax"|"concept"|"history"|"problem"|"operation"|"equivalence"|"notation"|"property"|"example"|"reference" }
- **CRITICAL**: Margin notes must be self-contained and restate the term
  - ✅ CORRECT: "Free variable — A variable not bound by any λ abstraction"
  - ❌ WRONG: "A variable not bound by any λ abstraction" (doesn't name term)
- **Format**: "**Term** — Definition/explanation"

**Content Constraints:**
- **Length**: 1-3 pages; prefer first page `layout`="two-column"
- **Margin notes**: 3-6 per page, each 15-25 words (enough to be self-contained)
- **First paragraph**: Start with `attributes.emphasis`="newthought"
- **Math**: 
  - Display equations: Use `attributes.equation_latex` for centered equations
  - Inline math: Use `$...$` for mathematical expressions in running text
    - ✅ CORRECT: `"The expression $f g h$ parses as $((f g) h)$"`
    - ✅ CORRECT: `"Substituting 7 for $x$ yields 7"`
  - Unicode symbols: λ, →, ←, ⇒, ⇔, α, β, γ, Ω, ω, ×, ·, ≡, ≤, ≥
- **Reading level**: Upper-undergrad; terse, factual; no fluff
- **Practice strips**: Prompts ONLY - NO answers (these are for active learning)
- **Self-check questions**: DO include answers - these verify understanding
- **Citations**: At least one reputable source with DOI/URL
- **Accuracy**: Do not invent facts; omit if unknown

**Validation Checklist:**
- All required fields present
- Each equation has `equation_latex`
- `page_number` starts at 1 and increments
- Arrays exist (even if empty)
- Margin notes are self-contained
- Lists use JSON arrays not strings
- Sources are real (or marked with "[NEEDS CLARIFICATION]")

**Guardrails:**
- If the request is under-specified, return a minimal 1-page scaffold and store 3–5 numbered clarification questions inside `metadata.provenance.notes`
- Otherwise produce the full card
- Validate internally before saving

**Self-Check Rubric:**
Before finalizing, adjust content to meet:
- **Accuracy**: No speculation, cite real sources
- **Clarity**: Short sentences, clear definitions
- **Annotation utility**: Margin notes actionable and self-contained
- **Balance**: Main content vs margin notes flow naturally
- **Schema validity**: All required fields present
- **Print suitability**: Short margin notes (15-25 words), avoid long lines

### Step 3: Save JSON to File

Write the generated JSON to a file in an appropriate location:
- Project context: Save to project directory (e.g., `./my-card.json`)
- General use: Save to `/tmp/study-card-YYYYMMDD-HHMMSS.json`

Inform the user where the file was saved.

### Step 4: Build PDF (if requested)

Use the helper script to build the PDF:

```bash
~/.claude/skills/tufte-press/scripts/generate-and-build.sh my-card.json --build
```

This will:
1. Validate the JSON against the schema
2. Convert JSON → LaTeX using Python
3. Compile LaTeX → PDF using Tectonic
4. Output: `my-card.pdf`

**Prerequisites:**
- `TUFTE_PRESS_REPO` environment variable (default: `~/proj/tufte-press`)
- tufte-press repository must be available
- Nix development shell (automatically entered if needed)

### Step 5: Print (if requested)

Use the helper script with print options:

```bash
~/.claude/skills/tufte-press/scripts/generate-and-build.sh my-card.json --build --print
```

**Print Options:**
- `--print`: Send to default printer
- `--printer NAME`: Specify printer
- `--copies N`: Print N copies (default: 1)
- `--duplex`: Enable duplex printing (long-edge for handouts)

**Example (duplex, 2 copies):**
```bash
~/.claude/skills/tufte-press/scripts/generate-and-build.sh my-card.json \
  --build --print --copies 2 --duplex
```

## Helper Scripts

### `generate-and-build.sh`

Complete workflow automation:

```bash
# Validate JSON only
./scripts/generate-and-build.sh my-card.json

# Generate PDF
./scripts/generate-and-build.sh my-card.json --build

# Generate and print
./scripts/generate-and-build.sh my-card.json --build --print --duplex
```

## Guidelines

### 1. Content Quality
- Base content on actual conversation history
- Include real citations when possible
- Mark uncertain information with "[NEEDS CLARIFICATION]"
- Keep margin notes concise but self-contained
- Use examples from the conversation

### 2. JSON Generation
- Generate valid JSON in a single response
- No markdown fences around JSON
- Validate structure before saving
- Use proper escaping for special characters

### 3. Build Process
- Always validate before building
- Check for tufte-press repo availability
- Handle build errors gracefully
- Provide clear error messages

### 4. Printing
- Confirm print settings with user before printing
- Recommend duplex for handouts
- Verify printer availability
- Show print queue status after submission

## Error Handling

**JSON validation fails:**
- Review error messages from `metadata-validate.sh`
- Common issues: missing required fields, invalid types, bad array formats
- Fix JSON and re-validate

**Build fails:**
- Check LaTeX errors in output
- Verify special character escaping
- Ensure `equation_latex` present for all equations
- Check margin note formatting

**Print fails:**
- Verify printer is online: `lpstat -p`
- Check print queue: `lpstat -o`
- Ensure user has print permissions
- Try default printer if named printer fails

## Example Workflow

**User**: "Create a study card about recursion from our conversation and print it"

**Agent** (using this skill):

1. Review conversation history
2. Extract key concepts about recursion
3. Generate JSON with proper schema
4. Save to `/tmp/study-card-recursion-20251110.json`
5. Run: `generate-and-build.sh /tmp/study-card-recursion-20251110.json --build --print --duplex`
6. Confirm: "Study card generated and sent to printer (2 pages, duplex)"

## Requirements

**Environment:**
- tufte-press repository at `~/proj/tufte-press` (or `$TUFTE_PRESS_REPO`)
- Nix with flakes enabled
- CUPS printing system (for print functionality)

**Dependencies (via tufte-press):**
- Python 3.11
- Tectonic (LaTeX compiler)
- jq (JSON validation)

**Skill provides:**
- JSON generation from conversation
- Build automation script
- Print integration
- Schema validation

## Notes

- **Conversation-aware**: Extracts content from chat history
- **Complete workflow**: JSON → PDF → Print in one skill
- **Production ready**: Uses validated pipeline from tufte-press project
- **Print-optimized**: Duplex support for handout workflow
- **Error recovery**: Clear messages and validation at each step
