Back to onyxcode.app
Documentation

Agent mode and permissions in Onyx Code

Four autonomy levels, unattended runs sandboxed in a git worktree, and a deny tier that beats every allow above it.

Applies to the current releasePlan and Auto are ProRuns on a local model

Autonomy is a dial, not a switch

Most agent tooling gives you one setting and asks you to trust it. Onyx Code gives you four, and the current one is shown as a pill next to the model selector so it is never ambiguous which you are in. Ask and Edit are on Free; Plan and Auto are Pro.

ModeWhat it may do
/planProposes changes and drafts code. Never edits a file or runs a command. Read-only by design
/ask (default)Confirms every file write, shell command and mutating tool call before it happens
/editCreates new files itself; a change to an existing file waits for your Keep. Still confirms shell commands and mutating tool calls
/autoRuns unattended. Only available inside a worktree, and falls back to Ask outside one. An edit to a file that already has a change waiting for your review joins that change and waits for your Keep too. An MCP tool the server does not mark as read-only still asks first

While unattended mode is active the status bar carries a prominent pill, so the state stays visible after you have switched files and forgotten about it.

Unattended runs happen on a copy of your branch

The reason /auto refuses to run outside a worktree is the whole design. An agent working unattended on your checkout is a bad trade even when it behaves, because the failure mode is discovering the damage later.

Instead, the agent works in an isolated git worktree: a real checkout of your branch in a separate directory, sharing the repository but not your working files. It can build, run and edit freely there. You review the result as a diff and decide, and main is untouched until you say so.

This is also what makes unattended mode usable rather than theoretical. The question stops being “do I trust this to not break my working tree” and becomes “is this diff any good”, which is a question you already know how to answer.

  • Apply carries all of it over. Applybrings every change the agent made in the worktree into your checkout, staged for you to commit. If your checkout has moved to another branch, or the worktree holds something git can’t carry over, Apply stops and says why in the chat, or keeps the worktree on disk, rather than deleting anything.
  • Out of your Source Control view. The worktrees live in .onyx-agents/, which is listed in your clone’s .git/info/exclude (never committed) and removed once the last worktree is applied or discarded.

Reading and writing files on demand

The model gathers its own context rather than waiting to be handed it. Mid-answer it opens files, lists folders and searches the workspace, then makes changes through a bounded tool loop.

  • write_file creates a file.
  • edit_file replaces a single span rather than rewriting the whole file, which keeps diffs small and reviewable.

In Ask and Edit, a change to an existing file is staged as a diffand reaches disk only when you Keep it, through the same Keep and Discard bar the rest of the editor uses. Auto writes through its tools, inside its worktree, but a code block’s change to an existing file still waits for your Keep, and so do an edit on top of a change waiting for review and one that would remove a large part of a file. A change to .onyxnoai, a permissions file, .vscode/*.json, a .code-workspace file or .cursor/mcp.json waits for your Keep in every mode. Reads and writes both honour your .onyxnoai rules, and Plan mode stays strictly read-only regardless of what it is asked to do.

  • No placeholders for your code. An edit that would put a line such as // ... existing code ... where your code was changes nothing, in any mode, and the model is asked for the real code.
  • No loops on an edit that can’t apply. The same failing edit is not run again; the model is told it would fail the same way and has to try something else.
  • An edit builds on a file created earlier in the same reply, and reading that file shows the version waiting for your review.

Three layers, and a deny that always wins

Permissions are the part worth reading closely, because this is where an agent tool is either trustworthy or merely confident.

  1. The deny tier. .onyxnoai plus built-in defaults covering .env, secrets and private keys. The agent host vetoes matching reads even in unattended mode, and even with approvals bypassed for the session.
  2. File-based rules in .onyx/permissions.json, fine-grained per command, path and tool. This is the layer to actually use.
  3. Settings-based allowances, kept for migration parity and all-or-nothing per tool kind.

A deny pattern beats every allow above it. That ordering is what makes the rules worth committing: a careless local override cannot re-enable something the team explicitly denied, so the file in the repository is the floor rather than a suggestion.

Two files, one committed and one not

Team rules and machine-specific ones are separated, because they have different lifetimes and different audiences.

FileStatusPurpose
.onyx/permissions.jsonCommittedTeam-wide rules, reviewed in pull requests like any other policy
.onyx/permissions.local.jsonGitignoredThis machine’s overrides: host-specific paths, your own allowlist

Allow rules apply once you trust the folder (the trust prompt when it first opens, or Workspaces: Manage Workspace Trust). Both files sit in the project, so a repository you clone could commit either one; until you trust it, everything that asks still asks and the deny rules apply as always. Its .vscode/settings.jsoncan’t choose the agent mode or add a settings-based allowance either: your own settings apply.

The pattern grammar is small enough to hold in your head:

text
Shell(git log:*)     prefix match on a word boundary
                     matches: git log, git log -3, git log --oneline
                     does not match: git logger

Shell(npm test)      exact command line

Read(src/**/*.ts)    workspace-relative glob, ** and * both supported
Write(.env*)         the same, for writes

MCP(server:tool)     one MCP tool, by the server's id and the tool's id
MCP(server:*)        every tool on that server

The shape is deliberately aligned with Claude Code’s settings file, so snippets paste across verbatim. Bash(...) is accepted as an alias for Shell(...) and normalised on first edit, which means a rule you copied from a colleague works rather than silently doing nothing.

A file with a syntax error approves nothing.While either permissions file can’t be read (a typo, a missing comma, a key written twice, or a key the file doesn’t have, such as "Deny"), no allow rule from either file applies, since a deny the broken file lost could have vetoed it. Deny rules apply as far as they can be read, a notice names the file and what is wrong with it, and the file is never rewritten until you fix it.

Run an agent that never leaves your machine

Plan, Ask, Edit and Auto, driven by a model running locally.

Free tier, no account, no sign-up, no telemetry. macOS, Windows and Linux.