I’ve heard “AI is going to replace developers” so many times this year that I now respond with a screenshot of my terminal. Three Claude Code sessions, four background tasks, an MCP server talking to Playwright, and the spinner is busy. Nothing about that workflow looks like one button labelled “write the app.”
This is the part that’s actually interesting — not the marketing claim, the day-to-day pattern. Here’s mine, in the form it’s settled into after eighteen months of iteration.
Table of contents
Open Table of contents
The setup
- Claude Code is the agent that touches files, runs commands, reads logs, and asks me questions when it’s stuck.
- ChatGPT is the second opinion. No filesystem access, no commits — just a smart pair to bounce ideas off.
- Dev containers are the guardrail. Every project runs Claude inside a Docker container with a strict network firewall and a clean filesystem mount.
- MCP servers are the bridges. Playwright, Cloudflare, MySQL, custom internal APIs — each exposed to Claude as a tool.
The interaction model: I type natural language, Claude does the typing. If Claude needs context, it reads files or runs commands. If it’s about to do something destructive, it asks. If it produces something wrong, I correct it and the correction goes into memory.
The one rule
AI writes the first draft. I read every line that ships.
That’s it. That’s the whole rule. Everything else — sub-agents, tool calls, model selection — is just how to make the first draft good enough that reading it is worth the time.
What this rule rules out:
- Shipping code I haven’t read.
- Trusting the agent’s summary of what it did. (
git diffis the truth.) - Letting the agent click “merge” or “deploy.”
What this rule rules in:
- Letting the agent run tests, linters, and type checks unattended.
- Letting it draft entire features, migrations, README sections.
- Letting it refactor across files I haven’t manually opened.
How a feature actually gets built
Walk-through of a feature I shipped last week — an iCal export endpoint for our event-ops platform. About two hours, start to finish.
1. I write a one-paragraph spec in chat. “Add /api/v1/schedule.ics that returns the workspace’s events as a VEVENT feed. Scope by workspace_id from the JWT. Respect timezone from workspace settings.”
2. Claude proposes a plan. It reads src/api/routes/, sees the existing route pattern, sees the auth middleware, and proposes the file structure. I approve.
3. Claude implements. It writes the route, picks an ical library, wires it up, and writes one happy-path test. It runs the test. It runs the type checker.
4. I read the diff. Three small things to fix: the date format wasn’t UTC, the SUMMARY field wasn’t escaped, the cache header was wrong for a feed. I tell Claude.
5. Claude fixes. Re-runs tests. Re-runs types. Done.
6. I push. No commit goes up that I haven’t read. Claude doesn’t push.
That’s the whole loop. The agent is fast. The agent is also wrong often enough that the reading step is non-negotiable.
The MCP layer
The thing that turned this from “fancy autocomplete” into “actual workflow” is MCP. Every external system Claude needs to talk to is a server. Two examples:
# Playwright MCP — Claude can drive a browser
npx -y @automatalabs/mcp-server-playwright
# Cloudflare MCP — Claude can deploy + manage CF resources
npx -y @cloudflare/mcp-server-cloudflare
Once those are running, Claude can:
- Verify a UI change by clicking through the app at 375×667.
- Run a Lighthouse audit and read the result.
- Check the live deploy logs.
- Run a SQL query against the dev D1 database.
All without me copy-pasting anything. Claude’s reach goes from “files in this repo” to “everything I trust it with on my laptop.”
The dev container guardrail
Letting an agent run shell commands at will is genuinely terrifying without a sandbox. So every project I work on has a .devcontainer/ with three properties:
- Filesystem isolation — only
/workspaceand a few specific mounts. Nothing else of mine is visible. - Network firewall — only a whitelist of domains (npm, GitHub, Anthropic, the specific APIs for that project). Even if the agent tries to exfiltrate, it can’t reach the destination.
- No credentials by default — secrets are passed explicitly when needed, never baked into the image.
The trade-off: a small upfront setup cost. The payoff: I run Claude with --dangerously-skip-permissions inside the container and trust that the worst it can do is mess up the container.
If you want to copy mine, the claude-sandbox template is on GitHub.
What I’ve stopped doing
The biggest shift isn’t what I added. It’s what I stopped doing:
- Stopped writing boilerplate. Routes, migrations, types, fixtures — Claude does the first 80%. I don’t even open the file.
- Stopped writing commit messages by hand for routine work. Claude drafts; I review.
- Stopped doing post-PR cleanup. Claude does it on the same loop as implementation.
- Stopped writing exhaustive prompts. The agent has memory of how I work. “Add a button that…” lands a lot closer than it used to.
What still matters
You. The reader.
The agent is fast at producing code. It’s not good at deciding what to produce. Every system I build still starts with me thinking about the right problem to solve, the right interface for the user, and the right shape of data underneath. Claude is a force multiplier on execution. It is not a force multiplier on judgement.
If you want the platform side of the story, the Cloudflare-native systems post covers the other half of how my stack composes.