Mateusz Śliwa
Data and AI engineer who ships mobile apps.
Zielona Góra, Poland. Open to remote or hybrid roles and to relocation. Available now.
MSc in Data Engineering, University of Zielona Góra, 2026. English C1, Cambridge C1 Advanced (2025).
I build with coding agents: Claude Code, Codex and Cursor.
This is my phone. Every app on it opens a working demo of the project. Drag the bar at the bottom up to flip through them as cards.
Download CVGitHubsliwa.mateo@gmail.com
On the App Store: EcoSort and TrueSky. EcoSort's website is ecosort.pl.
Projects
Each card opens the full story: what the project does, what was hard and what I built.
A photo of a printed bin calendar, read one month at a time
EcoSort shows which bins go out on your street and when. It reminds you the evening before, and the widget and the lock screen show what is next.
The hard part is the data
Every municipality publishes its schedule differently. Many publish a scan or a phone photo of a printed calendar: twelve months on one page, colour-coded days and a legend in the corner.
The obvious approach is to give a model the whole page and ask for the dates. On six hard scans the best version of that prompt got 24.5% of the cells wrong. A page holds hundreds of similar numbers, and where the model can't see each day clearly it fills in a regular pattern. In Wiśniew bio waste goes out once a month. The whole-page prompt returned it every week.
How the pipeline reads it
- Cut the page into monthsThe model marks the month frames, code moves the borders into the empty space between them, and a crop is rejected if its last visible day is wrong.
- Read each piece twiceTwo prompts read every month, with the legend attached. Tables get a second image with the columns spread apart.
- Break ties by majorityWhen the two reads disagree, a third read decides.
- Let code check what is certainSundays, public holidays, gaps in the rhythm, row counts, and that every address in the national register falls into exactly one zone.
- Hold back instead of guessingDoubt that the reads can't settle holds the zone back. A missing schedule is safer than a wrong date.
Results
Six scans and photos with 2,190 cells. The pipeline read each of them in three full runs, 6,570 cell results in all. A cell is one place, one waste type and one month, and it only counts as right if every day matches the document.
Green is right, red is wrong, grey is held back. The ground truth is 966 decisions I made by hand in the admin panel. The pipeline was tuned on these documents, so zero wrong dates is its best case, on documents it already knows. Documents it has not seen are the next test.
| Document | Cells | Prompt wrong | Pipeline wrong | Held back |
|---|---|---|---|---|
| Gierałtów, photo | 120 | 57.2% | 0 | 0% |
| Czerna, photo | 112 | 86.9% | 0 | 0% |
| Wykroty, photo | 120 | 76.7% | 0 | 0% |
| Wiśniew, scan | 147 | 77.8% | 0 | 33.3% |
| Szprotawa, sideways scan | 264 | 1.0% | 0 | 74.2% |
| Klimontów, three-page scan of tables | 1,427 | 11.3% | 0 | 10.1% |
| All six | 2,190 | 24.5% | 0 | 17.8% |
It is not better everywhere: in Szprotawa the prompt was nearly right and the pipeline held three quarters back. It also costs more: one call and about 25 seconds per document for the prompt, against a median of 33 calls and 4.5 minutes.
What I built
- The iPhone app in SwiftUI, with widgets, a Live Activity, reminders you can snooze or mark as done, and a schedule that works offline.
- An Android app in Kotlin and Jetpack Compose. It is built and not yet on Google Play.
- The backend in FastAPI and PostgreSQL: address search against the national TERYT register, schedules served as static JSON.
- The reading pipeline in Python with OpenCV, Tesseract, PyMuPDF and Gemini, and an admin panel in React and TypeScript.
- Sortuś, an assistant that answers questions using the resident's own schedule.
Six municipalities are published in the app. EcoSort on the App Store. The website is ecosort.pl.






Each project also has its own page: mateuszsliwa.dev/ecosort.
A brain game where the server keeps the score
Keenwit is a daily brain workout: 43 short games for memory, maths, language and focus, with streaks, duels and leaderboards. Difficulty adapts to each player. The name is a working one.
Why the server keeps the score
You can play offline, so the phone can't be the judge. A finished game waits in an outbox on the phone, and nothing moves XP, a streak or a ranking until the server has checked it.
- One-time seedSeeded games get a seed from the server. A replayed, expired or mismatched seed is rejected.
- Time windowThe result may be at most 5 minutes in the future and 30 days old, so games played offline still count.
- Rate limitPer client.
- Score normalised on the serverVery high scores need extra proof.
- A verdictAccepted, held for checking, or rejected. Only accepted results earn XP.
Prime Check: the server holds the answers
For this game the server goes one step further. It generates the questions, keeps the answers and sends the phone only the numbers. The phone plays them offline and sends back what you tapped. The server recomputes the score from its own copy and ignores the score the phone claims. This is the only game with that check so far.
The demo: two games
The phone has two of the 43 games. In Equinox you fill a grid with planets and comets: never three alike in a line, half of each, and the = and × links must hold. Star Sectors is the Queens kind of puzzle: one star in every row, column and colour sector, and stars never touch. Both use the app's own rules, boards and scoring. Each tutorial starts with the app's steps, then moves to a bigger board for the techniques that solve it: a sector stuck in one row, a gap between two alike, a full count.
How it is built
React Native with Expo, TypeScript and Skia, on a Fastify and PostgreSQL backend with JWT auth and an OpenAPI spec.




Each project also has its own page: mateuszsliwa.dev/keenwit.
Weather you read from a painting
TrueSky draws the weather as a painted landscape. The hourly forecast from Open-Meteo sets the light, the clouds, the wind and the rain, and the scene plays the matching sound.
How the scene works
Each landscape is a stack of painted layers: mountains, water, the shore, a cabin, a birch and a boat. Skia shaders light them for the hour, from first light to a quiet night with lit windows, drift the clouds with the wind and add rain, snow, fog or a storm. I kept it at 120 Hz by cutting the work done on every frame.
The business side
The app is free. TrueSky Pro adds landscapes and details for 21.99 zł a month ($7.99) or 55 zł once ($19.99), sold through RevenueCat. It is translated into 32 languages and sends weather alerts in the background. It has been on the App Store since 9 October 2026.
Expo, React Native, Skia, Reanimated, RevenueCat, Playwright for the web build.




Each project also has its own page: mateuszsliwa.dev/truesky.
What would X do? Answers in that person's own words
wwxd answers "what would X do?" from one person's own words. It ingests their public captions, podcast transcripts and articles, turns them into a wiki of their positions, and an agent answers with timestamped quotes from those sources.
Every quote is checked
A model can misquote someone, so a script looks up every quote in the transcript it came from. In the benchmark it found 158 of 160 cited quotes word for word. The two it missed were video titles.
Does it beat plain Claude?
On 40 questions over two wikis, a blind judge compared each wwxd answer with an answer from plain Claude. The judge came from another lab, Google, and had no access to the transcripts. It preferred wwxd on 34 of 40. Judges from three more labs, Anthropic among them, scored the same pairs and preferred wwxd at least as often. Claude with web search did no better: the judge from Google again preferred wwxd on 34 of 40.
On 24 opinion questions, a prompt that told the model to answer as the person contradicted that person 8 times. The wwxd answers contradicted them 0 times.
Ask a panel
Panel mode asks several people at once. Each answers from their own wiki. wwxd then maps where they agree, where they split and why, runs a debate round labelled as inferred, and ends with a synthesis. Answers read as prose, with the sources listed underneath.
What it can't do
It does not predict opinions a person hasn't voiced yet. I held back positions people took in 2026, and wwxd guessed them no better than plain Claude. It knows what someone has said, not what they will say next.
How it's built
A Python command-line tool and a Claude Code plugin, built in October 2026 under the MIT licence. The design follows Andrej Karpathy's "LLM wiki" idea. It can transcribe audio locally with faster-whisper and check by voice who is speaking. On 12 October 2026 it had 135 tests, which run in CI on Linux, macOS and Windows.
Python, Typer, yt-dlp, trafilatura, rapidfuzz, faster-whisper, Claude Code.
Each project also has its own page: mateuszsliwa.dev/wwxd.
Posters for small businesses, made without image generation
unslop (working name) makes posters and social media graphics for small businesses without image generation. Every letter is set in a real font, and every photo is real: the owner's own or licensed stock. It is in development, and the code is private.
Before and after
Each "before" below is a flyer a small business posted, made with an image generator. The generator draws letters as pixels, and one headline came out as "AMAZINIG". Each "after" is the same message made with the tool, where the text is typed copy set in a font.





The "before" posters are real AI-generated flyers posted by small businesses; they belong to their owners and I'll remove any on request.
How it works
- The agent writes a specA small JSON file with the layout, the brand colours, the copy and a real photo, the client's own or licensed stock.
- A renderer draws itHTML and CSS in Chromium through Playwright. The same spec always gives the same image.
- A linter checks the pixelsIt measures the rendered image: text that doesn't fit, overlaps, contrast against the real background, text hidden behind the subject, a price that doesn't show, the parts of a Story that Instagram's buttons cover, upscaled photos and missing glyphs.
- The agent fixes what it reportsIt changes the spec, and the renderer draws it again.
What it makes
In October 2026 it has 20 layouts and 15 visual directions. It exports Instagram posts in 4:5 and 1:1, Stories in 9:16, and A4, A3 and B2 print PDFs with bleed and embedded fonts. Stock photo search covers Unsplash, Pexels, Pixabay and Openverse and keeps the credits. Background removal runs locally, on the CPU.
An editor for the owner
The shop owner clicks any text to change it. Four big buttons change the layout, the colours, the photo and the copy, and one click downloads every format. An optional assistant runs on the Anthropic API with streaming and a cached system prompt, and every answer shows what it cost.
I build with coding agents, and I know how to set them up
Most of these projects were built with coding agents. I use Claude Code, Codex and Cursor side by side, follow new models and features as they come out, and try them on my own projects before I rely on them. Most of my commits since September 2026 name Claude as co-author.
Context the agent reads first
- A global policy for every agent: find the existing pattern before adding code, keep one source of truth, fix root causes, report only checks that actually ran. The card above quotes it.
- Repository instructions in AGENTS.md and CLAUDE.md with each project's commands and pitfalls, in Keenwit and the EcoSort pipeline.
- Skills for repeatable jobs, in one folder that Claude Code and Codex share. Two are mine: mac-ios for building and testing iOS apps from Linux, and store-screenshots for storeshots.
- Subagents for work that splits well: parallel searches, implementation, an independent review and a final check.
Cost, caching and limits
Stable instructions go first and stay unchanged, so prompt caching can reuse them, and the parts that change go last. I watch token use and rate limits. Sortuś, the EcoSort assistant, runs on a pool of API keys with daily quotas, per-user limits and a Gemma fallback.
Tools I build for agents
- storeshots prints JSON for every command, and its errors say what broke, how to fix it and which command to run next. Both tools ship with an agent skill.
- macsim gives an agent on my Linux PC a real iOS Simulator on a Mac: it builds the app, taps through it and takes screenshots. Open source, like storeshots.
Checking what comes back
An answer from a model is a draft until something checks it. In EcoSort that means two reads, a third when they disagree, code checks and an evaluation against 966 decisions I made by hand. In Keenwit the server checks every result before it counts. Code from an agent gets the same treatment: tests and review before it ships.
Models inside my apps
- EcoSort's reading pipeline uses a small Gemini model on one month or one table section at a time. The accuracy comes from the pipeline around it.
- Sortuś answers from the resident's own schedule on Gemini, with personal data scrubbed from the conversation.
Claude Code, Codex, Cursor, MCP, skills, subagents, Gemini, Gemma.
Who wins this round? My MSc thesis, and a skin lesion classifier
MSc in Data Engineering, specialising in data mining systems (2025–2026), after a BA in Economics (2021–2024), both at the University of Zielona Góra.
Thesis: win probability in Counter-Strike 2
A model that gives the probability of winning a round, second by second. I downloaded professional match recordings with Selenium, parsed them with demoparser2 and built the features in pandas: 9,196 maps, 187,361 rounds and 16.8 million game states.
I compared nine models, validated by match groups and walk-forward by quarter, with bootstrap tests, ablations, calibration and SHAP. Gradient boosting came out best: LightGBM log loss 0.527, ROC-AUC about 0.81–0.82 in the quarterly walk-forward tests, and an expected calibration error (ECE) of 0.0086 for the production XGBoost model. Predictions are served by FastAPI to a React app.
| Model | Log loss | ROC-AUC | Brier |
|---|---|---|---|
| LightGBM | 0.5267 | 0.8036 | 0.1790 |
| CatBoost | 0.5272 | 0.8059 | 0.1786 |
| XGBoost (production) | 0.5289 | 0.8017 | 0.1800 |
| Random forest | 0.5295 | 0.8035 | 0.1797 |
| MLP | 0.5323 | 0.8016 | 0.1807 |
| Extra trees | 0.5332 | 0.8043 | 0.1805 |
| Logistic regression | 0.5518 | 0.7918 | 0.1858 |
| Linear regression baseline | 0.5919 | 0.7889 | 0.1891 |
| Ridge classifier | 0.6044 | 0.7889 | 0.2074 |
| Test quarter | Training maps | Logistic AUC | XGBoost AUC |
|---|---|---|---|
| 2024 Q1 | 844 | 0.7302 | 0.6498 |
| 2024 Q2 | 1,448 | 0.7973 | 0.8049 |
| 2024 Q3 | 3,519 | 0.8005 | 0.8140 |
| 2024 Q4 | 5,315 | 0.8032 | 0.8183 |
| 2025 Q1 | 5,999 | 0.8051 | 0.8217 |
| 2025 Q2 | 6,457 | 0.8038 | 0.8190 |
| 2025 Q3 | 7,172 | 0.7980 | 0.8119 |
| 2025 Q4 | 7,828 | 0.8016 | 0.8142 |
| 2026 Q1 | 8,770 | 0.7956 | 0.8094 |

Skin lesion classifier
A machine learning course project on the HAM10000 images: malignant or benign. A custom CNN against a fine-tuned EfficientNet-B0 in PyTorch, with Optuna, focal loss, a weighted sampler, MixUp and test-time augmentation, plus Grad-CAM to show where the model looks. On 1,002 test images EfficientNet reached an AUC of about 0.93 and a malignant recall of 0.95; the custom CNN reached an AUC of 0.755. Tracked in MLflow, served in Streamlit.
Each project also has its own page: mateuszsliwa.dev/thesis, mateuszsliwa.dev/skin.
storeshots and macsim, both open source
Two tools that came out of shipping apps alone, from a Linux PC, with coding agents doing a lot of the typing.
storeshots
An open-source command-line tool that makes App Store screenshots from the running app. It captures the app in the iOS Simulator, lays the screens out as slides in HTML and CSS, renders them at the exact sizes Apple asks for, checks them on the rendered pixels (sizes, alpha, text size, cut-offs, contrast) and uploads them through the App Store Connect API. Every command prints JSON, so an agent can drive it. The EcoSort screenshots above and on the App Store were made with it.
storeshots on GitHubOpen the demo
macsim
I write code on a Linux PC, and iOS builds need a Mac. macsim turns a Mac on the network into a remote build server and iPhone Simulator. One command syncs the project over SSH, builds it with xcodebuild or Expo, installs it and launches it, while Metro keeps running on the PC with hot reload. An agent on the PC can tap, type and take screenshots in the Simulator, and I can watch it live in a browser. It ships with an agent skill for Claude Code and Codex, and I used it for the TrueSky and Keenwit builds.
Each project also has its own page: mateuszsliwa.dev/storeshots, mateuszsliwa.dev/macsim.
Write to me
sliwa.mateo@gmail.com. CV in English or Polish.

