Home / Articles

A Local Coding Agent Loop: Aider, Ollama, Git Worktrees and Easy Rollback

A bounded workflow for a local coding agent that keeps every change reviewable and reversible, using Aider, Ollama, a Git worktree, a focused test and a plain restore path.

Publisher: REACTAPP.TOP10 min read2345 words

This article is published in English.

Sources: A Local coding agent workflow with Aider, Ollama, and Git worktrees

Begin with the way back, and pick the model later. A local coding agent earns its place when it can finish one small, bounded loop: locate a defect, make a modest change, run the relevant check, and leave a diff that can be committed or thrown away.

The conservative stack for that loop assumes a repository already under Git with a focused test command:

  • Agent: Aider
  • Model runtime: Ollama, serving a model on the local machine
  • Isolation: a Git worktree
  • Search: rg, run from the repository root
  • Validation: whatever focused test command the repository already has
  • Recovery: git diff, then either a commit or git restore

Only the agent and the local runtime are new. Everything else is ordinary repository tooling, and the setup should not turn into a second development platform.

The roles are simple. Ollama serves the model. Aider operates inside a Git repository. A worktree gives the task its own checkout, usually on a dedicated branch, and git restore can drop uncommitted changes to named files. The pattern is intentionally narrow, aimed at repository work that has to stay reviewable and reversible. It is no benchmark, and it does not claim these tools beat alternatives everywhere. Commands, model names and approval behavior also shift with installed versions and local configuration.

A loop a person can review

The agent's output should be a small unit of progress that a developer can inspect. Broad, unattended access to a machine is the opposite of that.

The sequence:

  1. Create an isolated working tree.
  2. Find the implementation and its existing test.
  3. Define one outcome and its limits.
  4. Ask for a plan before any edit.
  5. Approve the plan or narrow it.
  6. Read the diff.
  7. Run the project check.
  8. Commit or restore.

The gates that count are procedural: nothing is edited before the plan is approved, and no change is kept before the diff and test have been read. Call them technical controls only if the installed agent and host configuration can really enforce them. Speed is worth having only when results stay easy to verify and undo.

An example: blank display names

Picture a TypeScript service that accepts blank display names although the API should refuse them. The repository has a focused test file and npm scripts for validation.

The task is not clean up validation. It reads like this:

Reject whitespace-only display names, update the existing test file, keep the public API unchanged, and run the focused test.

That hands the agent a behavior, a boundary and a check.

Give the change its own checkout

From the primary checkout:

git worktree add -b fix/display-name-validation ../service-display-name-fix
cd ../service-display-name-fix

A worktree is a second working directory attached to the same repository. The command above creates ../service-display-name-fix on the branch fix/display-name-validation and leaves the main checkout free for other work.

From here on, edits, test output and the pending diff stay away from the primary directory. Should the experiment prove pointless, its files can be restored, or the worktree removed after its status has been checked.

Find the code and the test first

Use the repository's own vocabulary to set scope:

rg -n "displayName|display name" src test

Say the search returns:

src/users/validateProfile.ts
test/users/validateProfile.test.ts

The boundary is now concrete. The agent needs those two files and the command that validates them, and a vague invitation to explore the whole repository adds nothing.

Start Aider on the local Ollama model

Before this step, confirm that Git, Aider, Ollama and rg are installed and that the Ollama runtime is available on this machine. The chosen model must also work with the installed versions of Aider and Ollama. Aider documents an Ollama provider: make sure the intended model exists in Ollama, then launch Aider from the worktree using the ollama_chat/ prefix on the model name.

ollama pull <installed-model>
aider --model ollama_chat/<installed-model>

Swap <installed-model> for the tag that Ollama actually holds. The same tag appears in both commands, since Ollama serves that model and Aider picks it by name.

Aider can track its changes through Git. Start it in the worktree, read the diff after each edit, and keep the commit decision in human hands.

It also ships in-chat commands, a repository map, configuration options and context-limit controls. They help with navigation, but none of them sets scope or proves a patch correct.

Make the first turn a plan

Restrict the agent's context to the relevant files, using the file-adding workflow documented for the installed Aider version, not Git staging. Then supply a prompt with an outcome, the permitted paths and a validation command:

Task: Fix whitespace-only display names being accepted.
Files in scope:
- src/users/validateProfile.ts
- test/users/validateProfile.test.tsConstraints:
- Preserve the public API.
- Do not edit generated files, lockfiles, deployment configuration, or unrelated tests.
- First, explain the current behavior, name the files you would change, and propose the smallest fix.
- Do not edit files until I approve the plan. Treat this as a required review step, and use any available approval controls in your local agent configuration to enforce it where possible.Validation:
- Run: npm test -- validateProfile
- Report the exact command run, files changed, test result, and any unresolved assumption.

A prompt like this heads off several common failures: tasks that balloon, edits outside the intended paths, and patches that come with no stated way to validate them.

Turn down broad plans early

A good first reply looks like this plan:

1. Inspect src/users/validateProfile.ts to confirm how displayName is validated.
2. Inspect test/users/validateProfile.test.ts for the existing validation-test pattern.
3. Add a failing test for a whitespace-only displayName.
4. Make the smallest validation change required to reject that input.
5. Run npm test -- validateProfile.

Before approving any write, ask:

  • Does the plan name the intended implementation and test?
  • Is it confined to a single behavior?
  • Does it say what validation change it proposes?

Stop if it mentions a schema migration, a dependency install, a lockfile update or unrelated endpoint changes. Narrow the task instead of approving an expansion that merely sounds reasonable.

The diff and the test result are the product

Once the plan is approved, repeat the same review sequence every time.

Look only at the agreed files

git diff -- src/users/validateProfile.ts test/users/validateProfile.test.ts

Here the expected result is a single new test for blank input plus one implementation tweak that satisfies it. How that tweak looks depends on the repository's existing validation contract, so check that only input that is blank after trimming gets rejected and that valid display names pass untouched.

Look for what a session summary can conceal:

  • the public API altered although the prompt forbade it
  • files touched beyond the agreed list
  • reformatting that has nothing to do with the bug
  • a new test that passes without ever hitting the target behavior
  • a validation tweak that also rejects legitimate names

The diff and the test outcome are the deliverable. The agent's own summary is a guide for reading, and it proves nothing about correctness.

Run the focused check

<repository-focused-test-command>

Replace the placeholder with the command and file-selection syntax the repository really uses.

Aider can lint and test automatically after code changes. That may shorten feedback cycles, yet the repository's own command remains the authority.

Keep or drop the change on purpose

If the diff and the test result look right:

git status
git add src/users/validateProfile.ts test/users/validateProfile.test.ts
git commit -m "Reject whitespace-only display names"

If they do not:

git restore src/users/validateProfile.ts test/users/validateProfile.test.ts

With no source given, git restore brings the two named files back from HEAD, discarding uncommitted edits to those files only. Check git status for staged changes, untracked files or modifications elsewhere before treating the experiment as discarded.

When the whole branch is disposable, remove the worktree once its status has been checked and anything worth keeping has been saved:

git worktree remove ../service-display-name-fix

Git manages linked working directories through its worktree commands. Recovery is a normal path, and it is what makes a small agent experiment safe to repeat.

Boundaries: filesystem, permissions, context

Launch from the repository root

Run the agent in the project directory or its dedicated worktree. Starting in a home directory and hoping a prompt will impose a boundary does not work.

The working directory supplies a default scope, yet it does not enforce anything. What the agent can actually reach is set by OS permissions, tool settings and whatever sandbox is in place.

Approve side effects deliberately

File writes, dependency installs, credential access, network use and infrastructure changes should all need deliberate approval. Where the agent or host cannot enforce that, treat it as a manual review step and do not present it as a technical control. Check which controls exist before relying on them.

OWASP lists prompt injection as a risk that can push an LLM-enabled application into unintended actions or disclosure of information.

A practical baseline:

  • Permit reading files in the intended repository.
  • Require approval before writes.
  • Require approval before shell commands with side effects.
  • Make network access opt-in.
  • Keep secrets out of the agent's ordinary context.

This manages blast radius. It makes no judgment on whether the agent is trustworthy.

Keep configuration small and visible

Aider reads YAML configuration, environment files and API-key settings. Shared project configuration should be visible, minimal and kept apart from secrets, and credentials never belong in a repository instruction file. Piles of global defaults that nobody can inspect or explain later are best avoided.

Provide the context the task needs

The repository map helps Aider grasp codebase structure, while context limits cap how much fits in one request. For a focused fix, supply the task, the relevant files, the validation command plus whichever project rules bear on the change. Pulling in generated files, every document or old unrelated commits mostly adds clutter.

A project contract for repeat work

If the same workflow comes up again and again, store a checked-in instruction file, a reusable prompt or a task template beside the code:

Project contract
Goal:
- [Describe one bounded outcome.]Scope:
- You may edit: [paths]
- Do not edit: [paths, generated files, secrets, deployment configuration]Conventions:
- Follow: [formatter, naming, architecture rules]
- Preserve: [public APIs, compatibility constraints]Validation:
- Run: [exact test, lint, type-check, or build command]
- Report: commands run, files changed, failures, and unresolved assumptionsDefinition of done:
- The requested behavior is implemented.
- Relevant checks have run, or the reason they could not run is stated.
- The final response summarizes the diff and any follow-up work.

The format is unimportant. What matters is that the constraints are visible.

Failure modes and smaller next steps

Searching too broadly. Stop, shorten the file list, and restart with paths or symbols taken from a search run by hand.

A large refactor proposal. Split the request at a testable seam. One failing test, one behavior or one refactor boundary beats an architectural mandate.

Edits outside scope. Reject the patch, restore the unrelated files, and name the forbidden paths in the next prompt.

An unsafe command request. Ask what it changes and why it is needed before approving.

A failing check. Ask for a diagnosis before allowing more edits, and require the failure, its likely cause and the smallest next experiment.

Slow local inference. Shrink the task and the context first. Evaluate another model or runtime setting only afterward. No performance comparison is made here, and any later one should record measured latency, model, runtime and hardware.

A faster agent that produces bigger, harder-to-review diffs has not improved the workflow.

Tune one thing at a time

When search, plan, diff, test and recovery behave predictably, adjust a single variable per round. Change the model if output quality is the bottleneck. Change the context strategy if relevant code keeps getting missed. Relax an approval default only once several small, scoped tasks have shown that the prompt was never protecting anything here, and even then keep diffs, tests and rollback available. Add automation last, once the validation command can be trusted.

Aider's setup is version-sensitive, so its configuration and release-history pages are worth checking before reuse. Compare every command, model identifier and config option with the Aider and Ollama releases actually installed on the machine at hand.

The decision rule is short: keep a tool or setting only if it improves task completion, reviewability or recovery.