DEV Community

Cover image for Stop Prompting Like It's 2024
Lars Moelleken
Lars Moelleken

Posted on

Stop Prompting Like It's 2024

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?
Enter fullscreen mode Exit fullscreen mode

Try

This is a first draft implementation.

Review it critically.

Assume there are mistakes.

Find concrete failures and prove them with tests.
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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?
Enter fullscreen mode Exit fullscreen mode
Review this.
Enter fullscreen mode Exit fullscreen mode
Assume this is wrong. Prove it.
Enter fullscreen mode Exit fullscreen mode

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?
Enter fullscreen mode Exit fullscreen mode

Try

The current tests are insufficient.

Add tests until they can expose incorrect behavior.
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

How

Use clear classifications:

INSUFFICIENT
INCORRECT
BROKEN
REJECTED
NOT DONE
Enter fullscreen mode Exit fullscreen mode

And remove unnecessary hedge words:

maybe
perhaps
try
consider
if possible
where appropriate
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

with:

This is incorrect.

Discard this approach and find the failure.
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

How

Combine three things:

measurable floor
+
anti-cheating constraint
+
independent verification
Enter fullscreen mode Exit fullscreen mode

The same pattern works outside testing.

Bad:

Improve performance.
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

Or:

Reduce PHPStan errors in this module from 47 to 0.

Do not add ignores.

Do not add baseline entries.

Do not weaken types.
Enter fullscreen mode Exit fullscreen mode

Why

Agents are extremely good at satisfying badly written requirements.

Ask:

Improve coverage.
Enter fullscreen mode Exit fullscreen mode

and technically this qualifies:

81.20% → 81.21%
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

becomes more useful when combined with:

mutation testing
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

How

Force this sequence:

Hypothesis
    ↓
Reproduction
    ↓
Evidence
    ↓
Implementation
    ↓
Verification
Enter fullscreen mode Exit fullscreen mode

Not this:

Suspicious code
    ↓
Plausible theory
    ↓
Immediate rewrite
    ↓
Tests still green
    ↓
"Fixed!"
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

And require evidence:

Before finishing, report:

- commands executed
- test results
- static-analysis result
- mutation result
- remaining assumptions
Enter fullscreen mode Exit fullscreen mode

How

Move the stopping condition outside the model.

The model saying:

Everything looks correct.
Enter fullscreen mode Exit fullscreen mode

is not verification.

The environment saying:

428 tests passed
PHPStan: 0 errors
Infection MSI: 94%
Enter fullscreen mode Exit fullscreen mode

is considerably more useful.

Why

The model should not simultaneously be:

author
+
reviewer
+
QA department
+
final authority
Enter fullscreen mode Exit fullscreen mode

That is an absurd control system.

For one of my PHP projects, the gates might be:

Codeception
PHPStan
Infection
php-cs-fixer
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

Sometimes the correct output from an agent is:

I cannot prove this.
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

into:

I introduced ValidationFrameworkFactoryStrategyManager
and migrated 37 unrelated files.
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

How

Define both:

what to solve
Enter fullscreen mode Exit fullscreen mode

and:

what deliberately not to solve
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

Try

Plan the next three months.

Create falsifiable milestones.

For every milestone define:

- objective
- evidence
- dependencies
- risks
- explicit non-goals
- completion criteria
Enter fullscreen mode Exit fullscreen mode

Then:

Implement milestone 1 only.

Keep the diff small.

Do not begin milestone 2.
Enter fullscreen mode Exit fullscreen mode

How

Separate:

planning horizon
Enter fullscreen mode Exit fullscreen mode

from:

implementation size
Enter fullscreen mode Exit fullscreen mode

My preferred model is:

Think in months.

Plan in milestones.

Implement in small diffs.

Verify continuously.
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

How

Treat context selection as part of the task.

The useful target is not:

maximum context
Enter fullscreen mode Exit fullscreen mode

but:

maximum relevant context
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

instead of:

Run the project's tests and static analysis.
Enter fullscreen mode Exit fullscreen mode

Why

The correct operational prompt for:

a small open-source PHP library
Enter fullscreen mode Exit fullscreen mode

is not the same as the correct prompt for:

a twenty-year-old internal IAM system
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

Bad memory:

On Tuesday we changed Parser.php because test 17 failed.
Enter fullscreen mode Exit fullscreen mode

Useful memory:

Empty strings and null represent different domain states.

Normalization code must preserve that distinction.
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

Then, for important work:

This is a first draft.

Assume it is wrong.

Break it.

Prove the failure.
Enter fullscreen mode Exit fullscreen mode

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)