# EONYX permissions and security: control over every action


An agent that reads and edits code and runs commands must operate **within explicit permissions**. In EONYX security is several layers: a static gateway, a file sandbox, plan mode and a coarse block on dangerous commands. Let's go through each of them.

<!--more-->

## The permission gateway

The first layer is who decides whether a tool may run and how: the static policy, the interactive dialog in the TUI and plan mode on top.

### Static policy

Tools are split into **always allowed** (read-only) and **requiring permission** (writes, commands, commits, MCP tools).

Always allowed with no questions asked: `read`, `ls`, `glob`, `grep`, `git_status`, `git_diff`, `git_log`, `todo_write`. Everything else goes through the gateway:

```json
"permissions": {
  "allowed_tools": ["bash", "write", "edit"],
  "sandbox": true
}
```

- **`allowed_tools`** — the list of tools that run without confirmation.
- **`sandbox`** — locks the file tools inside the project root (see below).
- **`--yolo`** (or `/yolo` in the TUI) — allows everything for the duration of the session.

If a tool is not allowed and `--yolo` is off, the static policy returns a denial like *"permission denied for tool …: re-run with --yolo or add … to permissions.allowed_tools"*.

{{< admonition type="note" title="A denial does not break the flow" >}}
A blocked tool is returned to the model as an **error result**, not as a crash. The model sees the denial and adapts — for example, it proposes another route. The conversation stays consistent.
{{< /admonition >}}

### The interactive layer in the TUI

In interactive mode a dialog works on top of the static policy: for a tool the policy did not let through, EONYX asks:

- **Allow once** — allow it a single time;
- **Allow always (this session)** — allow it until the end of the session;
- **Deny** — reject it (Esc = deny).

"Allow always" remembers the tool for the current session so you are not asked again.

### Plan mode

`/plan` is a stricter "think first" gateway. While it is on, only read-only tools are available (`read`, `ls`, `glob`, `grep`, `picker`, `git_status`, `git_diff`, `git_log`, `fetch`, `task`, `todo_write`); anything that writes or executes is blocked — **regardless** of `allowed_tools` and `--yolo`:

> plan mode is on: "…" is blocked until you approve the plan — run /plan to exit plan mode and enable edits

When the plan is ready, EONYX shows a dialog: **implement**, **allow edits** or **keep planning**. It is handy for having the agent explore the code and propose a plan first, so you approve it before it changes anything.

## Boundaries and guardrails

On top of the gateway there are hard boundaries that limit the damage: the file sandbox, the coarse block on dangerous commands and hooks.

### The file sandbox

`permissions.sandbox: true` locks the file tools (`read`, `write`, `edit`, `multi_edit`, `ls`) inside the **project root** (the directory containing `eonyx.json`; if there is none — the working directory). A path outside the root is rejected:

> path "…" is outside the project sandbox (…); set permissions.sandbox to false to allow paths outside the project

By default the sandbox is **off** — turn it on when you work on an untrusted task or want a guarantee that the agent will not touch anything outside the project. Tools without a path (`bash`, `glob`, `grep`, `fetch`, the git tools) are not restricted by the sandbox.

### Blocking dangerous commands

Below the permission gateway there is one more, coarse layer: the built-in shell (`mvdan/sh`) hard-blocks a small set of commands at the policy level — they cannot be allowed even with `--yolo`:

```text
shutdown · reboot · halt · poweroff · mkfs · init
```

An attempt returns the error *"command "…" is blocked by shell policy"*. This is insurance against catastrophic actions, not full isolation.

### Hooks

Additional control comes from **pre-hooks**: a `before` hook with a non-zero exit code **blocks** the tool. For example, forbid `bash` when the working directory is the home directory:

```json
"hooks": {
  "bash": { "before": "[ \"$EONYX_CWD\" = \"$HOME\" ] && exit 1 || exit 0" }
}
```

More on this in the article about hooks.

## Summary

{{< admonition type="abstract" title="Cheat sheet" >}}
- **Permission gateway**
  - reading is always allowed (`read`, `ls`, `glob`, `grep`, the git status tools, `todo_write`); everything else goes through the gateway
  - `allowed_tools` allows without questions, `--yolo` removes the gateway for the session
  - the TUI asks allow once / always / deny; a denial does not break the flow
- **Plan mode**
  - `/plan` — read-only until you approve the plan
- **Boundaries and guardrails**
  - `sandbox` locks the file tools inside the project root
  - the coarse shell block: `shutdown`/`reboot`/`mkfs`… not even with `--yolo`
  - pre-hooks can block a tool with their exit code
{{< /admonition >}}

