01 / 21
→ NEXT

How I use AI / a tour

Claude Code is my workhorse.
I build, run, and train with it.

I use it to develop apps, troubleshoot problems, and run my homelab infrastructure as code — writing and testing Ansible playbooks used to be a slog, now Claude does it better and faster than I did by hand. I've also built a NAS manager, and separately an AI-supported update manager that checks for breaking changes before deployment and warns me before patching. This is a tour of how, from infrastructure through to the deepest build: an AI investment analyst.

1,136
commits, 3 systems
4
servers, zero hand-written playbooks
1
subscription cancelled
6,569
lines, flagship app in 11 days
BUILD · commits per system ▲ 1,136 total
Real data: git log across three repos. Same tool, three very different jobs.

01 / Infrastructure as code

I use Claude to run my infrastructure — and to build my apps

My homelab spans an Oracle Cloud VPS, an HP EliteDesk G4 server, two Raspberry Pi 5s, and a scatter of ESP32 sensors. The four Linux hosts are managed as one Ansible repo, deployed automatically by self-hosted Gitea Actions on every push. I describe the change in plain English and Claude writes the role, the task, the template — reasoning about idempotency and host-scoping better than I bothered to when I did it by hand. The same agentic workflow — describe, generate, review, ship — is how I build every app in this deck.

◆ ROLES

bootstrap · docker · storage · watchdog · tailscale

Eight reusable roles apply consistently across all four hosts — new host, same playbook, site.yml --limit <host>.

▲ CI/CD

Push to main, fleet updates itself

Gitea Actions triggers a runner per host on every push — no manual ansible-playbook from my laptop, ever.

◇ PRIVATE

Tailscale, on a self-hosted coordinator

Headscale — my own Tailscale control plane, running on xenon — meshes all four hosts and gates everything that isn't meant to be public.

◆ PUBLIC

Cloudflare in front, Traefik behind

Public services either route through a Cloudflare Tunnel (no open ports) or straight through Traefik with Let's Encrypt certs issued via Cloudflare's DNS-01 API.

4
hosts, one ansible repo
833
commits, Jan–Jul 2026
94
active days
8
reusable roles

01 / Infrastructure as code — the deploy loop

1

Describe the change PLAIN ENGLISH

"Add a watchdog role that restarts a container if its healthcheck fails three times" — no YAML written by me at this stage.

2

Claude writes the role CLAUDE CODE

Tasks, handlers, templated compose fragments, and the vars.yml wiring — following the conventions already in the repo, not inventing new ones.

3

I review, then push GIT

I read the diff like any PR. If it's right, it goes to main — that's the only deploy step.

4

Gitea Actions converges the fleet CI/CD

One runner per host applies site.yml --limit <host> in parallel. Idempotent by design — safe to re-run, safe to fail halfway.

02 / How I build apps

I describe. Claude codes. I review. CI ships.

"It's not strictly speaking a methodology... it's more... the vibe of the thing."

Dennis Denuto, The Castle

No IDE marathon sessions. Development is a conversation: I say what I want in plain English, Claude Code reads the codebase, writes the change, and explains it. My job shifts from typing to deciding — and the same loop runs whether I'm shipping a feature, fixing a bug, or standing up a whole new app.

Describe intent

"Add a self-healing model picker to the coach" — or whatever the app of the day needs.

Claude implements

Model, migration, API route, UI — in one pass, following existing patterns in the repo.

I review & steer

Read the diff like a code review. Push back, refine, catch what the AI missed.

Push to main

Gitea Actions builds the images and deploys. I never run docker build by hand.

Watch it break

Real usage finds the edge cases. Each one becomes the next conversation.

02 / How I build apps — the same rhythm everywhere

  the same loop, across three unrelated codebases
6b181f8 Add dual-model selection layer for fast vs strong AI tasks     invest
a91c2e4 Add self-healing model picker with daily validation           training
f30d117 Add watchdog role: restart containers on failed healthcheck      infra
ab75482 Fix price forecast: handle empty LLM response and reframe prompt invest
c48e910 Replace Python best-picking with a SQL window function                training
7d2b6aa Fix idempotency gap in tailscale role on re-run                   infra

Different domains, same rhythm: add → fix → refine → harden. Small conversational increments, each one shippable. Context lives in CLAUDE.md and Claude's persistent memory, so every session starts already knowing the project — whether that project is a trading dashboard, a training log, or a fleet of home servers.

The same rhythm holds one level up, too: building agentic workflows themselves is still add → fix → refine → harden, just applied to the workflow instead of the app.

03 / When a subscription killed my training app

So I built my own. It's free, and better.

The app I'd used for years to plan marathon training quietly stopped working, and the fix the owner shipped was a subscription. Instead of paying for a worse version of what I already had, I asked Claude Code to help me build PMCDash: it syncs 18 years of Garmin history, models training load the way real coaches do — fitness, fatigue, form — and adds an AI coach that reads my actual data. It runs on my own server for nothing.

254
commits, 58 days
18
years of training data synced
676
activities, 6,534 km
$0
monthly cost, self-hosted
pmc.insightiq.au/pmc
Performance Management Chart: daily training load bars with fitness, fatigue and form lines
The core view. Daily load, accumulated fitness, and form.
/coach
AI coach chat interface grounded in the user's actual training data
The AI coach. Answers grounded in my real training history via tool calls.

04 / The deep dive

Now, the one I'll actually walk you through

INVEST is an analyst that never sleeps: a full-stack monitoring app for my ASX and US holdings, running on an Oracle Cloud VPS alongside my other public services, priced live, assessed daily by an LLM, and advised weekly. It's the build where every architectural decision mattered enough to explain — so this is where the tour slows down.

▲ WATCHLIST

Live multi-exchange quotes

ASX and US tickers side by side, with FX conversion to AUD, 52-week ranges, and price alerts pushed to my phone via ntfy.

◆ ASSESSMENTS

Daily AI verdicts

Each stock gets a Bullish / Neutral / Bearish call every day, grounded in that day's news — and it remembers its last five assessments for continuity.

◇ THEMES

Monitoring briefs

When I add a ticker, the AI writes five investment themes for it, then turns them into news search queries it tracks every day.

▼ FORECASTS

Scored predictions

The AI forecasts price ranges — and the app checks them against reality when they expire. The model is held accountable.

04 / The deep dive — the dashboard

invest.insightiq.au
Dashboard: watchlist of nine ASX and US tickers with live prices, day change, volume and 52-week range
The dashboard. Live watchlist across exchanges — USD positions converted to AUD, advancing / declining at a glance.

04 / The deep dive — per-stock detail

/stock/WBC
Stock detail page for WBC: price chart and the AI-written monitoring brief with five investment themes
Stock detail. Price history plus the AI-written monitoring brief.
/trends
Trend analysis page: per-stock cards with 7, 30 and 90 day sentiment trends and price forecasts
Trends. Rolling sentiment per stock, with scored forecasts.

05 / Architecture

I didn't consult Claude on this. Experience made the call.

Postgres over Mongo, Redis for caching, a handful of functions over LangChain — those calls came from being an engineer first, sharpened by years in Technology Governance evaluating exactly these kinds of trade-offs, not from asking an AI to weigh in. This is where experience and AI actually converge: I decide the architecture, Claude builds to spec.

docker compose · 4 services
frontend :3000React 18 · TypeScript · Vite · Tailwind · nginx proxies /api → backend
backend :8000FastAPI · async SQLAlchemy · APScheduler · the AI layer lives here
postgrespositions · assessments · trends · forecasts
redisnews cache · FX cache · advice cache (6h TTL)
Yahoo Financequotes via curl_cffi
TogetherAItwo LLMs, auto-selected
the platform it actually runs on
Traefikreverse proxy · Let's Encrypt certs
Gitea Actionsbuilds & deploys on push to main
restic + BackRestnightly snapshot of postgres & redis to NAS · 7d/4w/6m retention · healthchecks.io ping
◆ Why Redis in a one-user app?
News and LLM output are expensive to regenerate. Caching advice for 6 hours means the dashboard is instant and the API bill stays near zero.
◆ Why a built-in agentic layer, not LangChain / n8n?
The AI work here is a handful of well-defined steps — fetch, enrich, prompt, cache — not an open-ended agent loop. A few functions in analysis_service.py do the job, with no extra orchestration service to run, monitor, or trust.

06 / The model decision layer

Not every task deserves the expensive model

The app makes hundreds of LLM calls a week. Reformatting a news query doesn't need the same brain as judging my portfolio — so I built a routing layer: every AI task declares whether it needs strong judgment or just fast transformation. The result: the entire AI layer runs on ~$2 a month.

◆ strong — judgment, synthesis, advice ▲ fast — extraction, queries, summaries

07 / The monitoring themes

Every stock gets 5 signals worth watching

The moment I add a ticker, the two model tiers go to work together. The strong model thinks like a long-term shareholder and writes five key themes. The fast model then compresses each theme into a Google News query phrased the way journalists actually write headlines.

◆ Themes — strong model, on ticker add
▲ Search tasks — fast model, 4–7 words
Net interest margin trendThe core earnings driver for a bank.
Westpac net interest margin outlook
Housing & mortgage growthLoan book growth sets the revenue ceiling.
Australian mortgage lending growth
Credit quality & impairmentsBad debts are the downside scenario to watch.
Westpac bad debts provisions
Capital managementDividends and buybacks signal board confidence.
Westpac dividend buyback announcement
Cost-out & digital transformationThe efficiency story underpinning the margin thesis.
Westpac cost cutting technology

07 / The monitoring themes — feeding the verdict

1

News cron, every day SCHEDULER

All five theme queries run against the news sources daily, alongside the stock's general query. Results land in Redis, tagged per theme.

2

Themes feed the daily verdict STRONG MODEL

The 4:30pm assessment prompt includes a "theme-specific news today" section. The model must comment on each of the five themes before it's allowed a Bullish / Neutral / Bearish call — no verdicts from vibes.

3

Verdicts become trend lines HISTORY

Each verdict is scored (+1 / 0 / −1) and stored. Rolling 7, 30 and 90-day windows compare first-half vs second-half averages to call the direction.

4

Trend narratives FAST MODEL

For each window, the fast model writes a short narrative of what moved sentiment — the story behind the line on the Trends page.

This is the feature that makes the trend assessment mean something: the AI isn't reacting to generic headlines — it's tracking the five signals it decided matter for this specific stock, every single day.

08 / AI on my portfolio

Two flows: one deterministic, one agentic

The daily verdict and the Q&A advisor solve different problems, so they're built differently. One is a fixed pipeline where code does the arithmetic and the model only judges. The other lets the model decide, live, what data it needs — and go get it.

◆ DETERMINISTIC — daily verdict
1

Load positions SQL

Stocks and cash accounts, batch-loaded with sentiment and trend — three queries, no N+1.

2

Enrich deterministically PYTHON

Weights, P&L, sector/exchange allocation, cash yield — all computed, never asked of the model.

3

One structured prompt STRONG MODEL

The full brief plus a fixed contract: reply in exactly five sections, grounded only in the numbers given.

4

Cache & serve REDIS · 6H

No tool calls, no live queries — the model never touches the database directly.

▲ AGENTIC — Q&A advisor
1

Baseline context DB

Portfolio summary and watchlist are always fetched first, deterministically — no LLM decision involved.

2

Model plans & queries FAST MODEL · TOOLS

A bounded tool-calling loop over nine live tools — get_quote, get_stock_news, get_price_history and more — the model decides what it needs and queries the database itself.

3

Synthesize & stream STRONG MODEL

Gathered context plus conversation history stream back as the answer, over SSE.

4

Persist SQL

Both turns are saved so the next question has full conversational memory.

09 / Lessons

"Code is free now, but software is still expensive."

r/cursor

Infrastructure, apps, a training log, an investment analyst — different problems, same handful of lessons carried across all of them.

09 / Lessons — the framework

Anyone can vibe code Software 3.0. Getting a probabilistic model to output something that runs takes an afternoon. Orchestrating that into software you'd actually trust — unattended, touching real data, correct at 2am — takes knowing exactly where the model's probability ends and your deterministic system has to take over. Every build in this deck lives on that line somewhere.

Andrej Karpathy, "Software Is Changing (Again)" — Y Combinator AI Startup School, June 2025

SOFTWARE 1.0Explicit codeA human writes every branch, every rule, by hand. Fully deterministic. Trust comes from reading the code.
SOFTWARE 2.0Neural network weightsYou train a model on data and the "program" becomes learned weights. Still narrow and task-specific, with bounded inputs and outputs.
SOFTWARE 3.0LLMsGeneral-purpose systems that understand the world probabilistically — "a new kind of computer." You program them in plain language, and the same prompt can return different output on different runs.

What orchestrating Software 3.0 actually takes

◆ 01

Placing the boundary is a design decision

Ansible idempotency, cached advice, scored forecasts — each is a place I decided the model doesn't get the final word. Deciding where a system stops guessing and starts enforcing is architecture, done deliberately, component by component.

◆ 02

Data quality sets the ceiling on the answer

An LLM bridges the gap between what it's given and what's asked with probability — that gap is exactly as wide as the data is unreliable. High-confidence sources narrow it; noisy or stale ones widen it, no matter how good the model is. Quality in is reliability out.

◆ 03

Context narrows the guess — it doesn't replace the gate

Persistent project context and memory make every guess better, more often — true for any agentic workflow, not just this one. But better isn't certain. Treating good context as a substitute for validation is how a probabilistic component quietly becomes a single point of failure.

◆ 04

The validator has to be independent of the generator

An AI that grades its own homework will pass it. My price forecasts are scored against what actually happened, not by the model that made them.

◆ 05

Scrutiny should scale with the cost of being wrong

Formatting a search query and judging my whole portfolio aren't the same risk, so they don't get the same model or the same review.

◆ 06

The deterministic shell is where the skill lives now

Anyone can prompt a working app into existence today. What doesn't come free: knowing an N+1 query will crawl as data grows, that a scheduler must never block, that an Ansible role has to be idempotent before you'd trust it unattended overnight. That knowledge is the deterministic shell around the probabilistic core — the only differentiator left.

Closing bell / end of tour

MARKET CLOSED — for today

How I use AI: Claude Code across infrastructure, apps, and an AI investment analyst.

Presentation site: also written by Claude — of course.