Skip to content

Access levels

Every tool has an access level. assistant.access says the highest level the assistant may use, per integration.

LevelWhat it allowsAsks you?
noneNothing from this integration. Its tools aren’t offered.
readTools that look.No
writeAlso tools that add something, like saving a link.Always
controlAlso tools that change or remove something.Always

Each level includes the ones before it. write and control differ only in what you grant: both ask. See below.

config.yaml
assistant:
model: qwen3:8b
access:
default: read
downloads: control
docs: write
cameras: none

The keys are your instance names, the ones under integrations:, not the types. Two qBittorrent instances can have different levels. Valet reports a key that matches no instance as a config problem.

default covers every instance you don’t name. If access is left out, it’s { default: read }.

Two other keys are special:

  • config turns on editing the config. Without it, those tools don’t exist.
  • valet is Valet’s own tools: reminders, the timeline, the activity log. It defaults to write, so reminders work with no setup. Each one still asks.

Sign-in decides whether Valet may act at all. With auth.mode: none and no auth.trustNetwork, the assistant is capped at read, whatever assistant.access says. The same goes for MCP servers. See sign-in and network safety.

Any tool that isn’t read stops at an approval card and runs only after you press the button. That covers saving a link, filing a document, adding a to-do, and setting or cancelling a reminder.

So the two levels don’t change how it asks. They change what you’re granting: write lets the assistant add things, and control also lets it change or remove them.

A web page that says “save this” can make the model ask, and nothing more.

Each integration’s page lists its tools with their levels. Some examples:

LevelExamples
readDocker status and logs, Immich search, Paperless search
writeKarakeep bookmarks, Paperless filing, to-do list
controlqBittorrent pause and remove, Seerr requests, Plex (Tautulli) stopping a stream, Pi-hole pause

Every integration written with service() has one tool, and it’s read. The check that runs on them fails any tool that isn’t.

Access levels limit what Valet offers. They can’t limit what a key allows. If you give Valet an admin key, a bug or a bad plugin could use all of it.

So give each service the narrowest key it has. See give it as little as possible.