Six months ago, every AI-assisted coding session started the same way: I'd type a prompt, get a result, tweak the prompt, try again. It worked, until I noticed I kept solving the same meta-problems: reminding the AI of my conventions, re-explaining how I want code reviewed, re-describing my verification steps.

The fix wasn't better prompts. It was replacing prompts with a reproducible system.

The problem with ad-hoc prompting

When you prompt an AI coding assistant from scratch each time, you lose 3 things:

Consistency. Monday's code review catches different things than Friday's. Not because the code changed, but because your prompt did.

Compounding. Every good prompt dies at the end of the session. You can't iterate on something that doesn't persist.

Conventions. Your team has coding standards. Your AI assistant doesn't know them unless you tell it. Every single time.

What I built instead

Claude Code supports two things that changed how I work: a conventions file (CLAUDE.md) and Claude Code skills (reusable slash commands backed by markdown files).

The conventions file

My CLAUDE.md defines how the AI agent should behave in my codebase. Not just style preferences, but the full workflow:

### Before coding
- State assumptions that affect behavior, data, or security.
- If requirements are ambiguous, ask 1-3 targeted questions.

### After coding
- Remove dead code and unused imports.
- Run the full verification loop: format -> lint -> typecheck -> test.
- Cite what you ran and the outcome.

It also encodes cross-language principles I've landed on after years of software development and coaching developers: pure functions over OOP, explicit types at boundaries, errors as structured data. The AI reads this file automatically and applies it to every interaction.

This is the part that transfers to any AI tool. Whether you use Claude Code, Cursor, or something that doesn't exist yet, encoding your standards in a file the AI reads beats re-typing them.

Claude Code skills: codified workflows

Skills are markdown files that define multi-step workflows. I type /review and get a code review that checks correctness, security, design, testing, performance, and maintainability. Grounded in my own standards and adapted to the language I'm working in (Python patterns vs. Rust idioms).

It even ends with a "What this review might be wrong about" section with assumptions that could be challenged, alternative interpretations, and missing context. All to force me to think critically about the feedback instead of accepting it on autopilot. The AI is good at finding issues, but I own the review and want to apply my judgment at all times.

I also have a /review-iter skill that turns review comments into an iterative fix workflow. I use this on my own projects to work through GitHub Copilot review comments. This skill fetches the open comments and enters plan mode where I decide how to address each one. Once I've approved the approach, it commits each fix atomically. The AI handles the mechanical part (fetching comments, staging changes, writing commit messages). I handle the engineering decisions.

After a session, I can use the /retro skill to review what happened: what worked, what didn't, what did I learn, and what should I tackle next. These retrospectives catch patterns I'd otherwise miss.

A pattern across all of these: skills are read-only by default. /review produces feedback but doesn't touch code. /review-iter enters plan mode before making any changes. It's a nice hybrid mode where boundaries are intentional, thinking > rubber-stamping.

Small tools, loosely joined

The Unix philosophy applies here: do one thing well, pipe the output forward. Each skill handles one job. /feature turns a vague idea into a user story with acceptance criteria before I write any code. /review reads the resulting code and produces feedback. /retro captures what happened in a session, and /tip extracts reusable insights along the way. /explain turns a tricky piece of code into a teaching explanation I can share with developers. They're independent, but they compose.

This isn't just good design. It's how LLMs work best. A focused instruction with clear scope gets better results than a mega-prompt that tries to do everything. When I tried building an "all-in-one development assistant" skill, the output was mediocre across the board. When I split it into small, single-purpose skills, each one got sharp.

The same applies to CLAUDE.md. Instead of a wall of rules, it's organized into layers: agent behavior, cross-language principles, then language-specific conventions. The AI can apply the right section to the right context instead of sifting through one giant document.

Skills have a runtime cost

There's something most "how I use AI" posts skip: this system isn't free to run. Every time I invoke /review, the entire skill definition loads into the conversation context. That's input tokens I pay for on every subsequent message. My largest skill, a documentation generator, costs roughly 6,500 tokens loaded on every turn.

But skills aren't the biggest cost driver.

Conversation history is. LLMs replay the entire conversation as input on every turn. Turn 20 of a conversation pays for all 19 previous turns. A long session with verbose test output compounds fast. By comparison, a skill adding 1,000 tokens per turn is much cheaper than a 50-turn conversation with full pytest traces in the history.

Once I understood where tokens actually go, three design principles followed:

Keep skills focused. A 1,200-token skill that does one thing well beats a 6,500-token mega-skill in two ways: the output is better, and every turn after invocation is cheaper. When I audited my skills, I found repeated voice guidelines and word lists copied across five different skills. Trimming redundancy also pays off when you combine skills in the same session; each duplicate section compounds the cost.

Keep tool output quiet. A single pytest run can dump thousands of tokens into context that persist for the rest of the session. Run pytest -q instead of pytest, and chain verification steps into one command. These small changes compound over a session. Even better: put the verification loop in a pre-commit hook. The hook runs outside the context window. The AI only sees pass or fail. (For speed, prek is a Rust-based alternative to pre-commit.)

Keep conversations short. Fresh conversations for fresh tasks. It's tempting to keep going in a long session so the AI has all the context. But that context has a price tag, and it grows linearly with every message. This also increases the risk of hallucinations and errors compounding (also called "context poisoning"). Claude Code does compress older messages as the conversation fills up, so cost doesn't grow unbounded. Even with large context windows, more conversation history means more noise. The AI attends to all of it, including the parts that are no longer relevant. Starting fresh when the task shifts keeps the signal clean.

The same discipline applies to CLAUDE.md. My global one includes conventions for Python, Rust, and Bash. In a Python project, the Rust and Bash sections are dead weight, loaded every turn, never used. The fix is layering: keep only shared principles in the global file, and push everything repo-specific into a project-level CLAUDE.md. That second file earns its place by holding what the agent can't derive from a quick read: the build and deploy commands, the frontmatter shape, and the corrections I'd otherwise repeat every session (on this blog, "no em dashes", "students not clients"). The global file stays lean and the agent stops re-learning each repo from scratch.

None of this changes how the system works. It's the same skills, same conventions, same workflows. Structure your AI workflow like you'd structure code: small, focused, no redundancy.


Persistence is the other half of this: what carries forward when you start fresh.

By default, not much. Conversation history dies at session end. Decisions you explained in chat, constraints you discovered, why you chose approach A, gone unless they landed in a file.

Claude Code has a memory system for this: markdown files that load automatically at the start of every project session. Use them for (non-obvious) strategic decisions, preferences, and constraints you found in a session. Not code structure (read the code) or git history (use git log).

Commit messages also carry forward permanently, and Claude reads them. This is where the "why not what" of good commit messages matters. fix: slug comparison throws context away. fix: author initials must be lowercased before comparing to existing slugs helps the AI understand the nuance of the problem and the solution.

Good habit: end sessions by asking what did I decide today that is not persisted? Then commit it, log it as an issue or md file, or add it to Claude's memory. Otherwise you start the next session as if none of it happened and the AI proceeds accordingly.

Isn't this just prompt engineering?

Fair objection. Skills are markdown files with instructions. You could argue a good prompt in the chat does the same thing.

There's a real difference though: prompts drift, skills drift less. A prompt is whatever I type at 4 PM on a Friday. A skill is version-controlled, iterated on, and consistent across sessions. When I improve how /review works, every future review benefits. When I write a better prompt, it helps exactly once.

Skills don't fix bad judgment, they make it consistent. The system still needs an engineer behind it.

The principles are portable

The tool will change. The discipline won't. What matters is the shift from "talk to AI and see what happens" to "define your standards, codify your workflows, and let AI execute them consistently". I think this is one of the most important skills to develop right now as a developer.

3 things I recommend when starting with skills:

  1. Write your conventions down. Not for the AI. For yourself. The AI just happens to benefit from the same clarity you do.
  2. Codify the workflows you repeat. If you've explained how you want a code review done more than twice, that's a skill waiting to be written.
  3. Version control your AI workflow. It's code. Treat it like code. Iterate, improve, commit.

The models will keep changing. The tools will evolve. But practices and processes are timeless. If you want consistent code reviews, you need a consistent system. Building systems and workflows makes your AI more reliable and cuts your dependency on any particular model or vendor.