Everything is markdown: researching, planning and implementing in an age of AI agents
As a follow up to my recent article about how I no longer write code like a caveman, I thought I’d add a bit more information about what my day-to-day development workflow looks like over the past month.
There are a lot of things I’ve tried that did NOT work out well. But I think I’ve settled into a rhythm that seems extremely productive while also keeping me close enough to the code that I don’t lose essential details about the software I’m producing.
At one point, I tried jumping into full YOLO mode (Stage 6) and letting an agent one-shot several thousand lines of code from a PRD, but the PR was basically unreviewable and even when I shoved it through the review process, the first pass ended up being wrong in so many subtle ways, that it felt like it was basically wasted effort.
Now, I’m still solidly in stage 5 (coding agent under PR review), but my feedback loops are tight and there are almost no issues flagged by the code that’s generated.
Here’s the step-by-step of what that looks like.
Everything is markdown
The tldr is that instead of using “plan” mode and guiding the coding agent in a chat interface (even with Claude Code’s AskUserQuestionTool), it’s better to be able to view and annotate the full model output directly in a markdown (.md) file.
When someone posted their similar workflow on HN recently, I think the top comment nailed it:
I think the real value here isn’t “planning vs not planning,” it’s forcing the model to surface its assumptions before they harden into code.
LLMs don’t usually fail at syntax. They fail at invisible assumptions about architecture, constraints, invariants, etc. A written plan becomes a debugging surface for those assumptions.
So the goal is to surface the model’s assumptions and detailed plans into markdown files. Then I can annotate any part of the model’s output with questions, preferences or edits. Then I can feed that annotated markdown back to the model, a process that offers super-fine-grained steering.
Specific prompts
Here’s what that looks like more concretely:
1. Research current systems and patterns
In a large, existing codebase, there are often high-level design patterns your code should follow. Maybe there’s a certain way that code is expected to dispatch events to background tasks or multiple patterns for caching query results.
Even if you already know what the patterns are, compiling the research doc is useful because it creates a crash course for your agent to follow.
can you try to learn as much as you can about the ___ system?
it is mostly contained in the following directories but may rely on code from other places as well:
understand how it works deeply, including all of the specifics. please also find examples of how it is used and summarize the main usage patterns.
write a detailed report of your findings to .scratch/research/{SYSTEM_NAME}.md and include a timestamp of when it was last updated (ie today’s date)
The goal of the research docs are basically to provide real-world grounding that can be used next, in the planning stage.
These research docs should be somewhat generic and reusable, since they describe the current state of the world. The goal is not necessarily to make it specific to the feature you’re planning to build, but rather the existing patterns they are describing. I often re-use the same research docs when working across multiple features. I generally keep my research docs in .scratch/research/<system-name>.md
Skim the markdown doc and make sure it aligns with your understanding of the patterns, before continuing.
2. Initial planning doc = research doc(s) + current intention
Planning docs need less of an explanation, because you are already used to using “plan” mode within the agent. But this markdown-based approach to planning docs offers much better control.
To generate a planning doc, I basically tell the agent to consult one or more relevant research docs (for background and specific patterns), and then give a detailed description of the intention of what I am trying to build.
I’ve written before about how ‘intention’ is the main currency when working with LLMs. The prompt that you write to kick off the planning process is the part that requires the most focus and attention. The more details you can give the model about what you intend for it to do the better.
please read each of the following research documents and intention statement:
please come up with a step-by-step plan for how to implement this change. let me know if there are any issues, ambiguities or places where multiple options might exist. do NOT start on implementation yet.
include the exact text of this prompt as a section at the bottom called “initial prompt and feature intention”. please also include the date this plan was generated (ie today) and an estimate of lines of code that will be changed.
write the output to
.scratch/plan/{FEATURE_SUMMARY}.md
I have found the phrasing to be pretty important. Asking it to make a “step-by-step” plan breaks feature development into manageable, logical chunks. Highlighting ambiguities or options discourages the agent from guessing where something might be under-specified. Sometimes I had agents try to start implementing while I was still planning, so I tell it specifically not to do that.
3. Annotate the plan and resolve ambiguities
Now I go through and closely, carefully read through the generated plan, adding annotations that start with --> to anything that stands out. This is the step where the main value of this approach comes in, versus using the agents’ native “plan” mode with a global Y/N option.
I can ask “is this necessary?” or suggest “let’s remove this from scope for now” or note “let’s go with option B, prefer explicit over implicit”. I can just write those little fragments, prepended with the --> anywhere in the document I want. I could nix a whole section or step by annotating its heading, or offer a much lower-level change like the specific copy of an error message.
Another useful thing to check for at this stage – if the plan for the feature seems too large for a single PR, I can note that I’d like the agent to split the plan into smaller logical chunks that can be implemented and reviewed separately.
Once I’m satisfied with my annotations, I’ll prompt the agent (using the same chat context as when it generated the plan):
i went through and made some annotations on the plan doc, look for lines that start with
->for my notes.please update the plan to reflect those changes, then provide a summary of the decisions and changes made at the bottom of the doc.
That’s it. The agent will find the changes, fold them into the plan doc, and provide a summary of your changes and decisions. That way the plan doc is the single, canonical source of truth for what the coding agent should work on next.
4. Implement the plan, and update the planning doc
At this point, I’ll do another scan through the plan doc to make sure that it reflects the changes I’m expecting. Now we’ve got a super detailed and accurate blueprint for a coding agent to execute on.
I’ll start a new chat (to provide a full token usage context), and then I’ll tell the agent:
please read this plan doc and get started on implementation:
.scratch/plan/{FEATURE_SUMMARY}.mdupdate the planning doc to mark off each section as you complete it, and add any notes or issues you ran into during implementation of that section.
ensure that all code linters and formatters pass, and that you’re following conventions in @AGENTS.md and other coding agent rules. please implement the tests described in the plan, but do NOT worry about tests passing yet, i’ll review those later.
please add a summary of the completed implementation to the bottom of the doc.
By having the agent update the plan doc as it’s implementing, it keeps the plan doc as the real “source of truth” for the feature’s implementation. If the agent gets stuck or needs to be restarted, I have a concrete source for what has been completed and what still needs to be finished. It also adds notes for any deviations from the original plan, which are very helpful when reviewing the implementation.
I generally tell it not to worry about tests passing during the initial implementation, since agents tend to get stuck going back-and-forth making changes to the application and the tests, trying to get them passing. I’d rather see it stick to the plan and finish implementation, then I can manually verify the features work correctly before worrying about whether tests pass or not.
A planning doc that has up-to-date information on implementation has also been useful in situations where I might be using multiple agents in parallel, or when I have stacked branches that might need to resolve when features were added later on.
Now we’ve got a working implementation. Sometimes the first pass is all you need and you can create a PR right away. Often, I’ll need to make a few smaller adjuments or corrections as I go through the feature manually and verify it all works as expected.
5. Create PR, including the doc that guided the changes
The full plan doc (which also includes my initial prompt that generated it) is the real source of truth for the intention behind the changes. So it’s definitely helpful for a reviewer to have access to this when reviewing the code changes.
Since the documents tend to be large, I use markdown’s expandable <details> & <summary> tags so that the full planning doc is collapsible. Something like:
<details>
<summary>
plan doc used
</summary>
{PASTE ENTIRE PLAN DOC MARKDOWN HERE}
</details>
Since the doc is markdown and it’s being pasted into github’s markdown editor, it all “just works” in terms of formatting things like bullets, headings, tables, links, etc.
Bonus: .agent-skill repo
I’ve been using these prompts nearly every day for the past few weeks. Despite heavy use, I have only had to make occasional, light edits to them, and I realized they’re fairly project agnostic. So I decided to split them into dedicated “agent skills” following the official spec (no surprise, it uses markdown too 😀)
I created a github repo for them with a simple install.sh script that symlinks the agent skills to where claude expects to find them.
Now it saves me a lot of copy/pasting and I can easily invoke the commands within claude code:
/research (include system name and source files)/plan-create (include research docs and intention)/plan-update/plan-implement (include path to plan doc)
Some of the skills require no other input since they read their state from the git repo or our conversational chat history. Some skills do require other inputs, and I added guards to ensure the necessary context is provided by the user, telling the agent NOT to guess if something is missing.
There are also other commonly used prompts, like creating multi-line commit message for a set of changes, running all linters and tests locally before pushing to github, triaging reviewer code comments on the PR and more.
Check it out and star ⭐️ it if you find it useful!