Last week I built the first draft of an app. I used LLMs to write all the grind parts of it. This was the result of a formalisation of methods for coding with LLMs over the past few years brought to bear to smoothly execute a new app from the ground up.
Dependent on the tempo or phase within a project, I feel like I can now defer over 50% of written code to an LLM, leaving me to act as reviewer and giving me more time to think about my intentions and potential iterations.
This is incredible. And it requires revising my approach to coding. Paying attention to the phase and tempo was always important, but now that I can offload most of the coding work, holding the shape of intention and possibility in mind is the thing.
Here are some strategies and tactics for doing this, which I’ll then elaborate on:
Strategies:
- Clarify your thinking with LLM criticism
- Choose between speed vs. thoroughness
- Use reasoning models for architecture
- Use workhorse models for general code
- Manage the context window
- Recognise that you are the bottleneck
- Track your original questions
- Don’t anthropomorphise the LLM
- Make time to keep up with the scene
Tactics:
- Always speak to the computer in applicable contexts
- Use specific tools (Cursor/Windsurf)
- Use Warp as a terminal with LLM integration
- Follow the “be terse” rule for context management
- Write product overviews at project start
- Add feature summaries to project rules
- Maintain a changelog
- Supply the right docs
- They find JavaScript easy but CSS hard
- Take breaks to maintain perspective
Note that most of what I’ll address here is hopefully general for LLM coding but also probably quite specific to a developer who already knows a stack quite intimately (for example, mine is web apps). I didn’t discuss anything related to prototyping UI with v0 or Bolt, nor about working with brownfield projects (I’ve recently done this, post coming), both of which have their own specific methods.
Write down what you’re trying to make. Then ask an LLM to criticise it. Use it to clarify your thinking.
Do I need to be right or fast? Be explicit about your next question in terms of speed vs. thoroughness. This is the essential determinant for every request. Pay attention to the tempo and the phase you are currently within.
Use a reasoning model to think about architecture. This kind of thinking always benefits from immersion and time and sometimes it’s hard to even stop. Reasoning models can give you a leg up in a matter of minutes. o1, Grok 3, etc.
Use a workhorse to write general code. That is, anything from small bugs through to a small feature. Sonnet 3.5 is great. Sonnet 3.7 is currently too conscientious!
The context window is important. If you have a long chat, you’ll have a large context window. The effectiveness of your discussion will decrease. It’s that simple. This indicates you haven’t done the work to think about what you’re doing.
You are the bottleneck. As context windows continuously increase, you are the bottleneck. And you always will be. If you haven’t retained an understanding of the current situation, then you are Mickey Mouse on Bald Mountain, heralding forth an army of broomsticks to flood your codebase and your comprehension.
Record your original question. No matter what, sometimes you’re going to lose track of what’s happening and what you’re trying to do. That’s part of being human. Nothing wrong with it. Feel free to delete the code (you kept your Git clean, right?) and start again.
Don’t anthropomorphise the LLM. It’s awesome auto-complete, not a person. You’re not being judged, and no one’s watching you, so feel free to ask dumb questions. If you get frustrated with the LLM, pay attention to that, take a break and start again.
Keep up with what’s happening. Take note of what other people in your scene are doing and make space to test it out yourself. Sure, there’s a huge amount of noise but small experiments are easy and sometimes they pay off.
Speak to the computer. Typing is too slow. Because this was new for me, I found it hard to bother trying. Then it became a game-changer. I use this app. You’ll find you want to speak to it in every app, everywhere.
Use an LLM-enabled IDE. Cursor, Windsurf, Cody, whatever. It doesn’t matter so long as you find an IDE with built-in LLM support that you like and stick to it long enough to build habits. Personally, I use Cursor with Warp as my LLM terminal so I don’t have to remember grep.
Write your global rule. This one is good for web apps. “Be terse” is most important because, most of all, you have to manage the context window in your own head.
Write a product overview. Write a bare bones project overview at the start. Describe the app and its purpose and list your tech stack. Then don’t worry about it. If you find recurrent problems with your LLM code, update it.
Add feature summaries as project rules. Once you’ve completed a feature, write a summary (or ask your LLM to). Note the flow, the gotchas, what files used and add that to your project rules.
Use a changelog. As you start to compile features and your application grows, it’s useful to have a change log that you can give to the LLM and yourself to help keep on track and not solve problems twice.
Supply the right docs. Yes, you can supply URLs for crawling but sometimes you have to do more than that. Whether that’s for libraries or surrounding code, you may need to provide specific documentation for an LLM. I use Repomix as an IDE plugin or RepoPrompt’s code map feature. Keep it under 32k tokens!
LLMs find JS easy but CSS hard. I find that if I have issues with grid
or something like that, an LLM will fail abysmally and repeatedly. Maybe it’s because I really struggle to articulate those visual layouts in words and I’m mostly sticking with chat, not prototyping tools like Bolt, but I find CSS much easier to write myself.
Take a breath. Checking where you are in the process is how you prevent yourself from getting emotional with the AI. If you ask an LLM for text, it goes brrrrrrr. If you’re lazy and unintentional with those asks, you’ll get Mickey’s broomsticks swamping the basement of your mind in no time. You don’t want brrrrrrr, you want understanding and solutions. You are the bottleneck to that.
As my strategies and tactics have formalised, and given new models and better interface tooling for their use, I feel more capable and productive. When I consider new ideas, I have more confidence to think bigger about complex UIs that previously I’d have postponed for fear of complexity and scope. I’m also thinking more about the product and less about the code.
Undergirding all of this—much the same as any attempt at excellence—is humility. In order to use these large language models effectively, one has to let go of one’s identity. Brian Eno always called himself a “non-musician” and that allowed him to think freely about generative systems for creativity. The same applies here.
I think the best general metaphor for AI is as a mirror: it reflects back whatever you want. If you’re a hacker who treats their codebase like a toy train set, you may dismiss LLMs instinctively. Likewise, if you’re a designer who knows CSS, you may hit walls with LLMs quickly. In both situations, it pays to understand AI as the mirror on the wall showing you your reality faster than you anticipated.
How will you respond?
Topics: