Docs

Managed policy

A file IT pushes to a machine that turns parts of Toyon off for everyone who uses it. The person at the keyboard cannot change it, every key is locked, and toyon doctor shows what is in effect and where it came from. It is the same shape Chrome, Firefox, Docker Desktop and Claude Code use for managed settings, so the tooling that deploys those deploys this.

Where it lives

Platform Path Format
macOS /Library/Managed Preferences/dev.toyon.plist a configuration profile for the dev.toyon domain, installed at computer scope
macOS /Library/Managed Preferences/<user>/dev.toyon.plist the same profile installed at user scope
macOS /Library/Application Support/toyon/policy.json JSON, for a shop that pushes files with a script
Linux /etc/toyon/policy.json JSON

Every file that exists is read and merged. Where two set the same key, the stricter value wins. A JSON file must be owned by root and not writable by group or others; one that is not is treated as invalid. The profile plists are trusted as MDM's own location.

The CLI reads the files on every run. The daemon reads them once, when it starts, so a file pushed while it is running takes effect at the next toyon restart; toyon doctor says when the running daemon is behind.

Keys

Every key is optional. A key that is absent is allowed. Unknown keys are ignored, so a file written for a newer Toyon still reads.

Key Type What it turns off
updates boolean false: Toyon never checks for or installs a newer version, toyon update refuses, and a Toyon started with npx does not offer the global install. This governs self-update only; a person can still run npx toyon@latest, and pinning what runs is the job of your software allowlist.
deploy boolean false: toyon deploy refuses.
remote "any", "tailscale" or "off" off: toyon remote refuses and the daemon ignores a remote.json it finds. tailscale: only a *.ts.net name is accepted, so the shell opens over your tailnet and nowhere else.
agents list of agent ids Only the agents listed exist: the others are gone from the picker and are never installed. The builtin ids are claude, codex and opencode.
customAgents boolean false: ~/.toyon/agents.json is ignored, so nobody can add an agent of their own, shadow a builtin with one, or tune a builtin's environment and sessions.
brandedListener boolean false: the daemon does not bind port 80 for http://toyon.localhost; the shell is at http://toyon.localhost:4141 only.
planSignIn boolean false: signing in with a personal Claude plan is not offered in the chat, and a request for it is refused. Keys and gateways still work.

An example that keeps a company's laptops off the public internet and on its own accounts:

{
  "updates": false,
  "deploy": false,
  "remote": "tailscale",
  "agents": ["claude", "codex"],
  "customAgents": false,
  "planSignIn": false
}

The same file as a profile payload, for the dev.toyon preference domain:

<dict>
  <key>updates</key><false/>
  <key>deploy</key><false/>
  <key>remote</key><string>tailscale</string>
  <key>agents</key><array><string>claude</string><string>codex</string></array>
  <key>customAgents</key><false/>
  <key>planSignIn</key><false/>
</dict>

What a person sees

A verb the policy turns off says so and exits 1:

toyon: deploy is turned off by your organization's policy (/etc/toyon/policy.json)

In the app, the update chip does not appear, a greyed menu row reads "managed by your organization", the chat's sign-in card leaves the plan login out and says why, and the settings card (⌘,) carries one line naming what is off.

Checking it took

$ toyon doctor
ok   cli      toyon 0.4.1, bun 1.4.2, darwin arm64
ok   home     /Users/kyle/.toyon
ok   policy   /Library/Application Support/toyon/policy.json: updates off, deploy off, remote tailscale, agents claude, codex, custom agents off, plan sign-in off
ok   git      git version 2.47.0
ok   daemon   0.4.1 at http://127.0.0.1:4141, pid 41231
ok   updates  off by your organization's policy

A file that will not read is a failing line, and everything the policy governs is off until it is fixed:

FAIL policy   /etc/toyon/policy.json: not valid JSON (everything it governs is off)

When the running daemon started before the file changed, doctor adds a failing daemon line saying toyon restart applies the current one.

What it does not do

It is a policy for Toyon, not a wall around the machine. It cannot stop a person running another copy of Toyon, an older one, or the agents directly. The sandbox and the permission modes in trust.md are the same with or without it. What the policy guarantees is that this Toyon, on this machine, has the listed things off for everyone, and that doctor proves it.