TallpineTallpine Docs

Agent policy and managed config

Restrict or configure what agents may do, and lock those settings for a fleet with a managed policy file.

View on GitHub

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:

  1. Managed: a policy file deployed by an administrator (MDM).
  2. Environment: TALLPINE_AGENT_* variables in the daemon's environment.
  3. Project: a per-project override.
  4. User: the global setting in Settings, Harness, Agent policy.
  5. 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 --json

Output lines look like permissionCap.max: "auto" (managed, locked). Warnings, such as an unknown rule in the managed file, are listed too.

Rules

RuleSettingsDefaultProject override
permissionCapmax: none, auto, accept_editsnone (no cap)tighten-only
envFiltermode: inherit, allowlist; passthrough: list of namesinherit, empty listmode tighten-only; passthrough not overridable
githubCredsmode: env, helper, noneenvtighten-only
orchestratorApprovalsenabled: true/falsefalseallowed
repoAgentConfigenabled: true/falsetrueallowed
accountPoolplacement: default, random, most-headroom, least-used; failover: true/falsedefault, falsenot overridable
  • permissionCap forbids bypass/full access (auto) or anything above accept-edits (accept_edits). Strictness rises none < auto < accept_edits. An invalid value is never ignored: it applies the strictest level (accept_edits) and warns.
  • envFilter with allowlist starts 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, your passthrough names, and what the daemon sets for the session (TALLPINE_*, the project's environment, account variables). Passthrough names may end in *. See below.
  • githubCreds helper keeps GitHub tokens out of the agent's environment (git asks tallpine git-credential, gh runs through tallpine gh-exec); none refuses every request. See below.
  • orchestratorApprovals lets a project's orchestrator answer the permission prompts of that project's workers. A managed false forces it off for every project.
  • repoAgentConfig decides whether Claude Code workers load agent config committed to the repository they work in (project settings and hooks, .mcp.json servers). On by default; false launches the agent with your own settings only (--setting-sources user). A managed false forces 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), whatever repoAgentConfig says: capped sessions do not get the repository's .claude settings, hooks or MCP servers, and "don't ask again" approvals do not persist.
  • accountPool is 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:

PlatformFile
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.
  • schemaVersion newer than the app understands: the settings it knows are applied, with a warning.
  • Version 1 (the original flat file, {"maxPermission": "auto"}, with envMode and envPassthrough) 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>:

SettingVariable
permissionCap.maxTALLPINE_AGENT_PERMISSION_CAP_MAX (also TALLPINE_AGENT_MAX_PERMISSION)
envFilter.modeTALLPINE_AGENT_ENV_FILTER_MODE (also TALLPINE_AGENT_ENV_MODE)
envFilter.passthroughTALLPINE_AGENT_ENV_FILTER_PASSTHROUGH (also TALLPINE_AGENT_ENV_PASSTHROUGH), comma-separated
githubCreds.modeTALLPINE_AGENT_GITHUB_CREDS_MODE
orchestratorApprovals.enabledTALLPINE_AGENT_ORCHESTRATOR_APPROVALS_ENABLED
repoAgentConfig.enabledTALLPINE_AGENT_REPO_AGENT_CONFIG_ENABLED
accountPool.placementTALLPINE_AGENT_ACCOUNT_POOL_PLACEMENT (also TALLPINE_ACCOUNT_PLACEMENT)
accountPool.failoverTALLPINE_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.

  • placement picks the account a new session without a chosen one starts on: default (the default account), random, most-headroom, or least-used.
  • failover moves 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. git asks a credential helper (tallpine git-credential) and gh runs 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.

On this page