Skip to main content
Browse the documentation

Configuration

snaga.toml

Project and global configuration — agent behaviour, memory, permissions, hooks, MCP servers — and why a config file from a repo you cloned asks before it does anything.

Snaga reads snaga.toml from the working directory or ~/.config/snaga/. Layers apply in order: defaults, then global, then project, then environment.

[agent]
max_rounds = 20
temperature = 0.7

[memory]
enabled = true
playbook = true
reflection = true

[permissions]
auto_approve = ["read_file", "grep", "glob"]
deny = ["rm_all"]

[hooks]
enabled = true
[[hooks.after_tool_call]]
command = "cargo check"
tools = ["edit_file", "write_file"]

[[mcp.servers]]
name = "postgres"
command = "npx"
args = ["@modelcontextprotocol/server-postgres"]

The recognised sections are agent, memory, permissions, hooks, mcp and models. There is no model selection here — the platform chooses; see Getting started.

A config file from a cloned repo does not just run

This is the part worth knowing before anything else.

snaga.toml can declare shell hooks and MCP servers — that is, commands to run and subprocesses to spawn. A project-local one can also be committed to a public repository. So running snaga in a directory you just cloned would otherwise silently execute whatever its config said.

It does not. Project-local configs are untrusted by default. When one asks for side effects, Snaga stops and shows you what it wants:

  Project-local snaga.toml requests side effects:
    /path/to/snaga.toml
      · shell hook — cargo check after edit_file
      · mcp server — npx @modelcontextprotocol/server-postgres

You approve or you do not. Approval is remembered per project, and a changed snaga.toml asks again — otherwise someone who landed a commit in your repository would inherit a decision you made about a different file.

A global config in ~/.config/snaga/ is yours and is not treated this way.

Hooks

Hooks run around tool execution. Note the shape: [[hooks.after_tool_call]] is an array of tables, one per hook, not a single string.

[hooks]
enabled = true

[[hooks.after_tool_call]]
command = "cargo check"
tools = ["edit_file", "write_file"]

tools narrows a hook to the tools that should trigger it. Available points are before_tool_call, after_tool_call, on_error and on_turn_complete.

A hook is a command that runs on your machine every time it fires. Keep them fast — a slow before_tool_call is paid on every single tool call.

MCP servers

Servers declared here are connected at startup:

[[mcp.servers]]
name = "github"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-github"]
env = { GITHUB_TOKEN = "${GITHUB_TOKEN}" }

Environment variables interpolate, so credentials stay out of the file and out of your repository. Declaring a server counts as a side effect for the trust prompt above.

See Skills and MCP.

Permissions

[permissions]
auto_approve = ["read_file", "grep", "glob"]
deny = ["rm_all"]

This is per-tool. The shell command policy is a separate file with its own merge rules — see Changing the rules.