# RIS (Rechtsinformationssystem) Legal Research Workflow

Proven multi-tool approach for researching Austrian laws, DBA treaties, and tax regulations on JS-heavy government sites (RIS, Findok). Developed during DBA Österreich-Türkei pension research, 05.06.2026.

## The Problem

Austrian government legal databases (RIS, Findok) are JavaScript-rendered SPAs. Direct `curl` returns empty shells or HTML framework. Some RIS endpoints use WebForms-style session tokens and stateful page rendering that server-side readers can't replay — but NOT all. See "When each tool works" below for the current state as of 08.06.2026.

## When Each Tool Works (Empirical, 08.06.2026)

**jina.ai ✓ (works):**
- NormDokument pages with full query params: `?Abfrage=Bundesnormen&Gesetzesnummer=10001622&Paragraf=364c` — full statutory text extracted cleanly including metadata (Kurztitel, Kundmachungsorgan, Inkrafttretensdatum, Schlagworte)
- Justiz search results WITH Norm filter: `?Abfrage=Justiz&Suchworte=Veräußerungsverbot+364c&Norm=ABGB+§364c` — returns clean list of Rechtssätze with summaries, links, and NOR numbers
- Individual Justiz Rechtssatz/Entscheidung pages (`/Dokumente/Justiz/JJR_.../JJR_....html`) — clean markdown extraction
- RIS-Ergebnis search pages that resolve statically (without ASP.NET postback)
- DBA overview pages (NOR40110804)

**jina.ai ✗ (fails):**
- Seiten die ASP.NET postback + session state verwenden (z.B. manche "Ergebnis.wxe" Such-Ergebnisseiten) → "nicht mehr in Kraft" / 404
- Google Searches → 429 rate-limiting bei jina (nicht verwenden)

**Camofox (always works)**: Full JS rendering, handles all session state. Use when jina fails, or for initial exploration of RIS search results to discover document links/patterns. The `/links` endpoint is unreliable for Justiz search result pages (returns only navigation links with empty hrefs — SPA JS-routed).

## The Fix: Three-Tool Chain

### Tool 1: Camofox Browser (stateful rendering)
Use when jina.ai returns empty pages or 404s. The browser runs the JS, handles sessions, renders the actual document.

```bash
# Check Camofox is running
curl -fsS http://127.0.0.1:9377/health

# Open a tab with the legal document
curl -s -X POST "http://127.0.0.1:9377/tabs" \
  -H "Content-Type: application/json" \
  -d '{"userId":"kiwi","sessionKey":"default","url":"https://www.ris.bka.gv.at/..."}'

# Wait for JS rendering (5s minimum for RIS)
sleep 5

# Take screenshot
curl -s "http://127.0.0.1:9377/tabs/$TAB/screenshot?userId=kiwi&sessionKey=default" \
  -o /tmp/legal_page.png

# Extract links (for finding sub-articles, related docs)
curl -s "http://127.0.0.1:9377/tabs/$TAB/links?userId=kiwi&sessionKey=default"
```

### Tool 2: jina.ai reader (fast, try first)

```bash
curl -sL "https://r.jina.ai/<RIS_DOCUMENT_URL>" \
  -H "Accept: text/plain"
```

Best for: statutory text from NormDokument pages, Justiz Rechtssatz/Entscheidung pages, and search results that resolve without ASP.NET postback. See "When Each Tool Works" above for the current success/failure map.

### Tool 3: vision_analyze (reads screenshots)
When jina fails and browser screenshots are the only rendered content:

```
vision_analyze(image_url=/tmp/ris_page.png, question="What document titles and numbers are listed?")
```

**Critical pitfall:** vision_analyze can hallucinate legal text. It's good for:
- Extracting structured elements (table columns, document numbers, dates)
- Reading short labels and navigation items
- Identifying page status (e.g., "nicht mehr in Kraft")

It's NOT reliable for:
- Long paragraphs of legal prose (will paraphrase/hallucinate)
- Precise statutory language (invents plausible-sounding but wrong text)

## RIS Specific Patterns

### Finding a DBA (Double Taxation Treaty)

1. Search RIS: `https://www.ris.bka.gv.at/Ergebnis.wxe?Abfrage=Bundesnormen&Suchworte=T%C3%BCrkei+Doppelbesteuerung&...`
2. Open in Camofox, screenshot the results table
3. Extract document links from `/links` endpoint — each article row links to `.../eli/bgbl/iii/2009/96/A18/NOR40110822`
4. The NOR number increments: Art 1 = NOR40110805, Art 18 = NOR40110822, Art 23 = NOR40110826
5. Load individual article pages via jina.ai: `https://r.jina.ai/https://www.ris.bka.gv.at/Dokumente/Bundesnormen/NOR40110822/NOR40110822.html`

### Finding OGH Judikatur (Case Law) to a specific statute

**Goal:** Find all OGH Rechtssätze citing a specific ABGB paragraph (or any statute) and drill into individual decisions.

**Step 1 — jina.ai on Justiz search with Norm filter** (works reliably):
```bash
curl -sL "https://r.jina.ai/https://www.ris.bka.gv.at/Ergebnis.wxe?Abfrage=Justiz&Suchworte=Ver%C3%A4u%C3%9Ferungsverbot+364c&Norm=ABGB+%C2%A7364c" \
  -H "Accept: text/plain"
```
Key parameters:
- `Abfrage=Justiz` — the Justiz (courts) database
- `Suchworte=<URL-encoded keywords>` — simple, broad keywords work best; overly complex queries return empty
- `Norm=ABGB+§364c` — the Norm filter is powerful, restricts results to decisions citing that statute
- Returns: clean list of numbered Rechtssätze with summaries, GZ numbers, dates, and Document links

**Step 2 — jina.ai on individual decisions** (works reliably):
```bash
curl -sL "https://r.jina.ai/https://www.ris.bka.gv.at/Dokumente/Justiz/JJR_19961008_OGH0002_0050OB02243_96F0000_001/JJR_19961008_OGH0002_0050OB02243_96F0000_001.html" \
  -H "Accept: text/plain"
```
Returns the Rechtssatz text plus any Beisatz (annotations) and list of citing decisions.

**Step 3 — Camofox fallback** (when jina fails):
If the search results page uses ASP.NET postback and jina returns empty/404, open the search URL in Camofox:
```bash
curl -s -X POST "http://127.0.0.1:9377/tabs" \
  -H "Content-Type: application/json" \
  -d '{"userId":"kiwi","sessionKey":"default","url":"https://www.ris.bka.gv.at/Ergebnis.wxe?Abfrage=Justiz&Suchworte=Ver%C3%A4u%C3%9Ferungsverbot+Miteigentumsanteil"}'
sleep 6
curl -s "http://127.0.0.1:9377/tabs/$TAB/screenshot?userId=kiwi&sessionKey=default" -o /tmp/ogh_search.png
```
Note: The Camofox `/links` endpoint returns only navigation links (with empty hrefs) on Justiz search result pages — use screenshot + vision_analyze for structure, then jina.ai on individual decision URLs.

**Step 4 — RIS Justiz URL pattern for Norm-filtered search:**
```
https://www.ris.bka.gv.at/Ergebnis.wxe?Abfrage=Justiz&Suchworte=<keywords>&Norm=<statute>&ImRisSeit=Undefined
```
Example for § 364c ABGB:
```
?Abfrage=Justiz&Suchworte=Veräußerungsverbot+364c&Norm=ABGB+§364c
```
The `Norm` parameter is the secret weapon — it filters OGH decisions by the specific statute they cite, dramatically improving result relevance over keyword-only searches.

### Finding EStG Paragraphs

RIS URL pattern for EStG 1988 (Gesetzesnummer 10004570):
```
https://www.ris.bka.gv.at/NormDokument.wxe?Abfrage=Bundesnormen&Gesetzesnummer=10004570&FassungVom=05.06.2026&Artikel=&Paragraf=2&Anlage=
```

### Findok (BMF Tax Rulings)

URL pattern: `https://findok.bmf.gv.at/findok/search/show?q=<searchterm>`
- Uses JavaScript search — direct curl/jina rarely works
- For EStR 2000 (Einkommensteuerrichtlinien): use the "Richtlinien" navigation link in Camofox

## Worked Example: DBA Austria-Turkey Art 18 (Pensions)

1. **jina.ai on RIS search results** → 404 (ASP.NET session state)
2. **Camofox to RIS search** → Screenshot showed 10 results: "Doppelbesteuerung – Einkommensteuer (Türkei)" BGBl III 96/2009
3. **links endpoint** → Extracted NOR pattern: A1=NOR40110805
4. **jina.ai on individual articles** → Clean markdown for each article:
   - Art 18 (NOR40110822): "Ruhegehälter ... nur in dem Staat besteuert werden, in dem der Empfänger ansässig ist"
   - Art 19 (NOR40110823): "ÖFFENTLICHER DIENST" with citizenship exceptions
   - Art 23 (NOR40110826): Method article — lit. a Befreiungsmethode, lit. d Progressionsvorbehalt
5. **Camofox for EStG § 25, FinStrG § 29** → Screenshots for document status verification

## Lessons Learned

- **Don't fight RIS with curl alone.** The session token model defeats stateless HTTP. Accept that browser automation is the primary path for RIS.
- **jina.ai is the first resort, not the only resort.** Try it, but when it 404s on an obviously valid page, switch to Camofox immediately.
- **vision_analyze is the last resort for text.** Use it for structure/scaffolding, then use jina.ai on discovered URLs for the actual text.
- **NOR number patterns let you skip pagination.** Once you find the base NOR for Art 1, you can probe Art 18 by adding 17 to the number.
- **For § 364c ABGB domain knowledge (Belastungs- und Veräußerungsverbot)** — key OGH decisions, Familienkreis, Teilbarkeit, letztwilliges BuV, Alternativen — see `references/abgb-364c-veraeusserungsverbot.md`.
