Intent-Driven Programming: From Vibe Coding to Spec-Driven Development

Intent-Driven Programming: From Vibe Coding to Spec-Driven Development
QR code for this page

A course on AI-assisted software development from vibe coding, intent-driven and spec-driven approaches, context engineering and agents through change provenance, verification, rollback, and critical-system safety.

Unit 1: The Abstraction Evolution of Programming and the Concept of Intent

1.1. Rethinking Programming

Programming is often equated with writing code in a programming language. Yet code is not programming itself; it is one of the representations people use to transfer a solution idea to a computer.

At its most basic level, a programming problem can be considered through the following chain:

Problem → mental model → algorithm → representation → execution

An engineer first tries to understand the problem and then designs a solution for it. The solution may be an algorithm, a state machine, a data flow, a rule set, a mathematical model, or a combination of these. A programming language makes it possible to express that solution in a form a computer can process.

For this reason, it is incomplete to view the history of programming only as the history of languages. It is also the history of our ability to tell machines what we want from increasingly higher levels of abstraction.

In the early periods, the programmer largely told the computer how it should operate. Today, with generative artificial intelligence and software-development agents, we increasingly describe what we want, the boundaries within which we want it, and the conditions a correct result must satisfy.

This change does not eliminate programming. It changes the layer of the programming activity that is directly visible to the human developer.


1.2. From Moving Closer to the Machine to Moving Away from It

Every major development in the history of computer programming has hidden a certain class of detail from the programmer.

Machine code required working with numerical representations of processor instructions, while assembly language gave them symbolic names. High-level languages introduced variables, functions, and data structures instead of raw memory addresses and processor instructions. Operating systems abstracted a substantial part of hardware detail. Libraries and frameworks turned recurring infrastructure work into reusable components.

A rough progression can be described as follows:

Machine code
    ↓
Assembly
    ↓
High-level programming languages
    ↓
Libraries and runtimes
    ↓
Frameworks and domain-specific languages
    ↓
Visual and low-code development
    ↓
Natural-language, AI-assisted development

The common property of this progression is that, at each stage, the amount of detail the programmer must manage directly decreases.

A loop written in C may translate into many processor instructions at machine level. A single collection operation in Java may rely on memory management, runtime checks, and virtual-machine behavior. A Spring Boot annotation may stand on top of a broad infrastructure involving an HTTP server, routing, serialization, and dependency management.

AI-assisted programming can be viewed as a continuation of this abstraction trend.

Previously, we might write:

for (int i = 0; i < values.length; i++) {
    ...
}

For some tasks, we can now express an intention such as:

Group these records by date without changing the existing ordering behavior
and process them with the lowest possible additional memory cost.

The important difference is that artificial intelligence is more than a syntax converter. It interprets the stated objective, uses context, generates possible solutions, and materializes them in a programming language.


1.3. From Syntax to Intent

In traditional programming, the central question in an engineer's mind is often:

“How do I express the algorithm I designed in this programming language?”

In AI-assisted development, the question is increasingly becoming:

“How do I express the behavior the system must exhibit, its boundaries, and the criteria for correctness?”

The change may appear small, but it shifts the center of software production.

Traditional flow:

Problem
  ↓
Algorithm
  ↓
Programming language
  ↓
Compiler / interpreter
  ↓
Machine

An intent-oriented flow is closer to:

Problem
  ↓
Intent
  ↓
Specification
  ↓
Context and constraints
  ↓
Artificial intelligence / agent
  ↓
Programming language
  ↓
Compiler / runtime
  ↓
Machine

The programming language has not disappeared. A new interpretation and generation layer has been inserted between the human and the programming language.

For this reason, calling natural language directly a “new programming language” can be technically misleading. Natural language is ambiguous; the same sentence can be interpreted in different ways. Java, C, or Rust, by contrast, have formal syntax and explicit semantic rules.

A more precise statement is:

Natural language is becoming one of the new high-level control interfaces of the programming process.


1.4. Definition and Scope of intent-driven Programming

Intent programming is used here not as the name of a single standardized industry method, but as a conceptual umbrella for intent-driven AI-assisted development. In current practice, this space overlaps with more widely recognized or more precisely defined ideas such as vibe coding, Spec-Driven Development, and context engineering.

In intent-driven programming, the developer describes the behavior to be achieved, the boundaries, the properties that must be preserved, and the criteria for correctness instead of directly writing every implementation detail. Vibe coding represents a looser, outcome-driven end of this spectrum, while Spec-Driven Development disciplines intent through structured specifications, constraints, acceptance criteria, and verification.

Here, “intent” is more than a request such as:

Add user management.

A real engineering intent carries more information:

Preserve the behavior of the existing user-management flow.

Add the new user source to the existing authorization model.

Do not change the database schema.

Do not break existing API contracts.

Do not create any execution path that bypasses authorization checks.

Preserve the existing error semantics when external-service calls fail.

The developer is no longer describing only the requested behavior, but also the boundaries of the change space.

A more accurate model of intent programming is therefore:

Intent = what to do + what not to do + invariants to preserve + success criteria

When context, tools, and verification are added, an engineering process emerges:

Intent
+
Specification
+
Context
+
Constraints
+
Tools
+
Verification

A good outcome does not depend only on a well-written instruction. In AI-assisted code generation, the decisive factor is usually not a “clever prompt,” but whether the project architecture, rules, examples, tools, memory, and boundaries are supplied as the right context.


1.5. Prompt Engineering and intent-driven Programming Are Not the Same Thing

Writing effective instructions for an AI model is a useful skill. Treating that skill as the entirety of intent-driven programming, however, is insufficient.

For example:

Write a faster version.

is an instruction, but it is not an engineering specification.

The word “faster” does not answer questions such as:

  • Under what load?
  • Mean latency or worst-case latency?
  • Is throughput supposed to increase?
  • May memory consumption increase?
  • May consistency semantics change?
  • Must result ordering be preserved?
  • Is a behavior change allowed?
  • On what hardware will the measurement be made?

For this reason, more mature AI-assisted software development shifts the focus from prompt engineering toward context engineering and specification engineering.

Information a capable AI agent may need includes:

  • system architecture,
  • coding rules,
  • domain model,
  • data model,
  • API contracts,
  • security boundaries,
  • known technical debt,
  • performance targets,
  • previous architectural decisions,
  • behaviors that must not change,
  • acceptance criteria.

1.6. Vibe Coding

The term “vibe coding” became widely used in 2025 after Andrej Karpathy described a working style in which the desired behavior is stated in natural language and progress is driven mainly by the observed result rather than by closely examining the details of the generated code.

In its simplest form, the process may look like this:

Write the request
   ↓
Let AI generate the code
   ↓
Run it
   ↓
If an error occurs, give the error message to AI
   ↓
Try the new version

This approach can be extremely productive for small utilities, experiments, personal applications, and rapid prototypes.

The problem arises when the same method is moved into production systems without regard to risk class.

A program:

“appearing to work”

and:

“behaving correctly under all defined conditions”

are not the same thing.

Vibe coding is therefore treated here not as the whole of intent-driven development, but as its looser and less specification-driven end.


1.7. Spec-driven and Structured AI-assisted Development

Validation loop from intent through specification implementation tests and evidence
Intent to specification validation loop

There is a broad space between vibe coding and traditional engineering. One of the more disciplined approaches in this space is Spec-Driven Development. Here, the specification brings intent, requirements, constraints, acceptance criteria, and verification into a shared source for humans and AI.

An experienced developer may:

  1. analyze the problem,
  2. define the solution boundaries,
  3. make the architectural decision,
  4. assign a specific subtask to the AI,
  5. inspect the generated change,
  6. diagnose a failure,
  7. ask the AI to implement the correction.

Here, artificial intelligence is less a decision-maker and more an implementation accelerator.


A specification becomes executable through testability, not through the length of its prose. “The system must be fast” is not an acceptance criterion: the workload, concurrency, data volume, latency percentile, and expected behavior under failure must be stated. The change-producing agent also needs explicit invariants for interfaces, schemas, data flow, and backward compatibility. Successful execution of generated code does not prove those invariants. Each requirement should map to an independent test, measurement, or review finding.

1.8. Agentic Engineering

A software agent is more than a conversational model that produces a single answer.

It can receive a task, inspect the environment, read files, execute commands, observe the result, and determine its next step accordingly.

A simplified agent loop is:

Perceive the objective
    ↓
Plan
    ↓
Take action
    ↓
Observe the result
    ↓
Revise the plan if necessary
    ↓
Repeat

For this reason, having a powerful language model alone does not create a powerful software-development system.

1.8.1. The Agent Loop in Claude Code

Claude Code is a concrete example of this distinction. Through the terminal, filesystem, version-control state, and other permitted tools, it does more than produce text: it can inspect the environment, perform an action, observe the result, and use that result as evidence for the next step.

Treating this as a single “generate code” call misses the engineering structure. A more useful model is:

Intent
  ↓
Acquire context
  ↓
Choose an action
  ↓
Use a tool
  ↓
Observe the result
  ↓
Update the working hypothesis
  ↓
Use another tool if needed
  ↓
Verify

Model reasoning and the external effect of a tool call are separate concerns. Reading a file, invoking a compiler, obtaining a test result, or inspecting git diff creates new evidence. The agent can revise its next decision in response to that evidence.

The important engineering consequence is:

Agent quality is a property of the model + context + tool contracts + permissions + verification loop, not of the model alone.

The same model can therefore behave very differently in two repositories or under two tool configurations. A well-structured project exposes its build, test, static-analysis, and diagnostic paths. A poorly structured project forces the agent to spend much of its effort inferring the environment before it can safely change anything.

A plan is not proof either. It is a hypothesis about the system. Files, call chains, configuration, tests, and runtime outputs are evidence that confirms or falsifies that hypothesis.


Unit 2: Lifecycle, Architecture, Constraints, and Verification

Intent-driven development must turn natural-language requirements into observable acceptance criteria, invariants, and prohibited behaviors. Identify existing contracts and modules that must remain unchanged before implementation. Verify generated changes incrementally, separating compilation, functional regression, and behavioral-boundary checks. Faster generation does not remove the need for review and accountability.

2.1. The Changing software-development Life Cycle

A traditional software-development life cycle can be summarized roughly as:

Requirements
↓
Analysis
↓
Design
↓
Coding
↓
Testing
↓
Deployment
↓
Maintenance

Agile methods and DevOps had already shortened the time between these stages substantially. Artificial intelligence is blurring the boundaries between them further.

Today, a developer can discuss a requirement, evaluate a data model, draft an API, generate code, prepare tests, inspect a failure, and write documentation within the same working session.


2.2. Continuing Importance of Software Architecture

Artificial intelligence can propose architectural options, but real architectural decisions are not composed only of technical facts.

For example:

  • distributed or centralized?
  • consistency or availability?
  • low latency or high throughput?
  • off-the-shelf product or in-house development?
  • general solution or specialized solution?

The answers depend on business needs, operations, regulation, team structure, and expected future use.


2.3. Negative Specification

A traditional requirement usually describes what the system should do:

The user must be able to export the report.

When AI is used to modify an existing and complex codebase, positive requirements alone may be insufficient.

It may also be necessary to state:

Do not change the existing authorization behavior.

Do not change the database schema.

Do not affect the proven behavior on the Listener side.

Do not add a new dependency.

Do not change concurrency semantics.

Such statements can be considered negative specifications.

A strong task definition in intent programming can contain four parts:

What will be done?
What will not be done?
What must remain unchanged?
How will correctness be demonstrated?

2.3.1. Guidance Is Not Enforcement

Writing a rule in natural language does not make the rule mechanically binding. This distinction becomes critical in agentic development.

For example:

Do not run DDL against the production database.

is a strong engineering instruction, but the sentence itself is not an access-control boundary.

In tools such as Claude Code, different mechanisms address different parts of the problem:

CLAUDE.md / rules
→ guide behavior

permissions
→ constrain which tools or operations may be used

hooks
→ run deterministic checks or actions at defined events

sandbox
→ enforces operating-system boundaries, especially for shell processes

A requirement such as “never write to this directory” should therefore not remain only in a prompt when violation carries a high cost. Where feasible, the environment should enforce the boundary as well.

This leads to an important principle for intent-driven programming:

Do not merely remind the model about critical invariants; make them enforceable by the system where practical.


2.4. The Codebase Is Not the Whole System

An AI agent may read the entire source code and still fail to understand the complete system.

Codebase ≠ system

The real system is broader:

System =
Code
+ Data
+ Infrastructure
+ Hardware
+ Users
+ Operations
+ Security
+ History
+ Organizational constraints
+ Domain knowledge

This makes the problem of tacit knowledge particularly important in legacy systems.


2.5. Strengths of Artificial Intelligence Systems

Current generative AI systems are especially effective in software-development tasks with strong recurring patterns.

Examples include:

  • repetitive code generation,
  • writing API clients,
  • data transformations,
  • basic algorithms,
  • code explanation,
  • documentation generation,
  • format conversion,
  • test scaffolding,
  • identifying candidate defects,
  • modernizing old API usage,
  • locating relevant parts of a codebase,
  • small- and medium-scale refactoring,
  • multi-file implementation changes.

2.6. Reliability Limits of Artificial Intelligence Systems

It would be inaccurate to answer this question with a permanent list of things AI “cannot do.” Model capabilities change rapidly.

A better approach is to examine reliability.

Possible problems include:

  • missing context,
  • incorrect assumptions,
  • inventing nonexistent APIs or dependencies,
  • overlooking edge cases,
  • changes that appear locally correct but are globally wrong,
  • interpreting the requirement differently from the intended meaning,
  • silent behavioral changes.

The primary question should therefore not be:

“Can AI do this?”

but:

“What evidence justifies trusting this output as correct?”


2.7. As Generation Becomes Easier, Verification Becomes Harder

Verification backlog when generation outpaces review with computed steps and state transitions
Verification backlog when generation outpaces review
Generated inputs, invariant checking, and shrinking to a minimal counterexample
Property-based testing

Before AI-assisted development, implementation was often one of the main bottlenecks.

Agents can now generate changes containing hundreds or thousands of lines within minutes.

A new bottleneck therefore appears:

Old bottleneck:
implementation

New bottleneck:
verification

A change generated by an agent in thirty seconds may require half an hour for an engineer to understand.


2.8. Testing Is No Longer Only a defect-finding Tool

The diminishing returns of correlated tests where ten independent tests detect a defect with probability 0.97 but ten tests with correlation 0.3 only 0.76
Detection probability of correlated tests
Mutation-testing example where a comparison-operator mutation is killed by the x=10 boundary test
Mutation testing

In AI-assisted development, tests have an additional role.

A test is a machine-verifiable expression of intent.

For this reason, tests and evaluation sets are increasingly becoming a form of executable specification for artificial intelligence.


2.9. The Determinism Problem

The unbiased pass@k estimator for n 20 samples with c 6 correct giving 0.30 at k 1, 0.87 at k 5 and 0.995 at k 10, above the independent-draw approximation
The pass@k estimator

Classical programming relies largely on deterministic structures.

f(x) → y

A generative model, however, performs probabilistic generation.

This creates an interesting engineering situation:

Probabilistic development process
        ↓
Software expected to behave deterministically

As a result, reproducibility, version control, diff review, testing, and traceability become more important.


2.10. Intent Programming in Critical Systems

An error in a demonstration application and an error in a critical system do not belong to the same risk class.

In critical systems, incorrect behavior can cause:

  • data loss,
  • service interruption,
  • security vulnerabilities,
  • legal consequences,
  • physical harm.

Therefore, in critical systems:

As risk increases
↓
specification precision should increase
↓
verification should increase
↓
observability should increase
↓
authority boundaries should narrow
↓
human oversight should become stronger

2.11. Misinterpreting Speed in Critical Systems

The most visible advantage of AI tools is speed.

In software engineering, however, shorter development time is not by itself a measure of success.

A feature may be produced in ten minutes instead of two hours.

But if defect analysis takes two hours, if the change causes production incidents, creates technical debt, or introduces a security vulnerability, the real productivity gain is questionable.


2.12. The Production Rate of Technical Debt Has Also Increased

Artificial intelligence can generate good code quickly.

For the same reason, it can generate bad code quickly.

It is therefore incorrect to treat artificial intelligence directly as a “quality enhancer.”

A more accurate statement is:

Artificial intelligence is a capacity multiplier.


Unit 3: Professional Roles, Competence, and Productivity

Separate human and automated responsibilities by identifying decision rights. Requirement validity, architectural trade-offs, security exceptions, and deployment authorization demand distinct ownership. Tool-generated suggestions lacking measurable supporting evidence must not be treated as verified solutions. Preserve traceability among requested behavior, changed implementation, and the tests establishing confidence.

3.1. Opportunity for Junior Developers

Artificial intelligence can significantly increase the productivity of a junior developer.

A junior developer can inspect an unfamiliar API, generate example code, ask for an explanation of an error message, compare alternative algorithms, and generate test scenarios.

Used correctly, it can substantially accelerate learning.


3.2. Risk for Junior Developers

The same tool can weaken learning when used differently.

If a developer gives instructions without fully understanding the problem, copies the generated code, accepts it when it appears to work, and returns to AI whenever an error occurs, that developer may produce working software while their engineering competence develops much more slowly.

One of the important questions is therefore:

If AI removes the implementation work we previously had to perform in order to become experts, how will new experts be trained?


3.3. The Illusion of Competence

With artificial intelligence, a junior developer can produce an architecture document, tests, application code, an API, or SQL within minutes that looks highly professional.

The resulting artifact may appear far more advanced than the person's actual level of knowledge.

Output that looks senior-level
≠
senior-level reasoning

3.4. The Changing Role of the Senior Developer

As AI reduces implementation cost, the reasoning ability of a senior developer may become more valuable.

An experienced engineer often knows from experience which solution should not be implemented, which architectural boundary must be preserved, which optimization is unnecessary, and which defect can have serious production consequences.


3.5. Skill Atrophy for Senior Developers

The risk is not limited to junior developers.

If a senior developer delegates certain tasks entirely to artificial intelligence for years, they may lose reflexes in areas such as low-level debugging, SQL query analysis, memory behavior, or complex concurrency problems.

A healthy approach is not for artificial intelligence to think instead of the engineer, but to work with the engineer at a higher level of abstraction.


3.6. Definition and Scope of the Programmer Role

A programmer implements algorithms in code, uses data structures, understands programming languages, and fixes defects.

This is also the role most directly affected by artificial intelligence because syntactic generation and repetitive implementation work are among the software tasks most suitable for automation.


3.7. Definition and Scope of the Software Developer Role

A software developer does more than write code.

They consider the requirement, implementation, integration, testing, and maintenance of a feature together.


3.8. Definition and Scope of the Software Engineer Role

Software engineering is broader than producing code that works.

It aims to make a system reliable, maintainable, scalable, secure, measurable, and changeable.


3.9. The Computer Engineer

Computer engineering reminds us that software is not independent of hardware.

Real systems run on processors, memory, caches, storage, networks, input/output devices, and accelerators.

For this reason, in high-traffic and real-time systems, the difference between “working code” and an “appropriate engineering solution” becomes substantial.


3.10. The Computer Scientist

The idea that computer science loses its value in the age of artificial intelligence is incorrect.

Computability, complexity, algorithm analysis, graph theory, cryptography, information theory, and distributed algorithms remain fundamental.

AI can produce an O(n²) solution in a few seconds. Understanding why it collapses under millions of records requires computer-science knowledge.


3.11. Understanding Software and Writing Code Are Diverging

A person can produce large applications while writing very little code directly.

This raises a question:

Can software be produced without understanding software?

To some extent, yes.

In complex systems, however, recognizing that an AI-generated solution is wrong usually requires sufficient knowledge of the same domain.

To evaluate what AI has done, you must understand that work yourself to a meaningful degree.


3.12. Lines of Code Are No Longer a Productivity Metric

An agent can generate ten thousand lines of code in a few minutes.

Those ten thousand lines may create significant value, be unnecessary, or become technical debt.

Productivity should therefore be evaluated through measures such as problems solved, defect rate, production downtime, change failure rate, maintenance cost, performance, and security rather than the amount of generated code.


Unit 4: Performance, Concurrency, Security, and Trust

4.1. Performance Engineering

Artificial intelligence can provide useful performance suggestions.

But an instruction such as “make it faster” is dangerous.

Latency ↔ throughput
Memory ↔ CPU
Consistency ↔ availability
Precomputation ↔ memory
Parallelism ↔ concurrency cost

Performance intent must be measurable.


4.2. Concurrency

Concurrency is one of the areas that requires particular care in AI-generated code.

Code may compile, pass tests, and work with a single user while still producing a race condition in production.

For critical concurrent behavior, inspecting output alone is therefore insufficient. The invariants that must be preserved should be stated explicitly.


4.3. Distributed Systems

Intent programming becomes even more difficult in distributed systems.

Problems such as network partitions, delayed messages, retries, duplicate requests, ordering, clock skew, and partial failure arise across the system as a whole.

An AI system can satisfy a request to “add retries,” but an incorrect retry policy may cause the same operation to execute twice.


4.4. Cybersecurity

Artificial intelligence is a powerful assistant in security work.

It can scan code, identify weak patterns, correlate logs, and generate attack scenarios.

Security, however, is an adversarial domain.

The system must therefore also be evaluated under malicious input, while least privilege, attack surface, and trust boundaries are designed explicitly.


4.5. Digital Forensics

Artificial intelligence can make it easier to examine large data sets in digital forensics.

In a forensic process, however, technical correctness is not enough; evidence integrity, traceability, reproducibility, and chain of custody also matter.

A model producing a convincing result does not make that result forensically reliable.


4.6. The Trust Problem

A response being fluent, detailed, or technical does not prove that it is correct.

Linguistic confidence ≠ epistemic confidence

In software engineering, the corresponding distinction can be expressed as:

Compiling code ≠ correct code

and

Code that passes tests ≠ a correct system under all conditions

4.6.1. The Trust Chain Is Larger Than the Model

In agentic development, trust is not limited to the question “is the model correct?” It also depends on whether tool output came from the intended source, whether the agent inspected the correct files, whether its privileges are broader than necessary, and whether untrusted external content is being interpreted as instruction.

A useful trust chain is:

user intent
→ project instructions
→ permission boundaries
→ tool invocation
→ tool result
→ model interpretation
→ code change
→ verification evidence

A fluent final answer can create false confidence if any link in this chain is weak.

External text—web pages, issue descriptions, logs, documents, and tool results—should be treated as data unless it is explicitly authoritative instruction. Text contained inside such data does not inherit the authority of the project owner. This is the software-agent form of the prompt-injection problem.

Reliable operation therefore needs two complementary mechanisms:

  • context that improves decision quality, and
  • technical boundaries that limit the impact of a bad decision.

Good documentation and explicit tasks support the first. Least privilege, permission rules, sandboxing, source control, read-only credentials, separated secrets, and deterministic gates support the second.


4.7. Responsibility

Artificial intelligence can generate code.

An agent can modify code.

A system can be deployed automatically.

But when damage occurs in production:

“The model generated it that way.”

is not an engineering justification.


4.8. Artificial Intelligence and Legacy Systems

One of the most valuable application areas for artificial intelligence may be old and complex codebases.

An agent can locate relevant files, explain call chains, identify old APIs, and suggest change points.

Legacy systems, however, contain more tacit knowledge.

4.8.1. Using Claude Code-style Agents Safely in Legacy Codebases

In a legacy system, the first task is often not implementation but discovery. File age or class names may not reveal where behavior actually lives. A method that appears unused may be invoked through an external integration; duplicate records may be part of a historical contract rather than accidental corruption; an unusual error response may have become a client dependency over many years.

A safer sequence is:

discover first
→ verify call and data flow
→ state the behavior that must survive
→ reduce the change surface
→ make the smallest viable change
→ execute the real verification path
→ re-check the diff and blast radius

Claude Code's search, file access, git awareness, and command execution can accelerate this investigation, but speed does not remove implicit contracts. A modernization that looks locally cleaner can still create a regression in a denormalized or historically layered production system.

Legacy-project context should therefore include more than the technology stack. High-value context can include:

  • immutable data models,
  • known duplicate-data semantics,
  • error behavior that must be preserved,
  • external contracts that are not visible in the repository,
  • proven legacy routines that should not be replaced casually,
  • production dependencies unavailable in development,
  • modules whose behavior is explicitly out of scope.

When this knowledge cannot be reconstructed reliably from code, it deserves a deliberate place in persistent or task-specific context.


Unit 5: Context Engineering and Agent Infrastructure

5.1. Context Engineering

Authority hierarchy across policy repository task and evidence context
Context authority hierarchy

One of the most important skills in AI-assisted software development is managing context.

5.1.1. Persistent Context

Rules that apply to every task:

  • architectural principles,
  • coding standards,
  • security boundaries,
  • general constraints.

5.1.2. On-demand Context

Information required only for a particular task:

  • specific module documentation,
  • data model,
  • historical incident records,
  • relevant source code.

5.1.3. Context Surfaces in Claude Code

Claude Code provides several context surfaces with different lifetimes and costs. Project knowledge does not need to live in one ever-growing prompt.

A useful distinction is:

CLAUDE.md
→ persistent instructions written by humans

.claude/rules/
→ rules scoped to paths or topics

auto memory
→ local notes Claude derives for reuse across sessions

skills
→ reusable procedures and knowledge loaded for relevant task types

subagents
→ specialized workers with separate context windows

MCP
→ structured access to external tools and data

tool outputs
→ temporary evidence acquired during execution

conversation
→ decisions and working state accumulated for the current task

Duplicating the same knowledge across all of these surfaces is counterproductive. Information should be placed according to its lifetime and scope.

CLAUDE.md is appropriate for facts and rules that matter across many tasks: non-obvious build commands, architectural boundaries, immutable contracts, or team conventions. A detailed procedure needed only for database migrations does not need to consume every session; it is a better fit for a skill or task-specific reference.

Current Claude Code versions also provide auto memory. It can retain build commands, debugging observations, and project patterns across sessions. Auto memory is useful, but it is not an authority. A note can become stale after the codebase changes. Memory should therefore be treated as an index that accelerates rediscovery, not as a replacement for current source and verification.

5.1.4. The Context Window Is a Working Set

Everything that enters context competes for attention:

system instructions
+ project rules
+ conversation
+ file contents
+ tool outputs
+ loaded skills
+ MCP tool definitions
+ intermediate results

A larger context window does not justify preloading the entire repository. Cost increases, and relevant facts can become harder to isolate.

Claude Code addresses this in several ways. Some directory-specific instructions can load when relevant files are accessed; skill bodies load when invoked; MCP schemas can be deferred through tool search; subagents operate in separate context windows; and long sessions can be compacted.

These mechanisms share one principle:

Keep only always-needed information in always-on context; retrieve the rest when the task proves it is needed.

5.1.5. Separate Persistent Context from Working Evidence

A test log, transient stack trace, or one-off command output is not project memory. By contrast, “integration tests for this module are run with this command” may deserve persistence if it recurs across tasks.

Failing to make this distinction creates two problems:

  1. persistent instruction files accumulate ephemeral detail;
  2. observations that were once true are reused later without revalidation.

Context engineering is therefore not merely the act of adding information. It is the management of scope, lifetime, provenance, and freshness.


5.2. Designing the System That Produces Software

In AI-assisted development, the engineer's output may increasingly be more than source code.

Specifications
+
Context
+
Agents
+
Tools
+
Tests
+
Quality gates
+
Feedback

This system then produces code.

5.2.1. Claude Code as a Configurable Execution Layer

In Claude Code, the system around the model can be decomposed into mechanisms with distinct responsibilities:

CLAUDE.md / rules
→ what the agent must know

skills
→ how a recurring task should be carried out

subagents
→ which specialized context should perform the work

permissions
→ which tools may be used

hooks
→ which deterministic checks run at defined events

MCP
→ which external systems are exposed through structured interfaces

tests / linters / build
→ what evidence constrains the generated change

This resembles separation of concerns in conventional architecture. Using every mechanism for every problem increases both context and maintenance cost.

“Run the formatter after every Java edit” is better expressed as a deterministic hook than as a sentence the model must remember. “The domain layer must not import infrastructure” is a project rule. “Follow this database migration procedure” may be a reusable skill. “Read issue ENG-4521” can be exposed through MCP or an appropriate CLI.

The design rule is simple:

Give judgment to the model; give repeatable and mandatory work to deterministic mechanisms.

Interpreting a linter report can be model work. Ensuring the linter actually runs after a relevant change belongs to a hook, CI pipeline, or equivalent gate.

5.2.2. Tool Contracts Are Software Design

For an agent, a tool name, parameter schema, and response shape are an API between a probabilistic decision-maker and a deterministic system.

Ambiguous tools, overlapping capabilities, and oversized responses increase decision error and context cost. Good tool design therefore follows familiar API principles:

  • clear responsibility,
  • unambiguous parameters,
  • explicit error states,
  • compact output,
  • narrower interfaces for high-impact operations.

The same applies to MCP servers. MCP gives the agent a structured interface to external systems, but the protocol does not replace authentication, authorization, input validation, or audit controls on the server side.


5.3. Teams Composed of Humans and Agents

When AI agents are used as semi-autonomous software components that take on specific tasks, team structure may change.

Human
  ↓
Architectural decision and task definition

Agent
  ↓
Implementation

Test system
  ↓
Verification

Agent
  ↓
Correction

Human
  ↓
Final review

5.3.1. Subagents: Context Isolation Before Parallelism

A major value of Claude Code subagents is not merely doing more work at once. A subagent can work in its own context window with its own instructions and tool restrictions. Large exploration traces can therefore remain outside the main conversation.

A complex change can be decomposed, for example, as:

main agent
→ intent, scope, synthesis

exploration subagent
→ locate relevant files and call paths

security subagent
→ inspect authorization and data boundaries

verification subagent
→ identify affected test and validation surfaces

A subagent should return the evidence needed for the parent decision, not its entire working transcript. Otherwise context isolation is defeated by a large result payload.

Parallelism also has limits. Two agents editing the same files can create merge conflicts and inconsistent assumptions. Independent research, read-only analysis, or verification of separate modules is usually safer to parallelize.

The useful scheduling questions are therefore:

  1. What context does this task require?
  2. What tools and permissions are actually necessary?
  3. In what evidence format should the result return?

More agents do not automatically mean more effective engineering. Coordination, shared state, and verification costs rise as well.


Unit 6: The Future of the Profession, Responsibility, and Systems Thinking

6.1. The Fundamental Skill of the Future Is Systems Thinking

Knowing a specific programming language does not become unimportant.

But by itself, it may no longer be a sufficient differentiator.

A strong engineer of the future will be able to evaluate the following chain as a whole:

Requirement
↓
Domain model
↓
Architecture
↓
Data
↓
Concurrency
↓
Security
↓
Performance
↓
Failure modes
↓
Operations
↓
Observability

6.2. Future of Software Professions

It is not possible to provide a reliable number or date.

It is, however, highly plausible that task composition will change.

Work whose relative value may decrease includes:

  • repetitive code generation,
  • standard CRUD development,
  • mechanical transformations,
  • simple documentation production.

Work whose relative value may increase includes:

  • domain knowledge,
  • architecture,
  • security,
  • performance,
  • specification,
  • verification,
  • systems thinking,
  • technical accountability.

6.3. Future Relevance of Programming Knowledge

The amount of code knowledge required for simple software production may decrease.

As complexity and risk increase, however, the situation changes.

If a system performs financial transactions, processes personal data, carries very high traffic, operates in real time, or controls physical processes, engineering knowledge is required to evaluate the output of the production tool.


6.4. The Philosophical Dimension of Intent Programming

An engineer defines the requirement, designs the architecture, and states the constraints; an agent produces ten thousand lines of code, and the engineer reviews only the critical changes.

Who wrote the program in that case?

The artificial intelligence?

The engineer?

Or the system composed of the human and the artificial intelligence?

Authorship may increasingly approach the question:

Who designed the behavior?


6.5. The New Boundary Between Human Thought and Machine Production

Previously, most of the translation burden rested on the human:

Think through the algorithm
↓
Write the syntax
↓
Fix the errors

In the new approach, part of that translation is delegated to the model:

Human:
Objective + boundary + reasoning

AI:
Implementation + transformation + repetition

Human:
Verification + responsibility

6.6. Growing Importance of Fundamental Engineering Knowledge

As abstraction rises, lower-level knowledge may be used less frequently in everyday work while becoming more valuable when it is critical.

A developer may not deal with memory layout every day. But when a production problem is caused by memory pressure, someone must be able to recognize it.

Fundamental knowledge may therefore become less of a mechanical skill used continuously and more of a capacity to break through abstraction and understand the lower layers when necessary.


6.7. A Sound Engineering Model for Intent Programming

A practical working model can be organized as follows.

  1. Define the problem.
  2. Understand the existing system.
  3. State the intent.
  4. State the constraints.
  5. Define the success criteria.
  6. Provide the appropriate context.
  7. Generate the change.
  8. Verify it.
  9. Observe production.
  10. Feed the resulting knowledge back into the process.

Artificial intelligence then stops being a single “prompt → code” operation and becomes part of a closed-loop engineering system.

6.7.1. Applying the Model with Claude Code

The ten-step model can be translated into an operational sequence for a coding agent:

1. State intent and acceptance boundaries.
2. Separate behavior that must remain unchanged.
3. Discover the relevant repository surface.
4. Load project instructions and task-specific references.
5. Narrow tools and permissions to the task.
6. Produce a small change.
7. Gather build, test, static-analysis, or runtime evidence.
8. Inspect the diff and blast radius.
9. Compare the result with the original intent.
10. Persist only new knowledge that has lasting engineering value.

CLAUDE.md, skills, or auto memory are context layers, not the implementation and not proof of correctness. Evidence still comes from code, tests, compiler behavior, data contracts, and runtime observations.

Permissions do not replace a correct task specification either. An agent restricted to safe tools can still modify the wrong safe file. Safe execution and correct engineering are different properties.

A mature workflow combines both:

correct intent + sufficient context + constrained authority + real verification

6.8. A Concise Engineering Approach

In intent programming, the boundary between providing enough detail and providing unnecessary detail matters.

A long instruction is not always a good instruction.

The goal is not to tell the model everything, but to tell it the right things.

A good specification should be:

  • concise,
  • clear,
  • internally consistent,
  • measurable,
  • bounded.

Intent programming is not about saying more.

It is about reducing ambiguity.


Unit 7: Repository Context, Memory, and Verification Engineering

7.1. Repository Context Is an Engineering Artifact

A large repository cannot be understood efficiently by repeatedly loading arbitrary source files into an agent's context. The repository itself needs a navigable knowledge layer.

The context layer can be divided into six responsibilities: persistent rules, architecture maps, workflow descriptions, data contracts, known risks, and task-specific source. They do not need to load at the same frequency; information required on every task should not occupy the same context tier as material needed only for a narrow class of work.

Persistent instructions should contain rules that are broadly valid. Detailed architecture, database behavior, workflows, validation procedures, and historical lessons are better kept in focused documents that can be retrieved when needed.

This changes documentation from passive prose into part of the software-production system. A short entry document can tell the agent where to look. It does not need to tell the agent everything the repository contains.

This distinction matters because context has a cost. Large instruction files compete with the task, relevant source code, tool results, and the model's own working state. A repository guide is therefore more useful when it acts as a map than when it becomes an encyclopedia.

7.1.1. Physical Placement of Repository Context

Current Claude Code projects can make the theoretical separation concrete by distributing information according to scope:

CLAUDE.md
→ short, persistent, repository-wide instructions

.claude/rules/
→ path- or topic-scoped rules

.claude/skills/
→ on-demand workflows and domain knowledge

.claude/agents/
→ specialized subagent definitions

.claude/settings.json
→ permissions, hooks, and project behavior

.mcp.json
→ shareable MCP server definitions

docs/
→ detailed architecture and contract documentation

The general lesson is not the file names themselves. It is placing information according to loading frequency and enforcement requirements.

A rule needed on every turn may belong in persistent context. A procedure needed only for a particular class of work should load on demand. A boundary whose violation must be prevented should not remain only as documentation.

Repository context should also avoid becoming a hand-maintained copy of the repository. Duplicated file lists and class descriptions become stale quickly. A better design uses maps, search, symbol resolution, and targeted reading to return to the source of truth.


7.2. Progressive Disclosure of Context

Progressive repository-context loading versus eager monolithic token consumption

Giving an agent the entire repository at the beginning of a task may appear comprehensive, but completeness and relevance are different properties.

A more economical path moves from the task to a repository map, then to the relevant subsystem and workflow or contract, and only then to targeted source reading and implementation.

This is progressive disclosure: context is introduced as evidence makes it necessary.

A database-write change may first require the database contract and data flow. Only after the affected service is identified may the corresponding entity and persistence code need to be read. A user-interface change may require a workflow description and the relevant page implementation, but not database documentation.

The objective is not to minimize tokens at any cost. Removing a critical invariant to save tokens is false economy. The objective is to maximize useful information per token.

A compact but incomplete context can produce a fast wrong answer. A huge context can bury the important constraint among irrelevant details. Effective context lies between these extremes.

7.2.1. Progressive Loading with Skills

Claude Code skills are a direct example of progressive disclosure. A short description can make a skill discoverable, while the full SKILL.md content enters context only when the skill is used. Large references, examples, or deterministic helper scripts can remain separate inside the skill directory.

This avoids two opposite costs at once. Putting everything in CLAUDE.md creates permanent context bloat, while rediscovering every procedure for every task repeats exploration and token expenditure.

A good skill does not teach the agent generic framework knowledge. It captures a recurring project-specific decision path. “How should a migration be performed safely in this repository?” is more valuable than a general tutorial on database migration.

Progressive loading applies to tools as well. In environments with many MCP tools, carrying every complete tool schema on every turn is wasteful. Tool search and deferred loading keep the active surface closer to the needs of the current task.


7.3. Repository Maps and Knowledge Graphs

File names and directory trees provide useful structure, but relationships in mature systems frequently cross those boundaries.

A service may depend on an entity, a workflow may depend on several controllers, and a security rule may be documented far from the code that enforces it. A repository knowledge graph can represent such relationships explicitly.

Controller
   ↓ calls
Service
   ↓ uses
Repository
   ↓ maps
Entity

Graph-oriented repository tools can also connect code with architectural notes, workflow documents, specifications, and other artifacts.

One example is Graphify, which can build a project graph and expose operations such as query, path, and explain. Its supplied documentation describes local syntax-tree extraction for code and distinguishes directly extracted relationships from inferred ones. The important engineering idea is broader than a particular product: query the structure first, then read the smallest source set needed to verify it.

graph query
   ↓
candidate nodes and relations
   ↓
path/explanation
   ↓
targeted source read
   ↓
source-level verification

A graph is not a replacement for source code. It is a navigation and context-selection layer. An inferred relationship is evidence for where to investigate, not proof that runtime behavior has been established.


7.4. Maps, Workflows, Contracts, and Lessons Have Different Jobs

Repository documentation becomes more useful when each document type has a narrow responsibility.

  • Agent instructions: What rules must always be followed?
  • Code map: Where is a capability implemented?
  • Data flow: How does information move through the system?
  • Workflow: What sequence of behavior must remain intact?
  • Database contract: What persistence assumptions are invariant?
  • Runtime safety: What may safely be executed in each environment?
  • Known risks: Where can a seemingly local change cause damage?
  • Lessons: What previously failed, and what was learned?
  • Completion validation: What proves the task is complete?

Combining all of these into one large document reduces selectivity. Separating them allows an agent to retrieve only the material relevant to the current change.

The documents should point toward authoritative source rather than duplicate it unnecessarily. Duplicated facts drift. A map that says where a rule is implemented is often safer than copying the implementation into several documents.


7.5. Context Freshness Is Part of Correctness

A repository map that describes yesterday's code can be more dangerous than having no map at all because it creates false confidence.

Generated maps, graphs, and documentation therefore need a freshness strategy. Code changes should be validated first; contract changes should update the relevant documentation; the graph or index should then be refreshed so that the next task begins from current context.

Incremental updates are preferable when they can reliably identify changed material. Rebuilding every artifact after every small change may waste time and tokens; never updating them creates drift.

Automation can help. Repository hooks can refresh structural indexes after commits or branch changes, while explicit updates can follow merges or pulls. The exact mechanism is less important than the invariant:

The navigation layer must not silently become detached from the source it describes.

Generated context should also be excluded from recursive or cache-sensitive indexing paths where appropriate. Otherwise an automatically rewritten graph or report can itself trigger unnecessary invalidation or repeated indexing.


7.6. Token Efficiency Is Not Prompt Shortening

A short prompt can still cause enormous token consumption if the agent must rediscover the repository from scratch.

Conversely, a somewhat longer task specification may reduce total cost if it identifies the correct subsystem, invariants, validation path, and forbidden changes.

Total context cost ≈
Task specification
+
Repository exploration
+
Source reads
+
Tool output
+
Retries
+
Corrections
+
Verification

Optimizing only the first term is misleading.

Repository exploration is particularly important. Recent coding-agent research reports that separating repository exploration from implementation can reduce solver token consumption, while other work shows that indiscriminately adding repository instructions can increase inference cost without improving task success.

The implication is not that one retrieval technique is universally best. Static maps, lexical search, structural analysis, semantic retrieval, graph traversal, and agent-driven navigation have different strengths.

Retrieve evidence according to the task; do not preload context merely because it exists.

7.6.1. Tool Output and Schema Cost

A large share of token consumption may come from tools rather than from the user's prompt. A full test log, complete database schema, enormous git diff, or verbose MCP response can dominate context in a single operation.

Agent-facing tools therefore benefit from conventional data-access techniques:

  • filtering,
  • pagination,
  • range selection,
  • summary fields,
  • drill-down on demand,
  • sensible output limits.

For an agent, “more data” is not the same as “more evidence.” The correct line range or targeted query can carry more decision value than hundreds of kilobytes of raw output.

MCP tool names and schemas also consume context. As a tool catalog grows, descriptions should remain concise but discriminative, overlapping tools should be reduced, and high-impact operations should be represented by narrower interfaces when possible.

Token efficiency can therefore be viewed as:

useful evidence / total context cost

The objective is not merely to minimize the denominator; it is to maximize the decision value of what enters context.


7.7. Minimal Persistent Instructions

Persistent repository instructions are valuable because they can preserve invariants across tasks.

They can also become harmful when every local preference, historical detail, and temporary workaround is promoted into an always-loaded rule.

A persistent instruction should generally earn its place when at least one condition holds:

  • violating it can cause a serious defect,
  • it applies to many tasks,
  • it cannot be inferred reliably from the source,
  • it identifies an authoritative document that must be consulted,
  • it defines a mandatory validation or safety boundary.

Task-specific details belong closer to the task. The persistent core should carry only routing information and invariants; task-relevant documents can be retrieved through graph or search, followed by targeted source reading and runtime or build evidence.

Research published in 2026 on repository-level agent context reinforces the need for restraint: repository instruction files can increase exploration and inference cost when they contain unnecessary requirements. Persistent context should therefore be treated as a scarce engineering resource, not a dumping ground for everything the team knows.

7.7.1. Detecting Conflicts and Authority Boundaries in Persistent Rules

Before shortening repository instructions, determine what each rule governs. Record its scope (the whole repository or a subsystem), authority (persistent guidance, task request, or tool-enforced restriction), impact of violation, and observable validation. If one rule requires running the full test suite for every change while another mandates tests only for the touched module, the defect is a conflict of scope and priority, not a word-count problem. Removing a few sentences does not establish which rule is authoritative.

Security requirements, data invariants, and access boundaries should be backed by executable enforcement where possible. One-off task procedures do not belong in permanently loaded repository guidance. Compare each revision of persistent instructions on at least one routine task and one boundary-violation case, checking both unnecessary execution cost and safety regressions.

7.7.2. A Persistence Test for CLAUDE.md

CLAUDE.md is a natural home for persistent instructions, which also makes it easy to overfill. Not every useful fact deserves to load into every session.

Four questions are usually enough: is the information needed across many tasks; can it be inferred reliably from the repository; does getting it wrong cause recurring defects; and can it be stated briefly and operationally? Information is a strong persistence candidate when it is broadly applicable, hard to infer, and costly to rediscover or violate.

Examples include:

  • unusual build or test commands,
  • architectural dependency prohibitions,
  • invariants related to data loss,
  • directories that should be treated as read-only,
  • mandatory project-specific verification.

Framework tutorials, long API documentation, easily discoverable directory listings, and raw logs from a single incident generally do not belong in always-on context.

Keeping persistent instructions small is not a stylistic preference. It is attention-budget management.


7.8. Work Memory and Engineering Memory

Long-running AI-assisted development creates another problem: the same mistakes can be rediscovered repeatedly. The useful distinction is between working memory and engineering memory.

Working memory contains temporary state: what is currently being changed, files already inspected, unresolved questions, and intermediate tool results.

Engineering memory contains durable knowledge: a failed approach and why it failed, a hidden invariant discovered during debugging, a recurring validation requirement, or a dependency that repeatedly causes regressions.

Temporary traces should not automatically become permanent rules. The outcome should first be evaluated; only a reusable lesson should be distilled, stored with provenance, retrieved when relevant, and re-verified when the code has changed.

Graph-based tooling can support this by linking lessons to the concepts or files they concern. The important property is provenance: the agent should distinguish an observation extracted from current source, an inference, and a lesson derived from an earlier task.

This reduces repeated exploration without turning old experience into unquestioned truth.

7.8.1. Auto Memory: Convenience, Not Authority

Claude Code's auto-memory mechanism can carry useful notes across sessions. It can reduce repeated discovery for build commands, project preferences, and debugging observations.

But an automatically written note is not automatically a durable engineering fact.

Memory content should be classified as a verified project fact, a temporary task observation, or a model inference. The first category may deserve promotion to an authoritative project instruction or document. The second should expire. The third should not become an invariant until it is verified against current sources.

A safer principle is:

Let memory accelerate discovery; let current source and verification decide.

Memory can become stale as repositories evolve. Changes in architecture, commands, or paths can invalidate an old note without producing an obvious error, which makes provenance and freshness important.


7.9. Verification Should Follow the Same Scope as Context

Efficient context selection should be matched by efficient validation.

A small change does not always require the largest available test suite, while a critical cross-cutting change should not be accepted because one local test passed. Validation should expand from the change scope to affected contracts and workflows, and only move to a broader test surface when the risk justifies it. This is the validation counterpart of progressive disclosure.

The same repository maps that help locate implementation can help identify likely ripple effects. A graph path may reveal that a changed service reaches several controllers; a workflow document may reveal an interaction that a backend-oriented source search would never expose.

The agent should answer two different questions:

  1. What must I read to make the change?
  2. What must I verify to trust the change?

They overlap, but they are not identical.

7.9.1. Deterministic Verification Points with Hooks

When verification is too important to depend on the agent remembering to perform it, a deterministic gate is preferable.

Claude Code hooks can attach actions to lifecycle events. For example:

after a relevant file edit
→ run a linter

before a sensitive tool invocation
→ validate arguments

when the agent attempts to finish
→ run a mandatory check

The value of a hook is that execution does not depend on model recall. A hook still does not prove correctness by itself: the wrong test command can run deterministically every time. Mandatory execution and correct verification scope remain separate design problems.

For high-risk changes, validation should follow affected contracts, not only changed lines. Authorization changes require security validation; data-write changes require integrity checks; concurrency changes require race and ordering analysis; external API changes require contract verification.


7.10. A token-efficient intent-programming Workflow

The preceding ideas can be combined into a practical repository workflow:

  1. Read the small persistent instruction set.
  2. Classify the task and its risk.
  3. Query repository maps or the knowledge graph.
  4. Read only the relevant workflow, contract, and risk documents.
  5. Inspect targeted source and verify graph-derived assumptions.
  6. State the intended change and invariants that must remain unchanged.
  7. Implement the smallest coherent change.
  8. Run validation proportional to affected contracts.
  9. Update canonical documentation only when the contract changed.
  10. Refresh the repository graph/index.
  11. Record a durable lesson only when the outcome teaches something reusable.

This reduces repeated repository discovery while keeping source code authoritative.

The goal is more than lower token consumption. It is to spend tokens where they reduce uncertainty.

The workflow can be summarized by a simple ratio:

Context efficiency = relevant evidence / total context

The numerator matters more than simply shrinking the denominator.


7.11. The Repository Becomes Part of the Agent Harness

In traditional development, repository organization mainly serves human developers and build tools.

With coding agents, repository structure also influences machine reasoning.

Names, directories, documentation boundaries, maps, validation commands, tool interfaces, and generated indexes collectively form an agent harness around the source code.

This does not mean restructuring every project for an AI model. It means recognizing that machine-readable engineering discipline and human-readable engineering discipline increasingly overlap.

A well-structured repository helps humans locate behavior, agents retrieve context, reviewers understand change scope, automated checks verify invariants, and future work reuse validated knowledge.

The strongest form of intent programming is therefore not a long prompt.

It is a system in which the repository itself helps turn intent into a bounded, verifiable change.

7.11.1. Permissions, Sandboxing, and External Tools Extend Repository Architecture

What an agent can do inside a project is shaped by more than source code. Permission rules, hooks, MCP servers, local commands, and the execution environment form part of the effective development architecture.

Claude Code permission rules can allow, ask, or deny tool operations. Sandboxing can independently constrain filesystem and network behavior for Bash processes and their children. These mechanisms are complementary rather than interchangeable.

MCP servers expand the external action surface. The relevant question is therefore not only “which tool exists?” but also “which identity does it use, what data can it reach, and what operation scope does it expose?”

A useful model for critical environments is:

agent task
⊂
permitted tools
⊂
sandbox / operating-system boundary
⊂
external-system privileges
⊂
organizational security policy

The innermost natural-language instruction never replaces the outer security layers.

An AI-ready repository is therefore not merely well documented. It is a work environment whose tool access, verification gates, and blast radius have been deliberately designed.


Unit 8: Change Control and Evidence in Agentic Development

8.1. Constraint Harvesting and Proven Patterns in Agentic Development

As an agent-assisted project grows, every new task does not have to require a longer prompt. Repeated decisions can move into canonical repository context, narrowing the option space of later tasks. This requires extracting only durable, reusable knowledge from completed work. This process can be called constraint harvesting.

After a change, useful questions include:

Did a new invariant emerge?
Was a new proven pattern established?
Did an older decision become obsolete?
Was a failure learned that should not recur?
Which of these facts will actually matter to future tasks?

Not every observation should become a permanent rule. A temporary button dimension is not a project invariant; a rule that prevents an unbounded query over a very large dataset may be. Good repository context is not the context that contains the most information, but the context that contains information that changes decisions.

Proven patterns also improve agent reliability. If the closest working behavior is supplied as the reference instead of asking the model to design a new feature from scratch, the problem becomes:

new feature
= existing proven pattern
+ domain difference
+ explicitly allowed behavior difference

This reduces risk because the model does not need to invent a new data-access path, error presentation, responsive behavior, keyboard model, or authorization flow every time. Repetition here does not mean copying code; it means reusing the behavioral contract.

Change risk should also determine how much context is read and how deeply the result is verified. A local change with clear behavioral equivalence may need only the edited region and its direct callers. A change to persistence, authorization, concurrency, or a critical workflow requires end-to-end tracing, failure-path inspection, and rollback or recovery analysis.

low risk  -> narrow context + narrow verification
high risk -> broader impact analysis + stronger verification

Together with Prompt Engineering, this makes it natural to separate persistent project knowledge from task-specific instructions. From the perspective of Clean Code and Maintainability Engineering, the same idea reduces the change surface: new behavior is introduced only where the system is genuinely different.

Maturity in agentic development is not giving the model more text for every task. It is deciding which choices no longer need to be made and turning those choices into stable project contracts.

8.1.1. Authoritative Context Hierarchy and Negative Constraints

Agentic development needs more than a record of what should be done. Context should also state what must not be touched, which behaviors must remain invariant, and which source has authority when information conflicts. Large repositories often contain current code, old design notes, generated reports, and temporary instructions at the same time.

An explicit context hierarchy helps:

durable security / data invariants
              |
              v
current source and runtime contract
              |
              v
domain rules and proven patterns
              |
              v
task-specific instruction
              |
              v
generated reports and temporary notes

Information lower in the hierarchy should not silently override a higher-authority source. A generated analysis report can look newer than the source code and still be wrong about runtime behavior. In high-risk areas such as data writes, authorization, and concurrency, the agent should re-verify claims against the authoritative implementation.

Negative constraints also improve token efficiency. If the model already knows constraints such as “do not add a dependency,” “do not change the schema,” or “do not break the established keyboard path,” it does not need to explore solution branches that cannot be accepted. The constraints should remain concise and behavioral, however; hundreds of micro-rules turn context back into noise.

Verification scope can be derived from risk classes in the same way. Instead of repeating an entire test plan in every task, repository context can map categories such as a low-risk visual change, a data-write change, or an authorization change to reusable evidence requirements. The verification layers in Software Test Engineering then become policy rather than repeated prompt text.

Good context is not the context that contains the most information. It removes details that do not change decisions while keeping visible the boundaries whose violation would create a real regression.

8.2. Specification Drift and the Evidence Chain from Intent to Implementation

Intent begins in natural language and gains detail as it becomes an implementation plan, architectural decisions, and source-code changes. That refinement is necessary, but it also creates a risk that the original business objective changes silently. Specification drift occurs when the implementation satisfies the latest specification while that specification no longer represents the initial intent accurately.

Acceptance criteria, invariants, architectural decisions, changed files, and verification evidence should therefore remain traceable to one another. A long agent explanation is less valuable than being able to identify which constraint led to which implementation decision and which evidence verified that decision.

Agent-generated changes should not be judged by diff size alone. If a change affects the data model, authorization, error behavior, concurrency, or an external contract, the impact analysis and validation surface should expand to the same scope.

Passing tests is not sufficient evidence of preserved intent; a test suite can verify a wrong or drifted specification perfectly. Final review should compare the implementation with the user objective, acceptance criteria, and invariants, and should separately check whether unstated assumptions entered the code.

This chain is the smallest useful unit of traceability in intent programming: intent → constraint → decision → change → verification evidence. If any link cannot be explained, a technically functioning system has not yet demonstrated that it solved the right problem.

8.2.1. Conclusion

Every important abstraction layer in the history of programming has changed the way humans communicate with machines.

A new layer is now emerging:

Human
  ↓
Intent
  ↓
Specification
  ↓
Artificial intelligence / agent
  ↓
Source code
  ↓
Compiler / runtime
  ↓
Machine

This transformation is not the end of programming.

It is the next abstraction layer of programming.

As abstraction rises, engineering does not become unnecessary.

As generating code becomes easier, generating incorrect code also becomes easier.

As the volume of change grows, verification becomes harder.

As implementation details become less visible, the value of people who understand fundamental system behavior increases.

The most important distinction of the future may therefore not be between developers who use AI and those who do not.

A more meaningful distinction is between:

a person who can generate code with artificial intelligence

and

an engineer who can design, constrain, and verify a reliable system through artificial intelligence.

For programmers, code was the center for a long time.

In intent programming, the center is increasingly the definition of correct behavior.

Code still matters.

But code is no longer always the starting point.

Sometimes it is only an intermediate representation, generated by a machine from a well-expressed engineering idea.

8.3. Patch Provenance, Rollback, and Verification

In agentic development, it is not sufficient for a generated diff merely to "work." The relationship between the requested intent, supporting evidence, resulting change, and verification should remain inspectable.

8.3.1. Change Provenance

A useful chain for each patch is:

user intent
   ↓
harvested constraints
   ↓
inspected files / evidence
   ↓
change
   ↓
verification

This does not require storing a model's private reasoning. The auditable engineering artifacts are the input, explicit rationale, diff, and test evidence.

8.3.2. Small and Reversible Patches

A large automated rewrite can hide several assumptions inside one diff. Independent behavioral changes should therefore be separated whenever practical.

A good patch:

  • satisfies one explicit objective,
  • avoids unrelated formatting churn,
  • touches only relevant files,
  • restores the previous contract when reverted,
  • has known verification evidence.

A change may be technically revertible while still producing irreversible external effects, such as destructive data migration. Reversibility must therefore be assessed at the system boundary, not only in version control.

8.3.3. Test Evidence

Verification evidence bound to a source revision with computed steps and state transitions
Verification evidence bound to a source revision

An agent statement that "tests passed" is not sufficient evidence. The command, scope, and result should be visible:

build command
test command
targeted regression test
result

If no test exists, the agent should create an appropriate verification method or leave the unsupported assumption explicit rather than assuming success.

8.3.4. Human Approval Boundaries

Generating code and performing a consequential action are different capabilities. Separate approval boundaries may be appropriate for:

  • production deployment,
  • persistent data modification,
  • credential or secret use,
  • weakening a security policy,
  • writes to external systems,
  • difficult-to-reverse migrations.

This treats the agent as a bounded executor rather than as an all-powerful user.

8.3.5. Verifying the Final State

After a patch, the system behavior—not only the file contents—should be checked:

intent
  =? requirement
  =? diff
  =? test
  =? runtime behavior

If one of these links cannot be established, the work should be considered modified but not fully verified.

8.4. Appendix — Reusable Prompt for a token-efficient AI-ready Repository

The following prompt is intentionally compact. It can be copied into an AI coding platform at the root of an existing project to create a small repository context layer that reduces repeated exploration without turning documentation into a second copy of the codebase.

# Task — Build a Token-Efficient Repository Context
Layer

Make this repository easier for AI coding agents to
understand with minimal recurring context cost.

## Goal
Create the smallest useful set of Markdown context files
that lets future agents locate behavior, constraints,
workflows, risks, and validation paths without
repeatedly reading the whole repository.

## Rules
- Inspect before writing. Do not document assumptions.
- Source code, build/runtime configuration, schemas, and
  existing contracts are authoritative.
- Prefer pointers and maps over copied implementation
  details.
- Keep persistent instructions short; move task-specific
  detail into focused docs.
- Do not create a document unless it removes repeated
  repository discovery.
- Do not duplicate the same fact across files.
- Record invariants, boundaries, rationale, and
  navigation paths; avoid prose that can be inferred
  trivially from code.
- Mark uncertain or inferred statements explicitly.
- Preserve existing behavior. Do not refactor product
  code for this task.
- Do not add dependencies.
- Optimize for relevant information per token, not
  document count.

## Discovery
1. Read existing AI/project instructions first.
2. If a repository graph/index already exists, query it
  before broad source reads.
3. If Graphify is installed, prefer:
   - `graphify query "<task or subsystem>"`
   - `graphify path "<A>" "<B>"`
   - `graphify explain "<concept>"`
   Then verify important findings in source.
4. Otherwise use targeted search, build files, entry
  points, configuration, and representative source
  paths.
5. Do not read large files or entire directories unless
  required.

## Create or Improve Only What Is Useful
Use existing names when equivalent files already exist.
Prefer this structure, but omit irrelevant files:

- `AGENTS.md`
  - very short always-on rules;
  - where to look first;
  - forbidden/high-risk changes;
  - validation entry points.

- `CODEMAP.md`
  - capability/subsystem → authoritative
    files/classes/modules;
  - no implementation copy.

- `WORKFLOWS.md`
  - critical user/system flows;
  - ordered steps, state transitions, preserved
    behavior;
  - only workflows where sequence matters.

- `DATAFLOW.md`
  - important data paths across boundaries;
  - source → transformation → persistence/output;
  - identity, ownership, routing, caching or concurrency
    boundaries when relevant.

- `docs/ai/database-contract.md`
  - only if persistence matters;
  - identity rules, read/write boundaries, immutable
    schema assumptions, transaction/locking rules,
    migration constraints.

- `docs/ai/runtime-safety.md`
  - environments;
  - commands safe/unsafe to run;
  - production restrictions;
  - external-service and destructive-operation
    boundaries.

- `docs/ai/known-risks.md`
  - non-obvious regression areas;
  - legacy traps;
  - high-risk files/flows;
  - why they are risky.

- `docs/ai/completion-validation.md`
  - smallest validation required by change type;
  - syntax/build/runtime/manual checks;
  - when broader validation is required.

- `docs/ai/LESSONS.md`
  - only durable, verified lessons from previous
    failures or corrections;
  - include provenance and re-verification notes;
  - do not store transient task history.

Create fewer files if the project is small.

## Content Design
For every document:
- lead with the information an agent needs to act;
- use tables, short bullets, identifiers, paths, and
  invariants;
- remove repeated explanation;
- link to authoritative files instead of copying them;
- separate `FACT`, `INVARIANT`, `RISK`, and `VERIFY`
  only when the distinction adds value;
- avoid tutorials, generic best practices, project
  history, and style prose unless operationally
  necessary.

## Navigation Contract
Make `AGENTS.md` the small entry point.

It should direct future agents roughly as:

`AGENTS.md → relevant map/workflow/contract →
graph/query/search → targeted source → validation`

Do not put the full repository model in `AGENTS.md`.

## Freshness
If generated maps/graphs exist:
- document how they are refreshed;
- prefer incremental update;
- avoid indexing generated graph output recursively;
- after documentation/source changes, refresh only what
  is required.
If Graphify is already configured, finish with `graphify
update .`.

## Validation
Before finishing:
- verify every documented path/symbol exists;
- verify major claims against source/configuration;
- remove duplicate or speculative statements;
- ensure no secret, credential, personal data,
  production identifier, or environment-specific
  sensitive value was copied into docs;
- ensure the persistent context is substantially smaller
  than the repository knowledge it indexes.

## Output
Implement the documentation directly.
Return only:
1. files created/updated,
2. one-line purpose of each,
3. unresolved uncertainties,
4. exact refresh/validation command if one exists.

The prompt deliberately avoids asking the agent to “document the whole project.” Its purpose is to create a navigation system for context, not a textual clone of the repository.

Unit 9: Agent Architectures, Tools, and AI Engineering

9.1. From Intent to an Executable Contract with Structured Output

Intent-driven programming begins with a natural-language goal, but production software should not execute free-form model prose directly.

Natural-language intent
      |
      v
LLM
      |
      v
Structured candidate
      |
      v
Schema validation
      |
      v
Authorization + constraints + tests
      |
      v
Executable operation

A structured representation can include operation, target files, constraints, acceptance tests, and risk level.

Schema validity is not semantic correctness; the candidate still requires domain validation.

An operation proposed by a research agent is distinct from an operation authorized for execution. A request such as “compare the sources and prepare a report” becomes safer when decomposed into source selection, citation recording, computation and report generation, each with defined inputs, permitted tools, output schemas and verification conditions. A bibliographic entry generated by the agent must not be treated as verified until its source can be checked. Execution of a dependent step requires valid and traceable output from its predecessor. When an external tool fails or access is denied, the plan must fail explicitly rather than silently invent substitute evidence.

9.2. Function and Tool Calling

The model can propose:

tool = search_code
arguments = {...}

The application must verify tool allow-lists, argument schemas, file scope, read/write capability, and resource budget.

Tool calling does not turn the model into an authorization system.

For high-impact writes, a safer pattern is:

PLAN
  |
DRY RUN / DIFF
  |
VALIDATION
  |
APPROVAL
  |
WRITE

9.3. Planner–Executor Separation

Planner executor tool-result and replanning feedback loop
Planner executor feedback

A single agent that plans and executes everything can amplify its own mistakes.

Request
 |
 v
Planner
 |
 v
Step list
 |
 +--> Executor 1
 +--> Executor 2
 +--> Executor 3
 |
 v
Verifier

The planner decomposes the task, executors use constrained tools, and a verifier checks the result against the specification.

Small tasks may still be safer with one simple agent.

9.4. Agent Memory Is Not One Thing

Agent “memory” can refer to several layers.

short-term
 -> current conversation / task

working memory
 -> active plan and intermediate results

long-term
 -> persistent user/project information

knowledge base
 -> external information retrieved by RAG

These layers need different retention and authorization policies.

9.5. When Multi-Agent Systems Make Sense

Multiple agents can help when work genuinely decomposes into independent specialties, can be parallelized, has explicit result contracts, and benefits from separated permissions.

They also introduce coordination overhead, duplicated errors, context repetition, loops, and ambiguous responsibility.

more agents
   !=
more intelligence

9.6. MCP and A2A: Connecting Tools vs Connecting Agents

As of 2026, MCP and A2A represent different architectural boundaries.

MCP standardizes access from model-enabled applications to external tools and resources. The 2026-07-28 specification introduced a stateless core and authorization improvements.

A2A standardizes communication and task exchange between independent agent systems. The current released specification is 1.0.0.

Application
   |
  MCP
   |
Tool / Resource

Agent A
   |
  A2A
   |
Agent B

A coding agent can use an MCP-like tool layer for the file system or compiler and an A2A-like layer to collaborate with another agent.

9.7. Combining Local and Remote Models

Not every step requires the largest remote model.

local small model
 -> classification
 -> file summarization
 -> routine transformation

remote / stronger model
 -> difficult architecture problem
 -> large context
 -> complex reasoning

Routing must still follow data classification because summaries can retain sensitive information.

9.8. AI Engineering vs Coding with AI

AI engineering is broader than accelerating code generation.

problem definition
 |
data / context
 |
model selection
 |
prompt / tool contract
 |
evaluation
 |
serving
 |
observation
 |
regression / rollback

Rapidly generating a web application with an assistant is AI-assisted software development. Designing models, RAG, evaluations, tools, security, and monitoring as a production system is AI engineering.

The intent-driven principle is that natural-language intent can start the process, but engineering must convert that intent into testable specifications, permissions, and verifiable artifacts.

9.9. From Intent to Executable and Auditable Specification

Security and reliability are not independent bolt-on features; both shape how a system contains faults and abuse. In intent-driven development, a specification should describe not only the desired output but also the resource budget, permitted side effects, privilege boundary, secure default, and rollback condition; otherwise a model can generate a locally plausible change with an undefined blast radius. In denial-of-service scenarios in particular, the protection mechanism itself must not consume the availability it is intended to preserve.

  • Translate natural-language intent into verifiable acceptance criteria.
  • Bound generated changes with explicit blast radius and rollback plans.
  • Mechanically prevent agent/LLM output from acting outside authorized files and permissions.

References

  • Anthropic. “Automate actions with hooks.” Claude Code Docs. Accessed September 16, 2026. https://code.claude.com/docs/en/hooks-guide
  • Anthropic. “Beyond permission prompts: making Claude Code more secure and autonomous.” October 20, 2025. https://www.anthropic.com/engineering/claude-code-sandboxing
  • Anthropic. “Configure permissions.” Claude Code Docs. Accessed September 16, 2026. https://code.claude.com/docs/en/permissions
  • Anthropic. “Connect Claude Code to tools via MCP.” Claude Code Docs. Accessed September 16, 2026. https://code.claude.com/docs/en/mcp
  • Anthropic. “Create custom subagents.” Claude Code Docs. Accessed September 16, 2026. https://code.claude.com/docs/en/sub-agents
  • Anthropic. “Effective context engineering for AI agents.” 2025. https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents
  • Anthropic. “Extend Claude with skills.” Claude Code Docs. Accessed September 16, 2026. https://code.claude.com/docs/en/skills
  • Anthropic. “How Claude remembers your project.” Claude Code Docs. Accessed September 16, 2026. https://code.claude.com/docs/en/memory
  • Anthropic. “Writing effective tools for AI agents — with AI agents.” 2025. https://www.anthropic.com/engineering/writing-tools-for-agents
  • Gloaguen, T., Mündler, N., Müller, M. N., Raychev, V., Vechev, M. “Evaluating AGENTS.md: Are Repository-Level Context Files Helpful for Coding Agents?” ICLR 2026 MemAgents Workshop. https://www.sri.inf.ethz.ch/publications/gloaguen2026agentsmd
  • Graphify Labs. “Graphify.” GitHub repository, v8. Accessed September 16, 2026. https://github.com/Graphify-Labs/graphify/tree/v8
  • Gupta, A. “Spec-Driven Development: A Spec-First Approach to AI-Native Engineering.” Microsoft for Developers, June 10, 2026. https://developer.microsoft.com/blog/spec-driven-development-ai-native-engineering/
  • Heather Adkins; Betsy Beyer; Paul Blankinship; Piotr Lewandowski; Ana Oprea; Adam Stubblefield. Building Secure & Reliable Systems: Best Practices for Designing, Implementing, and Maintaining Systems. O’Reilly Media, 2020.
  • Karpathy, A. “There's a new kind of coding I call 'vibe coding'...” February 2, 2025. https://x.com/karpathy/status/1886192184808149383
  • Microsoft Research. “GraphRAG.” https://microsoft.github.io/graphrag/
  • OpenAI. “Harness engineering: leveraging Codex in an agent-first world.” 2026. https://openai.com/index/harness-engineering/
  • Zhang, S., Wang, M., Shi, Y., et al. “FastContext: Training Efficient Repository Explorer for Coding Agents.” arXiv preprint, arXiv:2606.14066, 2026. https://arxiv.org/abs/2606.14066
  • Zhu, J., Hu, M., Wu, J. “SWE Context Bench: A Benchmark for Context Learning in Coding.” arXiv preprint, arXiv:2602.08316, 2026. https://arxiv.org/abs/2602.08316
  • A2A Project. Agent2Agent (A2A) Protocol Specification, version 1.0.0. https://a2a-protocol.org/dev/specification/
  • Model Context Protocol. “The 2026-07-28 Specification.” 2026. https://blog.modelcontextprotocol.io/posts/2026-07-28/
Contents