Appearance
Merging and Precedence
When multiple scopes or policies contribute flags, arguments, launch profiles, and routing, the final launch configuration is produced by two steps: obtaining the single Active Policy document for the machine and merging scopes within that document.
What You'll Learn
- Where each platform gets its policy document, and what it runs on when none is delivered
- How scopes merge inside the Active Policy (Launch Profile > User Configuration > Policy > Global)
- How flags, arguments, mounts, networking, and routing resolve conflicts
- How authorization tie-breaks affect routing and handlers
Policy sources and delivery
Exactly one policy document is active on a machine at a time. There is no cross-source merging: all merges and tie-breaks below happen inside that one document. Where the document comes from differs by platform; how it is evaluated does not.
Windows
The Sandbox Manager service and the Launcher resolve the Active Policy in this order, taking the first that yields a decodable document:
- Server download —
GET /api/policyfrom the Turbo server, with a SHA-256 ETag so an unchanged policy is not re-downloaded, and aTurbo-Policy-Contractheader negotiating the strict document contract. The downloaded document is written to the machine-wide path below. A download that fails validation never replaces the stored file. - Machine-wide file —
%ProgramData%\Turbo\Launcher\policy.json, whether written by the sync above or deployed directly by SCCM, Group Policy or Intune (see Deployment). - In-memory last-known-good — the last document that loaded successfully in this process, kept when a newer candidate is refused.
- Embedded default — a built-in allow-all document (one
allowrule overtargetPath**,schemaVersion2). It is a bootstrap convenience, not a secure baseline: a Windows machine with no delivered policy is unfiltered, and the Launcher announces that once per process.
The refresh cadence is 5 minutes (configuration.policyUpdateIntervalMinutes adjusts it) plus a directory watcher on the policy folder, so a deployed file applies within seconds. There is no per-user policy file; per-user input is limited to User Configurations validated against the enterprise policy's templates.
macOS
The Turbo daemon (sandboxmanager) resolves the Active Policy in this order:
- Managed preferences — a policy document delivered by MDM as a managed-preferences plist.
- Machine-wide file —
/Library/Application Support/Turbo/policy.json. - Deny-all — with neither source present the daemon runs on an empty policy and nothing is launchable.
The daemon polls the sources' digests every 5 seconds and applies a change as soon as it decodes. A source is trusted only when its path is root-owned and not world-writable; an untrusted higher-precedence source fails closed rather than being demoted to the next one. The daemon does not download policy from a server. The macOS launcher never reads a file itself: it receives the daemon's decoded policy bytes over XPC, so launcher and daemon always evaluate the same document.
Empty policy versus no policy
- A document with no
apps(or an empty list) authorizes nothing, on every platform. The evaluator is the same everywhere. - No policy delivered at all differs only in the source of last resort: Windows falls back to the embedded allow-all default; macOS falls back to deny-all. Enterprise postures must deliver a policy on both.
Scope Precedence and Merge Order (Active Policy)
Once the Active Policy is selected, configuration merges from least to most specific:
- Global Configuration
- Application Policy
- User Configuration (per-user customizations validated against the Active Policy's templates — Windows only)
- Launch Profile
The following diagram summarizes scope precedence within the Active Policy:
Evaluation order
- Start with Global Configuration (
configuration.launch.runtimeand global mounts). - Merge the matching enabled
action: "allow"application policies together with any matching enabledaction: "modify"policies — the contributors — in contributor order (below). Apply theirmodificationsand collect their launch profiles (profiles) andcapabilities. Amodifypolicy contributes to this merge only; it never authorizes the app (see below). - Apply User Configuration (Windows only).
- If a Launch Profile is selected, apply its modifications last on top of the merged result.
Contributor order. Allow and modify rules are interleaved, not grouped: sort every contributor by priority ascending, and order equal priorities by id descending (ordinal, case-insensitive). Each contributor's modifications are layered over the previous one's, so the rule applied last wins a conflict — the highest priority, and among equals the smallest id. That is the same rule that picks the deciding allow (highest priority, then smallest id), so the deciding rule always has the last word over its peers. Identical on the Windows client, the macOS daemon and the macOS launcher.
User Configuration is a Windows-only scope; the macOS readers have no per-user file.
Merge Strategies by Data Type
| Element | Merge Strategy | Conflict Resolution |
|---|---|---|
| Mounts | Additive | id (or destination when id is missing) last-wins by scope; policy ties follow contributor order. |
| Arguments | Concatenation | replace overrides; otherwise prepend/append follow scope order. |
| Keyed flags | Last-wins | Scope precedence; policy ties follow contributor order. Windows only. |
| Switch flags | De-duplication | Deduplicate by exact string; ordered by scope. Windows only. |
| Networking | Mixed | Rules are additive; arrays replace; booleans last-wins; ports replace per scope. |
| File routing | Additive | Highest rule priority, then rule id; default: true within a rule wins first. |
Inside the Policy scope the consistent tie-break is contributor order: higher priority wins, and among equal priorities the smallest id wins. priority defaults to 500 when omitted.
Security and Authorization (Deny vs Allow)
Security rule: Deny overrides allow
During authorization, if any matching enabled policy hasaction: "deny", the launch is blocked and the app is treated as unauthorized, regardless of how manyaction: "allow"policies match.
Authorization evaluation occurs before visibility, modifications, capabilities, and routing resolution.
- Collect all enabled application policies that match the discovered executable. Matching evaluates
matchNonefirst (any hit vetoes the rule), thenmatchAll(AND),matchAny(OR), or thetargetPathshorthand. A rule with no positive form matches nothing. - If any matching policy has
action: "deny", authorization is denied — at every site, whatever the deny'svisibilityConstraintssay. The app is not visible and cannot be used by routing. - Otherwise, if any matching policy has
action: "allow", the app is authorized. The deciding allow is the matching allow with the highestpriority, ties broken by the smallestid. Modifications and launch profile merges proceed among the matching allow and modify policies in contributor order; a higher-prioritymodifyoverrides a lower one and the allow, but the deciding allow remains the rule the launch is attributed to, and itsvisibilityis the one applied. - If no allow policies match, the app is not authorized — even if one or more
action: "modify"policies match.modifycannot grant access; it only enriches a launch some allow policy has already permitted.
Site scoping
visibilityConstraints.siteRefs scopes allow and modify rules to the selected site: an allow or modify rule whose siteRefs does not include the selected site is not a contributor and does not authorize or enrich the app there. A deny is never scoped by siteRefs — it applies at every site. Sites exist on the Windows client and the macOS launcher; the macOS daemon has no site concept and accepts-ignores siteRefs.
Visibility is then decided by the deciding allow:
- Authorization (allow/deny) must pass first.
- The deciding allow's
visibilityapplies;"hidden"hides the app whatever other matching rules say. - When Sites are active and no site is selected, site-scoped rules are ineligible until one is (secure by default).
Site scoping does not affect file association routing — a hidden app can still serve as a handler.
Runtime settings and VM flags
Raw flags (turboFlags, configuration.launch.flags) are a deprecated Windows-only channel; the macOS readers accept and ignore them. Prefer the structured keys.
Flag key normalization
- A flag’s key is the portion after leading dashes up to the first "=" or whitespace.
--clipboard-size=1000→ keyclipboard-size--remote-sandbox→ keyremote-sandbox
Rules
- Keyed flags: Last-wins per key by scope precedence (Launch Profile > Policy > Global). Within the Policy scope, contributor order applies (highest
prioritywins, then smallestid). - Unkeyed flags (pure switches): De-duplicate by exact string; final order is Profile → Policies (in contributor order) → Global.
Example (flags)
- Global:
--clipboard-size=1000 - Policy A (priority 200):
--clipboard-size=500 - Profile: none
- Result:
--clipboard-size=500(Policy overrides Global). If the Launch Profile sets--clipboard-size=200, it wins.
For authoring runtime settings and examples, see: Schema Reference
Arguments
Fields
prepend: Insert before base shortcut arguments.append: Insert after base shortcut arguments.replace: Replace the entire argument string.
Rules
replaceoverrides bothprependandappendwithin the same scope.- Overall scope precedence is Launch Profile > Policy > Global.
- When no
replaceexists at any scope:- Prepend order: Global.prepend → Policies.prepend (in contributor order) → Launch Profile.prepend → base shortcut args
- Append order: base shortcut args → Global.append → Policies.append (in contributor order) → Launch Profile.append
arguments is applied by the Windows client; the macOS readers accept and ignore it.
Example (args concatenation, no replace)
- Global.append:
--enable=sandboxnetwork - Policy A.append:
--incognito - Launch Profile.append:
--hide-crash-restore-bubble - Result: [base]
--enable=sandboxnetwork --incognito --hide-crash-restore-bubble
For authoring arguments and examples, see: Application Arguments
Mounts precedence and merging
When mounts are defined at multiple scopes, final mounts are produced by deterministic precedence and merging:
- Scope precedence (most specific wins): Launch Profile > User Configuration (Windows) > Policy (App) > Global
- Additive merge: Mounts are additive across scopes.
- Conflict resolution:
- Identity is the mount's
id; whenidis absent,destinationis the identity. Conflicts on the same identity resolve last-wins by scope precedence (Launch Profile overrides Policy overrides Global). - Within the Policy scope, ties follow contributor order, consistent with flags/args.
- Identity is the mount's
- Shape:
{ id?, source, destination, access: readOnly | readWrite, createIfMissing?, siteRefs? }on both platforms;accessdefaults toreadWrite. The macOS daemon serves mounts natively; the Windows client maps them onto its--mountflag.
Visual merge & conflict resolution (mounts)
The following diagram summarizes how mounts are merged across scopes and how conflicts are resolved:
See authoring details and examples: Mounts & Shared Storage
Networking precedence and proxy routing selection
One proxyRouting shape, applied per platform: the macOS daemon enforces capabilities and evaluates each rule's destination match per connection; the Windows client selects a proxy per site from siteRefs and treats direct and deny as "no proxy" (it has no per-connection enforcement). See Networking.
Scope precedence (most specific wins)
- Launch Profile > Policy (App) > Global.
Capabilities merging
- Booleans (outboundAllowed, inboundAllowed, dnsAllowed): last-wins by scope.
- Arrays (protocols, dnsServers, dnsSearchSuffixes): last-wins replacement by scope for determinism.
- Ports (allow/deny):
- Within a scope: deny overrides allow at evaluation time.
- Across scopes: last-wins replacement of the entire ports object (Policy or Launch Profile can replace Global).
egressDefaultAction: last-wins by scope.
Proxy catalog (proxies[])
- Defined only at Global scope:
configuration.network.proxies. - App/profile scopes reference proxies by
proxyRef; they cannot define proxies.
Proxy routing rules
- Rules are additive across scopes (Global + Policy + Launch Profile).
- For each connection (macOS daemon):
- Filter to enabled rules whose destination
matchpasses (cidrs,ipRanges,hosts, optional ports/protocol). A rule withoutmatchmatches every destination. - Choose the rule with highest
priority(descending); ties break by ruleid(alphabetical).prioritydefaults to 500. - Apply action:
proxy: route viaproxyRef. If the proxy endpoint is unreachable the connection fails unless the rule names afailover(directordeny);proxyCandidateslists the only alternates health may pick.direct: connect without proxy.deny: block the connection (short-circuits).
- Filter to enabled rules whose destination
- Per site (Windows client): among enabled rules whose
siteRefsinclude the selected site (or have none), the highest-priorityproxyrule'sproxyRefis the proxy for every launch at that site;directanddenymean no proxy.
See authoring details:
- Networking structure and examples: Networking
- Destination matching patterns: Matchers & Patterns
Launch Profiles
Combining launch profiles
- Launch profiles from all contributors (matching allow and modify policies) are collected.
- Conflicts by profile
id(compared ordinal, case-insensitive) resolve to the profile from the highest-prioritycontributor; ties break by contributoridascending. Identical on every reader. - Launch profile modifications apply after all base modifications have been merged.
UI behavior
- The context menu shows Run (base), then one item per launch profile (
displayName), followed by diagnostic/reset entries.
See full launch profile details and examples: Launch Profiles
Routing selection and tie-breaks
Terminology
- fileTypes: central registry that determines what a file “is” (e.g., pdf, word-docs).
- fileAssociations: central UX that defines which handlers exist per verb (preview/open/edit/print), which are default, and which appear in Open With.
- apps[].capabilities: per-app declarations of supported fileTypes and verbs with invocation details; capabilities do not determine UI by themselves.
Resolution pipeline (per file and verb)
- Determine fileType:
- Match the file against
fileTypes[].match. If multiple match, prefer a more specific match when determinable (for example, a single-extension type over a broader multi-extension type that also includes the same extension); otherwise tie-break by fileType id alphabetical. - Extension matching is case-insensitive.
- Match the file against
- Collect routing rules:
- Gather enabled
fileAssociationsrules wherefileTypeRefequals the chosen fileType id.
- Gather enabled
- Aggregate handlers for the requested verb from those routing rules.
- Choose default handler:
- Any handler with
default: true. - Else highest routing rule
priority(descending). - Else stable alphabetical tie-break by routing rule
id(fallback to ruledisplayNamewhen id is missing).
- Any handler with
- Open With:
- All handlers where
showInOpenWith: true.
- All handlers where
- Security gating:
- Handlers referencing apps via
appRefortargetPathrequire an enabledaction: "allow"app policy that matches the executable; otherwise the handler is ignored.
- Handlers referencing apps via
- The Print action is available only when at least one routing rule provides
verbs.printfor the selected fileType. - If none provide
verbs.print, Print is not offered.
Tie-break ordering within Policy scope
When multiple enabled allow and modify policies match the same executable:
- The deciding allow is the allow with the highest
priority; ties go to the smallestid(ordinal, case-insensitive). - Modifications are layered in contributor order — ascending
priority, equal priorities byiddescending — so the rule that would win selection is applied last and wins conflicts. - Launch profile conflicts go to the highest-priority contributor, ties by
idascending. prioritydefaults to 500 on every reader when omitted.
Tie-breaks for file policies and routing rules
- File policies (list/import/export/open/delete): Conflicts within the active policy resolve by rule
priority(descending), then ruleidalphabetical (fallback to displayName when id is missing). - File association rules: Primary selection uses explicit
default: truewithin a rule and then rulepriority. When a tie-break is needed across rules, use ruleidalphabetical (fallback to displayName when id is missing).
Print routing and device-level printer settings
UI vs device responsibilities
- UI-level (routing): Print handlers defined in
fileAssociations.verbs.printresolve like other verbs. Selection order is rulepriority(descending), then ruleidalphabetical; within a rule,default: truewins, else array order. If no applicable rule providesverbs.print, the Print action is not offered for those files. - Device-level (runtime): Printer availability inside applications is enforced by the runtime using environment-specific configuration carried as opaque strings via flags. These settings do not change routing selection; they control whether printers are available during app execution.
Precedence for device-level settings carried via runtime settings
- Scope precedence: Launch Profile > Policy > Global
- Runtime behavior: Scalars are last-wins by scope; arrays use last-wins replacement. See: Schema Reference
Security gating for routing
Routing entries reference applications by appRef or targetPath. A referenced app must be authorized:
- There must be at least one enabled application policy with
action: "allow"that matches the executable (including high-assurance matchers if present). - Otherwise that routing entry is ignored.
For routing semantics and examples, see: File Types & Routing
Troubleshooting precedence
- “Flag didn’t take effect”: Check for a more specific scope overriding it (Profile usually wins). For keyed flags, verify the final key value.
- “Arguments missing”: Look for
replaceat any scope; it overrides prepend/append. If none, verify the scope concatenation order. - “Wrong launch profile won”: Ensure unique launch profile
id, or adjust policypriority/idto control tie-breaks. - “Unexpected file handler”: Confirm the chosen fileType, then inspect routing rule priority,
default: true, and rule ids; also ensure security gating did not filter out another candidate.
Templates and precedence
Configuration templates and user configurations are Windows-only; the macOS readers accept and ignore configurationTemplates.
- Active Policy: Templates are defined and enforced inside the Active Policy. See: Deployment and Policy sources and delivery.
- Authorization: The presence of templates does not bypass authorization. An app must still be discoverable and allowed by at least one enabled app policy with
action: "allow". Templates constrain user-provided inputs (environment variables and mounts). - Merge interactions: Templates do not contribute runtime settings or arguments directly. Standard merges for runtime/arguments remain unchanged (Launch Profile > User Configuration > Policy > Global).
- App linkage: Apps opt into templates via
apps[].configurationTemplates. Multiple apps can reference the same template to share a constrained configuration surface. - Validation timing: Environment variables referenced inside patterns are resolved at validation time. Mount constraints in templates are applied to user configurations at validation time.
Next steps
- Modifications & Flags: Modifications & Flags
- Launch Profiles: Launch Profiles
- File Types & Routing: File Types & Routing
- Testing & Validation: Testing & Validation
