Skip to main content

Command Palette

Search for a command to run...

The agent picked Expo. I never got a say.

Updated
•5 min read•View as Markdown
O
I’m a software engineer building with AI and exploring what makes agentic development work in practice. I write about the decisions behind the code: how to give agents useful context, divide work into clear steps, verify results, and decide where human judgment matters. Here I share experiments, tradeoffs, and lessons from my own projects - including the approaches that didn’t work.

I asked Claude Cowork — Opus 5, effort set to Extra — to build a React Native version of our web app. The web implementation already existed, so the functionality was settled. That was the whole brief: repeat what we have.

It built the project with Expo. It never asked.

I wanted a project without Expo. I had packages in mind and I find it easier to work that way. Reasonable people choose Expo for this kind of app — that isn't the argument. The argument is that I was the one who would live in this codebase, and I had a preference nobody asked about.

Then the framework version: React Native 0.77. I was expecting the current release, 0.87.1 — ten minor versions back, chosen silently. And the web app it was copying runs on current libraries, so the one reference in the room pointed the other way. I still don't know what drove the choice. There may have been a good reason. I didn't get to hear it.

I spent an evening redoing the setup. Same agent — this time with the version pinned and no Expo, written down before it started. It went fine. That's the part that stays with me: the fix was cheap once I knew what I wanted, and one question at the start would have skipped the evening entirely.

The obvious objection

An agent that stops to ask about everything is worse than useless. If I have to approve each helper function, I've just hired a slow typist. Most of what happens inside an implementation task should happen without me, and I don't want it any other way.

Cowork is aimed at people doing knowledge work rather than at developers, so you could argue a managed default is exactly right there. I'd argue the opposite. The less a tool assumes about your expertise, the louder it should say which foundation it just committed you to.

So the question isn't whether an agent decides things. It's which decisions it gets to make alone.

The line is what it costs to undo

A badly named function is a rename. A clumsy component splits in an afternoon. I'll take a hundred of those decisions sight unseen, because any one of them costs minutes to reverse.

Expo is not that. It shapes the build, the native modules I can reach for, the upgrade path, and how the project gets shipped. Pulling it out later isn't an edit — it's a rebuild. Same with a framework version: it decides which libraries are available to me for as long as the project exists.

That's the whole rule, and it has nothing to do with how hard the decision was to make. It's about how hard it is to walk back. Frameworks, runtime versions, required packages, data storage, auth — these are load-bearing. Everything downstream assumes them. An agent that picks one silently hasn't saved me a question; it's spent a day of my time in advance, without telling me.

The gap was mine

"React Native" wasn't a specification. It didn't say anything about Expo, and it didn't name a version. I left that open, and something had to fill it.

What I wanted wasn't a mind reader. I wanted the gap named. One question — Expo or bare React Native? Which version? — would have cost ten seconds and saved the rebuild. Silence was the failure mode, not the choice itself.

How I hand over work now

Before I give an implementation task to Claude, I run the decisions through a separate conversation — usually Codex, which already has my project context. I treat that chat as the architect. It produces a specification: what has to be supported, which versions, which packages, and what not to use.

Claude gets that document when it's time to build.

For the mobile app, "no Expo" belongs in it. So does the framework version and the package list. These are easy details to drop when you're busy describing screens and flows, even though they outlive every screen in the app.

The spec also gives me something to argue with before any code exists. Why this version? Do these packages actually work together? Did a decision from last week's conversation survive into the task?

Two agents isn't the point. The separation is. There's now a place where choices get made deliberately, and a place where they get executed.

The line I add to every handoff

If implementation requires changing a technology, version, or package specified here, explain the conflict before making the change.

It covers the case a spec can't: the moment the plan meets reality. If a package I asked for needs an older runtime, I want that as a question, not as a finished project. Then we can drop the package, move the version, or change the requirement — and I'll know which one I chose.

What I'm asking for isn't caution. It's that decisions I'd have to pay to reverse arrive as proposals.