How the Agent Thinks
Most AI coding tools start typing within 500 milliseconds of your prompt. It feels responsive. It feels fast. It also produces some of the worst code written this decade.
We built the Appsanic agent to do the opposite. When you give it a prompt, it pauses (sometimes for ten seconds, sometimes for thirty) and thinks. No code appears. No files open. You see a plan.
That pause is deliberate, and it's the best part of the whole build.
The failure mode of typing first
If you've watched enough AI coding demos, you've seen this sequence: prompt goes in, code comes out, the UI streams characters dramatically, and in a minute you have something that runs. The first impression is magic. The second impression, fifteen minutes later when you try to actually use what was built, is different.
The thing that went wrong wasn't the writing. It was the thinking that didn't happen before the writing.
A real feature touches a codebase in many places. A "friend system" isn't one component. It's a database table, a list of invite states, a screen to search for friends, a state manager that tracks pending requests, an analytics event, a push notification handler, and at least three edge cases you haven't thought about yet. If the agent types first and thinks later, it starts with the screen, improvises the data shape as it goes, adds a second screen that quietly assumes a different data shape, and by file seven the system has fought itself into a corner it can only escape by backing out everything and trying again.
Code that types itself without a plan is the computer equivalent of a contractor who starts framing walls before looking at the blueprint.
What the agent considers during planning
The planning phase isn't abstract. The agent walks a specific checklist before it writes anything. The checklist is the same whether the prompt is tiny or huge, which is why Pro's plan for a small change still feels structured.
The existing system. What screens already exist? What's in the navigation? What components are already built and reusable? What's the name of the auth store and what shape does it expose? Is there a design system or a loose collection of one off styles? Is there a pattern for error handling, or a free for all? Repeating the wrong convention is one of the most common ways AI generated code becomes unreadable, and the first defense is looking at the conventions that are already there.
The data shape. What tables does this feature need? What columns? What relations? If a table already exists and the feature extends it, the agent prefers an additive migration over a replacement. Row level security policies get specified here too: who can read what, who can write what, what's enforceable in the database vs. the client.
The flows. How does a user enter this feature? How do they leave? What happens if they navigate away mid flow? What's the empty state, loading state, error state? These are the edge cases that separate apps that feel real from apps that feel like demos, and they're almost always missing from a one line prompt.
The connectors. Does the feature need Stripe? Resend? Push notifications? Realtime subscriptions? Google Maps? Sentry? If yes, is the SDK already configured? What API keys need to flow through, and should they live in env vars or the Supabase secrets table? These are decisions, not implementation details, and the agent makes them once at the start instead of ten times across files.
The ambiguities. What did the prompt not say? The agent keeps a running list of choices it had to make on the user's behalf and surfaces them. "I assumed invites expire after seven days. Let me know if you'd prefer a different window." "I wired friend requests to push notifications but not email. Say the word and I'll add email." Ambiguity resolved once at the plan stage beats ambiguity discovered twenty minutes in.
Three plans, walked through
Let's look at plans the agent actually produced, ordered by prompt complexity.
Plan 1: small, localized
Prompt: "Add a daily habit reminder that notifies me at 8am."
- Schema: new
habitstable withid,user_id,title,notification_time(atimetype, local to the user),created_at. RLS so users can only read and write their own habits.- Screen:
HabitSettings.tsxat/app/(tabs)/habits. Lists habits, lets user add or edit one, picks notification time with the native time picker. Empty state: "Add your first habit to get a daily nudge."- State: new
habits-store.tsZustand slice. Optimistic updates on mutations, revert on error.- Push setup: registers on first habit creation if not already registered. Handles the "permission denied" case gracefully.
- Scheduler: on create or update, schedules a local notification via Expo's API. On delete, cancels it. Stores the scheduled notification ID on the habit row.
- Edge cases: user changes timezone (reschedule on app launch), permission denied (save time anyway, badge the habit with a warning), time in the past (schedule for tomorrow).
- Navigation: add a "Habits" tab with a bell icon.
Notice what the agent flagged that the prompt didn't mention: timezone handling, permission denial, the "time in the past" edge case. Those three alone typically save an hour of post launch debugging.
Plan 2: medium, touches multiple surfaces
Prompt: "Users should be able to comment on each other's posts."
- Schema:
commentstable withid,post_id(FK toposts),user_id(FK tousers),body(text, max 500 chars),created_at. Index onpost_idfor fast retrieval.- Feed screen: inline comment count pill on each post card. Tap navigates to post detail.
- Post detail screen: new. Renders the full post, then a scrollable comment list, with a text input pinned to the bottom (auto adjusts above the keyboard).
- Realtime: subscribes to
commentsvia Supabase realtime when the post detail is open. Unsubscribes on unmount. New comments animate in.- State: new
comments-store.ts. Methods:fetchForPost,create,delete(soft delete, we'll keep the row withdeleted_atso replies still resolve).- Moderation: add a "Report" long press action on each comment. Creates a row in a
reportstable we'll also add.- Notifications: when user A comments on user B's post, B gets a push notification (if enabled). Don't notify A about their own comments.
- Edge cases: deleted post (comments should fail gracefully if post is gone), optimistic insert (show the comment immediately on the author's screen, revert if the insert fails).
What's new here vs Plan 1: realtime subscriptions, a moderation primitive, cross user notifications, soft deletes. Each of those is a decision the agent committed to upfront. If you disagreed with any of them (say, you don't want notifications at all), the moment to say so is right now, before code starts being written.
Plan 3: large, ambiguous, cross codebase
Prompt: "I want to add a payment system for digital goods. Users should be able to buy onetime purchases and subscriptions."
The plan for this prompt is 28 bullet points, but the structure is the same:
Schema. New
products,one_time_purchases,subscriptions,webhook_eventstables.Stripe connector. I'll configure Stripe Checkout for both onetime and recurring. We'll use Stripe's hosted checkout, not embedded, because PCI compliance is simpler. I'll store Stripe product and price IDs in
productsand webhook the subscription lifecycle events intowebhook_eventsfor auditability.Screens. Storefront, product detail, purchase success, subscription management.
Entitlements. A
has_access(user, product_id)helper on both the client and the server, used to gate content.Webhooks.
/api/stripe/webhookroute. Handlecheckout.session.completed,invoice.payment_succeeded,invoice.payment_failed,customer.subscription.deleted. Each writes towebhook_eventsfirst (idempotent via Stripe's event ID) before mutating domain tables.Edge cases. Failed payment (a fixed grace window that cannot roll forward with a new period), refunds (reverse only the entitlement tied to the refunded payment), price increases (Stripe and the entitlement ledger share one exact proration timestamp), price decreases (schedule at renewal), repeat webhook delivery (idempotency key on events).
Things I'm not doing unless you ask. Tax calculation (Stripe handles US and EU basics, anything else is your call), coupons or promo codes, team or family subscriptions, gifting.
The last bullet is the quiet superpower. Large features always have a surrounding cloud of "could we also…" features, and Pro surfaces them explicitly rather than silently skipping them. You get to say "yes, also add coupons" or "no, that's scope creep" while the decision is still cheap.
How to make the agent's plans better
The quality of the plan tracks closely with the quality of the prompt. Three things reliably help:
1. Describe the user facing outcome, not the implementation. Bad: "Add a button that calls an API." Good: "When a user taps 'save draft,' the entry should persist locally so they can come back to it later, even offline." The first gets you a button. The second gets you a feature, because the agent now has enough context to make ten decisions you didn't mention.
2. Give scope constraints. "Don't change the existing auth flow," or "keep the current color palette," or "this should work on both the mobile app and the web dashboard" prevents the agent from taking the prompt as license to redesign surrounding things you didn't ask to change.
3. Name what you're unsure about. If you say "I'm not sure whether this should notify via push or email," the agent will propose both options and ask you to choose at the plan stage. If you stay quiet, the agent picks one, and the wrong pick is only discovered at the "code written" stage.
The best Appsanic prompts tend to read like concise briefs to a senior engineer: two to four sentences of intent, constraints, and uncertainties. They're not five word imperatives, and they're not thousand word specs.
The economics of thinking
Planning costs tokens. Pro uses meaningfully more of them than Fast. This is part of why Pro costs roughly 5 times per request. Reasonable question: is that worth paying?
On Pro's hardest requests, the longer planning pass reduces follow up corrections by 60 to 70%. Net: Pro finishes complex features with far less back and forth, and our measurements show it lands inside a 5 to 10% credit band run-to-run where Fast varies 20 to 35%. You pay more per request and get back predictability.
The framing that matters isn't "tokens spent thinking" but "tokens spent building a working feature." Every second the agent spends thinking is a second you don't spend reviewing, explaining, and asking it to try again.
What this means for you
If you've used Appsanic and noticed the moment where the UI says "The agent is planning…", that's not loading. That's the most valuable thing the agent does all session. Don't skip it. Don't rush it. The plan is where the bugs that never reach your codebase are caught.
We built an engineer, not a typist. This is what the difference feels like from the outside.
