Companion Essay № 001 · August 2026

Natural Language Is a Programming Language Now

When Requirements, Prompts, and Instructions Become Part of the Implementation

Companion to The Architecture of Nonfiction
Contents

“English is Just Another Programming Language.”

Andy Hunt and Dave Thomas, The Pragmatic Programmer

Natural language was part of software development long before 2026. Requirements, specifications, and design conversations shaped software before an AI system could write the implementation. Researchers were also translating natural-language descriptions into programs before current generative models.

AI coding assistants shortened that path. GitHub Copilot brought AI-generated code suggestions into editors with its technical preview in June 2021. ChatGPT’s public release on November 30, 2022 made a conversational, code-capable model directly available to the public.

Today, a sentence can start a software-development workflow. A coding agent can read a feature description, inspect a repository, propose a plan, edit files, run tests, execute commands, and prepare a pull request. The code still runs on a computer, but natural language increasingly determines which code gets written and which actions occur before anyone reviews it.

That makes writing part of the implementation path.

The sentence is deliberately broader than saying prompts matter. Prompts are only one source of written direction. User stories define product behavior. Repository instructions define standards. Existing code and comments supply local context. Plans record an interpretation. Acceptance criteria define the behavior that must survive review.

Natural language is not a deterministic programming language. It has no compiler-enforced grammar, stable execution semantics, or type system that guarantees one interpretation. That difference does not make the analogy useless. It makes the engineering problem more interesting because the system must accept an ambiguous instruction, select a plausible meaning, and continue.

A Working Login Can Still Be Wrong

During the rebuild of an internal point-of-sale application at a marketing services SaaS provider, even the login process depended on product-specific behavior. The existing application authenticated against the company’s CRM. After authentication, it retrieved additional CRM data and followed different authorization paths based on the user’s roles. Those paths determined the interface each user saw next.

“Build login” contains none of that.

A coding agent could respond to that instruction with a polished implementation. It might use Microsoft Entra ID, create local authentication, or send every authenticated user to one dashboard. The page could look professional, the validation could work, and the tests could pass. The implementation would still be wrong for the business.

DecisionA generic instruction permitsThe product requires
Authentication sourceAny conventional providerExisting CRM authentication
AuthorizationOne general authenticated stateMultiple role-driven branches
Post-login experienceOne default destinationAn interface selected by the user’s role
Definition of doneA working login demonstrationPreserved business behavior

The agent did not need a more elegant description of login. It needed the decisions hidden behind the word login.

Human developers also receive incomplete requirements. They compensate with institutional knowledge. They attended the meetings, remember why the odd CRM integration exists, recognize a familiar authorization pattern, or know whom to ask. An agent begins with the context it can access. When the missing information is not in the request, repository, instructions, or available conversation, the system has four options: retrieve it, ask for it, state an assumption, or guess.

The danger is that the last option can remain invisible until review or production.

English Was Already in the System

Hunt and Thomas were making this connection long before generative AI entered ordinary development work. Their advice was direct: treat English as another programming language and write documents with disciplines such as DRY, automation, and deliberate design. They were not arguing that a requirements document could be compiled. They were arguing that written artifacts deserved engineering care because they contained knowledge the software and its maintainers depended upon.

Software writers have also used good writing as a model for good code. Robert C. Martin describes readable code through qualities familiar from composition: meaningful names, focused components, separated concerns, and an order that helps a human reader understand the work. The direction of influence already ran both ways. Software borrowed cohesion, sequence, and reader awareness from writing. This framework brings software’s precise design vocabulary back to the writing that inspired it.

Martin later addressed a different boundary. He first presented SOLID in the context of object-oriented design, but Functional Design describes the principles as general software-design principles rather than rules confined to one programming style. That does not mean Martin applied SOLID to nonfiction or AI instructions. The Architecture of Nonfiction makes that extension and defines its limits.

The AI era adds another turn. Natural language still communicates knowledge to people, but it can also direct a machine that writes code and operates tools. An error in the writing no longer has to wait for a human developer to misunderstand it. The agent can convert the misunderstanding into implementation immediately.

The Execution Path Changed

Natural-language artifacts did more than preserve knowledge about software. They helped determine what software would be built from the beginning. Product owners wrote stories, architects wrote decision records, developers wrote comments, and operations teams wrote runbooks. People interpreted those documents, reconciled conflicts, filled gaps, and translated the result into implementation.

AI coding systems shorten that translation path. The same natural-language artifact can now influence planning, code generation, test creation, command execution, and review. As of August 2026, official agent guidance reflects that operational role. OpenAI’s agent-building guide, for example, treats clear instructions, explicit actions, necessary context, and edge-case handling as conditions for reliable workflow execution. The October 2025 Model Spec also describes repository files such as AGENTS.md, README files, and relevant code comments as context a coding assistant may be expected to follow.

Those files are not background reading in the ordinary sense. They alter behavior.

A sentence in an instruction file can require a test before a change is accepted. A story can preserve a business rule the model would otherwise replace with a common convention. An acceptance criterion can force two user roles down different paths. A style standard can cause generated code to use one architectural pattern and reject another.

The writing does not become the executable artifact. It becomes part of the control path that produces and evaluates the executable artifact.

That distinction matters. Calling a prompt “code” can tempt us to look for magic wording or believe that a sufficiently clever instruction will produce a stable result. The real system is larger. It includes the model, tools, repository, retrieved context, instruction hierarchy, tests, and human review. Natural language coordinates those parts without replacing them.

The brief enthusiasm for “JSON prompting” made that temptation visible. Wrapping an instruction in braces and labeled fields was promoted as a way to make model behavior more precise, reliable, or even deterministic. JSON can organize complex input, and a real JSON Schema can constrain machine-consumed output. It cannot supply missing intent. {"task":"build login"} is still “build login” with punctuation.

Prompt format can affect model performance, but it does not provide a universal programming language. A 2024 study comparing plain text, Markdown, JSON, and YAML found substantial differences across models and tasks, with no format performing best everywhere. The useful question is not whether the prompt looks like code. It is whether the complete instruction environment supplies the meaning, constraints, and verification the work requires.

This Is Not a Compiler

A compiler gives syntax and semantics defined by a language implementation. If the source violates the grammar, compilation fails. When valid source executes under the same specified conditions, we expect the language to preserve its meaning.

Natural language offers no equivalent guarantee. A short requirement can be grammatically flawless and still permit several incompatible implementations. “Notify the user when the job fails” leaves basic questions unanswered. Which user? Which failures? Through which channel? How quickly? Should repeated failures produce repeated notifications? What information may the message expose?

Written language also omits information available in speech. Noun-verb pairs such as record, permit, and object can be distinguished by stress, while emphasis can change what an otherwise identical sentence implies. Emphasizing the system, notify, the user, the job, or fails in “The system should notify the user when the job fails” answers a different objection or establishes a different boundary. Syntax usually resolves the grammatical role, but the words alone do not encode every distinction the speaker intended.

An AI system may notice those gaps and ask. It may also choose ordinary defaults because the instruction appears complete enough to act upon. Fluent output can hide the unresolved decision.

Research on code generation makes the risk concrete. Li and colleagues tested code generation from underspecified natural-language descriptions and found that clarification improved the precision of generated code across their evaluation metrics. The later ClarifyGPT work reached a similar practical conclusion: systems that identify ambiguity, ask targeted questions, and refine the requirement outperform direct generation from unclear requirements. These studies examine bounded code-generation tasks, not entire production systems, but they support the operational lesson. Ambiguity needs a resolution step.

Han and colleagues approach the problem from the requirements side. Their ArchCode work separates functional requirements from concerns such as robustness, performance, and maintainability, then generates tests tied to individual requirements. Their system also attempts to extrapolate omitted requirements. That is useful research, but extrapolation cannot recover a private business decision that never entered the available context. No general model can infer that this company’s login must authenticate against this CRM unless some accessible artifact supplies that knowledge.

The difference between a compiler and a language model is therefore not a reason to relax our writing standards. A compiler often refuses malformed input. An agent may make malformed intent look complete.

Vibe coding turns that failure into a development method. I recently translated a vibe-coded application that produces its desired output when it processes one request at a time. Production requires it to support multiple concurrent requests.

By August 14, 2026, the refactor was substantially complete, and the review had identified 24 significant issues, including memory leaks, data bleeding between objects, missing thread safety in several places, and a 3,233-line god class. No additional significant issues were expected beyond those already documented. The single-request limitation allowed happy-path behavior to stand as evidence of system correctness. Implementation volume did not establish sound object boundaries, resource lifetimes, or concurrency behavior.

That evidence does not prove that every defect began in one ambiguous prompt. It shows what can remain hidden when generated output stands in for an explicit specification, architectural constraints, and disciplined review. The system made incomplete intent look finished long enough for the defects to accumulate.

Missing Context Becomes a Decision

An omitted decision does not remain empty when the agent must finish the task. Something fills the space.

The safest outcome is a useful clarification question. “Should the application support concurrent requests?” forces the author to define a boundary the agent would otherwise fill. “Should login preserve the existing CRM authentication or move to the organization’s standard identity provider?” exposes the fork before code makes either branch expensive.

The dangerous outcome is a silent default. The agent selects the most familiar pattern, writes a clean implementation, and presents the result as complete. The code may be reasonable in isolation because the failure is not primarily syntactic or even technical. The system implemented a decision the organization never made.

This is a version of “works on my machine” for context. The instruction worked inside the author’s head because the author supplied missing facts without noticing. It failed when executed by a reader or agent that did not share those facts.

The remedy is not to paste every meeting note, standard, and historical explanation into every request. More context can create its own failures by obscuring the task, introducing stale guidance, or exposing conflicting instructions without an authority rule. The requirement needs the smallest sufficient interface: enough information for the agent to make the decisions the task permits and recognize the decisions it must not make.

That means context must be available, relevant, and authoritative. “Your AI Instructions File Should Be a Router, Not a Novel” shows how to implement that rule for engineering standards: keep the root instruction file small, route tasks to maintained topic-specific guidance, and load only the modules the work requires. For this argument, the important point is simpler: missing context is a dependency defect when the requested behavior cannot be produced correctly without it.

An Instruction Has a Contract

The parent essay describes a paragraph through preconditions, responsibility, and postconditions. The same contract is useful for an AI work item.

Contract elementAI-assisted development question
PreconditionsWhich business rules, codebase patterns, standards, and prior decisions must the agent know?
ResponsibilityWhat user or system outcome must this work produce?
PostconditionsWhich observable behaviors and tests prove the work is complete?

The login work can be expressed through that contract without prescribing every line of code:

Preconditions: The existing application authenticates against the CRM. User roles retrieved after authentication determine authorization and the post-login experience.

Responsibility: Implement login for the rebuilt point-of-sale application while preserving the existing authentication and role-driven behavior.

Postconditions: Each primary role group is authenticated through the CRM and reaches the approved interface for that role. The implemented behavior satisfies the relevant stories and acceptance criteria.

That instruction still leaves implementation choices open. It does not dictate class names, framework APIs, or control flow unless one of those details is already an architectural constraint. It defines the behavior the agent must preserve and the evidence a reviewer should expect.

The contract also needs a failure rule. If the story, repository, existing behavior, and standards disagree about authentication, the agent should not quietly decide which source wins. The instruction system must identify authority or require clarification.

If this contract feels familiar, it should. It has a useful parallel in Gherkin, which organizes executable specifications around Given, When, and Then. Given establishes the initial context, When describes an event or action, and Then states an observable outcome. Preconditions and postconditions have close counterparts in the first and third terms.

Gherkin was not created for AI. Cucumber’s description of Behavior-Driven Development presents it as a common language through which business and technical people can develop a shared understanding of the behavior they intend to build. The specification remains readable by people while automation checks it against the system.

That human origin makes its use with AI more interesting. In June 2026, Robert C. Martin described an agent pipeline that transforms informal specifications into tasks, converts those tasks to Gherkin, and generates acceptance tests from the resulting scenarios. I explored the same idea at the scale of a user story by adding Gherkin scenarios to make required behaviors more specific before AI-driven development.

The additional specificity was useful, but adopting Gherkin in the current process would have caused more disruption in newly formed product management and QA teams than it would have delivered in clarity and code quality. The juice was not worth the squeeze. The team chose not to adopt it now and will revisit the decision in 2027.

The parallel is structural. The two models solve different problems through a similar shape. A When describes a particular trigger or action within one scenario. A responsibility describes the broader job of the work item and may require several Gherkin scenarios to specify. The resemblance still matters: both structures turn natural-language intent into context, behavior, and evidence that can be reviewed and tested.

This is where writing architecture becomes operational. The work item needs one coherent responsibility. Its dependencies must be visible. Its interface must expose the context required by this task without forcing the agent to process every capability and policy the organization possesses. Its postconditions must survive a different implementation.

The System Is Larger Than the Prompt

“Prompt engineering” often puts too much attention on one message. Production work rarely depends on one message alone. The effective instruction environment may include:

  • A feature and its stories
  • Repository-level instructions
  • Topic-specific engineering standards
  • Existing code and tests
  • Architecture decisions
  • Tool permissions and limits
  • The agent’s plan
  • Reviewer corrections

These sources compose into a system. They can also conflict, duplicate knowledge, or overwhelm the task.

A giant prompt that repeats every standard is the instruction equivalent of a method with twenty parameters. The agent receives more information, but the interface becomes harder to understand and maintain. When a policy changes, copied instructions drift. When irrelevant material dominates the working context, the task-specific requirement becomes harder to distinguish.

The better pattern resembles ordinary software architecture. Keep stable standards in maintained sources. Let the work item reference the relevant standards instead of reconstructing them. Load the context required for the present task. State which instruction source wins when two sources conflict. Preserve review and test evidence that connects the implementation back to the requirement.

That is how SOLID, DRY, and YAGNI apply without turning the request into a miniature restatement of the parent essay:

  • Cohesion keeps each instruction source focused on one purpose.
  • Interfaces state what the agent may assume and must produce.
  • Dependencies make required context visible.
  • DRY keeps policies authoritative instead of copied across prompts.
  • YAGNI keeps speculative or irrelevant material out of the working context.
  • Refactoring improves the instruction system when repeated failures reveal a structural problem.

The goal is not one perfect prompt. The goal is an instruction architecture that can be understood, changed, and tested.

Test the Specification, Not Only the Code

An instruction does not become correct because it sounds clear to its author. Its interpretation has to survive contact with other people, the agent, the plan, and the implementation.

In Scrum, refinement is the first test of a specification: does the team understand the requirement well enough to build it? Asking an AI agent what questions it has about the requirement performs the same check before implementation. The questions expose missing context, ambiguous behavior, and assumptions that would otherwise become code.

The specification can be tested before it reaches an implementation agent. “The AI-Powered Requirements Pipeline That Makes Planning Faster” takes a feature through elicitation, story splitting, acceptance-criteria development, and a prefinement quality gate. If a story mixes operations, omits validation, or fails to define a clean vertical slice, it moves backward for revision instead of forward to implementation. The pipeline tests whether the writing is ready to govern code.

Review the plan before the code when the task is large enough to justify one. A plan reveals what the agent believes the requirement means while correction is still cheap. If the plan replaces CRM authentication with a standard identity provider, the team has found the misunderstanding before it spreads across controllers, services, tests, configuration, and UI behavior.

Then trace the generated changes back to their requirements and standards. Automated tests verify observable behavior, but they can only protect behavior someone identified. Review must still examine assumptions, omitted edge cases, source authority, security boundaries, and product decisions that the tests do not express.

When the defect began in the writing, fix the writing.

Correcting one generated implementation may solve the immediate problem. Leaving the ambiguous story or conflicting instruction untouched preserves the same defect for the next agent, developer, or rewrite. The specification is a maintained source of system behavior. It deserves a refactoring pass too.

This creates a disciplined loop:

  1. Test the requirement through team refinement or agent questions.
  2. Resolve ambiguities, then state the intended outcome and required context.
  3. Ask the agent to plan before it implements.
  4. Compare the plan with the requirement.
  5. Test the code against observable postconditions.
  6. Revise the code, specification, or instruction architecture where the failure originated.

The process does not eliminate judgment. It locates the judgment early enough for a person to exercise it deliberately.

Write Upstream of the Code

The login example did not require more words for their own sake. It required the right facts in the right places: the authentication source, the role-driven authorization paths, the intended user experience, and the definition of done. Once those decisions were explicit, the agent had a product to implement instead of a convention to imitate.

That is the practical meaning of natural language becoming a programming language. Writing now helps select behavior, constrain implementation, authorize actions, and define successful execution. It remains ambiguous, contextual, and dependent on human judgment, which is exactly why it needs engineering discipline.

When language directs the system, review it as part of the system.

Receipts

  • Development timeline: Microsoft Research’s 2016 work on program synthesis from natural language predates current generative assistants. GitHub launched the Copilot technical preview on June 29, 2021. OpenAI publicly introduced ChatGPT on November 30, 2022. These dates mark stages in the current development path, not the beginning of natural-language interaction with software.
  • English as a programming language: Andy Hunt and Dave Thomas’s official Pragmatic Programmer tips tell developers to treat English as another programming language and apply programming disciplines to documents.
  • SOLID across programming styles: Robert C. Martin’s Functional Design, Chapter 12 describes SOLID as general software-design principles rather than rules specific to object-oriented programming. Applying them to writing and AI instructions is this essay’s synthesis.
  • Code modeled on writing: Martin’s “First Principles” uses well-written prose as a model for code organized for human understanding.
  • Agent instruction design: OpenAI’s A Practical Guide to Building Agents recommends clear instructions, explicit actions, necessary context, and handling for edge cases to reduce errors in agent workflows.
  • Repository context: OpenAI’s Model Spec dated October 27, 2025 uses coding-assistant examples in which files such as AGENTS.md, README files, and relevant code comments can supply instructions and context.
  • Prompt format: He et al.’s “Does Prompt Formatting Have Any Impact on LLM Performance?” compares plain text, Markdown, JSON, and YAML across several GPT models and tasks. Format affected performance, but no format was universally optimal. OpenAI’s Structured Outputs guidance distinguishes schema adherence from merely producing valid JSON and notes that even schema-constrained output can hallucinate when the input cannot support a valid answer.
  • Clarification and code generation: Li et al.’s “Python Code Generation by Asking Clarification Questions” reports that clarification of underspecified natural-language descriptions improved generated-code precision across its evaluation metrics. Mu et al.’s ClarifyGPT study separately evaluates targeted clarification for ambiguous requirements.
  • Requirements and verification: Han et al.’s “ArchCode” organizes functional and nonfunctional requirements from textual descriptions and connects individual requirements to generated tests.
  • Executable specifications: The official Gherkin reference describes Given as initial context, When as an event or action, and Then as an expected observable outcome. Cucumber’s BDD documentation explains the human purpose behind the format: business and technical people develop shared understanding through concrete examples that remain readable by people and can be checked through automation.
  • Gherkin for AI development: In a June 2026 post, Robert C. Martin describes converting agent-produced tasks to Gherkin before a coder agent creates acceptance tests, unit tests, and implementation. His Swarm Forge demonstration documents Gherkin acceptance tests and Gherkin-level mutation testing as parts of the broader agent workflow.
  • First-party Gherkin exploration: Adding Gherkin scenarios to a user story improved behavioral specificity during AI-driven development. The author and team decided that adopting it immediately would disrupt newly formed product management and QA teams more than the added clarity and code quality justified. They plan to revisit the decision in 2027. This is an applied evaluation, not a controlled benchmark.
  • Login rebuild: The internal point-of-sale login example is a first-party account developed more fully in “Your AI Can Write Code. It Still Needs Stories”. The existing application’s CRM authentication and role-driven authorization made a generic login implementation incorrect for the business.
  • Vibe-coded application: By August 14, 2026, the application refactor was substantially complete. The author had identified 24 significant issues, including memory leaks, data bleeding between objects, missing thread safety in several places, and a 3,233-line god class, with no additional significant issues expected beyond those documented. The code produces its intended output when it processes one request at a time. This is a dated first-party observation, not a benchmark of all AI-generated software.
← The canonical essay