How to Set Rules and Permissions for a Coding Agent
In the previous experiments, I've already seen what happens when a local model gets more freedom.
It can read the right file and still hallucinate a method. It can correctly understand a task and still modify something I told it not to touch. It can even turn a shell command into the contents of a Java file.
Now I'm preparing to connect the agent to a real project.
Before I do that, I need something more concrete than: "Be careful."
The agent needs boundaries.
I want it to read code freely, make normal source changes, run tests, and iterate on failures without asking me for permission every thirty seconds.
I don't want it deciding on its own to install a dependency, delete a file, create a database migration, push to Git, or deploy something.
So the question becomes:
How much freedom does the agent need to be useful without giving it more authority than the task requires?
Start with persistent project rules
I already have one place for project-specific instructions:
AGENTS.md
This file tells the agent how the project should be treated.
For my Spring Boot project, it can contain rules such as:
## Coding Conventions
- Follow existing naming and formatting conventions.
- Keep controllers thin.
- Reuse existing abstractions before creating new ones.
- Avoid unrelated refactoring.
- Keep changes as small as reasonably possible.
It can also describe testing expectations:
## Testing Conventions
- Add or update tests when business behavior changes.
- Use the existing test framework and project conventions.
- Do not delete or weaken existing tests to make a build pass.
- Run relevant tests after modifying code.
These aren't instructions for one task.
They're persistent rules for how work should happen inside the repository.
The current prompt still tells the agent what I want changed. AGENTS.md tells it how I expect changes to be made.
But instructions alone aren't enough.
My earlier tests already showed that a model can ignore a perfectly clear sentence like:
Do not modify any files.
I need the harness and workflow to provide another layer of control.
Three permission levels are enough to start
I don't want a complicated security system for this experiment.
I start with three levels:
| YES | The agent may perform this automatically. |
| ASK | The agent must stop and request approval. |
| NEVER | The agent must not perform this action. |
The important part is deciding where each operation belongs.
For MyFinancesAPI, my initial permission model looks like this:
| Operation | Permission |
|---|---|
| Read/search source | ✅ YES |
| Edit source/test files | ✅ YES |
| Run local tests/builds | ✅ YES |
git status / git diff / git log | ✅ YES |
| Git commit | ⚠️ ASK |
| Git push | ⚠️ ASK |
| Branch operations | ⚠️ ASK |
| Delete files | ⚠️ ASK |
| Add/upgrade dependencies | ⚠️ ASK |
| Database migrations | ⚠️ ASK |
| Modify build configuration | ⚠️ ASK |
| Modify infrastructure or CI/CD | ⚠️ ASK |
| Read/modify secrets | ⚠️ ASK |
| Production deployment | 🔴 NEVER |
| Production database changes | 🔴 NEVER |
| Production secrets | 🔴 NEVER |
The categories follow a pattern.
Safe + local + reversible = YES
Persistent / destructive / external = ASK
Direct production impact = NEVER
This gives the agent enough freedom to complete a normal local coding loop without giving it control over everything around the code.
YES needs to be useful
It's tempting to put almost everything behind approval.
That would certainly feel safer.
It would also destroy much of the point of using an agent.
Imagine this workflow:
Can I read AccountService.java?
→ Yes
Can I read AccountRepository.java?
→ Yes
Can I edit AccountService.java?
→ Yes
Can I run AccountServiceTest?
→ Yes
Can I run it again after fixing the failure?
→ Yes
At that point, I'm operating the agent manually one permission at a time.
Normal development actions need enough freedom to form a useful loop:

Reading source, searching the repository, editing relevant source and tests, running local builds, and inspecting Git all belong in YES.
The agent should be able to repeat those operations while solving a normal task.
ASK is where consequences start getting larger
Some actions are perfectly reasonable during development but have consequences beyond the immediate source change.
Adding a Maven dependency is a good example.
The agent can:
Read pom.xml
Analyze dependencies
Recommend a library
automatically.
Actually changing the dependency graph requires approval:
Add dependency
→ ASK
The same applies to database migrations.
Reading an existing migration is normal project inspection.
Creating or executing one changes the database structure and deserves a checkpoint.
Git has a similar boundary:
git status → YES
git diff → YES
git log → YES
git commit → ASK
git push → ASK
git rebase → ASK
git reset → ASK
The agent can prepare the work.
I retain control over repository history and anything leaving my machine.
NEVER creates a hard production boundary
Some operations don't need a confirmation dialog because I don't want this local coding agent performing them at all.
For this experiment:
Deploy to production
Restart production services
Run production migrations
Modify production data
Access production secrets
Execute Terraform against production
are all:
NEVER
The agent can explain a deployment command.
It can inspect configuration.
It can prepare a script for me to review.
It doesn't execute the production operation.
This distinction also gives me a useful fallback when the environment isn't clear:
If the agent cannot confidently determine that an operation is local and reversible, move it toward ASK, not toward YES.
Uncertainty should reduce authority rather than increase it.
Git becomes the final record of what happened
Permissions can stop some actions, but they don't prove that the agent changed only what I intended.
I've already seen a model accidentally modify an existing method while adding a new one.
So every normal coding workflow needs to end with:
git status
git diff
The agent's summary might say:
Added validation to AccountService.
Git might say:
modified: AccountService.java
modified: AccountController.java
modified: pom.xml
The second version is the one I care about.
Git shows what actually changed, including modifications the model didn't intend or didn't mention.
For my workflow:
The agent explains its work. Git verifies its footprint.
This is also why I keep Aider's automatic commits disabled.
I want the diff to exist before repository history changes.
Now the permissions need a workflow
Rules are more useful when they describe not only what the agent can do, but also when it should do it.
So I define a standard loop for normal coding tasks:

The sequence matters.
I don't want:
Task -> Guess -> Edit -> Explain
I want the agent to inspect the project before modifying it.
For a request such as:
Add validation to transaction creation.
the first useful questions are:
Where is transaction creation implemented?
Which controller exposes it?
Where does validation currently happen?
What tests already cover this behavior?
Are there uncommitted user changes?
Only after answering those questions should editing begin.
Planning should match the size of the task
I don't want the workflow to become bureaucracy.
Changing a comment doesn't need a six-step implementation plan.

The workflow is a default sequence, not a requirement to produce unnecessary steps.
Failures become new context
The previous Aider experiment gave me one part of this loop already.
When javac returned:
error: ';' expected
I passed the actual compiler result back to the model.
Ministral diagnosed the problem and repaired it.
I want the same behavior on the real project:
Test fails
↓
Read actual failure
↓
Trace relevant code
↓
Determine cause
↓
Make smallest justified correction
↓
Run test again
A failing test isn't permission to start changing unrelated files until something turns green.
And the agent shouldn't:
- weaken a test just to make it pass;
- suppress an error;
- claim a command succeeded without execution evidence;
- expand the scope without a reason.
Verification has to come from what actually ran.
The permission model plugs directly into the loop
The workflow becomes more useful when every action passes through the permission boundary:

For example:
Run ./mvnw test
→ YES
→ execute
The agent doesn't need me for that.
But:
Add a new Maven dependency
→ ASK
→ stop and request approval
And:
Deploy to production
→ NEVER
→ do not execute
This gives the agent autonomy inside a boundary rather than autonomy over the entire environment.
Knowing when to stop is also part of the job
Permissions cover explicit operations, but some situations require judgment.
I want the agent to stop autonomous iteration when:
- the next required action is
ASK; - requirements are genuinely ambiguous;
- repeated fixes aren't converging;
- existing user changes may be overwritten;
- repository state becomes unclear;
- a test exposes a broader design decision;
- progress would require a production-impacting operation.
For example, imagine the agent discovers that the requested feature requires changing the database schema.
It shouldn't quietly create a migration because doing so would help finish the task.
The correct path is:
Feature requires schema change
↓
Migration = ASK
↓
Stop
↓
Explain why it is needed
↓
Wait for approval
Stopping isn't a failure of the agent loop.
Sometimes stopping is the correct result.
Human review is the default endpoint
The workflow deliberately ends before commit. I still want to inspect:
- what files changed;
- whether the implementation matches the requirement;
- whether tests actually cover the behavior;
- whether unrelated code changed;
- whether the architecture still makes sense.
A passing build proves something useful.
It doesn't prove everything I care about.
The agent can get the repository to a reviewable state. I decide whether the result belongs in the project.
Put the rules together
At this point, the agent has three complementary boundaries.
First, persistent project instructions:
AGENTS.md
→ How this project should be modified
Then permissions:
YES / ASK / NEVER
→ What authority the agent has
And finally the workflow:
Inspect -> Plan -> Modify -> Verify -> Diff -> Review -> How the work should progress
Together, the operating model becomes:

The rule I want to carry into the real project is much shorter:
Read broadly. Edit narrowly. Execute safely. Verify with evidence.
Guardrails don't make the model reliable
None of these rules make Ministral smarter.
They don't prevent hallucinations.
They don't guarantee that the agent will understand my architecture.
And they don't guarantee that a passing test means the implementation is correct.
The purpose is different.
The model will make mistakes. I want those mistakes to happen inside an environment where they are easier to detect, cheaper to reverse, and less likely to cross an important boundary.
So far, I've been designing that environment around small test files.
The next step will be different.
I'll connect Aider + Ollama + Ministral 3 8B to MyFinancesAPI and find out whether the model can understand enough of a real Spring Boot codebase to work inside these boundaries.
The rules are ready. Now the agent has to prove it can work inside them.