ris-mcp 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. ris_mcp-0.2.0/.github/workflows/ci.yml +13 -0
  2. ris_mcp-0.2.0/.github/workflows/release.yml +28 -0
  3. ris_mcp-0.2.0/.gitignore +14 -0
  4. ris_mcp-0.2.0/.python-version +1 -0
  5. ris_mcp-0.2.0/DATA_LICENSE +5 -0
  6. ris_mcp-0.2.0/LICENSE +21 -0
  7. ris_mcp-0.2.0/PKG-INFO +76 -0
  8. ris_mcp-0.2.0/README.md +54 -0
  9. ris_mcp-0.2.0/docs/index.html +227 -0
  10. ris_mcp-0.2.0/docs/publishing-the-dataset.md +53 -0
  11. ris_mcp-0.2.0/docs/stats.json +14 -0
  12. ris_mcp-0.2.0/docs/superpowers/plans/2026-04-15-ris-mcp-phase1.5-distribution.md +1090 -0
  13. ris_mcp-0.2.0/docs/superpowers/plans/2026-04-15-ris-mcp-phase1.md +2167 -0
  14. ris_mcp-0.2.0/docs/superpowers/specs/2026-04-15-ris-mcp-phase1-design.md +360 -0
  15. ris_mcp-0.2.0/docs/superpowers/specs/2026-04-15-ris-mcp-phase1.5-distribution-design.md +176 -0
  16. ris_mcp-0.2.0/pyproject.toml +45 -0
  17. ris_mcp-0.2.0/src/ris_mcp/__init__.py +1 -0
  18. ris_mcp-0.2.0/src/ris_mcp/applikation.py +47 -0
  19. ris_mcp-0.2.0/src/ris_mcp/cli.py +100 -0
  20. ris_mcp-0.2.0/src/ris_mcp/client.py +452 -0
  21. ris_mcp-0.2.0/src/ris_mcp/coverage.py +37 -0
  22. ris_mcp-0.2.0/src/ris_mcp/hf_import.py +58 -0
  23. ris_mcp-0.2.0/src/ris_mcp/ingest.py +105 -0
  24. ris_mcp-0.2.0/src/ris_mcp/ingest_bundesrecht.py +38 -0
  25. ris_mcp-0.2.0/src/ris_mcp/schema.sql +80 -0
  26. ris_mcp-0.2.0/src/ris_mcp/server.py +50 -0
  27. ris_mcp-0.2.0/src/ris_mcp/store.py +102 -0
  28. ris_mcp-0.2.0/src/ris_mcp/tools/__init__.py +0 -0
  29. ris_mcp-0.2.0/src/ris_mcp/tools/get_decision.py +68 -0
  30. ris_mcp-0.2.0/src/ris_mcp/tools/get_law.py +49 -0
  31. ris_mcp-0.2.0/src/ris_mcp/tools/search_decisions.py +82 -0
  32. ris_mcp-0.2.0/tests/__init__.py +0 -0
  33. ris_mcp-0.2.0/tests/conftest.py +16 -0
  34. ris_mcp-0.2.0/tests/fixtures/bundesrecht_search_page1.json +1 -0
  35. ris_mcp-0.2.0/tests/fixtures/bvwg_search_page1.json +1 -0
  36. ris_mcp-0.2.0/tests/fixtures/vfgh_search_page1.json +1 -0
  37. ris_mcp-0.2.0/tests/test_applikation.py +35 -0
  38. ris_mcp-0.2.0/tests/test_cli.py +28 -0
  39. ris_mcp-0.2.0/tests/test_client.py +161 -0
  40. ris_mcp-0.2.0/tests/test_coverage.py +64 -0
  41. ris_mcp-0.2.0/tests/test_e2e_smoke.py +35 -0
  42. ris_mcp-0.2.0/tests/test_get_decision.py +42 -0
  43. ris_mcp-0.2.0/tests/test_get_law.py +33 -0
  44. ris_mcp-0.2.0/tests/test_hf_import.py +79 -0
  45. ris_mcp-0.2.0/tests/test_ingest.py +73 -0
  46. ris_mcp-0.2.0/tests/test_ingest_bundesrecht.py +49 -0
  47. ris_mcp-0.2.0/tests/test_search_decisions.py +56 -0
  48. ris_mcp-0.2.0/tests/test_store.py +81 -0
@@ -0,0 +1,13 @@
1
+ name: CI
2
+ on:
3
+ push: { branches: [main, master] }
4
+ pull_request:
5
+ jobs:
6
+ test:
7
+ runs-on: ubuntu-latest
8
+ steps:
9
+ - uses: actions/checkout@v4
10
+ - uses: astral-sh/setup-uv@v3
11
+ - run: uv venv && uv pip install -e ".[dev]"
12
+ - run: uv run ruff check src tests
13
+ - run: uv run pytest -v
@@ -0,0 +1,28 @@
1
+ name: release
2
+ on:
3
+ push:
4
+ tags: ['v*']
5
+ jobs:
6
+ build:
7
+ runs-on: ubuntu-latest
8
+ steps:
9
+ - uses: actions/checkout@v4
10
+ - uses: astral-sh/setup-uv@v3
11
+ - run: uv build
12
+ - uses: actions/upload-artifact@v4
13
+ with:
14
+ name: dist
15
+ path: dist/
16
+
17
+ publish:
18
+ needs: build
19
+ runs-on: ubuntu-latest
20
+ environment: pypi
21
+ permissions:
22
+ id-token: write
23
+ steps:
24
+ - uses: actions/download-artifact@v4
25
+ with:
26
+ name: dist
27
+ path: dist/
28
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,14 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.pyc
4
+ .pytest_cache/
5
+ .ruff_cache/
6
+ dist/
7
+ build/
8
+ *.egg-info/
9
+ .coverage
10
+ *.db
11
+ *.db-wal
12
+ *.db-shm
13
+ .env
14
+ ingest.log
@@ -0,0 +1 @@
1
+ 3.11
@@ -0,0 +1,5 @@
1
+ The data ingested by this software from the Austrian Rechtsinformationssystem
2
+ (RIS, https://www.ris.bka.gv.at) consists of amtliche Werke within the meaning
3
+ of § 7 öUrhG and is in the public domain. Any redistribution of such data by
4
+ projects using this software is dedicated to the public domain under
5
+ Creative Commons Zero v1.0 (CC0-1.0): https://creativecommons.org/publicdomain/zero/1.0/
ris_mcp-0.2.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jonas Hertner
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
ris_mcp-0.2.0/PKG-INFO ADDED
@@ -0,0 +1,76 @@
1
+ Metadata-Version: 2.4
2
+ Name: ris-mcp
3
+ Version: 0.2.0
4
+ Summary: MCP server for Austrian RIS (court decisions + federal law) backed by a local FTS5-indexed SQLite mirror
5
+ Author-email: Jonas Hertner <jonashertner@protonmail.ch>
6
+ License: MIT
7
+ License-File: LICENSE
8
+ Requires-Python: >=3.11
9
+ Requires-Dist: beautifulsoup4>=4.12
10
+ Requires-Dist: click>=8.1
11
+ Requires-Dist: httpx>=0.27
12
+ Requires-Dist: huggingface-hub>=0.24
13
+ Requires-Dist: lxml>=5.0
14
+ Requires-Dist: mcp>=1.2
15
+ Requires-Dist: pydantic>=2.7
16
+ Provides-Extra: dev
17
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
18
+ Requires-Dist: pytest>=8; extra == 'dev'
19
+ Requires-Dist: respx>=0.21; extra == 'dev'
20
+ Requires-Dist: ruff>=0.6; extra == 'dev'
21
+ Description-Content-Type: text/markdown
22
+
23
+ # ris-mcp
24
+
25
+ > **👉 For end users: see [jonashertner.github.io/ris-mcp](https://jonashertner.github.io/ris-mcp/) for the three-command install.**
26
+
27
+ Local MCP server for the Austrian Rechtsinformationssystem (RIS) — court decisions and consolidated federal law, queryable from Claude (Code, Desktop, claude.ai).
28
+
29
+ [![CI](https://github.com/jonashertner/ris-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/jonashertner/ris-mcp/actions/workflows/ci.yml)
30
+
31
+ ## What
32
+
33
+ `ris-mcp` maintains a locally-mirrored, FTS5-indexed SQLite copy of the full Austrian RIS corpus and exposes it to Claude via MCP. Compare to [`philrox/ris-mcp-ts`](https://github.com/philrox/ris-mcp-ts), which is a thin live-API proxy: local mirror wins on search quality, latency, offline capability, and future citation-graph/reranking work.
34
+
35
+ ## Install (users)
36
+
37
+ See the [landing page](https://jonashertner.github.io/ris-mcp/).
38
+
39
+ ## Develop (contributors)
40
+
41
+ ```bash
42
+ git clone https://github.com/jonashertner/ris-mcp.git
43
+ cd ris-mcp
44
+ uv venv && uv pip install -e ".[dev]"
45
+ .venv/bin/pytest -v
46
+ ```
47
+
48
+ Run the MCP server locally:
49
+
50
+ ```bash
51
+ .venv/bin/ris-mcp serve
52
+ ```
53
+
54
+ Kick off a full backfill (2–3 days):
55
+
56
+ ```bash
57
+ .venv/bin/ris-ingest --full
58
+ ```
59
+
60
+ Emit coverage stats:
61
+
62
+ ```bash
63
+ .venv/bin/ris-ingest coverage --out docs/stats.json
64
+ ```
65
+
66
+ ## Licenses
67
+
68
+ - Code: MIT
69
+ - Data: CC0-1.0 (amtliches Werk per § 7 öUrhG)
70
+
71
+ ## Credits
72
+
73
+ - [ximex/ris-bka](https://github.com/ximex/ris-bka) — RIS OGD documentation
74
+ - [philrox/ris-mcp-ts](https://github.com/philrox/ris-mcp-ts) — different design, same goal
75
+ - [PhilippTh/ris-API-wrapper](https://github.com/PhilippTh/ris-API-wrapper) — Python wrapper precedent
76
+ - [opencaselaw.ch](https://opencaselaw.ch) — architectural inspiration
@@ -0,0 +1,54 @@
1
+ # ris-mcp
2
+
3
+ > **👉 For end users: see [jonashertner.github.io/ris-mcp](https://jonashertner.github.io/ris-mcp/) for the three-command install.**
4
+
5
+ Local MCP server for the Austrian Rechtsinformationssystem (RIS) — court decisions and consolidated federal law, queryable from Claude (Code, Desktop, claude.ai).
6
+
7
+ [![CI](https://github.com/jonashertner/ris-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/jonashertner/ris-mcp/actions/workflows/ci.yml)
8
+
9
+ ## What
10
+
11
+ `ris-mcp` maintains a locally-mirrored, FTS5-indexed SQLite copy of the full Austrian RIS corpus and exposes it to Claude via MCP. Compare to [`philrox/ris-mcp-ts`](https://github.com/philrox/ris-mcp-ts), which is a thin live-API proxy: local mirror wins on search quality, latency, offline capability, and future citation-graph/reranking work.
12
+
13
+ ## Install (users)
14
+
15
+ See the [landing page](https://jonashertner.github.io/ris-mcp/).
16
+
17
+ ## Develop (contributors)
18
+
19
+ ```bash
20
+ git clone https://github.com/jonashertner/ris-mcp.git
21
+ cd ris-mcp
22
+ uv venv && uv pip install -e ".[dev]"
23
+ .venv/bin/pytest -v
24
+ ```
25
+
26
+ Run the MCP server locally:
27
+
28
+ ```bash
29
+ .venv/bin/ris-mcp serve
30
+ ```
31
+
32
+ Kick off a full backfill (2–3 days):
33
+
34
+ ```bash
35
+ .venv/bin/ris-ingest --full
36
+ ```
37
+
38
+ Emit coverage stats:
39
+
40
+ ```bash
41
+ .venv/bin/ris-ingest coverage --out docs/stats.json
42
+ ```
43
+
44
+ ## Licenses
45
+
46
+ - Code: MIT
47
+ - Data: CC0-1.0 (amtliches Werk per § 7 öUrhG)
48
+
49
+ ## Credits
50
+
51
+ - [ximex/ris-bka](https://github.com/ximex/ris-bka) — RIS OGD documentation
52
+ - [philrox/ris-mcp-ts](https://github.com/philrox/ris-mcp-ts) — different design, same goal
53
+ - [PhilippTh/ris-API-wrapper](https://github.com/PhilippTh/ris-API-wrapper) — Python wrapper precedent
54
+ - [opencaselaw.ch](https://opencaselaw.ch) — architectural inspiration
@@ -0,0 +1,227 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>ris-mcp — Austrian RIS inside Claude</title>
7
+ <meta name="description" content="Local MCP server for Austrian court decisions and federal law. 700k+ decisions, fully offline, queryable from Claude." />
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>⚖️</text></svg>" />
10
+ </head>
11
+ <body class="bg-slate-50 text-slate-900 font-sans antialiased">
12
+
13
+ <header class="border-b border-slate-200 bg-white">
14
+ <div class="max-w-5xl mx-auto px-6 py-4 flex items-center justify-between">
15
+ <div class="flex items-center gap-3">
16
+ <span class="text-2xl">⚖️</span>
17
+ <span class="font-semibold">ris-mcp</span>
18
+ </div>
19
+ <nav class="flex gap-6 text-sm">
20
+ <a href="#install" class="hover:text-slate-600">Install</a>
21
+ <a href="#stats" class="hover:text-slate-600">Stats</a>
22
+ <a href="#roadmap" class="hover:text-slate-600">Roadmap</a>
23
+ <a href="https://github.com/jonashertner/ris-mcp" class="hover:text-slate-600">GitHub</a>
24
+ </nav>
25
+ </div>
26
+ </header>
27
+
28
+ <section class="max-w-5xl mx-auto px-6 py-20">
29
+ <h1 class="text-4xl md:text-5xl font-bold tracking-tight">Austrian case law + federal statutes, inside Claude.</h1>
30
+ <p class="mt-6 text-lg text-slate-600 max-w-3xl">
31
+ <code>ris-mcp</code> is a local MCP server that mirrors the Austrian Rechtsinformationssystem
32
+ (RIS) into a searchable SQLite database, so Claude (Desktop, Code, claude.ai) can answer
33
+ legal-research questions against the full corpus of published Austrian court decisions and
34
+ consolidated federal law. Free, open, CC0 data.
35
+ </p>
36
+ <div class="mt-10 flex flex-wrap gap-3">
37
+ <a href="#install" class="bg-slate-900 text-white px-5 py-3 rounded-lg font-medium hover:bg-slate-800">Install</a>
38
+ <a href="https://github.com/jonashertner/ris-mcp" class="border border-slate-300 px-5 py-3 rounded-lg font-medium hover:border-slate-400">GitHub</a>
39
+ </div>
40
+ </section>
41
+
42
+ <section class="max-w-5xl mx-auto px-6 py-12 grid md:grid-cols-3 gap-8">
43
+ <div>
44
+ <div class="text-3xl">🏛️</div>
45
+ <h2 class="mt-3 font-semibold">All published case law</h2>
46
+ <p class="mt-2 text-slate-600 text-sm">OGH, VfGH, VwGH, BVwG, 9 Landesverwaltungsgerichte, and special-body decisions — every judikatur source RIS publishes.</p>
47
+ </div>
48
+ <div>
49
+ <div class="text-3xl">📚</div>
50
+ <h2 class="mt-3 font-semibold">Consolidated federal law</h2>
51
+ <p class="mt-2 text-slate-600 text-sm">Every § and Artikel of Austrian Bundesrecht in its current Fassung, searchable alongside the case law that applies it.</p>
52
+ </div>
53
+ <div>
54
+ <div class="text-3xl">⚡</div>
55
+ <h2 class="mt-3 font-semibold">Sub-ms local search</h2>
56
+ <p class="mt-2 text-slate-600 text-sm">SQLite + FTS5 BM25 ranking. Your queries never leave your machine. Works offline.</p>
57
+ </div>
58
+ </section>
59
+
60
+ <section id="install" class="max-w-5xl mx-auto px-6 py-16 border-t border-slate-200">
61
+ <h2 class="text-3xl font-bold">Install</h2>
62
+
63
+ <!-- HF-DATASET-PENDING -->
64
+ <div class="mt-6 bg-amber-50 border border-amber-200 rounded-lg p-4 text-sm">
65
+ <strong>Status:</strong> the pre-built dataset is being uploaded (full backfill takes 2–3 days).
66
+ Until it lands on HuggingFace, step&nbsp;3 below will fail with a friendly message telling you
67
+ to run <code>ris-ingest --full</code> locally. Watch the <a href="#stats" class="underline">stats</a> section for updates.
68
+ </div>
69
+ <!-- /HF-DATASET-PENDING -->
70
+
71
+ <ol class="mt-8 space-y-6 text-slate-800">
72
+ <li>
73
+ <div class="font-medium">1. Install <code>uv</code> (the Python package runner).</div>
74
+ <pre class="mt-2 bg-slate-900 text-slate-100 rounded-lg p-4 text-sm overflow-x-auto"><code>curl -LsSf https://astral.sh/uv/install.sh | sh</code></pre>
75
+ <p class="text-sm text-slate-500 mt-1">See <a class="underline" href="https://docs.astral.sh/uv/">docs.astral.sh/uv</a> for Windows instructions.</p>
76
+ </li>
77
+ <li>
78
+ <div class="font-medium">2. Register the MCP server with Claude.</div>
79
+ <pre class="mt-2 bg-slate-900 text-slate-100 rounded-lg p-4 text-sm overflow-x-auto"><code>claude mcp add ris -- uvx --from git+https://github.com/jonashertner/ris-mcp ris-mcp serve</code></pre>
80
+ <p class="text-sm text-slate-500 mt-1">After <code>ris-mcp</code> is published on PyPI, this simplifies to <code>uvx ris-mcp serve</code>.</p>
81
+ </li>
82
+ <li>
83
+ <div class="font-medium">3. Download the pre-built corpus (one-time, ~12 GB).</div>
84
+ <pre class="mt-2 bg-slate-900 text-slate-100 rounded-lg p-4 text-sm overflow-x-auto"><code>uvx --from git+https://github.com/jonashertner/ris-mcp ris-ingest import-from-hf</code></pre>
85
+ <p class="text-sm text-slate-500 mt-1">Or run your own ingest with <code>ris-ingest --full</code> (2–3 days).</p>
86
+ </li>
87
+ </ol>
88
+
89
+ <h3 class="mt-10 text-xl font-semibold">Claude Desktop config</h3>
90
+ <p class="text-sm text-slate-600 mt-2">If you'd rather hand-edit <code>~/Library/Application Support/Claude/claude_desktop_config.json</code>:</p>
91
+ <pre class="mt-3 bg-slate-900 text-slate-100 rounded-lg p-4 text-sm overflow-x-auto"><code>{
92
+ "mcpServers": {
93
+ "ris": {
94
+ "command": "uvx",
95
+ "args": ["--from", "git+https://github.com/jonashertner/ris-mcp", "ris-mcp", "serve"]
96
+ }
97
+ }
98
+ }</code></pre>
99
+ </section>
100
+
101
+ <section class="max-w-5xl mx-auto px-6 py-16 border-t border-slate-200">
102
+ <h2 class="text-3xl font-bold">Why not <code>philrox/ris-mcp-ts</code>?</h2>
103
+ <p class="mt-4 text-slate-600 max-w-3xl">A legitimate TypeScript MCP wrapper for RIS already exists. It's a great fit for casual queries. <code>ris-mcp</code> is a different trade-off: build and maintain a local mirror so you get better answers.</p>
104
+ <div class="mt-8 overflow-x-auto">
105
+ <table class="w-full text-sm border border-slate-200 rounded-lg overflow-hidden">
106
+ <thead class="bg-slate-100 text-left">
107
+ <tr><th class="p-3">Capability</th><th class="p-3">philrox (live proxy)</th><th class="p-3">ris-mcp (local mirror)</th></tr>
108
+ </thead>
109
+ <tbody class="divide-y divide-slate-200">
110
+ <tr><td class="p-3">Claude can query Austrian law</td><td class="p-3">✅</td><td class="p-3">✅</td></tr>
111
+ <tr><td class="p-3">Search quality</td><td class="p-3">RIS field-based keyword</td><td class="p-3">FTS5 BM25 over full text</td></tr>
112
+ <tr><td class="p-3">Latency</td><td class="p-3">2–5 s per query</td><td class="p-3">&lt; 10 ms</td></tr>
113
+ <tr><td class="p-3">Works offline</td><td class="p-3">❌</td><td class="p-3">✅</td></tr>
114
+ <tr><td class="p-3">Survives RIS API outages</td><td class="p-3">❌</td><td class="p-3">✅</td></tr>
115
+ <tr><td class="p-3">Citation graph (future)</td><td class="p-3">❌</td><td class="p-3">Phase 2</td></tr>
116
+ </tbody>
117
+ </table>
118
+ </div>
119
+ </section>
120
+
121
+ <section id="stats" class="max-w-5xl mx-auto px-6 py-16 border-t border-slate-200">
122
+ <h2 class="text-3xl font-bold">Corpus</h2>
123
+ <div id="stats-loading" class="mt-4 text-slate-500 text-sm">Loading stats…</div>
124
+ <div id="stats-body" class="mt-6 hidden">
125
+ <div class="grid md:grid-cols-3 gap-6">
126
+ <div class="bg-white border border-slate-200 rounded-lg p-5">
127
+ <div class="text-sm text-slate-500">Decisions</div>
128
+ <div id="stats-decisions" class="text-4xl font-bold mt-1">—</div>
129
+ </div>
130
+ <div class="bg-white border border-slate-200 rounded-lg p-5">
131
+ <div class="text-sm text-slate-500">Laws (articles)</div>
132
+ <div id="stats-laws" class="text-4xl font-bold mt-1">—</div>
133
+ </div>
134
+ <div class="bg-white border border-slate-200 rounded-lg p-5">
135
+ <div class="text-sm text-slate-500">Last refreshed</div>
136
+ <div id="stats-refreshed" class="text-lg font-medium mt-1">—</div>
137
+ </div>
138
+ </div>
139
+ <h3 class="mt-10 font-semibold">By court</h3>
140
+ <div id="stats-by-court" class="mt-3 grid md:grid-cols-3 gap-2 text-sm"></div>
141
+ </div>
142
+ </section>
143
+
144
+ <section id="roadmap" class="max-w-5xl mx-auto px-6 py-16 border-t border-slate-200">
145
+ <h2 class="text-3xl font-bold">Roadmap</h2>
146
+ <ul class="mt-6 space-y-3 text-slate-700">
147
+ <li>✅ <strong>Phase 1</strong> — ingester, SQLite/FTS5 store, three MCP tools.</li>
148
+ <li>🚧 <strong>Phase 1.5</strong> — PyPI release, public landing page, pre-built HF dataset.</li>
149
+ <li>🔜 <strong>Phase 2</strong> — resolved citation graph: find_leading_cases, find_citations, find_appeal_chain.</li>
150
+ <li>🔜 <strong>Phase 3</strong> — semantic reranking and a remote hosted MCP endpoint (no local install).</li>
151
+ <li>🔜 <strong>Phase 4</strong> — Materialien: RV-Begründungen and Stenographische Protokolle for teleological interpretation.</li>
152
+ <li>🔜 <strong>Phase 5</strong> — Landesrecht, commentary integration if viable.</li>
153
+ </ul>
154
+ </section>
155
+
156
+ <footer class="border-t border-slate-200 mt-16">
157
+ <div class="max-w-5xl mx-auto px-6 py-10 text-sm text-slate-600">
158
+ <p>
159
+ Code: MIT. Data: CC0-1.0 — Austrian RIS content is amtliches Werk per § 7 öUrhG.
160
+ Not legal advice. Builds on the documentation work of
161
+ <a class="underline" href="https://github.com/ximex/ris-bka">ximex/ris-bka</a>,
162
+ learns from
163
+ <a class="underline" href="https://github.com/philrox/ris-mcp-ts">philrox/ris-mcp-ts</a>,
164
+ <a class="underline" href="https://github.com/PhilippTh/ris-API-wrapper">PhilippTh/ris-API-wrapper</a>, and
165
+ <a class="underline" href="https://opencaselaw.ch">opencaselaw.ch</a>.
166
+ </p>
167
+ </div>
168
+ </footer>
169
+
170
+ <script>
171
+ (async () => {
172
+ const loading = document.getElementById("stats-loading");
173
+ const body = document.getElementById("stats-body");
174
+ const courtsEl = document.getElementById("stats-by-court");
175
+
176
+ const makeRow = (court, count, fmt) => {
177
+ const row = document.createElement("div");
178
+ row.className = "flex justify-between bg-white border border-slate-200 rounded-lg p-3";
179
+ const name = document.createElement("span");
180
+ name.textContent = court;
181
+ const num = document.createElement("span");
182
+ num.className = "font-medium";
183
+ num.textContent = fmt(count);
184
+ row.appendChild(name);
185
+ row.appendChild(num);
186
+ return row;
187
+ };
188
+
189
+ const makeEmpty = (msg) => {
190
+ const d = document.createElement("div");
191
+ d.className = "text-slate-500";
192
+ d.textContent = msg;
193
+ return d;
194
+ };
195
+
196
+ try {
197
+ const r = await fetch("stats.json", { cache: "no-cache" });
198
+ if (!r.ok) throw new Error("no stats");
199
+ const s = await r.json();
200
+ const fmt = (n) => (n || 0).toLocaleString("en-US");
201
+
202
+ document.getElementById("stats-decisions").textContent = fmt(s.total_decisions);
203
+ document.getElementById("stats-laws").textContent = fmt(s.total_laws);
204
+ const refreshed = s.generated_at
205
+ ? s.generated_at.slice(0, 19).replace("T", " ") + " UTC"
206
+ : "—";
207
+ document.getElementById("stats-refreshed").textContent = refreshed;
208
+
209
+ const byCourt = s.decisions_by_court || {};
210
+ const entries = Object.entries(byCourt).sort((a, b) => b[1] - a[1]);
211
+ if (entries.length === 0) {
212
+ courtsEl.appendChild(makeEmpty("No decisions yet — backfill in progress."));
213
+ } else {
214
+ for (const [court, count] of entries) {
215
+ courtsEl.appendChild(makeRow(court, count, fmt));
216
+ }
217
+ }
218
+
219
+ loading.classList.add("hidden");
220
+ body.classList.remove("hidden");
221
+ } catch (e) {
222
+ loading.textContent = "Stats not available yet.";
223
+ }
224
+ })();
225
+ </script>
226
+ </body>
227
+ </html>
@@ -0,0 +1,53 @@
1
+ # Publishing the pre-built ris-mcp dataset to HuggingFace
2
+
3
+ Run after the full backfill (`ris-ingest --full`) completes on any one machine.
4
+
5
+ ## 1. Generate a fresh stats report
6
+
7
+ ```bash
8
+ ris-ingest coverage --out docs/stats.json
9
+ git add docs/stats.json
10
+ git commit -m "Refresh stats.json after backfill"
11
+ ```
12
+
13
+ ## 2. Prepare the DB for upload
14
+
15
+ ```bash
16
+ DB=~/.local/share/ris-mcp/ris.db
17
+ sqlite3 "$DB" "PRAGMA wal_checkpoint(TRUNCATE);"
18
+ shasum -a 256 "$DB" | tee "${DB}.sha256"
19
+ ```
20
+
21
+ ## 3. Upload to HuggingFace
22
+
23
+ ```bash
24
+ huggingface-cli login # one-time
25
+ huggingface-cli upload voilaj/austrian-caselaw "$DB" ris.db
26
+ huggingface-cli upload voilaj/austrian-caselaw "${DB}.sha256" ris.db.sha256
27
+ ```
28
+
29
+ If the repo does not exist, first:
30
+ `huggingface-cli repo create austrian-caselaw --type dataset --organization voilaj`.
31
+
32
+ ## 4. Write a dataset card
33
+
34
+ Manually edit `README.md` on the HF repo (web UI). Include:
35
+ - Source: Austrian RIS Web Service v2.6 (data.bka.gv.at)
36
+ - License: CC0-1.0 (amtliches Werk per § 7 öUrhG)
37
+ - Schema reference: this repo's `src/ris_mcp/schema.sql`
38
+ - How to use: `pip install ris-mcp && ris-ingest import-from-hf`
39
+
40
+ ## 5. Remove "coming soon" banners from the landing page
41
+
42
+ In `docs/index.html`, search for `<!-- HF-DATASET-PENDING -->` and remove each marked block (2 places). Commit:
43
+
44
+ ```bash
45
+ git commit -m "Announce HF dataset availability"
46
+ ```
47
+
48
+ ## 6. Tag a docs-only release
49
+
50
+ ```bash
51
+ git tag -a v0.2.1 -m "Pre-built dataset now available on HuggingFace"
52
+ git push origin v0.2.1
53
+ ```
@@ -0,0 +1,14 @@
1
+ {
2
+ "generated_at": "2026-04-15T22:04:07Z",
3
+ "total_decisions": 3200,
4
+ "total_laws": 0,
5
+ "decisions_by_court": {
6
+ "Justiz": 3200
7
+ },
8
+ "corpus_span": {
9
+ "earliest": "2025-09-29",
10
+ "latest": "2026-03-25"
11
+ },
12
+ "last_aenderungsdatum": "2026-04-15",
13
+ "schema_version": 1
14
+ }