vibe coded with ❤️
Rune · MDM

Thing

Profile Fragments, Merged on Device

Let each policy request be its own small configuration profile, and have the client merge whatever MDM delivers into one effective configuration.

Problem

macOS does not merge two configuration profiles that target the same preference domain. If two profiles set the same key, one of them wins, and which one is undefined. Real organisations layer policy ("department A may only use server X; some of A may also use server Y"). With a single domain, admins must build one combined profile per population (A, A+B, …), and that number grows combinatorially.

Context & forces

  • MDM scoping (smart groups, assignments) is the admin's natural tool for deciding who gets what.
  • Admins want to add, change and remove one rule without touching the others.
  • The target software often accepts only one policy (one file, one domain).
  • A broken or half-delivered profile must never loosen security.

Solution

Give every request its own preference domain under a shared prefix, e.g. <app>.policy.<name> or <app>.wf.<name>. Because the domains differ, macOS never has to merge anything: every fragment arrives intact. The client reads all domains with the prefix and merges them itself, by documented rules.

 MDM scoping            Mac: /Library/Managed Preferences          Client
 ┌────────────┐        ┌──────────────────────────────┐       ┌───────────────┐
 │ baseline   │──────▶ │ app.policy.baseline          │──┐    │ merge by      │
 │ dept A     │──────▶ │ app.policy.deptA             │──┼──▶ │ priority +    │──▶ one effective
 │ vendor B   │──────▶ │ app.policy.vendor-b          │──┘    │ per-key rules │    configuration
 └────────────┘        └──────────────────────────────┘       └───────────────┘

Merge rules (most restrictive wins)

A plain "highest priority wins" is not enough for security settings. Thing uses per-key rules:

  • Objects merge key by key; scalars come from the highest-priority fragment.
  • Grant lists (servers, permissions a fragment provides) are combined, so access can be added by a separate fragment.
  • Restriction lists (the only models allowed) are intersected; disjoint lists mean "nothing allowed", with a warning.
  • Locks are on if any fragment sets them; kill switches off if any fragment says so; limits take the minimum or maximum.
  • Ordered enums (e.g. sandbox modes) take the strictest value.
  • Deny wins: denies remove entries after merging, whatever the priorities.

Restrictive rules apply independently of priority: a high-priority fragment can grant more, but it cannot quietly undo another fragment's restriction.

For developers

  • Discovery: enumerate root-owned regular files with the prefix in the managed-preferences folder (device channel only). Each fragment carries an ID, priority, description and an enabled flag; complex content may also arrive as a JSON string for MDM text fields.
  • Ordering: priority descending, ties broken by ID, so the result is deterministic.
  • Rules are data (per key path, with wildcards), not code paths, so new settings need no release.
  • Rendering is deterministic (sorted keys): the same fragments always produce the same bytes, which makes change detection a hash comparison.
  • Fail-safe: if any fragment cannot be parsed, keep the last applied state. The broken one might carry a deny, so applying "the rest" could loosen policy.
  • Re-merge on profile-list changes and file-system events, coalesced.

Consequences

  • One small profile per request; MDM scoping does the population logic.
  • Removing a profile removes exactly its contribution.
  • Admins must understand the merge rules, so the client should report the effective result and where each value came from (see Völva).
  • Rules are per key; dependencies between keys are not cross-checked automatically.
  • The client becomes policy-critical: it needs strong failure behaviour and reporting.

Known uses

  • Mimir merges com.spectrechen.mimir.policy.* fragments into one native policy file per AI agent harness. It applies the full rule set above, with the rules coming from a signed vendor catalog.
  • Ratatoskr holds one workflow per domain (com.spectrechen.Ratatoskr.wf.<name>) next to a main domain. Workflows are combined rather than conflict-resolved, so admins can deploy, scope and remove them one at a time.

Name

The Thing was the Norse assembly where many voices met and one law came out of it, much as many fragments become one policy.