Context Is the Real Interface to a Coding Agent
The small Java repository from my previous tests contains two files. Finding the right context there isn't particularly difficult. My real projects are different.
The Personal Finances API has controllers, services, repositories, entities, tests, configuration, dependencies, and Git history. The Music App adds Next.js, TypeScript, components, stores, database code, and its own conventions.
Before I let the agent work on either project, I need to answer a more fundamental question:
How does the agent know what it needs to know?
I could give it the entire repository, but that wastes context on files unrelated to the task.
I could give it only the file I think matters, but then I'm doing the discovery work myself and might hide an important dependency.
The useful answer is somewhere between those two extremes.
Context isn't just source code
When I started thinking about context, my first mental model was mostly:
Task + Relevant source files -> Model
But a coding agent needs more than source files.
Suppose I ask it to modify a Spring Boot endpoint. Before writing anything, there are several things I would want it to know:
What project is this?
Which Git repository am I in?
Does it use Maven or Gradle?
Is there a Maven Wrapper?
Where is the source?
Where are the tests?
Are there already uncommitted changes?
What commands are valid?
What architecture should the change preserve?
What is the agent not allowed to touch?
Some of these answers come directly from the repository.
Others don't.
This gives me two different types of context:
Project Discovery -> What exists?
And
Project Instructions -> How should I work with it?
Keeping those responsibilities separate becomes the foundation for how I want the agent to understand a project.
Discover facts before asking the model to infer them
The first layer is project discovery.
My rule here is simple:
If a tool can determine something reliably, don't ask the model to guess it.
For example, I don't need an LLM to look at a few Java files and decide that the project "probably uses Maven."
I can check:
git rev-parse --show-toplevel
and inspect whether the repository contains:
pom.xml
mvnw
build.gradle
gradlew
If mvnw exists, I have much stronger evidence that the build should use:
./mvnw
instead of whatever Maven installation happens to exist on my computer.
The same applies to my Next.js project.
If I find:
package.json
pnpm-lock.yaml
I don't need the model to decide whether I probably use npm, yarn, or pnpm.
The repository already told me.
So I define discovery as a read-only step that happens before the agent starts modifying anything:
Locate project
↓
Determine Git boundary
↓
Detect project/build type
↓
Detect source/test directories
↓
Determine valid commands
↓
Identify important configuration
↓
Produce project context
↓
Agent starts working
This reduces the amount of basic project information the model needs to infer.
The filesystem wins over conventions
Framework conventions are useful shortcuts, but they shouldn't become facts.
A typical Spring Boot project might contain:
src/main/java
src/main/resources
src/test/java
src/test/resources
A multi-module project might look completely different.
A Next.js project might use:
app/
components/
lib/
or:
src/app/
src/components/
src/lib/
The discovery process can use conventions to know where to look, but it should report what actually exists.
The rule I want to preserve is:
Conventions help discovery, but filesystem reality wins.
This becomes especially important when the agent starts running commands.
A Node project doesn't automatically have:
pnpm test
The discovery process should read the scripts section of package.json and verify that a test command actually exists.
Guessing a method name is bad enough. Guessing commands and executing them is a much less attractive experiment.
Git is part of the context too
Git isn't only my recovery mechanism.
It also tells the agent something important about the state of the project before it touches anything.
I want discovery to collect at least:
git rev-parse --show-toplevel
git branch --show-current
git status --short
Imagine the project already contains:
Branch: dev
Working tree: dirty
Modified:
AccountService.java
Those might be my changes.
If the agent starts working without knowing that, it can easily confuse existing modifications with its own work.
So the initial project context should include the Git boundary, current branch, working-tree state, and existing changed files.
This also reinforces another distinction:
Workspace ≠ Project
A future workspace might contain both:
workspace/
├── finances-api/
└── music-app/
Each repository has its own context, commands, Git state, and rules.
The directory I opened isn't necessarily the boundary the agent should operate within.
Discovery doesn't mean loading everything
Finding a file and loading a file into the model are two different decisions.
Suppose discovery finds:
pom.xml
README.md
application.yml
docker-compose.yml
terraform/
.env
This is useful information.
It doesn't mean all of those files belong in every prompt.
For example:
.env exists
may be useful context.
Its contents are not.
I want sensitive files such as:
.env
.env.local
.env.production
credentials
private keys
excluded from automatic model context.
The agent can know:
.env.local [present, contents excluded]
without reading its secrets.
The same principle applies to ordinary files.
Discovery answers:
What exists?
Context selection answers:
What does this task actually need?
Combining those two questions would push me back toward dumping the repository into the model.
More context isn't automatically better context
Local models make this trade-off especially visible.
Every irrelevant file consumes part of the context available for the task.
If I ask the agent to fix a transaction service test, giving it every controller, entity, configuration file, and unrelated service doesn't necessarily help.
A better path is:
Task
↓
Project map
↓
Likely relevant files
↓
Inspect those files
↓
Follow dependencies as needed
↓
Load more context only when justified
This resembles how I explore an unfamiliar codebase myself.
I don't read every source file before fixing a bug. I start with the failing test, follow the implementation, inspect related dependencies, and expand outward until I understand enough to make the change.
The agent needs the same ability to navigate.
The goal isn't minimum context.
It's relevant context.
Some project knowledge can't be discovered from files
Discovery can tell the agent that TransactionController.java exists.
It can't necessarily tell the agent:
Controllers should handle HTTP concerns only. Business logic belongs in services.
The code may suggest this pattern, but now I'm depending on the model to infer an architectural rule from examples.
There are also rules such as:
Do not modify migrations automatically.
Do not install new dependencies.
Do not commit or push.
Use existing shared form components.
Run relevant tests after changing business behavior.
These aren't discovery problems.
They're instructions.
So I need a second context layer.
Give the project its own instructions
I want each repository to have a small, human-readable instruction file at its root:
AGENTS.md
Its purpose isn't to document the entire codebase.
The source already does that better.
Instead, AGENTS.md captures decisions and constraints that are difficult or risky to infer.
A basic structure looks like:
# Project Instructions
## Project Overview
## Architecture
## Coding Conventions
## Testing Conventions
## Build and Run Commands
## Restricted Operations
## Project Terminology
For a Spring Boot project, the architecture section might say:
## Architecture
- Controllers handle HTTP concerns only.
- Business logic belongs in services.
- Persistence uses Spring Data JPA repositories.
- Keep database access inside the repository/service layers.
The coding conventions can contain rules such as:
## Coding Conventions
- Reuse existing abstractions before creating new ones.
- Avoid unrelated refactoring.
- Keep changes as small as reasonably possible.
Now the model doesn't need to rediscover those expectations from a handful of source files every time.
Don't turn AGENTS.md into another codebase
There is an obvious temptation here.
If context helps, why not put everything into AGENTS.md?
Repository structure. Every service. Every method. Database entities. API endpoints. All the implementation details.
Then I've recreated the same problem in Markdown.
For example, this is poor persistent context:
TransactionService contains:
- createTransaction()
- updateTransaction()
- deleteTransaction()
...
The source can tell the agent that, and the description can become stale as soon as I change the class.
This is much more useful:
Business rules for transactions belong in the service layer.
One describes an implementation the agent can inspect.
The other describes a design decision it should preserve.
So my rule for AGENTS.md becomes:
Document decisions and constraints that are difficult to discover from code. Let the agent discover implementation details from the repository.
The same rule helps keep the file small enough to remain useful.
Stable rules and current tasks also need separation
I don't want temporary tasks inside AGENTS.md either.
Something like:
Add pagination to the transaction endpoint.
belongs in the current prompt.
Otherwise, an old request can survive into future sessions and become accidental context.
The layers now look like this:
Repository
│
├── Project Discovery
│ What exists?
│
└── AGENTS.md
How should the agent work?
│
↓
Current User Task
What do I want now?
│
↓
Agent
Each layer has a different lifetime.
The repository changes as the code changes.
AGENTS.md contains persistent rules.
The prompt contains the current task.
What happens when the sources disagree?
Once there are several context layers, I also need an order of authority.
My initial priority becomes:
1. Current explicit task
↓
2. Project AGENTS.md
↓
3. Deterministic project discovery
↓
4. Existing code conventions
↓
5. Framework conventions
↓
6. Model assumptions
Suppose Maven is installed globally, but AGENTS.md says:
Use ./mvnw test
The agent should use:
./mvnw test
And if I explicitly authorize something normally restricted for one task, the current instruction can override the persistent rule.
The model's assumption comes last.
There is rarely a good reason to let probabilistic inference overrule information the repository can state directly.
The context strategy is becoming clearer
At this point, I don't need to build a sophisticated retrieval system or custom project scanner.
I first want a reliable process:
Discover broadly
↓
Build a small project map
↓
Load persistent project rules
↓
Receive the current task
↓
Select likely relevant files
↓
Follow dependencies when needed
↓
Edit only after enough context exists
This gives me a better definition of context than simply "whatever fits in the model's context window."
Context has different jobs:
| Context | Purpose |
|---|---|
| Discovery | Establish factual project information |
| AGENTS.md | Preserve architecture, conventions, and boundaries |
| Repository files | Provide implementation details relevant to the task |
| Current prompt | Define what needs to change now |
| Git state | Separate existing work from agent changes |
The difficult part isn't giving the model as much information as possible.
It's giving it the right information at the right time.
Context is the interface
Earlier in this experiment, I thought about the interface to the model mostly as the prompt.
Agentic coding has made that view feel too small.
The model sees the project through whatever the harness chooses to expose:

If the wrong files are selected, the model reasons from the wrong evidence.
If architectural rules are missing, it has to infer them.
If too much unrelated code is loaded, useful context competes with noise.
If project facts can be discovered deterministically but I leave them to the model, I'm spending reasoning on something a simple filesystem check could answer more reliably.
So context isn't just input to the agent.
Context is the interface through which the agent sees the project.
Before I test whether the model can understand my real Spring Boot codebase, I need to give it a reliable way to enter that codebase in the first place.