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:

  • Frontier models for hard architectural calls and deep refactors
  • Fast models for autocomplete and repetitive patterns
  • Local/self-hosted models for privacy-sensitive codebases and offline 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.

evalharness applies the same instinct to AI systems. An eval harness is a test suite for a nondeterministic system, so I built one the way a test-framework engineer would: every score is a deterministic pure function, baseline runs are committed to git and gate CI like any other regression test, and a retrieval improvement doesn’t get promoted until it survives a held-out split. Most eval tooling asks an LLM to judge quality; mine treats ā€œthe numbers must be re-derivable by anyone, foreverā€ as the non-negotiable starting point.

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 Five 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, the standard voice pipeline (speech-to-text, then LLM, then text-to-speech) meant 3-5 second round-trips, a dealbreaker for a conversation simulator: a 3-second pause in a sales call destroys the whole point. No amount of tuning fixes a pipeline that’s structurally too slow, so instead of stitching one together I built the app around OpenAI’s Realtime API over a direct WebRTC connection, with the backend reduced to minting ephemeral tokens. That got ~500ms responses and natural interruptions. I didn’t invent the transport; the engineering was recognizing which architecture could actually serve the user’s experience and committing to it early, rather than shipping the easy version and hoping.

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.

5. Every Dependency Is a Liability

A package isn’t free code, it’s a commitment: its bugs become my bugs, its transitive dependencies become my attack surface, and its maintainer’s account security becomes my problem. One npm install can pull in hundreds of packages I’ll never read, and supply-chain attacks target exactly that blindness. So before I add a dependency, the question isn’t ā€œis there a library for this?ā€ but ā€œwhat does this buy me that a hundred lines of my own code doesn’t?ā€

Sometimes the answer is a lot: I’m not writing my own PostGIS. But my browser tools (JSON Viewer, CSV Viewer, Markdown Viewer, Apex Log Parser) are single-file PWAs with no framework and no build step; JSON Viewer and the Apex Log Parser run on zero runtime dependencies outright, and the others pull in only the focused libraries they exist to wrap, like PapaParse and marked. SF Assistant is a full RAG system in pure Java, right down to a dependency-free test harness running 1,000+ tests, because JUnit would have broken the constraint the whole project was built to prove. Fewer dependencies means less bloat, fewer breaking upgrades, and a supply chain short enough to actually audit.


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.

Classifieds Briefing does it with classified listings. Six regional markets get scraped daily, scored against a tuned buy box, and audited by Claude; what comes out is a briefing that answers the only question that matters: what’s worth driving to see.

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.