Here are some key things that I've found working with Cursor that have really helped take it to the next level.
- Ensure that you have a well written .cursorrules file. Cursor Directory has some great starting points.
- The @Docs is crazy powerful. Cursor may not have indexed the version of the dependencies required. Using
@SomePackageDocs
vastly improve the accuarcy of code generation related to a depenency. - @web is also a very strong tool, but doesn't get added by default when using Cursor's composer. While you may not always need
@web
, its very useful for more obscure implementations.
The most important thing by far is cearly articulating what you want to do. The more well defined your requirements the less deviation from the request will happen. I've added a prompt example.
Think of talking to the LLM like your talking to a evil genie. It's going to find the best way it can think of to do exactly what you asked it to do, this includes taking short cuts and doing the bare minimum required to solve your problem. Specificity is your friend and ally. While you might have to write longer prompts you are still creating far less keystrokes then writing code typically.
Cursor is superpowerful, but that doesn't mean that it knows everything or understands your intent 100% of the time. What I've been doing to combat this is a concept of feature.spec
file. These typically live within a directory directly related to a specfic feature and is used to when I want to modify existing functionality across multiple files.
I've found that only using the composer with no guard rails, LLMs can get a bit agressive in how changes are made and in some cases can remove existing functionality unexpectedly. These guard rails ensure that all requirements are met even when doing complex changes.
If you are using the Cursor composer be sure to either add the file or @TwitterFeature.spec
to insure that the requirements are there, then clearly defined the changes you'd like to make. Example
After making making changes I highly suggest updating your specfile. This can be done via the composer with @spectfile - update the spec file based on the changes made
Lets say I wanted to modify the existing TwitterUser
type to include a new property called lastLogin
. First I'd open the composer(full screen) and give it the following prompt @TwitterFeature.spec - modify add {lastLogin:string} to the TwitterUser type
. Once I approve the changes that are made the next prompt I'd run would be @TwitterFeature.spec - update the spec file to account for the changes to the TwitterUserType
- Sometimes LLMs/cusor like to be a cheeky little fuck. This is very true when your doing very complex changes where the context window is quite large - sometimes you wil LLMs/Cursor replace existing functionality with
// exiting functionality
- I kid you not. Be aware of this. - Writing test seems to be a wild card. I'm still trying to find the best way to write test to do unit testing. E2E testing is even more complex, I don't suggest it right now.
Exmaple prompt to write unit test.
Write a unit test using Jest to test the generateFakeTwitterMessages functionality. You should test all positive and negative test possible. This includes srings, arrays, objects, numbers or anything else you can think of.
- Testing IMO is much more important now that when writing code by hand. LLMS like to take short cuts and this may alter existing code to implement the changes you have asked it make. Example
- Review the changes before approving them.
in this next image you can see that it made changes that I didn't directly request
And here is a unexpected change where
./index.ts
exports have changed