Warning: Mammoth post ahead
…
Estimated reading time: ~6 mins, or around 0.000014% of your life.
If you’ve been using Cursor for a while, and started to get into more complex projects with it, you’ll almost certainly have come across the challenges of keeping things on track.
It’s not something specific to Cursor of course, it tends to be the nature of AI-assisted coding in general. Small context easy, big context hard. The models have come a long way, but in general humans still tend to do better at knowing what actually belongs in the bigger picture.
Ok, but what is this post? Why would I read it?
I’ve been using Cursor (and other LLM tools) for over a year, so I figured I’d share some of the tricks that have helped me to handle some larger projects. YMMV, but hopefully this might help some folks to squeeze some extra juice out of the AI-assisted orange.
1. Use Composer
Chat’s great for those little quick questions and asides, but (at the time of writing) it doesn’t checkpoint like Composer does. In case you haven’t spotted it, Composer checkpoints your conversation. If things are going sideways, or you’re spending too much time on bugfixes, you can easily track back to an earlier known-good state before the model started mangling your code.
2. Git, git, git
Git. Not everyone loves git. Some parts of it are hairy-scary. Thankfully most of it is abstracted away by VS Code and so the scary bits you won’t have to touch. But if you’re not using it, and I mean frequently, you’ll eventually hit a moment where you discover a mis-applied diff obliterated one of your files a while ago, and it’s too late to turn back the clock.
Storage is cheap, so commit little and often. Don’t fall into the trap of waiting until your project is perfect before you commit, because it almost never is. Git commits are not milestones worthy of a fanfare, they’re handy little checkpoints. Learn how to turn back time, and it’ll save you hours of heartache.
3. Introductory prompts
If you want the model to love decoupling and encapsulation, tell it that it does. If you want it to be an expert in the tech you’re using, tell it that it is (I’ll explain down at the very bottom why). I usually start every Composer session with some boilerplate that encourages good coding practices – you can even find some of these shared online – and if it starts to drift away from that as the context blurs, I start a new session.
3b. Notepads
If you don’t have a notepad describing your goals, and have it permanently stapled to your Composer context, you’re seriously missing out. This one should be considered pretty much essential for any project worth more than a handful of queries, as it’s easily the best way to keep the model on track and well-“motivated”.
4. Shorter Composer sessions
The temptation (a bit like putting off your git commits) is to wait for something to be “just so” before you move on to the next topic and session. But if wayward issues and bugfixes derail your coding, you can end up with very long Composer sessions.
From my experience, not only do these make the UI very sluggish, they also degrade the quality of the output. My most joyous experiences with Composer tend to be near the top of a session, and the hair-pulling parts tend to be when the session is getting too long – that’s when the hallucinations and the circular changes happen (“Ah yes, A will not work, you must B [applies]”; “Ah yes, B will not work, you must A”; repeat). You can also spot this when the model starts spontaneously answering an earlier question instead of the one you just asked…
Get used to going again in a fresh session: re-paste your enthusiastic boilerplate, explain where you got up to and what’s broken, and continue with better, cleaner results.
5. Demand a plan
My most successful sessions tend to follow a standard format:
- Throw in the boilerplate prompt about how great the AI is at the chosen languages and libraries
- Explain the high level view of the system
- Explain what you want to achieve next
- Tell the AI not to code yet, but to summarise what you’ve said, and then output a plan for greatness. Take a copy of this and be ready to paste it back into conversation if the context seems to be degrading.
Then every prompt or every few prompts, request that the AI replies by:
- Explaining in detail what it’s going to do next, being clear about the logic, how a good solution should work and why it’s a great idea (this leads to better code quality in my experience)
- Making the code changes
- Recapping the plan and articulating what’s next
Going through this cycle of making the AI explain itself and recap the plan seems (seems, YMMV) to keep the bigger picture fresher in its most recent context and stop things getting all mangled.
PS: Also consider pasting it into a Notepad and including that in your context, because life is short.
6. TDD
You’ve heard of Test-Driven Development right? If you’re a CompSci type, you may recall it as that thing you feel like you’re supposed to love, because you can demonstrate that your code isn’t broken and it meets your functional spec. Enumerate your assumptions, write the tests, then write the code to make the tests pass.
It’s the same thing that on smaller projects will have many coders go “ehhhhhh… I just want to write the code: writing the tests is going to make everything take twice as long”. It’s also often tedious as ****. And of course many folks then develop a habit of skipping it, because life is short and who has the time, right?
BUT: AI!
This was a pretty big revelation when I started trying it out. For mid-sized projects, go through the initial descriptive tests, but don’t ask the AI to write the code for you, ask it to write the tests. It’s traditionally the boring, time consuming bit, the part that humans hate and AI is pretty darn good at (most of the time).
Make your initial conversations code-free, explore the topic and the system design, get the model to describe an ideal system for you, and then tell it to generate the code structure but with most of it mocked up or left as “TODO”. But then make it write the unit (and later integration) tests for you.
Then when you start to get into the code proper, not only can you point out the model’s failings by pasting the failed tests back at it – much easier than convincing it to understand your hand-wavy description – but also the AI always has the test harness to read, which is a great way to keep success criteria fresh in its context. It’s machine-readable, unambiguous and describes your desired system behaviour, and it’s always there to verify your assumptions.
For me, taking this approach has enabled a lot of AI-assisted work that might otherwise have been too complex for straight-ahead coding.
Final thoughts
Phew, this turned out to be a lot longer than I expected. If you got this far, congratulations, have a GDPR-compliant cookie.
One last comment about what the AI is doing for you, and then I promise I’m done.
It’s this: don’t forget that LLMs are essentially sophisticated automated con-artists with access to a lot of training information. Their only trick is to tell you what they “think” you want to hear, and they will do whatever it takes to keep up the illusion that they’re actually intelligent.
It’s why you get hallucinations (for fun, try asking ChatGPT which specific episode of your favourite TV series has a particular character wearing a bright blue jacket – it’ll make up almost anything to sound convincing).
It’s also why telling them they’re experts kinda works. They will respond in a way that sustains the illusion, choosing words (and syntax) that would be consistent with an expert response. And why sometimes it can even help by telling them to go slowly and take their time. They don’t actually take any longer to respond. But sometimes you get higher quality answers, because they’re more in keeping with what a careful, methodical expert would say – again to preserve the illusion.
Okay, I’m done for real. Hope this ends up being useful to at least one person using Cursor for AI-assisted coding, or at least gives some AI-related food for thought. If it did that for you, feel free to leave a Like, or maybe even reply with your own tips to help bump it up on this busy forum.
PS: The title isn’t me being rude to you. The idiot is me.
Addenda et Corrigenda
- Don’t say “yes”. Based on bitter experience, if the model says “Would you like me to go ahead and implement that for you?” and you answer “yes”, you have a non-zero chance of it leaping back to an irrelevant part of the conversation and trying to relive that moment. Always give a clear instruction like “yes, please go ahead and implement the changes you have just recommended” to save yourself the bafflement and burnt credits.
- Do demand debug logging. If things aren’t working out properly – and especially if you get into the dreaded “Don’t do A, do B; Don’t do B, do A” loop – tell the AI to put in vast amounts of debug logging, and then paste those logs back to it wholesale. The models’ capacity for reading pages of tedious logs to spot the one tiny error is definitely superhuman. It’s usually a pretty good way to highlight to the model where it’s made an incorrect assumption. Sometimes even the act of making the model include the logging can cause it to fix elusive bugs, much like “talk me through your steps” works with a junior dev.