Stelladocs
Agent Tools

Permissions

How Stella's per-tool permission model separates read-only tools from mutating and shell tools, and how PreToolUse hooks can gate or block tool calls.

Every tool the agent can call — built-in, custom, or provided by an MCP server — has a per-tool permission model. This is what lets Stella treat a harmless file read differently from a shell command that can change your system.

Read-only vs. mutating tools

Tools fall into two categories:

  • Read-only tools only observe your workspace and environment. They never change files, run commands, or perform side effects. These tools are marked read_only: true. The authoritative read-only set in the built-in catalog is read_file, grep, glob, gather_context, explorations, ci_status, repo_status, task_list, the read-only issue tools (search_issues, get_issue, list_labels, list_members), the read-only web tools (web_search, web_fetch, web_extract_assets) when the web opt-in is on, and — once stella init has built the code graph — graph_query. Read-only tools are also the only ones eligible for speculative execution during the model stream.
  • Mutating and shell tools can change files, execute commands, or perform other side effects. Examples include write_file, edit_file, delete_file, bash, build_project, run_tests, save_memory, screenshot, web_download, and verify_done.

The read_only: true marker is the signal that a tool is safe to run without changing anything. Tools without it should be treated as capable of side effects — note that screenshot and verify_done are mutating even though they only write into .stella/ or shell out to a test command.

Read-only vs. mutating is a property of the tool, not of a specific invocation. Some friendly names are actually families whose members split across the boundary — within the issue tools, search_issues / get_issue / list_labels / list_members are read-only while create_issue / update_issue / close_issue / start_work_on_issue are mutating. The same split runs through the repo family (repo_status is read-only; repo_commit / repo_push / repo_pull / repo_rollback are mutating) and the task board (task_list is read-only; the other five task_* tools are mutating).

Gating tool calls with hooks

The permission model is enforced ahead of each tool call, and it can be extended with lifecycle hooks. In particular, a PreToolUse hook runs before a tool executes and can block it: if the hook exits with a non-zero status, the tool does not run and the model receives the hook's message instead.

This gives you a programmable gate in front of any tool. A PreToolUse hook's matcher is a glob over the tool name, so you can target a single tool (for example, bash) or a family of tools.

For blocking by pattern without a hook script, Stella also has native workspace-rule guards enforced at the tool boundary: guard-tool (deny a tool), guard-deny-command (a glob over the bash command), and guard-deny-path (a glob over a file tool's path). A rule such as guard-deny-command: "git push --force*" is hard-enforced per invocation.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "bash",
        "hooks": [
          {
            "type": "command",
            "command": "./scripts/guard.sh",
            "timeoutMs": 5000
          }
        ]
      }
    ]
  }
}

For the full hook model — events, matchers, timeouts, and the JSON payload delivered on stdin — see Hooks.

Stella is totally free and open source, dual-licensed MIT or Apache 2.0— your choice: MIT's three-paragraph simplicity, or Apache 2.0's explicit patent grant that enterprises prefer. Use it, fork it, embed it, ship it — no account, no phone-home, no strings. What that means →

On this page