05 / Personal project · 2026
Two weeks, one new stack, 243 tests
A Python desktop app with 243 tests and 4-platform CI, built in two weeks in a stack I had never shipped.
- Role
- Solo Developer
- Timeline
- ~2 weeks
- Type
- Cross-platform desktop activity tracker
- Stack
- Python 3.12 · FastAPI · SQLAlchemy 2.0 · PySide6 · PostgreSQL · Vue 3 · Tailwind CSS 4
At a glance
- Cross-platform desktop activity tracker: foreground app usage, screenshots, idle time. Local-first, no cloud required.
- Built in ~2 weeks in a stack I had never shipped: Python 3.12, FastAPI, SQLAlchemy 2.0, PySide6.
- 243+ tests, strict mypy, ruff, vue-tsc. More automated verification than most client budgets ever allow.
- AI-assisted on purpose, engineering-led on principle. The architecture, reviews, and every accepted line were mine.
01 / Why
A tool I wanted, and a claim I wanted to prove
I wanted an activity tracker that kept its data on my machine: what apps I use, when I'm idle, screenshots I can search. Without shipping my work life to someone's cloud. None of the existing tools fit, which is the oldest reason in software to build one.
The second reason was professional. My resume says I learn fast; a resume would say that. screen.io is the demonstration: pick a stack I had never shipped. Python desktop apps are about as far from Laravel SaaS as it gets. And produce something with production discipline in two weeks. In public, with the test suite as the receipt.
02 / Architecture
Layered like it plans to live
Speed came from constraints, not shortcuts. The backend is layered: services hold logic, repositories own persistence, models stay dumb. OS-specific behavior (active-window tracking, screenshots) lives behind Protocol interfaces. macOS gets a PyObjC adapter; Windows and Linux get stubs that satisfy the same contract. A small hand-rolled DI container wires it: no framework, no magic, everything traceable.
The concurrency design is the part I'd defend in a systems interview: capture workers (screenshots, activity, idle detection, cleanup) never touch the database. They publish to a thread-safe event bus, and a single writer thread owns all persistence. No lock contention, no interleaved write bugs, and the Qt main thread stays free to keep the UI at 60fps. A FastAPI daemon on localhost serves 13 routers and a WebSocket feed to the Vue dashboard.
03 / Discipline
Fast is only fast if it's still standing in week three
The test suite runs 243+ cases: repositories tested against a real temporary database (because mocked SQL tests prove nothing about SQL), services tested with fakes injected through those Protocol seams, and the Vue frontend under vitest. Strict mypy across the codebase caught a class of bug the tests never even saw: None-leaks across layer boundaries, mostly.
None of this rigor was required for a personal tool. That's the point. Client work rarely budgets for the testing culture I want to bring to it; screen.io is where I practice that culture at full strength, so it's a habit rather than an aspiration.
04 / The AI part
AI-assisted, with the emphasis on assisted
I built screen.io with an AI pair (opencode with a free model), and I'll say so plainly rather than let the two-week number imply something it shouldn't. The AI accelerated the parts that deserve acceleration: unfamiliar API surfaces, boilerplate, the hundredth similar test case.
What it could not do is the actual work. Choosing the layering. Insisting on a single-writer thread. Deciding what a Protocol boundary owes its callers. Rejecting generated code that compiled but lied. Review standards stayed high, and that is why two weeks was possible. Senior engineering with these tools means the speed changes but the responsibility stays the same.
05 / Platform work
Shipping to four platforms from one repo
GitHub Actions builds a matrix with macOS ARM64, Intel, Linux, and Windows targets. PyInstaller produces both onedir and onefile bundles; a version tag becomes a GitHub Release with artifacts for each platform. macOS needed entitlements and permission flows for Screen Recording and Accessibility, the kind of platform paperwork that turns "runs on my machine" into "installable by a stranger."
- tests, pytest + vitest
- CI build platforms
- API routers + WebSocket
- weeks from empty repo
06 / Next
Designed but not yet built
Cloud sync exists as a design (an outbox pattern queuing local changes for eventual upload), deliberately unimplemented until the local-first core earned it. Windows and Linux adapters are the other obvious frontier; the Protocol seams mean implementing them touches no service code.
07 / Lessons
What two weeks in a foreign stack taught me
- Learning speed is mostly architecture. With clean seams, ignorance stays local. You can be new to PyObjC without being new to software.
- A single-writer thread is the cheapest concurrency correctness you can buy. Boring beats clever, again.
- Strict typing pays fastest in unfamiliar territory. Mypy was my senior reviewer in a stack where I had none.
- AI assistance raises the ceiling on speed and lowers the floor on quality. Which one you get is a review-discipline question.