← Back to Writing
Challenge Started Mar 2, 2026 · Updated daily

30 Days AI Challenge

Every day this month I'm doing one new thing with AI — and documenting it here. No rules on what counts: it could be art, a tool, a workflow, a conversation, a build. The only rule is that it has to be something I've never done before.

Progress Day 4 of 30

4 days completed · 26 to go

Day 01 Technical Mar 2, 2026

I built my entire portfolio with AI — and shipped it to GitHub

I'd been meaning to build a personal site for years. Today I stopped making excuses and built the whole thing in one session using Claude Code as my co-pilot.

We started with a folder structure, installed a few AI agent skills, pulled my CV, and designed the whole thing from scratch — Swiss minimalism, custom colour palette, Archivo + DM Sans typography, smooth scroll reveals, count-up metrics, and a timeline that draws itself as you scroll.

Then I pushed the whole thing to GitHub for the first time using SSH keys. No tutorial. No hand-holding. Just figuring it out.

What I learned

  • AI doesn't replace thinking — it amplifies it. The clearer your prompt, the better the output.
  • Setting up SSH keys for GitHub is way less scary than it sounds.
  • "Done" beats "perfect". This site will evolve — the important thing is it's live.

Tools used: Claude Code, HTML/CSS/JS, Tailwind CSS, Git, GitHub Pages

Day 02 Technical Mar 3, 2026

I built a tool that reads my Gmail and LinkedIn and tells me where every job application stands

Job searching is embarrassingly manual. I had recruiter emails in Gmail, LinkedIn InMails I'd half-replied to, and a spreadsheet that was already two weeks behind. Every week I'd spend 20 minutes just finding where things stood — before I could do anything useful with the information.

Today I built something to fix it. The tool runs on a schedule, reads both inboxes, uses Claude to extract the company, role, and application status from each message, deduplicates everything, and writes a clean Markdown digest. One file, one read, and I know where I stand.

How it works — four steps:

  • Gmail — OAuth2 + Gmail API. Keyword query for "application / interview / offer / rejection / recruiter", paginated up to 500 messages, body extracted and truncated to 2000 chars.
  • LinkedIn — Playwright with a persistent browser session. Log in once (headful), then it runs headless every day and scrapes your message threads for job-related conversations.
  • Claude — messages are batched 20 at a time. Each batch gets serialized into labeled text blocks and sent to Claude with a prompt asking for structured JSON: company, position, status, date, source, notes. I strip any non-JSON prefix before parsing — Claude occasionally adds a brief explanation even when you ask it not to.
  • Report — a Markdown file with a stats table, application status table, and Claude-generated highlights. Then a local web UI to view it in the browser.

The most interesting design problem was the dedup/merge logic. You often get 3–4 messages about the same application — a confirmation, a recruiter follow-up, an interview invite. Each one might be parsed as a separate entry. The merge step groups by normalized (company, position), keeps the most recent date, and resolves status conflicts by priority: offer → interview → screening → applied → rejected → unknown. This means if you have an offer and also a confirmation email from the same company, the offer wins.

I also made LinkedIn failures non-fatal. If the browser session expires (which it will), the tool logs a warning and continues with Gmail-only data. A scheduled job shouldn't break because of a stale cookie.

What I learned

  • Using Claude as a structured extractor — not a generator — is one of its most underrated use cases. Give it raw text, get back clean JSON. It beats regex for messy real-world email content every time.
  • Designing failure modes matters as much as the happy path. Making LinkedIn non-fatal meant I could schedule the whole thing without babysitting it.
  • A tool that runs itself is different from a tool you use. The value isn't in the automation — it's in the forcing function. When the digest shows "5 applications with no update in 10 days," you follow up.

Tools used: Claude Code, Node.js, TypeScript, Gmail API, OAuth2, Playwright, Claude claude-sonnet-4-6, node-cron  ·  Read the full writeup →

Day 03 Technical Mar 4, 2026

I tried to build an API. I built Contra instead.

The plan for Day 3 was clean: build a small public REST API — something Claude-powered, useful, maybe something other people could call. It sounded like a perfect one-day scope. It was not.

The moment I started sketching it out, the list of prerequisites exploded. OAuth or API keys — which one and how? Cloud hosting — serverless function, VPS, Railway? Rate limiting so nobody runs up my bill? And then the one that really stopped me: security. A misconfigured public endpoint can expose way more than you intended. Injection attacks, SSRF, leaking secrets through error messages — getting it right takes real care, and getting it wrong in public is embarrassing at best and dangerous at worst.

I decided not to rush it. A public API done properly is a one-week project, not a one-day one. So I pivoted to something equally technical, completely self-contained, and way more fun.

I rebuilt Contra Stage 1 as a fully playable browser game — in a single HTML file. No server, no auth, no attack surface. Just a canvas, a game loop, and Claude Code helping me design every system from scratch.

What ended up inside that one file:

  • HTML5 Canvas 2D renderer with a 3-layer parallax jungle background and scrolling camera
  • Full game loop — physics, AABB collision detection, variable-height jumping, enemy wave spawning
  • 5 enemy types with distinct AI: walker, shooter, armored, jumper, and stationary turret
  • 3 power-ups (Spread shot, Rapid fire, Barrier shield), destructible crates, indestructible barriers, one-way platforms
  • Web Audio API sound engine — every sound effect synthesized in code, no audio files
  • 3 boss fights, each harder than the last — ending with a skull fortress called Crimson Omega and a dramatic zoom-out into a wider arena

What I learned

  • Knowing when not to ship is a skill. Rushing a public API with weak security is worse than not building it at all.
  • Self-contained builds have real value — no dependencies, no attack surface, no cloud bill. Sometimes a single HTML file is the right architecture.
  • Claude Code is genuinely good at game logic. Describing collision resolution, boss phase transitions, and audio synthesis in plain language and getting working code back is still kind of wild.

Tools used: Claude Code, HTML5 Canvas, Web Audio API  ·  Read the full post →  ·  Play the game →

Day 04 Technical Mar 9, 2026

I scored my product roadmap with AI — and built the dashboard to prove it

A quick note before we get into it: Days 5 through 8 were supposed to happen. They didn't. I came down with influenza — the real kind, not the "I feel a bit off" kind — and spent most of the week horizontal. The challenge paused. I'm back now, and I'm continuing from where I left off.

Day 4's project had been sitting in my notes since before I got sick: a Roadmap Reality Check tool that takes your product roadmap items — pasted as text or uploaded as a CSV — runs them through Claude, and returns a health score with flags, reasoning, and recommendations for each item. Every analysis is persisted to a database and charted over time so you can see whether your roadmap is getting healthier or drifting further from reality.

This was a real step up in complexity. Previous days had me building single-file tools or games. Day 4 is a proper multi-layer app: Express backend, database, file upload, AI analysis, and a charted history view — all running locally with no build step.

How it works:

  • Input — paste roadmap items as free text (one per line) or upload a CSV with any column naming convention. The parser normalizes both into a numbered list with all available fields.
  • Analysis — Claude receives the list and returns a JSON object: an overall score (0–100), a 2–3 sentence executive summary, top issues, and a per-item breakdown with score, flags, reasoning, and a concrete recommendation.
  • Flags — five categories Claude can assign: Vague, Stale, Unanchored, Dependency Risk, and Stakeholder-Driven. Each gets its own color badge so problem patterns jump out visually.
  • Persistence — every analysis is saved to a local SQLite database (using Node 24's built-in node:sqlite module — no native compilation required).
  • History dashboard — a bar chart (Chart.js) plots every overall score over time, color-coded green/amber/red. Below the chart is a clickable list: click any entry to reload that analysis in the results view.

The most interesting technical decision was the database choice. The plan called for better-sqlite3, but it fails to compile on Node 24 — no pre-built binaries for arm64 and the native build requires a C++20 compiler that the current Xcode tools don't supply. Switched to node:sqlite instead — it's built into Node 24, zero install, and the API is nearly identical. One of those "the platform grew up" moments.

What I learned

  • Claude as a structured scorer is powerful. Give it a rubric and a list, and it returns consistent, actionable evaluations — much more useful than a free-form critique.
  • The history dashboard changes the value proposition. A single score is a snapshot. A trend line is a feedback loop. The tool becomes 10× more useful the second time you run it.
  • Don't fight the platform. Node 24 ships with SQLite — use it. The right dependency is sometimes no dependency.

Tools used: Claude Code, Node.js 24, TypeScript, tsx, Express, node:sqlite, csv-parse, multer, Chart.js, claude-sonnet-4-6  ·  Read the full post →

Day 05 Coming soon

Next entry coming up...

Want to see what I build next?

I'll be updating this page daily throughout March. Find me on LinkedIn or GitHub to follow the journey.