- lately, I find myself mostly writing markdown plans instead of code
- in these plans, I
- verbalize my thoughts on what the implementation should look like
- link relevant files, which I found during my research phase
- using GitHub Copilot, I can then turn these plans into code
- essentially, the artifact of my work has inverted:
- previously, I thought about a plan, and wrote code
- now, I write a plan, and think about code (when reviewing it)
- my main tool for thought has changed as well:
- previously, I thought by wrangling code
- now, I just think; Copilot wrangles
- this is possible because the feedback-loop has become quicker, since coding can be largely automated
- I often read discussions where developers say “agentic coding just doesn’t work”
- that’s why, in the next few bullet points, I’ll share my current workflow in an attempt to explain the black magic
- first of all, write a spec including:
- what do you want to implement?
- how can it be achieved?
- where to make the changes?
- take your time; for a medium sized task, this usually takes me 10-30 minutes
- my current spec template looks like this:
### Description *1-3 high level sentences on what i want to implement* e.g.: "Users want to... Therefore we need a button to..." ### Knowledge *all information required for the implementation as bullet points* e.g.: - you can get the data from /api/foo/bar - the result is a json object with a `bar` key ### Plan (high level) *high level implementation plan as ordered list* e.g.: 1. add the button to the [overview page](...) 2. write component tests 3. write api tests
- before moving on, I verify the spec is understandable without extra context:
- this is like checking code for un-imported dependencies
- however, here a dependency means missing information rather than code
- ideally, this spec contains only task-specific information
- additional context should be supplied automatically via instruction files
- instruction files are markdown files automatically sent with your prompt based on file-path patterns (
applyTo
regex in frontmatter).
- instruction files are markdown files automatically sent with your prompt based on file-path patterns (
- my instruction file structure looks like this:
main.instructions.md # applyTo: '**'
frontend.instructions.md # applyTo: 'frontend/**'
backend.instructions.md # applyTo: 'backend/**'
testing.backend.instructions # applyTo: 'backend/**/test/**
serviceA.backend.instructions # applyTo: 'backend/serviceA/**
serviceB.backend.instructions # applyTo: 'backend/serviceA/**
- this dynamic prompting approach greatly reduces the amount of information I have to add to my spec prompt
- once the spec is done, I use Copilot to compile it into its own low-level implementation plan
- it’s like a dry run
- the resulting plan may verbose, but reviewing it is usually worth it:
- often, Copilot gets something wrong
- errors may also reveal unclear parts or even mistakes in my original spec
- when that happens, I refine the spec and re-generate the implementation plan
- next, I feed the implementation plan to Copilot, which incrementally:
- Adds logic & tests.
- Runs tests
- If they fail, it fixes issues and reruns tests.
- If they pass, it moves to the next logic/test.
- usually, the generated code only needs minor adjustments
- this is the point, where I actually write code
- other than that, source code is now mostly immutable by my own hands
- just like a mechanic wouldn’t attach a door with his bare hands, I don’t implement new code without Copilot anymore
- essentially, agentic coding requires completely thinking throught tasks before implementing them
- furthermore, you need to be very conscious of what information is necessary and how it can be accessed
- this is a skill known as context engineering
- I hope you learned a bit about it in this post ^^