My Approach

I build AI-powered tools end-to-end, and I build them to last. There are a lot of impressive demos out there that fall apart the moment they meet real users. Mine don't, and the reason is that I spent years in quality engineering before I started shipping products. That background shows up in everything I build.

I Build Tools I Actually Need

I don’t build portfolio projects to impress recruiters. Every one of these started because I had a real problem and got frustrated enough to solve it myself.

RepoAudit exists because I kept inheriting codebases and needing to understand them fast. TALON exists because I wanted to evaluate land for real estate investment and no existing tool could answer the questions I actually had. Classifieds Briefing exists because I was planning a mountain relocation and got tired of re-reading the same six classifieds searches every morning, trying to remember whether that ā€œ7.3 dieselā€ was the good engine or the troubled one. The rest of the catalog follows the same pattern: a real problem, real constraints, and a tool I have to live with afterward.

That last part is why they’re built with rigor. The alternative is debugging my own shortcuts at 2am.


How I Work: AI-Augmented Development With Engineering Discipline

LLMs aren’t replacing developers. But a developer who actually knows how to use them can ship in days what used to take weeks, and not by cutting corners.

Before Writing Code: Architecture First

I don’t start with main.py. I start with a conversation.

I’ll spend 30 minutes with an LLM sketching out the system, trade-offs between patterns, where the bottlenecks are going to be, whether composition or inheritance makes sense here. The AI pushes back on assumptions I didn’t realize I was making. By the time I write the first line of code I’ve already explored the dead ends and settled on the right approach, which means I’m not refactoring it out of a corner three weeks later.

During Development: Match the Tool to the Task

I use AI-powered IDE tooling to generate boilerplate, catch bugs before runtime, and suggest refactors I wouldn’t have thought of. But I match the model to the work:

I’m not dogmatic about any of this. The tooling changes every few months. What doesn’t change is matching capability to task complexity, and not using a frontier model to format a JSON blob.

After Writing Code: AI-Powered Review

I feed whole codebases to LLMs and ask the questions I’d want a senior engineer to ask: where are the circular dependencies, which modules are doing too much, what breaks if this API starts rate-limiting me.

That habit eventually became its own product, RepoAudit, which runs multiple analysis profiles (architecture, security, AI maturity, documentation) against any repo and generates a structured report. The tool I wished existed every time I inherited somebody else’s codebase.

The end result is that I ship features in days instead of weeks, and they still have test coverage, clean interfaces, and solid error handling.


The Quality Engineering Edge

A lot of people building with AI can move fast, but they can’t tell you whether what they shipped actually works. Years in QA gave me a systematic understanding of how software fails, and that shows up everywhere in my work.

Tests Are the Architecture

Most developers write code, then write tests. I write the tests first, then the code.

When I built my Lead Generator I wrote the entire test suite before I scraped a single website. In TALON the test suite is the specification for a hexagonal architecture whose domain layer has zero framework dependencies. If your tests are hard to write, your design is wrong, that’s usually the cheapest signal you’ll get, and it’s the one most people ignore.

Data Is Hostile Until Proven Otherwise

I don’t trust APIs (they’ll change their schema), LLMs (they’ll hallucinate), user input (it’ll be malformed), or my own assumptions (they’ll be wrong). Especially my own assumptions.

In BookParser validation gates sit between every component, so when the LLM invents an entity ID that doesn’t exist, the system catches it, logs it, and retries with corrective feedback. In Reddit Research, circuit breakers and rate limiting keep long-running scraping jobs alive when an API has a bad afternoon. In TALON, the LiDAR orchestrator assumes every one of its three government data sources will eventually fail, because every external source eventually does.

Distributed systems break in weird ways. I’d rather handle it upfront than debug it at 2am.


The Four Principles

1. Architecture Enables Speed

Good architecture isn’t gold-plating. It’s removing friction. The 2 hours I spend refactoring to kill a circular dependency is 2 days I don’t spend debugging when requirements change next month (and they always change).

I use established design patterns not because they sound smart, but because they’re battle-tested solutions to recurring problems: Strategy Pattern for swapping AI providers without code changes, Abstract Factory for ingesting disparate data sources through one interface, circuit breakers for self-healing systems, dependency injection for testability. Under the Hood maps which pattern lives in which project.

TALON is the clearest example. Hexagonal architecture with strict dependency inversion means the domain layer is pure business logic with zero framework imports. Swapping the database, adding a new data source, replacing the LLM provider, none of it touches the core domain. Months of sustained development in, the architecture hasn’t needed a rewrite. It just absorbs new features.

2. Latency Is a Feature

Speed isn’t raw performance, it’s perceived responsiveness. When I built Voice Coach, standard 3-5 second API round-trips were a dealbreaker for a conversation simulator, a 3-second pause in a sales call destroys the whole point. So I architected a peer-to-peer system over WebRTC that dropped latency to ~500ms and enabled natural interruptions. The right call was to architect for the user’s experience, not the easiest implementation.

3. Intelligence Belongs at the Data Layer

Raw data isn’t knowledge. In Reddit Research I use semantic clustering to deduplicate insights before anything touches an LLM. If 50 people say the same thing in different words, the system recognizes it as one cluster, cutting LLM calls by ~90% without losing signal.

TALON takes this further. Raw government datasets get enriched at the data layer before a user ever touches them, slope, canopy, soil suitability, ownership classification. By the time a user asks ā€œfind me a south-facing lot with mature hardwood,ā€ the intelligence is already in the data, the query is just a filter.

4. Privacy Is the Default

I build local-first whenever I can. Chronicle runs entirely on SQLite with zero cloud dependencies. Prism supports local LLMs via Ollama. Voice Coach’s transcripts never leave the browser. Cloud sync is opt-in, not mandatory.


From Raw Data to Useful Answers

There’s a pattern across my projects: they start by swallowing messy data and end by answering questions about it.

YouTube Knowledge Extractor started as a transcription tool. Now it pulls structured QA pairs and knowledge graphs out of entire channels, output you can actually fine-tune a model on.

TALON does this with government land data. Shapefiles, LiDAR point clouds, soil surveys go in; ā€œfind me a south-facing 10-acre lot with mature hardwood and road frontageā€ comes out the other side as a natural-language query against enriched spatial data.

RepoAudit does it for codebases. Raw source files go through architecture, security, AI maturity, and documentation analysis, and out comes a structured report that catches things a manual review would miss.


Fast and Correct Are Not Opposites

I take problems from concept to shipped product. AI lets me move fast; QA discipline means what I ship actually works. Moving fast is only useful if what you ship holds up, and rigorous engineering is only useful if you ever finish. I’ve built both habits, and they reinforce each other more than they fight each other.