Christian Toledo. Full-stack engineer who ships and operates his own systems.
Close to seven years building production web and mobile apps, at product companies and as a consultant. React, React Native, Vue, Angular and .NET, for clients including PostNord, Nordic Wellness and Inera's 1177, the national healthcare platform millions of Swedes use. On my own time I build the same way: a ride-tracking app now in closed beta, running on two manufacturers' Bluetooth protocols I reverse-engineered myself, and a home lab of five systems I run and document like production.
Most recently a fullstack developer at Dear Friends and Nexer AB. Originally from Cuba, based in Gothenburg since 2011, and currently looking for my next team.
Not demos. One is an Android app and backend in closed beta with real users; the other is the platform it runs on. Both have real failure modes, and a written history of the decisions behind them: the protocol reverse-engineering, the physics regressions, and the infrastructure calls that went into each.
// mobile + backend
Cityroam
A ride computer for electric boards and scooters: an Android app and a self-hosted backend that talk to the hardware directly over Bluetooth. Two different manufacturers' proprietary protocols, both reverse-engineered and reimplemented from scratch. No vendor SDK, and no cloud account needed to ride.
In closed beta. The source is private, so the deep dives are the readable version: protocol notes, the physics model, and the decisions behind both.
Two vendor protocols, neither of them documented: the Tynee board's Tuya SDK was reverse-engineered and deleted outright, replaced by a from-scratch Kotlin GATT client verified byte-for-byte against a Python reference. The NAVEE scooter had no SDK to remove in the first place, so its encrypted challenge-response handshake had to be worked out from a real capture of the official app.
Physics fitted to your own rides: the backend fits per-mode rolling resistance, drag, and drivetrain efficiency by regression over real trip history, rather than trusting a manufacturer number or guessing linearly from battery percentage.
Offline first, by construction: every finished trip is written to the phone's own SQLite queue before any network call, so a ride exists the instant it ends whether or not the backend is reachable. Recording survives the app being backgrounded or killed outright.
Clean GPS from noisy hardware: raw phone GPS is road-snapped through a self-hosted OSRM instance and enriched with weather sampled across the whole route, so a ride that genuinely crosses from sun into rain shows that.
The Proxmox host and deploy pipeline that five separate systems run on. Not a pile of Docker containers, but a platform with infrastructure as code, encrypted secrets in git, drift detection against live state, and a written record of every real decision behind it.
Source is private, since it holds the encrypted secrets and the network layout for a house I live in. The deep dive covers the architecture and the decisions.
Push to main is the deploy: a self-hosted GitHub Actions runner applies the repo to the host and every container. Ansible for most stacks, GitOps for the ones where a webhook-speed redeploy earns its extra complexity. Chosen per stack, not dogmatically.
82 written decision records: every non-trivial call has a documented reason, including the ones that turned out wrong and had to be reverted. That habit is the actual point of the project.
Actually monitored: a daily drift check runs the playbook against live state and alerts if anything was hand-edited outside the pipeline, plus automated backups and real failure alerting, not just “the container is still running.”
It hosts the other project: Cityroam's backend runs on this platform, deployed by the same pipeline. The two projects on this page aren't independent. One runs on the other.
casa-verde isn't one project. It's a Proxmox host and a deploy pipeline that five separate systems run on, each with its own stack, its own failure modes, and its own entries in the decision log.
// media pipeline
Media automation & streaming
A sixteen-container pipeline that finds, sorts, subtitles, and serves media, plus a photo library doing face recognition on the same integrated GPU that handles video transcoding.
Sonarr, Radarr, Lidarr, Prowlarr and Bazarr for acquisition and subtitles; Jellyfin and Navidrome for playback; Immich as a self-hosted Google Photos replacement
Jellyfin runs on the host rather than in a container specifically to get direct iGPU passthrough for hardware transcoding
A recurring Bazarr out-of-memory crash was root-caused rather than papered over with a restart policy
Home Assistant running the house, with a voice assistant whose speech recognition, speech synthesis, and language model all run on my own hardware, plus a deliberate split to a cloud model for everything that isn't about the house.
Whisper for speech-to-text, Piper for text-to-speech, and Ollama for the language model, all self-hosted and all originally proven viable on CPU alone before any GPU was bought
A hard privacy boundary: anything touching the home stays local by design; open-ended questions go to a separate cloud pipeline on a different wake word
Lights, blinds and motion sensors migrated onto Matter, while the dimmer switches stayed where they were, because moving them would have made things worse
Home AssistantOllamaWhisperPiperGroqMatterDocker Compose
A Project Zomboid dedicated server for me and my friends, running about fifty mods with fully automated mod and update management.
The interesting constraint is that a mod update can break an existing save, so the automation has to be careful about when it applies one rather than just pulling latest
Provisioned and updated from the same Ansible repo as everything else, so there's no hand-configured server that only I know how to rebuild
Local DNS with real hostnames and network-wide ad blocking, a reverse proxy in front of every service, and no open inbound ports at all. Remote access goes through a Cloudflare tunnel with authentication in front of it.
Nothing is port-forwarded. Every externally reachable service sits behind Cloudflare Tunnel with Cloudflare Access authenticating in front of it
AdGuard Home as the local resolver, giving every service a real .lan hostname and blocking ads network-wide
Self-hosted push notifications, so alerting doesn't depend on a third-party service staying free
Push to main is the deploy. Ansible for most stacks, GitOps for the ones where webhook-speed redeploys are worth an extra moving part, chosen per stack rather than dogmatically.
A self-hosted GitHub Actions runner applies the repo to the host and containers on every push; secrets are encrypted in git with SOPS and age
A daily drift check runs the whole playbook in check mode against live state and alerts if anything was hand-edited outside the pipeline
The architecture diagram on the repo's front page is regenerated by CI from an editable source, so it can't quietly go stale
Nine years of employment across product companies and consultancies. As a consultant the employer is who paid, but the client is what the work actually was, so both are listed.
Front-End Developer Intern
Plejd AB · 2019 to 2020
Worked in a professional, 100,000+ line Angular.js/Vue.js codebase at a Swedish smart-home hardware company, building internal tools used by 50+ employees daily. My first real production codebase, alongside studying front-end development at Medieinstitutet
Clients & platforms
Plejd
Smart-home hardware
Swedish · listed company
Internal tools used daily by 50+ employees
Angular.jsVue.jsFigma
Front-End Developer
Nordic Retail Group (prev. Digital People) · Dec 2020 to Jan 2023
Sole frontend developer on Enginio, a Vue.js platform for building advertising campaigns and brand activations, from early startup through acquisition
Built a reusable Vue.js component library in Storybook, and owned frontend architecture, tooling, and CI/CD
Cut initial load time from 4.2s to 1.8s through lazy loading and bundle optimization
Clients & platforms
Enginio
B2B SaaS · advertising and brand activations
Sole frontend developer: architecture, component library, CI/CD
Built and shipped two React Native apps with Expo, one for Nordic Wellness and one for its premium brand Grand Fitness, each pulling live content and pricing from the Umbraco site behind it
Ran both projects end to end: testing, weekly test builds out to testers through TestFlight and Google Play Console, public releases, and managing the project itself
Built and maintained Umbraco (.NET) sites for several of the agency's clients, plus ongoing WordPress upkeep
Clients & platforms
Nordic Wellness
Gym chain
Largest in the Nordics · 300+ clubs
React Native app (Expo) and the Umbraco site behind it. Owned the pipeline from testing to public release
Grand Fitness
Premium gym brand
Part of Nordic Wellness
React Native app (Expo) and the Umbraco site behind it. Owned the pipeline from testing to public release
Client work delivered through Nexer AB and Dear Friends. Logos and names are trademarks of their respective owners, shown to identify projects I contributed to, not as an endorsement.
AI
How I actually work with AI.
Not a list of models I've heard of. This is what I run, what I decided and why, what it costs, and the one part of it I haven't solved yet.
Local, on my own hardware
Seven models pulled locally through Ollama (general, coding, and embedding), running on my own GPU. Before any of that, I checked whether the home voice assistant actually needed a GPU at all, and it didn't: speech-to-text runs about six times faster than real time on CPU alone. The research came before the purchase.
Cloud, chosen per job
Claude, OpenAI, Gemini, DeepSeek, z.AI and Groq, picked by task, cost, and latency rather than loyalty. There's one boundary I don't cross for convenience: anything touching my home stays on local models, by design. Open-ended questions go to a cloud pipeline on a separate wake word.
Agents as real tooling
Seven purpose-built subagents, deliberately split into read-only reviewers, test runners, and stack-specific implementers, plus agent instructions committed per repo. One of them drives a real Android build on an emulator and looks at the screenshots, rather than trusting that a step reported success.
In practice
45–57s → ~5–6svoice assistant latency, fixed by scoping the model and prompt correctly, not by buying hardware
768 candidatesa fuzzy-matching regression I caused, diagnosed, and rolled back the same day
402M tokens · $18.90routing bulk agent work to cheap models and reserving the expensive ones for what needs them
182 tasks · 47 delegatedreal multi-agent orchestration across code, architect, and review modes
7 local modelsrun on my own GPU, after proving CPU-only inference was viable first
1 problem still opena local model that fabricates rather than admits uncertainty: documented, partly mitigated, not solved
The last figure is the one I'd want to be asked about. A local model that confidently invents an answer is a much more interesting problem than one that's simply slow, and I'd rather write that down than pretend the setup is finished.
What I run
Local
Ollama
Agents
Claude CodeRoo CodeClineCodexGemini CLI
Providers
AnthropicOpenAIDeepSeekz.AIGroqOpenRouter
Activity
Still building, most days.
Client work, my own products, and open source, across public and private repositories.
1,549 contributions in the last year
Showing the last saved snapshot. Live data is temporarily unavailable.
The About page covers the path from Cuba to Gothenburg and what I get up to outside of code, and the blog goes into detail on how Cityroam and casa-verde work. I'm looking for a team that cares about technical quality and ships real things. If that sounds like you, get in touch.