Files
hermes-ice/homelab/raw/articles/forge/reference/docs-permissions.md
Hermes Agent e4d91aadf9 Initial commit: homelab infrastructure wiki
- Full Obsidian vault content
- Host configs (ice, grizzley, ubuntu, proxmox, truenas, panda, hyte)
- Media stack documentation
- Traefik HA setup
- Automation scripts
- Bachelor party planning
2026-05-24 16:08:40 -07:00

6.2 KiB
Raw Blame History

type, agent, source, scraped, content_hash
type agent source scraped content_hash
agent-doc ForgeCode https://forgecode.dev/docs/permissions/ 2026-04-28T21:02:25.021876+00:00 c5cb7af7

permissions.yaml

permissions.yaml is ForgeCode's policy file for built-in tools. It only matters when restricted mode is enabled in .forge.toml.

Start with the simplest possible example

This policy does three things:

  • allows reads anywhere
  • asks before writes
  • blocks rm
policies:  - permission: allow    rule:      read: "**/*"  - permission: confirm    rule:      write: "**/*"  - permission: deny    rule:      command: "rm*"

That is the whole mental model.

Turn it on

permissions.yaml does nothing until restricted mode is enabled:

restricted = true

Add that to ~/.forge/.forge.toml, or to the .forge.toml inside your custom config directory if you use FORGE_CONFIG.

When restricted = false, ForgeCode behaves normally and does not gate tool execution through this policy file.

Where the file lives

ForgeCode reads the file from its config directory:

  • macOS/Linux: ~/.forge/permissions.yaml
  • Windows: %USERPROFILE%\.forge\permissions.yaml
  • Custom config directory: $FORGE_CONFIG/permissions.yaml

If restricted mode is enabled and the file does not exist yet, ForgeCode creates it with a default allow-all policy.

That default looks like this:

policies:  - permission: allow    rule:      read: "**/*"  - permission: allow    rule:      write: "**/*"  - permission: allow    rule:      command: "*"  - permission: allow    rule:      url: "*"

So turning on restricted mode alone does not make ForgeCode stricter. The restriction comes from the rules you write.

The shape of the file

Every file starts with one top-level key:

policies:  - permission: allow    rule:      read: "**/*.rs"

A simple policy has two parts:

  • permission: what should happen
  • rule: what should match

Permission values

Value What it means
allow Run the operation immediately
deny Reject the operation immediately
confirm Pause and ask you first

Rule types

A rule matches exactly one kind of operation:

Key Matches Example
read File reads and file searches "docs/**/*"
write Writes, patches, and deletes "src/**/*"
command Shell command strings "git *"
url Network fetches "https://api.github.com/*"

You can also scope any rule to a working directory with dir:

- permission: allow  rule:    write: "**/*.rs"    dir: "/home/user/project/*"

That rule only applies when the current working directory matches the dir glob.

How ForgeCode evaluates policies

A matching allow is not always final. ForgeCode can keep scanning because a later deny or confirm may still need to stop the operation.

Suppose ForgeCode wants to run git status.

run `git status`  -> check rules from top to bottom  -> matching deny?    stop and reject  -> matching confirm? stop and ask  -> matching allow?   remember it and keep going  -> nothing decisive matched? ask by default

That last line matters: no matching policy means confirm, not allow.

What ForgeCode actually checks

Built-in tools are mapped into four operation types:

Tool family Checked as
Read, FsSearch read
Write, Patch, MultiPatch, Remove write
Shell command
Fetch url

Some tools are exempt from this policy system, including SemSearch, Undo, Plan, and Task.

MCP tools also bypass this file entirely. permissions.yaml governs ForgeCode's built-in tools, not external MCP integrations.

Confirmation mode

When a matching rule returns confirm — or when nothing matches and ForgeCode falls back to confirm — you get a prompt with three choices:

Choice Result
Accept Allow this one operation
Reject Deny this one operation
Accept and Remember Allow it now and append a matching rule to permissions.yaml

The remembered rule depends on what you approved:

Operation Generated pattern
Read or write file.rs *.rs
Fetch https://example.com/api example.com*
Run git push origin main git push*
Run ls ls*
Read or write a file with no extension No rule is added

This makes confirmation useful for tightening policies gradually instead of designing the whole file up front.

Logical policies

Simple rules cover most setups. When they do not, permissions.yaml also supports all, any, and not.

policies:  - all:      - permission: allow        rule:          read: "src/**/*"      - permission: allow        rule:          dir: "/home/user/project/*"          read: "**/*"  - any:      - permission: allow        rule:          read: "**/*.rs"      - permission: allow        rule:          read: "**/*.toml"  - not:      permission: deny      rule:        command: "rm -rf/*"

Use these sparingly. Most policy files are easier to reason about when each rule does one obvious thing.

Good patterns

Here are a few narrower patterns.

Allow writes only for one kind of file

policies:  - permission: allow    rule:      read: "**/*"  - permission: allow    rule:      write: "**/*.rs"  - permission: deny    rule:      write: "**/*"

Allow one API, deny the rest

policies:  - permission: allow    rule:      url: "https://api.github.com/*"  - permission: deny    rule:      url: "*"

Allow writes only inside one project directory

policies:  - permission: allow    rule:      write: "**/*"      dir: "/home/user/myproject/*"  - permission: deny    rule:      write: "**/*"

Common mistakes

Turning on restricted mode and expecting instant safety

Restricted mode only enables policy evaluation. If the generated permissions.yaml still allows everything, ForgeCode still allows everything.

Forgetting the fallback behavior

If no rule matches, ForgeCode asks. That is usually what you want, but it can feel surprising if you expected silent denial.

Trying to control MCP tools here

You cannot. This file covers built-in tools only.

Where to go next

If you have not enabled restricted mode yet, start with the .forge.toml setting in the .forge.toml reference.

Then come back and write the smallest policy file that matches how you actually work.