For a while I thought the answer was going to be a better prompt.
There's a lot of content out there promising exactly that. Frameworks with acronyms. Templates with ten variables. Systems that demand you write a persona, establish a context, specify a voice, and close with a call to action. I tried most of them. A few helped a little. None of them moved my work from frustrating to shippable.
What did move it, across a couple hundred hours of real project work, was four changes so unglamorous I keep forgetting to mention them. They are not about prompting. They are about feeding the model a cleaner picture of what it's being asked to do.
1. Write the brief before you write the code
The failure mode I hit over and over went like this. Open Claude Code. Type "help me build X." Two hours later I'm five rewrites deep because every thirty minutes I realize a decision I hadn't communicated. Data format I never specified. Failure mode I never considered. A corner of the problem where one sentence of context would have saved the afternoon.
The fix is a single message, sent before any code exists:
Before we write anything, figure out what we're actually building. Ask me the five or six questions you need answered to avoid a false start. One at a time. Do not propose code until I say go.
That's it. That's the whole trick. What comes back is a short list of questions that, in the old workflow, I would have answered in code form through trial and error.
I've lost count of how many Saturdays this has saved me. For trading work, for web apps, for SQL queries, for CSS, for refactors — same move, same effect. The model isn't the bottleneck. The missing context is the bottleneck. Writing a brief is just forcing the missing context into the room.
2. Put the memory in a file the model already reads
Here is a thing Claude Code does that most users don't know about. If there's a file called CLAUDE.md in your project root, the model reads it at the start of every session. Automatically. No prompt needed.
If there isn't one, the model opens every session with no memory of your conventions. Every time. Which is why you keep telling it — for the twelfth time — that this repo prefers Polars over Pandas for new code.
Writing a CLAUDE.md takes thirty minutes. Editing it takes five. Not writing one costs an hour a week forever.
What I keep in mine, in rough order:
What the project is and who uses it. One paragraph, plain English.
The stack. Package manager, language version, the libraries that are in, the libraries that are out. Not "use modern Python" — the exact version number.
Conventions that matter. Named exports only. No classes unless a framework forces it. Type hints everywhere. Tests next to source, not in a separate tree. Whatever your team's version of "this is how we do it here" is.
Commands. Test, dev, build, deploy. One line each. Copy-paste ready.
Env var names. Never values. A pasted secret in a committed CLAUDE.md becomes a git-history incident that ruins an afternoon.
The no-go list. Don't install new dependencies without asking. Don't touch the production .env. Don't bypass failing tests with .skip. Don't modify the public schema without a migration. Short, specific, absolute.
Known quirks. The 2022-06-17 tick anomaly. The webhook that needs the raw body before signature verification. The nav that breaks if you JSON.stringify the user object. The things that have already cost me a day — written down so they never cost me a second one.
A small side project: I got tired of writing this from scratch for every new repo, so I built a CLAUDE.md Generator. Eight stack presets prefill the boring 70%. You edit the rest. Ten minutes instead of whenever-I-get-around-to-it.
3. Give the model live data, not a screenshot of data
For anything where the answer depends on real numbers, I've stopped pasting CSVs into prompts.
Instead I wire the model to the source. The mechanism is MCP — servers that plug an AI client into an external data source the way a USB hub plugs a laptop into a printer. I have MCP servers hooked up for my CMS, my analytics, my hosting provider, and one or two vertical tools. When I ask "which blog posts from the last 30 days have the most internal links?" the model queries the CMS directly. No export. No paste. No interpretation of a stale snapshot.
The reason this matters isn't novelty. It's that the model's output is only as good as its view of the world at the moment of the question. A CSV pasted yesterday tells a different story than a database queried now. Stale context produces stale answers that sound current because the model says them confidently. That confidence is the thing that bites you.
If you're starting with zero MCP servers installed, wire up the one for your most-used data surface first. Everything else can wait.
4. Write a spec that can only be wrong one way
This is the change that surprised me the most. When the spec is fuzzy, the code is fuzzy. When the spec is tight, the code is — often on the first try — exactly the code in the spec. None of it has anything to do with clever prompting. It's a property of the spec itself.
Fuzzy:
Write a helper to detect momentum breakouts.
Tight:
Write a pure function
detect_breakouts(df). Input: a pandas DataFrame with columnsdate,close,volume. Output: the same DataFrame with one new Boolean column,breakout. True on rows where the 20-day rolling return is strictly greater than 8% AND today's volume is strictly greater than 1.5× the 20-day average volume AND the prior row'sbreakoutwas False. No other new columns. No mutation of the input. Raise ValueError if any required column is missing.
The fuzzy version returns something that looks right and breaks under testing. The tight version returns either the function you asked for, or — much more useful — an error message that reveals the one ambiguity you hadn't resolved yet.
My habit now: when a first draft goes sideways, I don't reach for a clever prompting framework. I reread the spec, find the ambiguity, fix it, rerun. The fix is almost always there.
What changed when I did all four
Before: fifteen minutes of real work sandwiched between an hour of re-explaining the project and forty minutes of debugging code that solved the wrong problem. Session end, a partial feature and a vague sense of "what did I even do today."
After: the session starts with the project already loaded through CLAUDE.md. The brief surfaces the decisions I haven't made. The data is live. The spec is tight. The first draft is usually 80% of what ships. The remaining 20% is my judgment call — taste, a sharper constraint, something I didn't know I wanted until I saw the first draft.
That 20% is the part that should be mine. The other 80% was friction dressed up as work.
The short version
A brief before code. A memory file in the repo root. Live data, not pasted data. A spec that can only be wrong one way.
None of it is a prompt trick. That's why nobody's selling a course about it.
Related tools on the site: the CLAUDE.md Generator for the memory file, the Prompt Enhancer for when a spec really does need tightening, and the MemPalace Setup for multi-project long-term memory via MCP.
Informed in part by a Medium piece titled "900+ Hours of Using Claude Code for Trading" from the AI in Trading channel. Framing and examples in this post are my own; credit where concepts originate elsewhere.