xref-rag — Cross-Reference-Aware RAG for Legal Documents
View on GitHub ↗The EU AI Act end to end — the 144-page PDF is indexed into 2,019 labelled chunks, and “point d article 96” is answered by exact lookup: Article 96(1)(d) on p. 114, checked against the PDF itself. The five provisions Article 96 cites are listed under the passage; Article 50 is opened in place and matches the regulation’s own text, while the machine pane shows Ollama’s Llama 3.2 running 70% on a 4 GB GPU. 2 min 28 s, no narration.
A desktop application for asking questions of long legal texts — regulations, directives, contracts — that treats them as what they are: numbered provisions that point at one another. Ingestion recovers that structure, so a question naming a provision is answered by looking that exact piece up rather than by similarity search, and every cross-reference in the text is drawn into a graph the reader can follow from any passage. Only then does a language model come in: Llama 3.2, run on the user’s own machine by Ollama, writes the answer from the retrieved text alone, citing it by number. The whole thing installs like any other program — no Python, no terminal, and no document ever leaves the machine.
Structure-aware ingestion: PDF, DOCX and TXT are stripped of running headers and footers, then cut at the document’s own markers — chapter, section, article, recital, annex, paragraph, point, sub-point — each accepted only if it follows on from the numbering before it, so a cross-reference that happens to open a line is never mistaken for a heading. Every chunk carries its full address and the page number printed on it.
Queries are routed before they are searched. One that names a provision — “Art. 66(2)(e)”, “recital 148”, even a mistyped “artilce 66” — is answered by exact metadata lookup, with no similarity involved; if the named paragraph does not exist, the app says so and lists the ones that do, instead of letting the model answer from a neighbouring passage.
Everything else goes to hybrid retrieval: MiniLM embeddings in ChromaDB and BM25 keyword scores, merged by Reciprocal Rank Fusion. How many passages come back is decided by the scores rather than a fixed top-k — every passage close to the best, never fewer than three or more than eight — then trimmed to what fits the model’s 4,096-token context.
Cross-references — “Article 5(2)”, “Annex III”, “Article 11 of Regulation (EU) 2019/2144” — are extracted at ingestion into an SQLite edge table and classed as internal, external or missing. Under each retrieved passage they form a tree whose rows open in place into the cited text and its own references, so a chain of citations reads top to bottom.
Ollama’s job is the last step only: it serves Llama 3.2 locally, and the backend calls it at most once per question, after retrieval has finished — parsing, lookup, ranking and the reference graph never touch the model. The question and the numbered passages go in, ordered so the strongest sit at the start and end of the prompt, where a small model attends best; a direct answer and where in the document it comes from come back as JSON, citing passages by number, at temperature 0 so the same question gets the same answer.
It ships as an installer, not a repository: PyInstaller freezes the backend into one executable that the Tauri app launches and that exits when the app does, and embeddings run on ONNX Runtime rather than PyTorch to keep it small. First launch finds a running Ollama or sets one up with the model in a folder the user picks, checking the download against Ollama’s published SHA-256, and GitHub Actions builds the Windows and Linux installers for every tagged release.
One exact lookup, start to finish — “point d article 96” brings back Article 96(1)(d) from p. 114 and nothing else, with the five provisions Article 96 cites listed under it, each tagged with the point it is cited from. The answer beside it cites that one source, and the side pane shows what it cost: 294 of the 4,096-token context, with the Llama 3.2 that Ollama serves sitting 70% on the GPU and 30% in system RAM.
A miniature SQL database built from scratch — no parser generator and no database backend. A hand-written tokenizer and parser turn typed SQL into command objects that execute against tables persisted as JSON, and each comparison operator is its own strategy class, so supporting a new one means adding a class rather than another branch.
SELECT * FROM students
NAME | ID | LASTNAME
-------+----+---------
ashley | 23 | borro
max | 66 | bright
Pency | 12 | Brown
(3 rows)
SELECT * FROM students WHERE ID BETWEEN 10 AND 30
NAME | ID | LASTNAME
-------+----+---------
ashley | 23 | borro
Pency | 12 | Brown
(2 rows)
SELECT * FROM students WHERE NAME IN ('max', 'Pency')
NAME | ID | LASTNAME
------+----+---------
max | 66 | bright
Pency | 12 | Brown
(2 rows)
A live session against the sample table: a full scan, then the BETWEEN and IN operators narrowing it. Results are formatted as an aligned table with a row count, the way a real client would print them.The whole engine in one frame — a table is just a JSON file of a name, a schema and its rows (top), and the REPL reads, filters and prints it back (bottom).
Universal University App — Role-Based University Management System
Java 17 · Spring Boot 4 · Spring Security · JWT · JPA/Hibernate · PostgreSQL 16 · Docker Compose · Angular 21 · TypeScript · Angular Material
A three-tier university management system that forks at the front door: you pick a portal before you even sign in, and what you can reach afterwards is decided by the role you hold. Teachers create subjects, add and enrol students, assign grades and keep a roster of everyone they teach; students see only the courses they are enrolled in and the marks they have been given. Authentication is stateless — a signed JWT on every request instead of a server-side session — and the same rules are enforced on both sides of the wire.
Two roles, ROLE_STUDENT and ROLE_TEACHER, held as a many-to-many join against the user — the whole permission model falls out of which one you hold.
Authorisation is enforced twice over: Angular route guards keep the wrong screens out of view, and Spring Security @PreAuthorize checks guard the endpoints themselves, so a hand-written request cannot walk around the missing button.
Stateless JWT auth — passwords BCrypt-hashed, tokens signed and verified by a servlet filter ahead of the security chain, and no session kept on the server.
A JPA/Hibernate model over PostgreSQL, with a unique constraint on the enrolment pair so the same student cannot land in one subject twice.
Postgres and pgAdmin both come up from one docker-compose file, so the database side of the stack is a single command.
The fork the whole system turns on — the role is chosen before any credentials are entered, and it decides which half of the app exists for you.A teacher creating a course. The nav bar above it — Assign Grade, My Students, Add Student, Enrol Student — is the half of the app a student signing in never sees.The teacher’s roster, joining users, enrolments and grades into one view — searchable by name, username or ID, with each student’s marks shown against the subject they were given for.
Incoming third-year Computer Science student with hands-on backend development experience in raw Java, Spring Boot, and Python, building secure, layered, and scalable systems. Fluent English communicator (C1) with a structured, detail-oriented approach to software engineering — adaptable and quick to learn new technologies, frameworks, and concepts.
Education
Łódź University of Technology — Computer Science
2024 – present · International Faculty of Engineering, Łódź, Poland · GPA 4.01 · expected graduation May 2028
Medium of instruction: English. Relevant courses: Algorithms & Data Structures, Java Fundamentals, Databases, Software Engineering, Computer Architecture, Interactive Web Applications (Spring Boot).
Technical Skills
Languages: Java, Python, C
Frameworks & Libraries: Spring Boot, FastAPI, LangChain
Desktop application that answers questions about large, densely cross-referenced documents (EU AI Act, Canadian research-ethics policy, US federal regulations) with exact, source-cited answers, running fully offline.
SQL Database Engine in Java
Java · Gradle · Jackson
Relational database engine built from scratch: hand-written SQL parser, Strategy-pattern comparison operators, JSON-based persistence, and an interactive CLI.
Languages
Ukrainian — native · English — C1 · Polish — A2
Certificates
2024 — Duolingo English Test: 135, C1 (CEFR)
2024 — National Multi-Subject Test (English): 200/200