Skip to main content

Lessons from the Lab

The Archive

10 experiments. 10 lessons. Each one taught something worth keeping.

0 experiments0 categories0 lessons0 technologies
Full-Stack Application

Stax

Personal Finance. Enterprise Grade. | Financial Warrior Edition

The most ambitious build of the sprint. A full-stack personal finance platform with 234 API endpoints across a FastAPI backend and Next.js frontend. Dual-database architecture: PostgreSQL for transactional data, DuckDB for analytical queries. 2,000+ tests scoring 91/100 on the quality gate. Features included multi-account management, bank format adapters for Dutch and Philippine banks, transaction categorisation, XP-based progression system, and a complete dashboard with charts and insights. Built with enterprise patterns — CQRS for command/query separation, event sourcing for audit trails, and vertical slice architecture for feature isolation. The domain layer was frozen at v1.0.0 when I recognised the scope had outgrown a personal tool.

LessonEnterprise patterns are powerful — CQRS, event sourcing, and vertical slices gave me a vocabulary for complex systems. But over-engineering a personal finance tool taught me that domain freezing is a discipline, not a failure. Know when the architecture serves learning, not the user.

FastAPINext.jsTypeScriptPostgreSQLDuckDB
Game Development

The Beggars Sect

Text-based martial arts RPG with branching philosophy paths

A CLI RPG set in a wuxia-inspired world where philosophy paths shape your combat style. Built with Ink (Inkle's narrative scripting language) on a TypeScript engine. The system featured chi cultivation mechanics, an Active Time Battle combat system with 55+ martial techniques, AI enemies that adapted to your fighting style, and branching narrative paths based on your philosophical alignment. Reached v0.3.8 with a 25-minute playable prologue and over 20,000 lines of world-building content — faction lore, technique trees, dialogue branches. The design-first approach worked: every mechanic was documented before it was coded, and the architecture stayed clean throughout. Archived because ambitious scope without a shipping deadline is a trap — the world kept expanding but the product never shipped.

LessonDesign-first absolutely works — documenting mechanics before coding kept the architecture clean across 20,000+ lines. But world-building is addictive, and ambitious scope without a shipping deadline is a trap. The project kept growing in depth but never moved toward a release.

TypeScriptInkClaude AITesting
Simulation

AION

Geopolitical simulation with AI agents

A turn-based geopolitical simulation where AI-driven nations negotiated, allied, and went to war. Python backend powering the simulation engine with a React/Vite frontend for the command centre UI. Features included an interactive world map, detailed country profiles with economic and military stats, a diplomatic system with treaty negotiation, trade agreements, and espionage mechanics. Each AI nation had its own strategic personality — aggressive, diplomatic, isolationist — driven by decision trees and weighted priorities. The vision was enormous: hundreds of nations, historical scenarios, and emergent geopolitics. Shelved when it became clear that the content requirements dwarfed the engineering effort — for simulations, content architecture matters more than code architecture.

LessonAI agent simulations need enormous content to feel alive — hundreds of nations, events, and scenarios. For sims, content architecture matters more than code architecture. The engineering was clean but the content pipeline would have taken months of dedicated writing. Know when to shelve.

PythonReactViteSimulationAI Agents
AI & Machine Learning

Ronin

Game AI framework with reinforcement learning

A PyTorch-based game AI framework that learned to play Tetris through reinforcement learning. Ran on a PyBoy Game Boy emulator — the AI saw raw screen frames, processed them through a CNN policy network, and learned to clear lines via PPO (Proximal Policy Optimisation). Built a live training dashboard with WebSocket streaming that visualised metrics in real-time: reward curves, loss graphs, episode length, and the actual game screen as the agent played. The training pipeline handled frame preprocessing, reward shaping, and experience replay buffers. The agent showed genuine learning — stacking patterns, clearing lines, adapting to piece sequences — but training on a homelab GPU was painfully slow. What took cloud instances hours took days locally.

LessonReinforcement learning on homelab hardware is painfully slow — what takes cloud GPUs hours takes days locally. More importantly, the gap between a cool experiment and a useful product is wider than expected. A Tetris agent that can clear lines is impressive to watch but has zero path to revenue.

PyTorchReinforcement LearningPyBoyPython
AI & Machine Learning

Generals AI Mod

Reinforcement learning for C&C Generals

An AI that learned to play Command & Conquer: Generals through PPO reinforcement learning — real-time strategy, not a toy environment. The architecture evolved through multiple iterations: started with basic CNNs, progressed to transformers for spatial attention, then mixture of experts (MoE) for specialised sub-policies, and finally added RND (Random Network Distillation) curiosity for exploration. Each architecture taught something about RL at scale. Fixed 36+ bugs across the game's combat, save/load, and particle systems just to make the training environment stable. The agent learned to build bases, train units, and execute basic attack strategies. The most technically challenging project in the sprint — interfacing Python RL with a 2003 C++ game engine through memory reading and input injection.

LessonRL architecture exploration is addictive — each new technique (MoE, attention, curiosity) promises better results. But at small scale, advanced techniques add complexity without proportional gains. The diminishing returns hit hard when you're running on consumer hardware. Sometimes the simple architecture with better reward shaping outperforms the clever one.

PythonReinforcement LearningPPOTransformers
Full-Stack Application

ScanSys

AI-powered invoice automation

An invoice scanning and processing system powered by LLM technology. Users uploaded invoices (PDF, images), the system extracted structured data — vendor, amounts, line items, tax calculations, dates — using Claude AI for intelligent parsing. Built on Next.js with hardened authentication: middleware-based session management, CSRF protection, and role-based access. The upload flow included data integrity checks, duplicate detection, and a processing pipeline that handled multi-page invoices. An analytics dashboard visualised spend patterns, vendor breakdowns, and monthly trends. The system was production-ready with full test coverage and CI/CD, but shelved when it became clear that enterprise-grade invoice processing needs enterprise budgets — the LLM accuracy ceiling for structured extraction from messy real-world invoices wasn't reliable enough for a solo project without human-in-the-loop verification.

LessonEnterprise invoice processing needs enterprise budgets. The LLM accuracy ceiling for structured extraction from messy real-world invoices isn't reliable enough without human-in-the-loop verification. A solo project can build the pipeline but can't absorb the error rate that paying customers would reject.

Next.jsLLMInvoice ProcessingAuth
AI & Machine Learning

HoI4 AI Agent

Strategic AI for Hearts of Iron 4

An AI agent for Hearts of Iron 4 — a grand strategy game with one of the most complex state spaces in gaming. The agent used hierarchical decision-making: strategic layer (war goals, alliance management, production priorities), operational layer (army composition, front assignment, logistics), and tactical layer (division movement, combat engagement). Built a focus detection system that read the game's national focus tree and evaluated optimal paths based on current game state. The production readiness push added security hardening, full test coverage across all decision layers, and a CI/CD pipeline. The biggest technical challenge wasn't combat — it was evaluation scoring. How do you score a strategic position in a game with hundreds of interacting variables? That question drove weeks of iteration on heuristics and weighting systems.

LessonGame AI for complex strategy games lives and dies on evaluation scoring, not combat logic. How do you score a strategic position with hundreds of interacting variables? That question is harder than any pathfinding or combat algorithm. The state space is enormous and the feedback loops are slow — you won't know if a strategic decision was right until 50 turns later.

PythonGame AIStrategyCI/CD
Content Platform

Rift Codex

Mastery guides for League of Legends

A content platform delivering in-depth champion mastery guides for League of Legends. Each champion guide went through a four-stage pipeline: AI generation with Claude for the initial draft, manual review for accuracy and voice, structured audit against a quality checklist, then publish. The site ran on Next.js 15 with static export to Cloudflare Pages — zero server costs, instant page loads. Content was authored in MDX with custom components for ability breakdowns, matchup tables, rune recommendations, and build paths. The content quality was genuinely high — guides that competitors charged for. But the economics were wrong: each guide took hours of curation time, traffic grew linearly with content volume, and the monetisation path (ads, premium) didn't scale toward the mission. High quality, low leverage.

LessonContent sites don't scale toward financial independence. The content quality was real — guides that competitors charged for — but each one took hours to curate, traffic grew linearly, and the monetisation path didn't compound. High quality and low leverage is the wrong economics for the mission.

Next.jsTypeScriptClaude AICloudflare PagesMDX
Freelance Development

WebsiteBuddies

Professional websites for small businesses

A freelance web development agency targeting small businesses in the Netherlands. The technical infrastructure was solid: Docker-based WordPress development environments for reproducible builds, Claude Code automation for rapid site scaffolding, structured delivery pipelines with staging previews and client approval gates. First (and only) client was Get Your Coach — a personal training business in Den Haag. Built them a responsive WordPress site with booking integration, service showcases, and SEO optimisation. The delivery was smooth, the client was happy. But the lesson hit hard: I'd built an entire agency infrastructure — development workflows, client onboarding templates, pricing models, contract templates — before having a single client pipeline. The infrastructure was the fun part. Client acquisition was the hard part. Building backwards.

LessonFreelance agencies need clients before code. I built an entire agency infrastructure — dev workflows, onboarding templates, pricing models, contracts — before having a client pipeline. The infrastructure was the fun part; client acquisition was the hard part. Building backwards taught me that the unsexy work (sales, networking) comes first.

WordPressDockerClaude CodeFreelance
Infrastructure

Sulat

Self-hosted email system for genkaw.com

A complete self-hosted email infrastructure for the genkaw.com domain. Mailcow handled the mail server (IMAP, SMTP, spam filtering, DKIM signing), Cloudflare Email Routing handled inbound delivery without opening ports, and Resend SMTP relay handled outbound delivery with proper SPF/DKIM/DMARC alignment. SOGo provided webmail access. Four mailboxes across two users, SSL via Let's Encrypt, and the whole stack ran in Docker containers on the homelab. No port forwarding required — everything tunnelled through Cloudflare. The system worked, emails delivered reliably, spam filtering caught the junk. But the maintenance overhead was brutal: deliverability monitoring, blocklist checks, certificate renewals, Mailcow updates, and the constant paranoia that one misconfigured DNS record would land all outbound mail in spam folders. Archived in favour of managed email — pragmatism over purism.

LessonSelf-hosted email is a nightmare. The system worked — emails delivered, spam got filtered — but the maintenance overhead was brutal. Deliverability monitoring, blocklist checks, certificate renewals, and the constant paranoia about DNS misconfigurations. Pragmatism over purism: some things are better managed.

MailcowCloudflareDockerEmail

The experiments are done. The work continues.