Back

The emergence of Agent-First Software Design

Feb 05, 2026
The emergence of Agent-First Software Design

There's a shift happening in how we build software. For decades, programming meant writing explicit if/else decision trees. Parse this response. Handle this edge case. Chain these steps together. But a new paradigm is emerging where the job of the software engineer isn't to write discrete code for each step, but to give instructions to an AI agent harness and let it figure out the execution.

I’m not interested in talking about whether software engineering is dying or not (at least not right now). Rather, there is a new way to program emerging.

I’ll illustrate this with a recent project…

Over the weekend I built Debra, my email secretary. Like everyone, I get so so so much spam these days that my inbox is basically unusable. I built a Claude Code skill that takes passes at my inbox and archives the junk. It worked surprisingly well, so … let’s automate!

Architecture for my email bot

Debra is an automated email secretary that runs on a daily cron. She fetches my recent inbox, classifies senders, reads and summarizes important emails, archives spam, and sends a morning report. I can reply in plain text to approve classifications or make changes, and the system updates itself via git push.

The Old Way: Discrete Scripts and Brittle Pipelines

This project was completely vibe coded. But, initially, Claude Code steered me wrong.

Claude Code's todo list

The architecture was textbook software engineering:

  1. Write a gmail_client.py to pull emails via API
  2. Write a classifier.py to categorize senders (spam, important, newsletter, etc.)
  3. Write an email_processor.py to read and summarize content
  4. Write a report_generator.py to create the daily summary
  5. Write a main.py to orchestrate the whole pipeline

Each module had hardcoded Anthropic API calls, explicit parsing logic, and rigid control flow. The classifier returned a JSON object with specific fields. The processor expected those exact fields. Everything was tightly coupled.

This is the old way of writing software. Brittle to errors and requires a lot of upfront thinking into each and every path it can take. It’s working AGAINST gravity. We should be letting the model cook, and getting out of its way.

The New Way: Tools + Instructions

The rewrite took a fundamentally different approach. Instead of discrete modules with hardcoded logic, there's now a single agent harness that has access to the tools it needs. For this, I used the headless Claude Code SDK.

Revising the Claude Code plan

The core of the system is a prompt in loop1_daily.py in the form of CLAUDE.md and sandbox files. The agent primarily uses three tools: Bash (to run commands), Read (to read files), and Write (to create files). The prompt tells Claude what tools are available—a set of Gmail scripts for fetching, archiving, and sending emails—and what configuration files exist. Then it describes the goal: process the inbox, classify emails, take appropriate actions, generate a report.

This is the new way of software engineering. Define the problem scope, define the tools needed, and let the agent figure it out.

Our complete solution

When Claude runs, it autonomously:

  • Executes the Gmail fetch script via Bash
  • Reads the resulting JSON file
  • Makes classification decisions based on context
  • Runs archive scripts for emails that should be archived
  • Writes a markdown report summarizing actions taken

The key insight is that the agent maintains context across all these steps. It understands what it fetched, why it classified something a certain way, and what actions it took.

Now we update the prompt, not the architecture

The power of this approach became clear when dealing with expired Gmail tokens. In a traditional system, handling auth errors would require:

  1. Adding try/catch blocks around API calls
  2. Writing a check_auth.py script to detect token status
  3. Creating a fallback flow when auth fails
  4. Generating a different report type for auth failures
  5. Testing all the new code paths

Instead, the solution was to add a few sentences to the orchestrator prompt:

If you encounter authentication errors like "Token has been expired or revoked" or "invalid_grant", do NOT continue processing emails. Instead, generate an auth failure report explaining the issue and instructing the user to re-authenticate.

No new code. No new modules. No parsing logic. The agent reads the error output from the Gmail scripts, understands what it means, and adapts its behavior accordingly. It figures out how to detect the error, decides to stop processing, and generates an appropriate report—all from natural language instructions.

I can imagine all coding looking like this: instructions over if/else trees. It’s easier and way more robust to changes.

Future-proof your code for model improvements

The most compelling argument for agentic engineering is what happens over time. Traditional code doesn't get better on its own. The if/else trees you wrote five years ago work exactly the same today… maybe even worse if user behavior changes.

On the other hand, models and agent harnesses are getting better at an insane rate. If you are an AI Engineer, you are probably rewriting code every few months with each shiny new agentic idea.

Write software to take advantage of upcoming AI releases. Prepare for future models instead of locking into brittle coding logic.

This is a form of future-proofing that traditional software doesn't have. You're not encoding solutions; you're encoding problems. And as models get better at solving problems, your systems benefit without code changes.

I can see a future where every application is a long-running agent, and all coding is in the form of instruction writing.

The first platform built for prompt engineering