My current advice for making the machine write code/solve problems for you successfully, condensed:
First, use Claude Code if you can. It's the best at this and has been for some time. It leverages the terminal, terminal tools, and the fancy markov chains to work in a way that feels familiar to people who are terminal users.
Second, you must always remember it is a machine. It does not think. It is closer to the "do what I mean machine" than it used to be, but it is still a markov-chain-shaped intern that does what we tell it to do mindlessly. Garbage in, garbage out. Interrupt it ruthlessly without sentiment if you figure out it's heading down the wrong path.
Third, context is everything. The context window is how many word-tokens about the problem space the model can consider. Roughly, token counts map to context size. Hard problems benefit from models or providers who give you lots of context to work inside. BUT! You can also use different models for different parts of a task! And here's the crucial insight:
Nothing is one-shot. Do everything in plan-then-act cycles. You have to specify what you want to get done clearly, and you have to work with the robot to make a plan for how to do it. When you're happy with the plan, you tell it to act.
- Describe the change you want to make in the system, at a high level, the way you would in a project plan.
- Use clear and precise language.
- Describe what you want, not what you don't want.
- Use Claude's plan mode with a model like Opus 4 with lots of context.
- Refine the plan until you're happy.
- The best plans can be done in stages. Context windows always limit you, so work inside them.
- Execute on the plan one stage at a time with a model like Sonnet 4. (Opus 4 works great here if your access to it is not throttled.)
- Manage context actively. When you're done with a stage, ask Claude to write out the current status of the work in a file, and then tell it
/compact
to crunch down its context. - Sometimes it'll get stuck. Stop it and fix the problem yourself with your still quite superior meat brain.
- It's faster than you are, and it has the entire purloined Internet at hand to search, but you are smarter.
One shot solutions rarely work unless something is very simple or you've set up a repo already so Claude has everything it needs. All of the work is in planning & specification. (Sound familiar?). Go high level, and describe the change you want to effect in the code exactly the way you would to an eager intern who wants to help and can research things instantly but will also go in very strange directions if you leave a gap.
You can instruct the robot to stop and ask for guidance if it encounters a gap.
I find it helpful to tell it to write unit tests before making changes, run them periodically while doing work, then run them again at the end. Remind it to behave like a good engineer. It won't necessarily without the request.
The prompts don't have to be too wordy, despite all this. Be willing to iterate. Here's the prompt I wrote while sick out of my mind to get my midi track generator thing started:
We are going to take the python neo-Reimannian generators and generalize them into a Rust neo-Reimannian generator library and CLI to invoke the library in different permutations and combinations. We're going to start with the library itself. There are two abstractions we need to consider: human representations of notes and musical concepts, and midi. Midi is our output format. Our input format is a textual representation of notes and scales: A, B, B♭, B♭m, and so on. Our internal format should be types. We are likely to end up with enumerations for things like major and minor triads, neo-reimannian transformers, and mode constrainers (so that we can constrain to a mode!). We need to think about our types and the kinds of data we start with, how we transform it in our example scripts, and how we eventually write it out as midi. This will help us define a good set of types for representing the corners of music theory we'd like to represent.
We'll want to represent rhythmic ideas at some point, so we should leave space for those concepts to exist.
The usage of this library will be very similar to how we've used our python scripts, only we won't have to repeat ourselves with the transformations setup. At some point, we can consider moving to reading a structured text input for tracks: one track per kind of generator.
What's your approach to this idea? How would you improve or extend it? In particular, how would you approach generalizing the rhythm aspect?
This worked because there was already some context in a couple of python midi generator scripts that I leaned on.
One last thing about how it's not a person: It will tell you you're the most brilliant person all the time. You can tell it not to if this bugs you or if you find it luring you into personifying it despite everything.
Oh, and it will point out problems with your designs if you ask it to analyze them. Give it a point of view and tell it how to resolve tradeoffs, just like you would another engineer. It is a programming tool that does a lot of boring stuff surprisingly well, but it's a tool, not a pairing partner. It's a souped-up IDE. Keep the interesting work for yourself.