> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mirage.strukto.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent profiles

> Choose what each agent can run and which files it can see.

A profile gives an agent session its permissions. Agents can share a
workspace while seeing different files and using different commands.

## What a profile controls

| Setting | Purpose |
| - | - |
| `commands.allow` | Limit the session to the listed tools. |
| `commands.ask` | Require approval for matching commands. |
| `commands.deny` | Refuse matching commands. |
| `paths.hide` | Make matching files and folders invisible to the session. |
| `paths.show` | Make a specific path visible within a hidden folder. |
| `mounts` | Restrict a data source to `read`, `write` or `exec` access. |
| `cwd` and `env` | Set the session's starting directory and environment; `env` takes the same literals and [credential pointers](/home/configuration#environment-and-credential-pointers) as the workspace's. |

## Example: a research agent

This profile lets an agent browse and search `/data`, keeps it read-only,
and hides `/data/private`.

```yaml workspace.yaml theme={null}
mounts:
  /data:
    vfs: ram

profiles:
  researcher:
    cwd: /data
    mounts:
      /data:
        mode: read
    paths:
      hide: [/data/private]
    commands:
      allow: [ls, cat, grep, find, stat, pwd]

profile: researcher
```

Replace RAM with your [VFS](/home/setup/vfs). `profile: researcher` selects
the default for new sessions; another session can use a different named
profile. A profile cannot grant access beyond the workspace's permissions.

## Rule matching

Command patterns match token prefixes. `git push` matches `git push origin main`.
Spelling and order matter: `rm -rf` does not match `rm -r -f` or
`rm --recursive --force`. A `*` token matches any token; trailing `*` is redundant.

Omitting `commands.allow` adds no tool allowlist restriction; `allow: []`
admits no installed tools. This list does not govern shell functions,
executed paths or direct VFS calls. The shell's own tests count as commands
under their own names: an allow list admits `[ ]` only if it names `[`,
`[[ ]]` only if it names `[[`, and a path rule judges the file operand of
`-e`, `-f` or `-nt` in all three spellings as it does for `test`, however the
operand is spelled.

Ask and deny rules can name commands, paths, or map a command to its paths:

```yaml theme={null}
commands:
  allow: [rm]
  ask:
    - {commands: {rm: ["/data/review/*"]}, reason: deletes need review}
  deny:
    - {commands: {rm: ["/data/*"]}, reason: data is retained}
```

Within one profile’s rules, the deeper literal anchor wins for each path.
Deny wins at equal depth.
Here, `rm /data/review/note.txt` asks for approval despite the broader deny;
`rm /data/other.txt` is denied. A multi-path command must pass each path's checks.

A rule written under a mount section speaks for that mount: for a line whose
working directory or paths lie in it, for a walk or a move of a directory that
holds it (`grep -r`, `ls -R`, `mv`), and for each entry inside it that a line
reaches on its own (`cp -r`, `chmod -R`).

`paths.hide` and ask/deny path entries may be absolute paths or slashless
name patterns such as `*.pem`, including inside mount sections.
`paths.show` entries must be absolute paths. A literal path covers its subtree;
glob patterns use `*`, `?` and `[`, and `*` can cross `/`. A rule naming only
`paths` also applies to direct VFS operations.

`paths.hide` makes a path appear absent; `paths.show` reopens a more specific
path. A hide stays where it is written, so moving a directory that holds a
hidden path, or one the session reaches only through a `paths.show` below it,
is refused with `Permission denied`: the hidden content would land in view.
Ask and deny rules control operations while leaving paths visible.
A hidden path is also left out of what commands and CLIs print from their own
data, and out of their counts and totals: `git status`, `git ls-files`,
`git diff --stat` and `git log --name-only` neither name nor count a file
another session staged under it. A link that leads into a hidden path is
hidden as well, for every command: `readlink -f`, `test -L`, `ln`, `touch -h`,
`chown -R` and `find -newer` meet it as a name that is not there.

A repository's history counts as the path too. Under a hide, no revision ever
held it: `git show HEAD:secret.txt` answers as it would for a path never
committed, `git log -S` finds nothing in it, and an object id stored only
there names nothing. A checkout or a branch switch leaves a hidden file as it
is: an edit to it neither blocks the switch nor is named in git's refusal. A
switch that would remove it, by writing a file where its directory stands, is
refused, naming only the visible path. Under a deny rule, git refuses to print
the path's content from any revision (`git log -p`, `git show HEAD:secret.txt`)
as it refuses the file, and still lists the name.

Use [Explain](/home/policy/explain) to check a rule before running a line.
For conditions beyond these patterns, attach a [policy script](/home/policy/scripts).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.