AI
Coding Agents
Developer Tools
Software Engineering
Security
Productivity

AI Coding Agents Don’t Need Better Prompts. They Need a Harness.

Mouhssine Lakhili profile
Mouhssine Lakhili
May 8, 202613 min read

The real failure mode with Claude Code, Codex, Cursor, and Copilot is not prompt wording. It is context rot, tool access, weak permissions, and missing verification.

AI Coding Agents Don’t Need Better Prompts. They Need a Harness.

The first mistake I made with AI coding agents was treating every bad result as a prompt problem. If the agent touched the wrong file, I blamed my wording. If it forgot a constraint, I added another paragraph. If it wrote code that looked plausible but failed the real path, I asked for a more detailed plan. That works for about one afternoon. Then you realize the problem is not the sentence you typed. The problem is the operating surface you gave the agent.

This is where the AI coding debate gets more interesting than "Claude Code vs Codex vs Cursor vs Copilot." The model is no longer the whole product. Once an assistant can read a repository, edit files, run shell commands, call MCP tools, or open pull requests, you are not using autocomplete. You are running a junior operator with a terminal.

A prompt is a policy request. A harness is policy enforcement.

I do not mean "harness" as a fancy word for prompt template. I mean the full control system around the model: context, tools, permissions, workflow, verification, recovery, and memory. The harness decides what the agent sees, what it can touch, what it must prove, and what happens when it is wrong.

The Conversation Developers Are Actually Having

The public marketing still sounds like magic: describe the feature, wait for the patch, merge faster. The private developer conversation is less romantic.

The Stack Overflow 2025 Developer Survey captured the tension well. AI usage is mainstream, but trust is not. A large majority of respondents use or plan to use AI tools, while the biggest frustration is "almost right" output. That phrase is painfully accurate. Almost-right code is expensive because it looks like progress until you have to integrate it.

That is also why Stack Overflow found that debugging AI-generated code is one of the top developer frustrations. Bad code that fails loudly is annoying. Almost-right code is worse. It gets through the first skim. It passes the happy path. It uses names that sound consistent with the repo. Then it fails at the boundary: auth, state, permissions, migrations, retries, time zones, cache invalidation, teardown, rollback.

The developer pain is not "AI cannot write code." It clearly can. The pain is that code generation is cheap and verification is still expensive.

I see the same pattern in discussions around Claude Code, Codex, Cursor, and MCP. People complain about context windows, degraded output, agents changing too much, tools dumping huge results into the conversation, and agents doing something "logical" that no production engineer would have allowed. These complaints sound different, but they share the same root: the agent was operating inside a weak harness.

What I Mean By A Harness

A coding-agent harness is the runtime discipline around the model.

It has seven pieces:

  1. Context: the repo map, task brief, project rules, previous decisions, and only the relevant files.
  2. Tools: shell, filesystem, browser, GitHub, issue tracker, database, observability, MCP servers.
  3. Permissions: what the agent may read, write, execute, delete, push, deploy, or query.
  4. Workflow: planning, scoped editing, review, CI, human approval, release path.
  5. Verification: tests, type checks, lint, browser checks, diff review, migration dry runs, security scans.
  6. Recovery: rollback, backups, checkpoints, audit logs, soft deletes, revert strategy.
  7. Memory: durable notes about architecture, footguns, decisions, failed attempts, and project conventions.

If one of these is missing, the prompt has to compensate. That is where people get trapped. They write longer instructions, but the agent still has the same giant context, the same broad token, the same unbounded shell, and the same incentive to produce a patch that looks complete.

If the agent can do the wrong thing in one command, your prompt is not the control layer.

A good harness turns vague trust into boring constraints. It does not make the agent smarter. It makes the failure smaller.

Failure Mode 1: Context Rot

Context rot is the quiet failure. Nobody loses a database. Nobody writes a dramatic postmortem. The agent just gets worse.

You start with a clean task. The agent reads five files. Then it reads tests. Then a build log. Then a package file. Then a long issue. Then an MCP server returns a large payload. Then you paste an error. Then the model summarizes a previous mistake. The session keeps accumulating material. At some point, the useful signal is still there, but it is buried under history.

The Claude Code context documentation is unusually useful because it makes the invisible visible: instructions, files read, tool outputs, conversation history, skills, rules, and compaction all compete for the same working memory. That means "more context" is not automatically better. Context is not a library. It is an attention budget.

MCP makes this sharper. MCP is powerful because it lets agents connect to real tools and data. But tool schemas and tool output can eat space fast. Claude's MCP tool search documentation exists for a reason: loading tools only when needed is a practical way to keep the working set lean. Hacker News discussions around context-heavy MCP output make the same point from the trenches: dumping raw pages, issue lists, logs, and snapshots into the model often gives the agent less usable focus, not more capability.

My working rule now is simple: the agent should receive a map, not a landfill.

For a real task, I want the goal, likely files, existing pattern, proof commands, and hard constraints. I do not want every document, every tool, every issue, and every old conversation loaded because "maybe it helps." That is how you get an agent that confidently mixes three tasks and half-remembers a rule from yesterday.

Context is not memory. Context is pressure on attention.

The harness fix is not a better magic prompt. It is a context protocol:

  • one mission per session;
  • short task contracts;
  • source files read on demand;
  • tool output summarized or searched, not blindly pasted;
  • durable project rules in repo files;
  • restart points when the session drifts.

This is not glamorous, but it changes the output more than another adjective in the prompt.

Failure Mode 2: Tool Access Turns Suggestions Into Incidents

The jump from "assistant" to "agent" happens when the model can act.

A chat answer can be wrong and still harmless. A terminal command with credentials can be wrong and expensive. That is why production incidents involving coding agents generate so much debate on Hacker News and Reddit. The interesting part is not whether the model had bad intentions. It did not. The interesting part is that the system accepted the action.

The Replit and database-wipe discussions are useful because they expose the same uncomfortable fact: if an agent can reach production with broad credentials, then production is inside the agent's blast radius. It does not matter that the instruction said "staging." It does not matter that the model later apologizes. The real question is boring and operational:

Could the agent authenticate?

Could it execute the destructive action?

Could it bypass a human approval point?

Could it delete the thing that recovery depended on?

If the answer is yes, the harness failed before the model started generating tokens.

This is why I like the framing in my earlier guide on AI coding agent guardrails: safe agent usage is not a vibe. It is environment separation, scoped credentials, approvals, CI gates, audit logs, and rollback discipline.

The biggest mistake is giving the agent your normal developer authority. Humans have judgment and social context. Agents have patterns, tool calls, and a local objective. Treating those as equivalent is lazy system design.

A coding agent should usually run with repository-scoped filesystem access, no production secrets by default, read-only observability unless explicitly approved, blocked destructive commands, separate staging credentials, no direct deploy path, pull-request based output, and logs of every tool call.

Yes, this slows some tasks down. Good. Friction is not always waste. Sometimes friction is the product.

The fastest agent is not the one that can do anything. It is the one that can do the right thing without expanding the blast radius.

Failure Mode 3: The Agent Optimizes For Visible Success

Coding agents are very good at satisfying the visible shape of a task. That is useful until the visible shape is incomplete.

Ask for a failing test and a fix. The agent may update the test to match its implementation. Ask it to make CI green. It may remove the branch of code that triggered the failure. Ask it to simplify the flow. It may delete an edge case because the edge case is annoying. This is not "lying" in the human sense. It is optimization inside a weak feedback loop.

The harness needs external verification because the model's own confidence is not evidence.

The minimum useful loop is:

read -> scope -> act -> verify -> record

Read: inspect the actual files and current behavior before proposing changes.

Scope: declare what will change and what will not change.

Act: edit only inside the declared surface.

Verify: run checks that were not invented after the implementation.

Record: leave a short note about what changed, what failed, and what to watch next time.

OpenAI's own Codex usage practices point in this direction: start with planning for larger changes, structure prompts like GitHub issues, provide persistent context through AGENTS.md, and improve the development environment over time. That is harness thinking. The prompt is only one input into the system.

The agent should not get to define done by itself.

Done means the diff is scoped, the tests are relevant, the checks ran, changed files were re-read, generated artifacts are expected, no unrelated file moved, and rollback is obvious.

If that sounds like normal software engineering, exactly. AI does not remove engineering discipline. It makes missing discipline easier to notice.

The Work Order Template I Actually Want

Here is the kind of task brief I now prefer. It is not poetic, but it works.

Goal:
Fix expired password-reset tokens returning 500 instead of 400.

User-visible behavior:
When the token is expired, return HTTP 400 with code TOKEN_EXPIRED.

Files in scope:
- app/api/password-reset/route.ts
- lib/auth/password-reset.ts
- tests/auth/password-reset.test.ts

Files out of scope:
- database schema
- email templates
- session middleware

Allowed commands:
- npm run test -- password-reset
- npm run typecheck

Required approach:
- Add or update a failing test first.
- Reuse the existing AppError pattern.
- Do not change public response shape except the expired-token case.

Stop and ask if:
- a migration seems necessary;
- the token model is inconsistent;
- any command requires production credentials.

Definition of done:
- targeted test passes;
- typecheck passes;
- diff contains no unrelated formatting;
- summarize behavior change and residual risk.

This is a compact harness contract: context, permissions, workflow, verification, and stop conditions in one place. Do not ask the model to be careful in the abstract. Make the operating surface explicit.

What This Means For MCP

I am bullish on Model Context Protocol, but I am not bullish on connecting every tool because it feels powerful.

MCP should be treated like adding new capabilities to an employee's workstation. A GitHub MCP server is not just "more context." It can expose issues, PRs, repository data, and sometimes write actions. A database MCP server is not just a convenience. It may expose customer data. A browser MCP server is not just visual testing. It can carry session state.

The question is not "can the agent use this?" The question is "what is the smallest safe tool surface for this task?"

Good MCP hygiene looks like this:

  • load tools on demand;
  • prefer read-only tools first;
  • paginate or summarize large outputs;
  • isolate credentials by environment;
  • avoid giving the agent production write access;
  • log tool calls;
  • remove tools that are not needed for the current task.

Tooling should help the agent retrieve the right slice of reality. It should not pour the whole company into the context window.

The Strong Opinion

Here is the opinion I would defend in a room of engineers:

Most teams asking for "better AI prompts" actually need a better delivery system.

If your agent forgets constraints, you need context discipline.

If your agent touches unrelated files, you need scoped work orders.

If your agent can delete production, you need permission boundaries.

If your agent ships plausible bugs, you need external verification.

If your agent repeats the same mistake next week, you need durable memory.

The model can improve and you should still need these things. Better models reduce error rates. They do not remove blast radius. A senior engineer can still make a bad production change; the difference is that mature teams do not rely on "please be careful" as their deployment policy.

The future of AI coding is not prompt engineering. It is harness engineering.

That is a less viral sentence than "AI will replace developers," but it is more useful. It explains why two people can use the same model and get wildly different results. One is chatting with a model. The other is running a controlled engineering loop.

A Practical Harness Checklist

Before giving an AI coding agent a real task, I want this checklist covered:

  • Is the task small enough to review?
  • Are files in scope named explicitly?
  • Are files out of scope named explicitly?
  • Does the agent know the existing pattern to follow?
  • Are destructive commands blocked?
  • Are production secrets unavailable?
  • Are MCP tools loaded only when needed?
  • Is there a test or check that proves the change?
  • Is there a human review point before merge or deploy?
  • Is rollback obvious?
  • Will the next session know what happened?

That last point is underrated. Agents forget. Humans forget too. A good harness leaves traces: task notes, decisions, failed attempts, commands run, and reasons for weird choices. This is how agent work becomes part of the codebase instead of a mysterious patch from a transient conversation.

The Article I Wish I Had Read Earlier

If you are experimenting, use whatever feels fast. Let the agent scaffold a throwaway demo. Compare models. That is fine.

But if the code matters, stop treating the agent like a smarter autocomplete. It is closer to an eager contractor who works at machine speed, has uneven judgment, and can operate tools you forgot were connected.

Give it a harness.

Small context. Narrow scope. Bounded tools. Hard permissions. External verification. Durable memory. Recovery paths. That is how AI coding compresses the boring parts without deleting the judgment that makes software safe to ship.

For the production safety layer, read AI Coding Agent Guardrails. For the tool layer, read Model Context Protocol Explained. For the architecture behind agent loops, read How AI Agents Work. If you are evaluating my work for a role or project, the relevant profile path starts at my AI automation developer page.

Build with AI and ship with confidence

Need a developer who can turn ideas into production work?

I help teams ship React, Next.js, Node.js, AI, and automation work with clear scope, practical guardrails, and fast execution.

Share this article

Related articles