# Why Markdown Is the Wrong Default for AI Instructions

We've become very comfortable putting instructions for AI into Markdown. It makes instructions easy to write. It does much less to help us establish whether those instructions are complete, whether they contradict one another, or whether the person approving them understands the behaviour they describe. Those problems become harder to ignore when an agent can turn an approved plan into a substantial implementation before anyone looks closely at the details again. A single file can quietly become background context, design proposal, implementation plan, permission policy and acceptance criteria. Each section looks respectable. The relationships between them remain largely implicit. Thats where I think Markdown becomes the wrong default, when we expect a readable text document to carry the whole instruction and review process.

Thariq Shihipar explores part of this problem in ["Using Claude Code: The unreasonable effectiveness of HTML](https://claude.com/blog/using-claude-code-the-unreasonable-effectiveness-of-html)", published on 20 May 2026. He describes preferring HTML for richer agent outputs, including specifications and plans, and passing those artefacts into subsequent implementation and verification sessions. Its a practitioners article rather than a research paper demonstrating that models follow HTML instructions more accurately. His argument concerns how people engage with agent output. The connection to instructions follows when the artefact a person reviews becomes the specification an agent implements. That connection deserves more attention than a debate about file extensions.

If an agent spends several minutes preparing a detailed implementation plan. You skim it, recognise the right terminology, and tell it to continue. The resulting implementation might follow the plan quite closely. Unfortunately, you never established that the plan described the system you wanted. Better presentation can help you catch that gap. Explicit requirements can help you record the correction. Validation and tests can help establish whether the implementation satisfies it. There is useful work for all three, and a long Markdown file can easily blur them together.

Take a document submission service built around a .NET API, object storage and asynchronous processing. Users upload a document, receive a submission identifier and check its processing status later. An initial instruction could be as simple as this:

```text
Implement document submission.

Stream the upload into object storage without buffering the complete file
in application memory. Validate the submission, publish a processing
request and return a submission identifier.

Make the endpoint idempotent and handle failures safely.
```

An experienced engineer can read that and imagine a reasonable solution. An agent can do the same. They may imagine different solutions. "Validate the submission" could mean checking the request metadata before reading the body, checking the document structure after upload, or completing every content check before accepting the request. "Handle failures safely" says almost nothing about the behaviour the caller should observe. "Idempotent" leaves the identity of a repeated operation unspecified.

Writing those sentences in HTML would preserve every ambiguity. The first improvement must be to the requirements themselves. Now imagine the agent expands the instruction into a 300-line plan. It includes separate sections for API behaviour, storage, messaging, cancellation and retries. Theres considerably more information, but the central sequence still requires the reviewer to assemble several sections in their head. A small sequence diagram immediately makes one proposed interpretation easier to inspect:

![](https://cdn.hashnode.com/uploads/covers/67c36038c69a4b7143c5fc49/d349face-ac6d-4937-8c6f-e42e3f82e96d.png align="center")

The diagram exposes a decision that the prose may have buried. The document exists, but processing has not been requested. The client receives a failure and may retry. Does the next request reuse the stored document? Does it create another one? Can the system recover if the client never retries? The diagram has earned its place by making a specific problem visible. This also demonstrates why a blanket claim that Markdown cannot express useful designs would be weak. The diagram above can live inside a Markdown file and render in an environment with Mermaid support. Markdown plus a suitable renderer is already a richer experience than plain text.

The remaining limitation becomes apparent when there are several failures to inspect. A static diagram shows one sequence. An interactive review page could let the reviewer choose the failure point, inspect the resulting durable state and compare the response against the proposed requirements. For the submission service, I would want to examine what happens after upload completion, after acceptance is committed, after message delivery and after the processing result is committed. Each boundary has a different recovery story. Repeating "retry on failure" in four paragraphs makes those differences easy to miss. A more precise design might separate the upload from the acceptance transaction. The API first reserves a submission identity associated with a tenant scoped idempotency key. It streams the file into temporary storage. After the required initial checks, a database transaction marks the submission as accepted and inserts an outbox record. The API returns an accepted response after that transaction commits. A separate dispatcher delivers the processing request.

That is a proposed design for this example, with its own operational requirements. Object storage does not participate in the database transaction. Temporary uploads need reconciliation and cleanup. Concurrent requests using the same key need a defined response. The outbox dispatcher and consumer need to tolerate repeated delivery. Those details belong in the specification rather than being left for the agent to invent during implementation.

![](https://cdn.hashnode.com/uploads/covers/67c36038c69a4b7143c5fc49/5c57b979-d1c7-44f3-9a5d-434efb4b5c05.png align="center")

Notice how the diagram creates further questions. What happens if the API loses its database connection during commit and cannot tell whether acceptance succeeded? What if the accepted response is lost? What if a dispatcher publishes successfully but fails before recording that fact? A useful review artefact should make those questions easy to explore. It should also distinguish settled requirements from open decisions. An attractive diagram that quietly fills in the blanks can create more confidence than the design deserves. For this example, the instruction could be refined into something much more concrete:

```text
Acceptance occurs only after the database transaction containing the
accepted submission state and its processing outbox record commits.

A retry with the same tenant and idempotency key must resolve to the same
logical submission. A conflicting payload must not be accepted as that
submission. Specify how payload equivalence is established and how an
in-progress retry is reported before implementing this behaviour.

A completed upload without committed acceptance remains temporary and
must be reconciled. Do not delete an object referenced by an accepted
submission.

Delivery may occur more than once. Processing must prevent a repeated
message from creating a second committed business result.
```

The improvement comes from naming the states, boundaries and obligations. A richer interface helps the reviewer discover and approve them. The written requirements preserve the decision after the interface has been closed. The phrase "AI instructions" covers another problem as well, the difference between describing a policy and enforcing it. Imagine a repository instruction saying:

```text
Do not run database migrations against production without approval.
```

That is understandable guidance. It does not establish what counts as production, which migrations were approved, who approved them, whether approval has expired or how the execution environment checks it. Putting the same text under a bold heading called "Critical Rules" does not answer those questions. Neither does converting it into an HTML warning panel. For a workflow that can perform the action, the instruction needs support from the execution system. An illustrative approval request could make the target and action explicit:

```json
{
  "operation": "apply-migration",
  "environment": "production",
  "migrationSetDigest": "sha256:<digest-of-reviewed-migrations>",
  "approvalReference": "approval-4821"
}
```

This JSON is a proposed application contract, not a standard agent format. It becomes useful only when trusted software validates it, checks the referenced approval and binds that approval to the exact operation and target. The model must not be able to grant itself permission by inventing a reference or setting an `approved` field to `true`. The contrast between readable guidance and enforceable policy exists regardless of the document format. Markdown encourages trouble when its familiarity leads us to treat the guidance as the complete solution.

![](https://cdn.hashnode.com/uploads/covers/67c36038c69a4b7143c5fc49/0b6ee14b-cb8b-4f03-92c8-def94fe0d3b0.png align="center")

The human review interface and the enforcement mechanism have different jobs. A readable page can help the approver understand the migration. The execution service must still make its decision using trustworthy records and the actual operation being attempted. The same division is useful for less sensitive instructions. A project may require a timeout to be positive and below a configured maximum, a generated configuration to contain certain fields, or an API contract to use an agreed error shape. These are opportunities for deterministic checks. There is little benefit in asking a model to repeatedly interpret prose when software can validate the relevant constraint directly. Structured data helps because fields can have defined meanings. It does not automatically remove ambiguity. A JSON property named `safe` is no more precise than the sentence "make it safe". A schema can verify that a string exists without establishing that its contents describe the correct behaviour. We still need engineering judgement. We can make better use of it by separating decisions that require interpretation from constraints that can be checked mechanically.

User interface work provides a particularly clear example of why instructions should sometimes begin with interaction. Suppose the request is to "show upload progress clearly and let the user cancel". That sounds straightforward until someone tries the proposed interface. Upload progress reaches 100%, but server side processing continues. The user presses Cancel. Does the system stop processing, hide the item, discard the document or simply stop waiting for a response?

A prototype lets a reviewer experience the distinction between transferring bytes and completing the business operation. It may reveal that the interface needs separate states, different wording and a cancellation outcome that depends on when the request arrives. For a deliberately simplified example, the agreed behaviour could be represented as a state machine:

![](https://cdn.hashnode.com/uploads/covers/67c36038c69a4b7143c5fc49/59769e0a-f64c-4db7-8dfe-3e7a3190c250.png align="center")

This diagram deliberately focuses on cancellation, a full specification would also define failures and recovery. Even within that limited scope, it exposes an uncomfortable but useful possibility, a cancellation request may race with completion. A requirement that promises immediate cancellation would be misleading if the implementation cannot provide it. The interface may need to say "Cancellation requested" until the server confirms the outcome. It may need to explain that the operation completed before cancellation could take effect.

Those decisions are much easier to discuss when the reviewer can trigger each scenario in a prototype. Once agreed, they need to become explicit instructions and acceptance criteria. Otherwise, the prototype is merely an appealing demonstration with no reliable connection to the implementation. Thariq’s [companion gallery](https://thariqs.github.io/html-effectiveness/) includes custom editing interfaces that export the user’s decisions. That pattern is especially relevant, the interface supports exploration, and an explicit export turns the resulting choices into input for the agent.

For our cancellation example, a compact decision record might look like this:

```json
{
  "requirementId": "SUB-CANCEL-004",
  "revision": 3,
  "decision": "accepted",
  "scenario": "completion commits before cancellation takes effect",
  "expectedState": "Completed",
  "userMessage": "Processing completed before cancellation took effect.",
  "verification": "Exercise cancellation and completion concurrently; confirm the persisted outcome is displayed."
}
```

Again, this is an illustrative format. Its usefulness depends on the surrounding workflow. The revision needs to correspond to the accepted specification. The implementation needs access to it. Verification needs to exercise the actual state transition rather than merely checking whether the message appears somewhere in the source code. There is also a practical trap in interactive artefacts: the browser may contain decisions that the underlying file does not. A selected option can exist only in memory. A value can be calculated by JavaScript after an interaction. An edited field can remain unsaved. An agent that reads the original HTML source may receive none of those changes.

A model with browser access may be able to inspect rendered state, but that still leaves the question of which state was approved and whether it can be reproduced later. Explicit export and versioning provide a more dependable hand off. I would treat the accepted requirements as authoritative and the review interface as a view over them. Exploration could produce proposed changes. Approval would record a new revision. Implementation and verification would refer to that revision, rather than whichever browser tab happened to be open most recently.

![](https://cdn.hashnode.com/uploads/covers/67c36038c69a4b7143c5fc49/7a4fe519-cdff-4a9f-901c-467b880352e3.png align="center")

This also gives us a better way to investigate disagreements. If the implementation behaves unexpectedly, we can ask whether it violated an accepted requirement, followed an obsolete revision or exposed a requirement that was never decided. Those are different problems and need different fixes. A single growing instruction document often makes them harder to distinguish. An early section says to keep uploads synchronous. A later section introduces background processing. A final note says to preserve existing behaviour. The document remains valid Markdown while the intended behaviour becomes uncertain.

Using a schema cannot resolve every semantic conflict either. It can, however, make selected decisions explicit and give validation software something concrete to inspect. Stable requirement identifiers help connect discussions, changes and verification evidence without relying on a model to infer which paragraph supersedes another. For teams trying this approach, I would start with one difficult workflow rather than redesigning every instruction file. Pick a feature where people regularly disagree about state, failure behaviour or acceptance criteria. Ask the agent to expose the uncertainty before asking it to implement anything.

A practical prompt could read:

```text
Review the proposed document submission workflow before implementation.

Create a self contained HTML review page showing the state transitions,
acceptance boundary and recovery behaviour. Let me select failure points
and inspect the resulting durable state and caller visible response.

Use the supplied requirements as the source. Label missing decisions as
unresolved. Do not invent guarantees to complete the diagram.

Keep settled requirements separate from proposed changes. Give each
proposed change a stable identifier and provide an export containing the
base revision, selected changes and remaining unresolved questions.

Treat this page as a review artefact. Do not modify the application yet.
```

The important parts are the scope, the handling of uncertainty and the explicit output of the review. Asking only for a "beautiful interactive specification" leaves the agent free to optimise for presentation while hiding the engineering questions. After reviewing it, the next instruction could be much narrower:

```text
Implement accepted requirements revision 7.

Use the exported decision record to identify the agreed behaviours.
Report any conflict with the existing application before resolving it
through an assumption. Keep unresolved decisions unresolved.

For each changed behaviour, provide verification evidence tied to its
requirement identifier. Include the lost response retry and repeated
message-delivery scenarios specified in the accepted requirements.
```

This workflow does not require HTML everywhere. The accepted requirements could remain in Markdown if they are clear and easy to maintain. Structured fields can be introduced where they support useful validation. The review interface can use diagrams and interaction where those help a human inspect the design. Short repository instructions are another sensible use of Markdown. Build commands, naming conventions, project boundaries and concise explanations of architectural intent benefit from being easy to search and review in Git. Id keep those files small and direct. Turning them into interactive pages would often add maintenance without improving understanding.

There are costs to richer review artefacts. Presentation code can overwhelm a diff. A simulation needs its own checks. A page must work with a keyboard and should not depend on colour alone to communicate an important distinction. A diagram can disagree with its data, and a prototype can model an easier problem than the application actually faces. For recurring reviews, a stable renderer backed by versioned requirements is often a better investment than regenerating hundreds of lines of HTML and JavaScript each time. The data changes remain visible, while the presentation stays predictable. For a one off design exploration, a disposable page may be sufficient, provided its accepted decisions are captured elsewhere.

The amount of detail also needs judgement. A short explanation does not become more useful when split across six tabs. An oversized specification does not become easier to reason about merely because sections can collapse. Rich presentation should expose the decisions and relationships that deserve attention, while unnecessary content should be removed. The practical test is whether the representation helps someone make a better decision. Can they identify a missing recovery path? Understand a race condition? Distinguish a promise from an assumption? Record an outcome precisely enough that implementation and verification can agree on what success means?

That is the argument for moving beyond Markdown as the automatic choice for AI instructions. We need compact guidance where prose works well, richer interfaces where review depends on interaction, structured records where decisions need validation, and execution controls where a rule must actually be enforced. An article like this is comfortable in Markdown because its main job is to explain an argument. A specification that authorises an agent to change a production system has additional responsibilities. We should choose its supporting tools with those responsibilities in mind. A plan nobody properly reviews is a weak foundation for an autonomous implementation, however neatly its headings are arranged.
