An AI-First Development Case Study.

A portfolio of tools, systems, and infrastructure -- all built around, and with, a custom AI development workflow.

One of my closest friends, R, first introduced me to Claude Code around mid-December 2025, and offered me the opportunity to get my first proper experience using an agent-first workflow. I had previously commonly relied on Gemini or ChatGPT to provide focused aid and research support and used tools like Cursor or GH Copilot for autocomplete and code navigation, but overall, up until that point, the term "vibe coding" was one that generally stirred rolling eyes and raised eyebrows than anything else. On the other hand, I've known R for long enough to know that if he's this enthusastic about getting me to try something, there has to be something behind it. So I gave it a shot.

Opus 4.5 had just recently released - or, well, depending on whatever "recently" means in this sector - and I used the even more-recently released Claude Code VSCode extension to take my first steps in agentic coding. I pointed it at a big multimedia codebase for a web game I had built over the course of the last few years, told it to do a review and see if it can figure out some of the more obnoxious bugs I'd been wrestling with, and it worked away. I was certainly impressed; my personal understanding of the state of the tech had clearly lagged behind significantly. But I knew nothing about how to actually use this tool: I didn't use CLAUDE.md, I didn't utilize skills or plugins, I frequently let sessions auto-compact, mixed very different concerns into the same chats, and so forth. Predictably, after an impressive initial showing, the agent's performance began to tank. So I shrugged and went about my way. I never merged the changes the agent made.

Then, in early January, I decided to give it another shot: actually try to figure out how to pilot this thing. Best practices, trial-and-error, experimentation. What I quickly realized is that I had been flying the wrong plane all along, and below is what I've built since making this realization.

Pi: The Agent Core Workflow

Pi is an open-source agent development toolkit, which comes with several modules: one of them is the Pi coding agent, which is a very to-the-point and distilled basic coding agent harness. It comes with four agent tools: bash, read, write, edit. It also manages your logins and sessions, and allows you to freely switch agents mid-conversation between providers. And that's it - out of the box, it doesn't come with anything else. No plan mode or workflow helpers, no web search, no subagents, no permission gate - it's as basic as a harness can come. What makes it special, of course, is that it's extremely extensible, and extend it I have: into a full development engine with over 10 custom TypeScript extensions comprising workflow, context management, and quality-of-life; a set of tools reimplementing and enhancing useful features from Claude Code, as well as original workflow concepts; and a carefully tuned, fully hand-written, compact system prompt that enforces plan-before-execute discipline.

Pi screenshot 1 Pi screenshot 2 Pi screenshot 3
Extensions
11
Custom TypeScript plugins
Agent tools
26
22 custom + 4 std pi
System prompt: pi
~5k
tokens (OpenAI tokenizer)
System prompt: CC
~18k
tokens (OpenAI tokenizer)

Orchestration

The task board is the centerpiece - a full dependency-resolution engine with automatic status cascading, parallel subagent dispatch (up to 4 concurrent workers), and a live TUI showing progress across all running agents. Obviously based on the Claude Code feature, which is itself inspired by the Beads workflow, my implementation of this goes a step further: Tasks require a plan file before they can be created, enforcing the think-first discipline at the system level. Each task includes all information needed for a subagent to start working on the task on a clean context with no exploring: a description of what is to be done, a list of relevant files, and a link to the plan file that spawned the Task. This can all persist through sessions with a custom clear command, which allows seamless continuation of task lists.

The main agent only has a single tool to orchestrate the task agents, meaning adherence to protocol can be enforced: start_tasks will only dispatch workers if the main agent confirms it has inspected and validated the previous stage's output. Epics allow for keeping track of multiple plans across several sessions. Task dependency tracking and state management is fully automated: all the main agent has to do is kick off a batch, and all tasks will automatically cycle through their states and unblock tasks that depend on them. The use of this system is heavily emphasized through the main agent's SYSTEM.md system prompt, as well as through state-dependent targeted message injections from the extensions themselves. Pi will, with no directed prompting, always write a detailed implementation plan, present it for confirmation, create tasks from it, and then use the task system to implement work.

Context Engineering

One thing becomes very clear to anyone who uses agents in an extended fashion: LLM context windows are finite, fickle, degrade with noise, and context use should be minimized wherever possible. The natural benefit to using a custom harness is that it allows us much more granular control over the agent's context. To this effect, I built a three-layer system: selective context compression (prune stale tool results without losing the thread - the agent itself decides what to keep and what to discard), escalating pressure alerts that append hidden messages with increasing urgency to modify Claude's behavior across four severity tiers, and tooling that carries important context between sessions without summarizing, like Tasks and Project Todos, which carry their own information and are, effectively, an atomic work item that any agent with no further knowledge outside of the project's CLAUDE/AGENTS.md could complete without wasting tokens on exploring.

This not only reduces context, but also "defragments" it in a way: because all tool calls in-between the user messages disappear, the agent has a much more present concept of all design decisions made up until that point. Through the agent's autonomous use of this feature (it tends to decide to discard exploration/code context right before writing out the plan to a file), I was, in one example, able to implement over 20 Task items using the Task system in a single session. A full tool use prune can frequently recover context use from the mid-60s to the low 20s, without a noticeable increase in coherence and speed. Bonus: the session literally costs less. The turn in which the agent prunes will be hit with a high rate of cache-writes, which is a single cost spike; but every subsequent turn is significantly cheaper since we're literally sending fewer tokens. It pays for itsself within 3-4 turns, but grants us both agent coherence immediately and savings after that, continuously.

Quality Gates

My workflow with Pi is clearly and explicitly laid out, step-by-step, in its system prompt, and all of its custom tooling is designed to implement it. Because we can directly control whether the agent gets another turn and can always interrupt its process programmatically based on session state, we can move past encouraging behavior through prompting and crossed fingers, to enforcing it through quality gates. The possibilities for integration with existing tooling are practically limitless - for instance, on every file write, run it through our linter pipeline. If it fails, roll back the change, stop the agent, and automatically tell it to do it properly. "Sloppy" agent behavior can't be prevented, but it can be monitored and corrected at a code level, fully deterministically.

The Extensions

The default pi-coding-agent package comes with a few example extensions that ship with the dist in node_modules and can be installed and activated without much hassle; the extensions below do not include them. Below is a list of extensions I've either built from scratch or modified so heavily from their original example that it's, effectively, a new extension.

tasks
Task board with dependency resolution, workflow enforcement, parallel dispatch, epic grouping, live TUI viewer
subagent/
Isolated agent spawning -- example extension shipped with pi, but extended for deep integration with the Task system
compress-context
Selective pruning of stale tool results from the context window, with the selection made by the agent itself
context-pressure
4 tiers of escalating alerts; modifies agent behavior through regular message injections as context fills
questionnaire
Rich TUI questionnaire with tabs, multiselect, annotations, free text; modeled after the Claude Code extension
plan-mode/
Read-only exploration mode, tool allowlisting, plan submission flow; integrates with Task system
insight/
Session-level analytics -- token usage, costs, activity heatmaps, HTML reports; OR User-level analytics - working style, challenges, suggestions
web-search
Brave Search integration with injection-defense wrapping
codex-review
Iterative Codex review/fix loops using native GPT-Codex integration: Codex reviews, Claude fixes, until clean or iteration cap reached; Codex's structured output helps enforce the cycle
todo/
Per-project TODO tracker with priority- and staleness-based reminder message injection for incidental findings and "not right now" tasks
tmux-hooks
Originally made by R for Claude Code; reimplemented as a pi extension: flashes and recolors tmux tabs when the agent is idle or prompting the user for response

Design Philosophy

The whole system is built around both layered reinforcement and structural control; I don't think either is alone on its own to enforce agent behavior. Plan mode prevents writes, an OPCI (Outline, Propose, Confirm, Implement) task evaluation workflow prevents trigger-happy LLMs from jumping straight to the code, the task board requires a plan file and its use is heavily reinforced throughout with automated prompt injections, context pressure alerts escalate from gentle reminders to hard blocks. No single mechanism is THE safety net, they all overlap intentionally. Agents can be crafty, and if they want it enough, they can circumvent their way around any single measure.

I don't sandbox pi. I've never regretted it. I've regretted it once with Claude Code and ran it sandboxed from there on; now I couldn't even imagine going back to Claude Code, because I no longer believe Claude Code gives the user enough control over the agent, its data, and its behavior to ensure a consistently effective performance. It can be very effective with enough babysitting, but that sort of goes against the idea of automated workflows.

The Agency Supervision Layer

When your AI agents are productive enough to run in parallel across machines, you need a way to supervise them. The Agency is a real-time web dashboard for monitoring and controlling concurrent pi sessions - a "mission control" for AI-assisted development. Everyone who dives into the rabbit hole deep enough to worry about usage limits on a Max 20x plan will eventually self-roll one of these, and this is my take at it.

Agency screenshot 1 Agency screenshot 2 Agency screenshot 3

Built with SvelteKit, Svelte 5, xterm.js, node-pty, and raw WebSocket channels. The pi-side integration is a fire-and-forget extension that pushes session state on every lifecycle event - the dashboard has zero coupling to the agent's operation and will run even on pi installs that don't have the extension at all; the session cards will just be missing additional details, but sessions are still detected, fully controllable, and newly spawnable.

Nova: 48 Hours, One Server Proof of Velocity

So above is what I've built. It's the result of a LOT of consistent and steady experimentation throughout the months of January and February. Most of this time was spent working on non-critical personal projects and deliberately trying as many different workflow approaches as possible to see what works for me. I got my first Claude subscription in late December and started exploring my workflow in early January; once I had an idea of what I'd need, I quickly discovered Pi through research, and from that point on, things started moving quickly: I first installed pi on my desktop on February 10. Everything in this document has been created since.

So here is NOVA: a fresh Fedora machine, plugged in on a Tuesday morning. By Wednesday evening, it was running 20+ Docker containers serving a full personal infrastructure, several self-developed apps, a fully automated deployment pipeline, a full-fledged recursive ad-filtering DNS server that all home traffic is routed through, a reverse proxy, and two database pools (Postgres & Maria) - all built and configured through the pi workflow, from scratch. The Fedora Live USB is still plugged into it. NOVA was the perfect green field I was looking for - a fantastic test to see how quickly and effectively I can put this workflow into action on a very specific, scoped, multi-discipline project. This is how it went.

Nova screenshot
Containers
20+
Running services
Custom Apps
4
SvelteKit, built from scratch

Infrastructure

Pi-hole DNS Nginx Proxy Manager PostgreSQL 17 Redis 7 MariaDB Unbound Tailscale VPN

Self-Hosted Tools

Monica CRM Dawarich Location Actual Budget Stirling PDF MeTube SnapDrop ConvertX Prowlarr Pterodactyl Games

Custom Applications

Agency Dashboard Freckle (AI Journal) Nova Tunes (Music) Nova Home (Landing, Dashboard, Status)

Everything accessible over *.nova.local domains via automatic DNS registration. A custom deployment tool, nova-deploy, takes a project directory and a subdomain name and handles the rest: builds the Docker image(s), creates the container, registers the DNS entry, and wires it into the reverse proxy. Effectively, this means you use one command from code to running service. It'll write Dockerfiles for repositories that don't have one, but it can also be supplied with Docker compose files and will deploy them all the same.

None of this is theoretical. This is a daily-driver workflow I've been building and refining through constant real use. Every extension exists because I hit a real problem during my experiments with personal projects and solved it; every safety layer is there because I saw what can go wrong without it. It's very much still a work-in-progress, but I suspect all agentic tools will be for the foreseeable future. All we can do is throw whatever we can find at the wall and see what sticks; this is what I've managed to make stick for me.

In my opinion, the role of an engineer isn't going to necessarily evolve to that of a code reviewer, because I don't think an engineer's knowledge of code syntax and design patterns will be valuable for too much longer. What I think will still be valuable is the instinct for what to build instead of how to build it. In effect, this means that every team's ideal AI workflow is different. There is no way around the hands-on experience of having figured one out from zero, or the judgment to help fellow team members find theirs. What is quickly becoming crystal clear, however, is that this IS the future of software development. Models are only going to get stronger, and what they can already do is more than enough to instate real, productive, automated, and tangibly value-providing workflows, provided they are set up with the correct guardrails.

I believe we are currently within an industry-wide critical time window, in which making the correct decision at the correct time can make or break a company's transition into this new paradigm. The earlier you start training your team, the easier your journey will be: your workflows will be designed for current capabilities, and the models are only going to get stronger and more autonomous. And as engineers, I also believe we have nothing to fear - as strong as these tools are, and as much stronger as they will be getting still, it's becoming clear that, in the end, nothing is a substitute for experience. Through our existing technical knowledge and architectural instinct, we have the privilege of having a much easier time extracting a model's full potential. Writing code is now cheap, but knowing what code to write, and knowing how it most efficiently achieves what it sets out to do is still a denominator; and it arguably surged in value significantly.

Exciting, terrifying, uncertain times ahead.