Agent policy and managed config
Restrict or configure what agents may do, and lock those settings for a fleet with a managed policy file.
Agent policy is a small set of rules that govern how Tallpine launches agents: how much permission they get, which environment variables they inherit, how they obtain GitHub credentials, and how sessions are spread over several signed-in accounts.
Every rule is off by default. An install with no policy configured behaves exactly as before: agents inherit the daemon's environment, no permission cap applies, the project's orchestrator cannot answer worker approvals, and sessions stay on the default account. Nothing restricts or changes agents until a user, project, or administrator turns a rule on.
Layers and precedence
Each setting is resolved from five layers, highest precedence first:
- Managed: a policy file deployed by an administrator (MDM).
- Environment:
TALLPINE_AGENT_*variables in the daemon's environment. - Project: a per-project override.
- User: the global setting in Settings, Harness, Agent policy.
- Default: off.
A setting set by the managed file or the environment is locked: Settings shows it as read-only and a write to it is refused. Project overrides never beat managed or environment values, and security settings are tighten-only per project: a project may make agents stricter than the user's global value, never looser. A loosening override is ignored with a warning.
See what is in force, and which layer set each value:
tallpine policy show # global
tallpine policy show --project <id> # with that project's overrides
tallpine policy show --session <id> # the decision recorded for a launch
tallpine policy show --jsonOutput lines look like permissionCap.max: "auto" (managed, locked). Warnings, such as an unknown rule in the managed file, are listed too.
Rules
| Rule | Settings | Default | Project override |
|---|---|---|---|
permissionCap | max: none, auto, accept_edits | none (no cap) | tighten-only |
envFilter | mode: inherit, allowlist; passthrough: list of names | inherit, empty list | mode tighten-only; passthrough not overridable |
githubCreds | mode: env, helper, none | env | tighten-only |
orchestratorApprovals | enabled: true/false | false | allowed |
repoAgentConfig | enabled: true/false | true | allowed |
accountPool | placement: default, random, most-headroom, least-used; failover: true/false | default, false | not overridable |
permissionCapforbids bypass/full access (auto) or anything above accept-edits (accept_edits). Strictness risesnone<auto<accept_edits. An invalid value is never ignored: it applies the strictest level (accept_edits) and warns.envFilterwithallowliststarts agents with only a curated base list (what git, gh, ssh, node, go and common toolchains need), the variables of the agent's own harness, yourpassthroughnames, and what the daemon sets for the session (TALLPINE_*, the project's environment, account variables). Passthrough names may end in*. See below.githubCredshelperkeeps GitHub tokens out of the agent's environment (git askstallpine git-credential,ghruns throughtallpine gh-exec);nonerefuses every request. See below.orchestratorApprovalslets a project's orchestrator answer the permission prompts of that project's workers. A managedfalseforces it off for every project.repoAgentConfigdecides whether Claude Code workers load agent config committed to the repository they work in (project settings and hooks,.mcp.jsonservers). On by default;falselaunches the agent with your own settings only (--setting-sources user). A managedfalseforces it off for every project. Tallpine's own hooks and permission mode are passed on the launch command line, so they apply either way. Reviewers never load repository agent config. While a permission cap or any managed policy value is active, Claude Code workers load only your own settings (--setting-sources user), whateverrepoAgentConfigsays: capped sessions do not get the repository's.claudesettings, hooks or MCP servers, and "don't ask again" approvals do not persist.accountPoolis not a restriction; it switches on account spreading. See below.
Managed config for administrators
The managed layer is read from a fixed location per platform:
| Platform | File |
|---|---|
| macOS | /Library/Managed Preferences/ee.justdev.tallpine.plist |
| Linux | /etc/tallpine-daemon/policy.json |
| Windows | %ProgramData%\Tallpine\policy.json |
On macOS push it as a custom-settings configuration profile for the preference domain ee.justdev.tallpine (Jamf "Application & Custom Settings", or any MDM that writes to Managed Preferences). A plain JSON file at the same path is also accepted. On macOS the plist is converted with the system plutil.
TALLPINE_MANAGED_POLICY_FILE overrides the path, but only in development builds. A release binary ignores it, so a user who controls the daemon's environment cannot point it at a weaker file.
Format
Version 2 nests settings by rule. This minimal file caps agents below bypass mode, switches the environment to an allowlist, and keeps GitHub tokens out of agent environments:
{
"schemaVersion": 2,
"rules": {
"permissionCap": { "max": "auto" },
"envFilter": { "mode": "allowlist", "passthrough": ["CORP_PROXY_*", "NPM_TOKEN"] },
"githubCreds": { "mode": "helper" },
"orchestratorApprovals": { "enabled": false },
"repoAgentConfig": { "enabled": false },
"accountPool": { "placement": "least-used", "failover": true }
}
}The same policy as a macOS plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>schemaVersion</key><integer>2</integer>
<key>rules</key>
<dict>
<key>permissionCap</key><dict><key>max</key><string>auto</string></dict>
<key>envFilter</key>
<dict>
<key>mode</key><string>allowlist</string>
<key>passthrough</key><array><string>CORP_PROXY_*</string><string>NPM_TOKEN</string></array>
</dict>
<key>githubCreds</key><dict><key>mode</key><string>helper</string></dict>
<key>orchestratorApprovals</key><dict><key>enabled</key><false/></dict>
<key>repoAgentConfig</key><dict><key>enabled</key><false/></dict>
<key>accountPool</key>
<dict><key>placement</key><string>least-used</string><key>failover</key><true/></dict>
</dict>
</dict>
</plist>Include only the rules you want to manage; anything omitted stays under user, project, and default control. Check the result with tallpine policy show: every managed value reports (managed, locked).
Failure behavior
- Missing or unreadable file: no managed layer.
- Malformed file, or an invalid value in a field that declares a strictest value (the permission cap): the strictest value is applied, locked, with a warning. An admin who wrote a file clearly meant to restrict, so failing open would void the lock.
- Unknown rule or setting: ignored with a warning.
schemaVersionnewer than the app understands: the settings it knows are applied, with a warning.- Version 1 (the original flat file,
{"maxPermission": "auto"}, withenvModeandenvPassthrough) is still accepted.
Environment variables
Each setting can also be set in the daemon's environment, which locks it like the managed file. The name is TALLPINE_AGENT_<RULE>_<SETTING>:
| Setting | Variable |
|---|---|
permissionCap.max | TALLPINE_AGENT_PERMISSION_CAP_MAX (also TALLPINE_AGENT_MAX_PERMISSION) |
envFilter.mode | TALLPINE_AGENT_ENV_FILTER_MODE (also TALLPINE_AGENT_ENV_MODE) |
envFilter.passthrough | TALLPINE_AGENT_ENV_FILTER_PASSTHROUGH (also TALLPINE_AGENT_ENV_PASSTHROUGH), comma-separated |
githubCreds.mode | TALLPINE_AGENT_GITHUB_CREDS_MODE |
orchestratorApprovals.enabled | TALLPINE_AGENT_ORCHESTRATOR_APPROVALS_ENABLED |
repoAgentConfig.enabled | TALLPINE_AGENT_REPO_AGENT_CONFIG_ENABLED |
accountPool.placement | TALLPINE_AGENT_ACCOUNT_POOL_PLACEMENT (also TALLPINE_ACCOUNT_PLACEMENT) |
accountPool.failover | TALLPINE_AGENT_ACCOUNT_POOL_FAILOVER (also TALLPINE_ACCOUNT_FAILOVER) |
Per-harness environment allowlist
With envFilter.mode set to allowlist, each agent receives the credential variables of its own harness only: a Claude Code worker gets ANTHROPIC_*, Claude Bedrock/Vertex routing and AWS/Google credentials for them, but not OPENAI_*; a Codex worker gets OPENAI_* and CODEX_*. A harness the filter does not recognize gets the union of all lists. This limits ambient credentials, not what an allowed agent can do: a harness still sees its own credentials.
If a tool fails because it needs a variable that was dropped, add its name to passthrough (Settings, or the environment variable above). Each launch's decision record lists the dropped variable names, never values: tallpine policy show --session <id>. An invalid mode value is reported and ignored rather than cutting agents off from their tools.
Permission cap
permissionCap.max limits the most permissive mode agents may run in. auto forbids bypass/full-access modes; accept_edits forbids anything above accept-edits. The cap also applies to a chat switching permission mode mid-session, so a managed tightening takes effect for chats already running.
Account pool and failover
When you have several signed-in accounts for one harness (Claude Code, Codex), accountPool can spread work across them. Both settings are off by default.
placementpicks the account a new session without a chosen one starts on:default(the default account),random,most-headroom, orleast-used.failovermoves a session whose account hit a usage limit to another account with headroom, instead of waiting for the reset.
Rotating several personal subscriptions to avoid usage limits may conflict with the provider's terms; for teams, prefer organization seats or API keys.
GitHub credentials
githubCreds.mode decides how an agent gets GitHub access:
env(default): a token is placed in the agent's environment (GH_TOKEN).helper: no token in the environment.gitasks a credential helper (tallpine git-credential) andghruns through a shim (tallpine gh-exec); each asks the daemon for the project's token per use, with an audit line and the ability to deny. This removes the token from env dumps, logs, and every child process, but does not stop an agent from invoking the helper.none: every request is refused.
A token the project's own environment sets (GH_TOKEN, GITHUB_TOKEN, or TALLPINE_GITHUB_TOKEN) keeps winning, and the decision record notes which variable name did. Per-project GitHub identity is set with the project's githubUser field (a valid GitHub login); see Projects.
On Windows the helper and shim are not implemented yet, so helper falls back to the token in the environment and logs a warning.