Jeison Eccel

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:

YESThe agent may perform this automatically.
ASKThe agent must stop and request approval.
NEVERThe agent must not perform this action.

The important part is deciding where each operation belongs.

For MyFinancesAPI, my initial permission model looks like this:

OperationPermission
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:

Agent 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:

Standard Agent Loop

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.

Workflows

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:

Agent Permissions

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:

Operation Model

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.