Back to Feed
article 3m read

A no-commands rule for the offline code agent, and an apply step that runs commands anyway

The local-model edit pipeline has a solid shape: snapshots, bounded retrieval, hash-checked diffs, staging, quarantine and an audit log. Reading the diff back, the config full of safety rules is never loaded, and apply runs any post-step command a proposal carries.

Article DepthPractice

Flow

What each step checks, and what it skips

  1. 1Snapshot

    Hashes every file. The ID also includes the time it was made.

  2. 2Retrieve

    Sends only top pieces under a size limit, each labeled with its source.

  3. 3Propose

    Rejects replies missing fields. Accepts a commands field.

  4. 4Apply

    Re-checks hashes and stages diffs. Runs every command it is given.

  5. 5Folder check

    Compares text, and probably refuses every new file.

  6. 6Publish

    Moves files one at a time and writes an audit line.

  7. 7Rules file

    Lists limits and a no-commands rule. Nothing loads it.

Never running shell commands is what the rulebook I wrote for my offline coding agent says. Then I read the apply step back. It runs whatever commands the proposal hands it.

The controller lets a local model suggest code changes without anything leaving my network. The model runs on one machine at home and the controller on another. The same day, I pulled the hosted-API key out of my older chat page, along with the form that saved it and the hourly check on it. Chat now talks to the local model, and the model name is a setting I can change.

Four steps from question to change

Snapshot lists every file in the project with a hash of its contents, and gives that list an ID. Retrieve picks the most relevant pieces of code, up to a size limit, and labels each piece with where it came from. Propose sends those pieces to the model and only accepts a strict JSON reply: which files to change, a diff for each, and the hash each file had when the model saw it.

Apply checks each file's hash again and stops if anything changed. It applies the diffs in a separate staging folder, never on the real files, and lint-checks the result. If that passes, the files move into the project and a line goes into an audit log. If it fails, the staging folder goes to quarantine so I can look at it.

The model never writes a file. It only writes a proposal.

A rulebook nothing reads

I also wrote a config file full of rules: no internet, no commands, size limits, protected folders. Reading the diff back, nothing in the controller loads it. The real settings are written into the code.

The command rule matters most. The reply format includes a field for commands to run after the change, and apply runs every one of them. If you follow the README and pass the model's reply straight to apply, the model's commands run on the controller. I haven't tried it to see.

A few more gaps, all from reading the code:

  • The size limits aren't checked anywhere.
  • The folder check compares text, so a neighboring folder with a longer name slips through.
  • New files probably get refused every time, because the check needs the file to already exist.
  • Files move into place one at a time, so a failure halfway leaves a mix of old and new.
  • The controller has no login.

The folder check takes one line to get right:

The change is to compare the shared parent path with the root instead of matching text.

It compares whole folder names, so a sibling folder with a longer name would not pass.

Before I'd let it touch a real project

None of this is fixed yet. The config has to be loaded at startup and checked where each rule applies, or the rule has to go. New files should be checked against their parent folder. The commands field should probably be removed so the model can't name one at all. And publishing needs one single swap, or a record it can recover from, before I'd point this at anything I care about.

Keep reading

Pick up a connected idea or branch into a nearby one.

5 paths forward