This is a submission for the Hacktoberfest Weekend Challenge: Build for a Friend.
What I built
MatchMind is a local AI analyst for Brazilian football, built for Bruna Boaventura, my girlfriend.
Bruna had a hard time finding Brazilian clubs' results and historical data. So I built her one place to look things up — and a way to just ask.
MatchMind puts the numbers together and lets her ask questions in Portuguese to an AI that runs on her own computer. You pick a club and get:
- the Brasileirão 2026 table, computed from the season's results, with all 20 crests;
- recent form and the last three matches with possession, shots, corners, fouls, goal scorers, cards, stadium and referee;
- a "Ver escalações" button that loads both line-ups: formation, coach, minutes and player ratings;
- the squad with appearances, goals, assists and ratings;
- 20+ years of Série A history (2003–2024): titles, season-by-season position and coach, the club's top scorers, discipline, and head-to-head records with the scorers of the last meetings;
- a chat with Gemma 3 4B running locally through Ollama, which answers only from that data and separates FATO (fact) from INTERPRETAÇÃO (interpretation).
The rule behind everything: the numbers come from data or from deterministic code, never from the model. If something is missing, MatchMind says "Indisponível" instead of guessing.
Demo
A real answer generated locally by Gemma 3 4B (CPU only):
Line-ups for a match, loaded on demand:
Série A history:
What Bruna said
"Interessante, pois traz dados históricos de 2003 até hoje, contendo gols e estatísticas."
("Interesting, because it brings historical data from 2003 until today, with goals and statistics.")
That was exactly the gap she had: the history is what made it useful for her. (To be precise about coverage: the historical dataset runs from 2003 to 2024, and the current 2026 season comes from a separate live source.)
Code
Darrkkens
/
matchmind
Local AI analyst for Brazilian football: Brasileirão table, match stats, lineups and 20 years of Série A history, with Gemma running locally via Ollama. Go + Vue.
MatchMind
Your local AI analyst for Brazilian football. · Seu analista de futebol brasileiro com IA local.
MatchMind is a Brasileirão dashboard with a Vue 3 interface (in Brazilian Portuguese), a Go REST API and an open-weight model (Gemma) running locally through Ollama. Pick a club and see the league table, recent form, the last matches with statistics, scorers, cards and lineups, 20+ seasons of Série A history, and ask an AI analyst questions that are answered only from that data.
- No account, no cloud AI, no API key required. Optional keys only add more statistics.
-
Facts first. Every number comes from a cited source or a deterministic Go calculation; the AI separates
FATOfromINTERPRETAÇÃOand must say when data is missing. - Honest about coverage. Missing data stays missing; the UI shows sources, retrieval times and notices.
Contents
-
Backend: Go (standard library +
pgxfor an optional PostgreSQL cache). - Frontend: Vue 3 + TypeScript, interface in Brazilian Portuguese.
-
AI: Gemma 3 4B through Ollama's
/api/chatwith structured JSON output. - MIT license, CI with
go vet,go test -raceand the frontend build, plus contributing guide and issue templates.
Quick start: ollama pull gemma3:4b, then go run ./cmd/server in backend/ and npm run dev in frontend/. No account and no API key are needed.
How I built it
OpenFootball (results, CC0) ──┐
Série A history CSVs (GPL-2.0) ┼─► Go API ─► deterministic stats, table, form
Optional stats API + cache ───┘ │
▼
compact JSON context for this question
▼
Gemma 3 4B via Ollama (local)
▼
Go validates the JSON and adds FATO / INTERPRETAÇÃO
Data I can trust. Results come from OpenFootball (CC0). The 2003–2024 history comes from Adão Duque's Brasileirão dataset, downloaded at runtime. I computed every season's final table from the results, and the champions match the official list for all 22 seasons; the scorers file matches the final score in 100% of matches since 2015. Where the source has gaps (its 2016 and 2024 statistics are mostly zeros), MatchMind drops those averages instead of showing fake numbers.
Linking sources without guessing. Per-match statistics, scorers and line-ups come from an optional API. A match only receives that data when round, opponent, home/away side and final score all agree with OpenFootball. Line-ups abbreviate names ("G. Gómez") while player stats use full names ("Gustavo Gómez"), so I wrote a matcher that understands initials. It links 95% of starters; the rest (nickname vs. legal name) are shown without numbers rather than guessed. Every API response is cached — in PostgreSQL if you run docker compose up — so a finished match costs one request, ever.
Grounding the model. The browser never sends context. For each question, Go rebuilds the club snapshot and sends Gemma a JSON envelope that keeps the data separate from the question and is explicitly treated as untrusted. Gemma returns facts, interpretation and sources_used; Go validates the structure and the allowed source names and adds the labels itself.
What real testing taught me. Mocked tests passed, but running the real model exposed two problems:
- Too slow. As I added history, line-ups and cards, a question on a CPU-only machine went past my 240-second timeout. The fix was to make the context depend on the question: the full table, the season history, the head-to-head records, the squad or the cards are only sent when the question is about them. The context for "where are we in the table and how many titles?" dropped from about 11,400 to 5,400 characters, and the answer came back in about three minutes.
-
Technically true, actually wrong. Gemma answered that Palmeiras "has 4 Brazilian titles". That's the count in the dataset, which only covers 2003–2024; Palmeiras has more. The prompt already said so, but a 4B model doesn't always follow a sentence buried in a prompt. So I renamed the field the model sees to
serie_a_titles_2003_2024_only. The next answer said "4 Série A titles between 2003 and 2024" — the answer you see in the screenshot above. When a rule really matters (like flagging sample data from an API test key), Go appends the warning itself instead of trusting the model.
Why does open matter?
-
It runs on her machine and costs nothing. After
ollama pull gemma3:4b, there's no per-question fee, no AI account and no key to protect. The football data sources used by default are open too. - Her questions stay local. With the default settings, the questions and the club data are processed on the same computer. Nothing goes to a model provider.
-
I control the whole stack. When the model was too slow, I didn't wait for a vendor: I changed what the model sees. When it phrased something misleadingly, I changed the data contract. I can swap in
gemma3:12bon a stronger machine with one environment variable. - The trade-off is honest. A 4B model on a CPU is slow (1.5–3 minutes per answer) and can still omit something that is in its context. That's why the numbers on screen come from code, not from the model, and why every answer says which data it used. A big hosted model would answer faster, but it would cost money per question, need an account, and send everything off the machine — for a personal football tool, those trade-offs aren't worth it.
AI assistance
I built MatchMind with the help of an AI coding assistant (Claude Code), which I directed, reviewed and tested throughout. All data, screenshots and the model answer shown above come from running the real application.
Prize categories
- Best Use of Gemma — Gemma 3 4B runs locally through Ollama as the analyst at the core of MatchMind. The project shapes its context per question, constrains it with structured JSON output, validates every answer in Go, and documents where the model still fails.





Top comments (0)