Coding agents got much better.
Our prompts often didn't or we use inefficient chat messages.
In 2026, I don't try to find magical sentences that somehow make the model smarter.
I try to make the task hard to misunderstand, hard to game, and easy to verify.
After years of using LLMs on real codebases, these are the ten prompting patterns I keep coming back to.
1. Call It a "First Draft" and Attack It
Instead of
Is this implementation correct?
Try
This is a first draft implementation.
Review it critically.
Assume there are mistakes.
Find concrete failures and prove them with tests.
How
Change the task from confirmation to falsification.
For important changes, I go one step further and review the implementation in a fresh context:
You are reviewing a first draft.
You get:
- the requirements
- relevant repository context
- the patch
- the tests
Assume the implementation may be wrong.
Find evidence.
Do not give the reviewer the previous agent's 40-message explanation of why every decision was supposedly brilliant.
Why
Framing changes the task.
These are not equivalent:
Is this correct?
Review this.
Assume this is wrong. Prove it.
The first invites confirmation.
The last explicitly asks for adversarial evidence.
If the same agent wrote the code, its context also contains all the reasoning that justified the implementation. A fresh review removes part of that anchoring.
Humans already struggle to review their own decisions objectively.
Giving confirmation bias a GPU didn't magically solve it.
2. Use Sharp Language and Remove Hedge Words
Instead of
Could you maybe improve the tests where appropriate?
Try
The current tests are insufficient.
Add tests until they can expose incorrect behavior.
Or my less diplomatic version:
Add tests until you find at least one real regression.
If your tests cannot distinguish broken behavior
from correct behavior, your tests are shit anyway.
How
Use clear classifications:
INSUFFICIENT
INCORRECT
BROKEN
REJECTED
NOT DONE
And remove unnecessary hedge words:
maybe
perhaps
try
consider
if possible
where appropriate
The profanity is not the important part.
The classification boundary is.
And there is a funny bit of 2026 evidence here.
When Claude Code's source was accidentally exposed through a published source map in March 2026, people inspecting it found explicit frustration detection that classified phrases including profanity.
So wording is not necessarily just some irrelevant wrapper around the "real" request.
Modern agent harnesses can inspect language before we even get to what the model itself does with those tokens.
Why
Compare:
Maybe review this.
with:
This is incorrect.
Discard this approach and find the failure.
They communicate different:
- expectations
- confidence levels
- quality thresholds
- acceptable continuations
Human communication contains lots of social cushioning because humans have feelings.
The coding agent doesn't need emotional cushioning.
It needs to know which side of the acceptance boundary its output currently occupies.
Ambiguity is an API bug.
3. Close the Cheap Escape Hatches
This may be the most important pattern.
Instead of
Improve test coverage.
Try
Increase test coverage by at least 10 percentage points.
Do not add tests that merely execute code.
Use mutation testing to verify that the new tests
detect behavioral changes.
Investigate surviving mutants.
How
Combine three things:
measurable floor
+
anti-cheating constraint
+
independent verification
The same pattern works outside testing.
Bad:
Improve performance.
Better:
Reduce median runtime by at least 20%.
Do not increase peak memory usage by more than 5%.
Run the benchmark at least five times.
Report the median before and after.
Or:
Reduce PHPStan errors in this module from 47 to 0.
Do not add ignores.
Do not add baseline entries.
Do not weaken types.
Why
Agents are extremely good at satisfying badly written requirements.
Ask:
Improve coverage.
and technically this qualifies:
81.20% → 81.21%
Mission accomplished.
Human disappointed.
Machine wondering why the human keeps moving the goalposts.
Coverage alone has another cheap escape:
A test can execute a line without meaningfully checking its behavior.
That is why:
coverage
becomes more useful when combined with:
mutation testing
Coverage asks:
Did this code execute?
Mutation testing asks:
Would your test notice if this code were wrong?
Much better.
My general rule:
If there is a stupid but technically valid way to satisfy your prompt, assume an agent will eventually find it.
Close the loophole before execution starts.
4. Make the Agent Prove the Bug Before Fixing It
Instead of
Fix this bug.
Try
Do not change production code yet.
First reproduce the suspected bug with a failing automated test.
Only after the failure is proven:
1. implement the smallest fix
2. rerun the regression test
3. run the complete validation suite
How
Force this sequence:
Hypothesis
↓
Reproduction
↓
Evidence
↓
Implementation
↓
Verification
Not this:
Suspicious code
↓
Plausible theory
↓
Immediate rewrite
↓
Tests still green
↓
"Fixed!"
Why
Without reproduction, you may never know whether:
- the reported bug actually existed
- the agent's explanation was correct
- the patch fixed that specific bug
- the new test protects against regression
Coding agents can produce plausible fixes extremely quickly.
That makes evidence more important, not less.
Implementation is becoming cheap.
Knowing whether you are implementing the right thing isn't.
5. The Model Never Decides When It Is Done
Instead of
Make sure everything works.
Try
DONE WHEN:
- the regression test fails before the fix
- the regression test passes afterward
- the complete test suite passes
- static analysis passes
- mutation score does not decrease
- the public API remains unchanged
- no unrelated files are modified
And require evidence:
Before finishing, report:
- commands executed
- test results
- static-analysis result
- mutation result
- remaining assumptions
How
Move the stopping condition outside the model.
The model saying:
Everything looks correct.
is not verification.
The environment saying:
428 tests passed
PHPStan: 0 errors
Infection MSI: 94%
is considerably more useful.
Why
The model should not simultaneously be:
author
+
reviewer
+
QA department
+
final authority
That is an absurd control system.
For one of my PHP projects, the gates might be:
Codeception
PHPStan
Infection
php-cs-fixer
For another project they may be completely different.
The exact tools do not matter.
The principle does:
The model proposes. Mechanical systems verify.
And BLOCKED must be a valid result.
If a requirement cannot be satisfied under the current constraints:
STOP.
Provide:
- the blocking requirement
- evidence
- affected constraint
- smallest contract change that would unblock the task
Do not silently weaken the requirement.
Sometimes the correct output from an agent is:
I cannot prove this.
That is far better than fabricated success.
6. Define Scope, Non-Goals, and Restart Rules
Coding agents notice neighboring problems.
Lots of them.
That can turn:
Fix validation bug.
into:
I introduced ValidationFrameworkFactoryStrategyManager
and migrated 37 unrelated files.
A timeless software tradition, now automated.
Try
GOAL
Fix the validation regression.
CONSTRAINTS
- keep the public API unchanged
- do not introduce dependencies
- do not modify unrelated modules
NON-GOALS
- no framework migration
- no API redesign
- no general validation cleanup
- no unrelated formatting changes
And if the agent violates the contract, don't politely negotiate with the patch.
This patch is incorrect.
Problems:
1. the public API changed
2. the regression is not reproduced
3. unrelated files were modified
Discard this implementation.
Restart with:
1. failing regression test first
2. minimal production change
3. public API unchanged
4. complete validation
5. report mechanical evidence
How
Define both:
what to solve
and:
what deliberately not to solve
Then make rejection explicit when the result crosses those boundaries.
Why
Scope is part of correctness.
A technically elegant solution that solves three extra architectural problems may be a terrible patch.
Explicit non-goals make YAGNI promptable.
And an explicit restart is much clearer than spending six follow-up prompts trying to repair an approach that violated the basic contract from the beginning.
Treat the output like a failed build:
FAILED
WHY
EXPECTED
RETRY
Not like a colleague whose self-esteem depends on keeping 70% of the previous patch.
7. Give Agents Larger Planning Horizons, but Small Implementation Steps
Instead of
Plan the next step.
Try
Plan the next three months.
Create falsifiable milestones.
For every milestone define:
- objective
- evidence
- dependencies
- risks
- explicit non-goals
- completion criteria
Then:
Implement milestone 1 only.
Keep the diff small.
Do not begin milestone 2.
How
Separate:
planning horizon
from:
implementation size
My preferred model is:
Think in months.
Plan in milestones.
Implement in small diffs.
Verify continuously.
Why
Human project management evolved around human execution speed.
A developer might work two days on "the next step."
An agent may finish it before you've finished your coffee.
If every tiny step requires another human prompt, the human becomes the scheduler.
But giving the agent a large planning horizon does not mean:
Autonomously rewrite this repository for three months.
It means the agent understands where today's small change is supposed to lead.
Macro-plan.
Micro-execute.
8. Treat Context as an Engineering Dependency
A perfect prompt with wrong context produces a beautifully structured mistake.
Instead of only
Refactor the parser.
provide or derive:
PROJECT CONTEXT
- production runs PHP 8.3
- Parser.php contains canonical normalization behavior
- empty string and null have different domain semantics
- public APIs are consumed by external packages
- a previous refactor broke empty-string handling
- static analysis runs at maximum configured level
But don't solve the problem by dumping the entire repository into the context window.
Use:
Identify the files, tests, documentation, decisions,
configuration and historical constraints relevant to this task.
Explain why each selected context source matters.
Ignore unrelated project history.
How
Treat context selection as part of the task.
The useful target is not:
maximum context
but:
maximum relevant context
Why
Real implementation decisions depend on project-specific facts:
- supported runtime versions
- architecture
- deployment constraints
- existing tests
- backwards-compatibility promises
- dependency versions
- previous regressions
- CI behavior
- intentionally duplicated code
- failed previous approaches
None of that can reliably be reconstructed from:
You are an expert senior developer.
Context is not decoration around the prompt.
Context is a dependency of the task.
9. Use L2 Meta-Prompts as Prompt Compilers
This is where I think prompting gets much more interesting.
A normal prompt tells the agent what to do.
An L2 meta-prompt creates the correct project-specific prompt first.
L1
Fix the parser bug.
Add tests.
Run static analysis.
Still generic.
L2
You are not implementing the task yet.
Your job is to create the project-specific operational prompt
that another coding agent should execute for this task:
TASK:
Fix the parser bug without changing existing public behavior.
Inspect the repository before creating the prompt.
Resolve project-specific facts from repository evidence.
At minimum determine:
- language and supported runtime versions
- package/dependency manager
- actual test framework(s)
- exact relevant test commands
- static-analysis tools and configured levels
- formatter/linter commands
- mutation-testing tools, if configured
- CI validation relevant to this change
- architecture and repository conventions
- public API / backwards-compatibility constraints
- relevant existing tests
- likely affected components
- AGENTS.md, CONTRIBUTING.md, ADRs or equivalent instructions
- historical regressions relevant to this task
Do not invent tools, commands or constraints.
Derive them from repository evidence such as:
- dependency manifests
- lock files
- CI configuration
- test configuration
- static-analysis configuration
- formatter configuration
- mutation-testing configuration
- existing scripts
- documentation
- existing tests
Then generate ONE ready-to-execute operational prompt.
Do NOT write generic instructions such as:
"run the tests"
"use the project's test framework"
"run static analysis"
when the repository allows the actual command to be resolved.
Write concrete instructions such as:
"Run `vendor/bin/codecept run unit`"
or:
"Run `composer phpstan`"
only when those exact commands are supported by repository evidence.
Structure the generated prompt as:
GOAL
PROJECT CONTEXT
RELEVANT COMPONENTS
CONSTRAINTS
NON-GOALS
IMPLEMENTATION APPROACH
VERIFICATION
DONE WHEN
If a required fact cannot be determined,
mark it UNKNOWN instead of guessing.
Do not implement the task.
Output only the final project-specific operational prompt.
How
The L2 prompt acts like a compiler:
Task
+
Repository
↓
Discover project facts
↓
PHP version
test framework
exact commands
CI gates
static analysis
architecture
BC constraints
existing tests
↓
Compile
↓
Project-specific L1 operational prompt
So the final generated prompt might contain:
Tests use Codeception.
Add the regression to:
tests/unit/ParserTest.php
Run:
vendor/bin/codecept run unit
Static analysis:
vendor/bin/phpstan analyse -c phpstan.neon
Mutation testing:
vendor/bin/infection
instead of:
Run the project's tests and static analysis.
Why
The correct operational prompt for:
a small open-source PHP library
is not the same as the correct prompt for:
a twenty-year-old internal IAM system
even when both happen to use PHP.
The human should provide the intent.
The repository already contains much of the operational context.
The L2 prompt combines them.
That scales much better than manually maintaining one universal monster prompt containing every rule accumulated since humans discovered Markdown.
Context is project-specific. Good operational prompts should be project-specific too.
10. Let Successful Sessions Teach Future Sessions
Agent sessions are temporary.
Project knowledge shouldn't be.
After a useful discovery
That worked.
Update AGENTS.md with the reusable constraint
that prevented the original failure.
Do not record task-specific implementation history.
Record only knowledge that should change how future agents
operate in this repository.
Bad memory:
On Tuesday we changed Parser.php because test 17 failed.
Useful memory:
Empty strings and null represent different domain states.
Normalization code must preserve that distinction.
How
Promote only durable findings from temporary working context into persistent project instructions.
The loop becomes:
Prompt
↓
Execute
↓
Verify
↓
Discover
↓
Learn
↓
Update project context
↓
Better next prompt
Why
Without learning, tomorrow's agent can repeat yesterday's mistake.
But storing everything is just as bad.
Eventually AGENTS.md becomes a landfill of obsolete task history that poisons future context.
So memory has to earn its place.
Ask:
Would knowing this change how a competent agent should approach a future task?
If yes, preserve it.
If not, let it disappear.
Forgetting is part of good context management too.
The Pattern Behind All Ten
These techniques look different, but they keep collapsing into the same operational contract:
Operational Prompt
=
Goal
+ Context
+ Constraints
+ Verification
+ Done When
Goal
What observable result must exist?
Context
Which project-specific facts affect the solution?
Constraints
Which shortcuts and changes are forbidden?
Verification
Which external tools determine whether the result is correct?
Done When
What exact evidence allows execution to stop?
That is how I increasingly prompt coding agents in 2026.
Not:
You are a world-class software engineer.
Think step by step.
Please provide your best possible solution.
But:
Here is the goal.
Here is the relevant context.
Here are the boundaries.
Here is how reality will be measured.
Here is exactly when you are done.
Then, for important work:
This is a first draft.
Assume it is wrong.
Break it.
Prove the failure.
And as projects get larger, I increasingly don't even want to manually write that operational prompt.
I want an L2 meta-prompt to inspect the project and compile it for me.
Because the future of prompting is not finding increasingly clever magic words.
It is requirements engineering for machines that execute ridiculously fast.
Sharp language matters.
Context matters more.
Evidence beats confidence.
And the machine does not get to decide that the machine is correct.
Top comments (0)