Agent preferences
The mngd agent has three layers of preferences. Each layer overrides the one before it: a user’s local choice, an org-wide policy pushed from the admin portal on every check-in, and a Configuration Profile pushed via MDM that locks fields the user can’t change.
How it works
Section titled “How it works”Local preferences (Settings window) ↓ overridden byOrg policy (managed-preferences API → /checkin response) ↓ overridden byMDM Configuration Profile (com.mngd.agent + com.mngd defaults domains)A field set via MDM wins over anything the org pushes, which wins over whatever the user picked locally. Locked fields appear in the Settings window with a “Managed by your admin” label and a disabled control — the agent never silently applies a policy without showing the user what’s in force.
The agent only reads org policy on a successful check-in. It re-applies MDM overrides immediately after, so a server push can’t accidentally unlock a managed field.
Quick start
Section titled “Quick start”For a new admin who wants to verify a single Mac is reporting back to the mngd dashboard.
Open Settings on the Mac
Section titled “Open Settings on the Mac”Click the mngd icon in the menu bar, then click the gear in the popover footer. Or right-click the icon and choose Preferences….
Set the update-check cadence
Section titled “Set the update-check cadence”In the General tab, pick a value from Check for updates. Daily is the default. Every 4 hours is a common production choice; Hourly is fine for testing.
Decide on auto-install
Section titled “Decide on auto-install”Leave Auto-install updates off until you’ve verified the device is appearing in the dashboard with its inventory populated. When you turn it on, the agent installs available updates on its next sync cycle without prompting the user.
You’re done. The first check-in lands within 60 seconds. The device shows up in Devices in the admin portal with installed apps and detected updates. Settings changes take effect on the next sync cycle (5 minutes by default) — there is no separate Save button.
What the agent does
Section titled “What the agent does”On startup and on every sync cycle (5 minutes by default), the agent:
- Loads local preferences saved by the Settings window.
- Reads any Configuration Profile keys macOS has bridged into the
com.mngd.agentandcom.mngddefaults domains. - Calls
/api/v1/agent/v1/checkin. If the response includes anagent-configblock, applies those fields to the in-memory copy. - Re-applies MDM overrides on top so a server push can’t clobber an admin-locked field.
- Reflects the merged result in the Settings window. Any field with an MDM override is disabled and labeled Managed by your admin.
What the agent does not do:
- The agent does not install updates unless Auto-install updates is on. Vulnerability scans and patch detection still run; nothing installs until the toggle is flipped, either by the user or by the org-wide policy.
- The agent does not phone home for preferences outside the regular check-in cycle. Click the sync icon in the popover header to force one.
- The agent does not push MDM-managed fields back to the server. If an admin has locked the Slack channel via Configuration Profile, the agent’s UI shows the locked value but refuses to overwrite it on the server side.
Auto-install is off by default. A fresh install on a Mac with no Configuration Profile and no org policy reports inventory and shows notifications. It does not patch anything until Auto-install updates is enabled — locally, by org policy, or by MDM.
Configuration
Section titled “Configuration”In the Settings window (per-user)
Section titled “In the Settings window (per-user)”Each Mac stores these in its own preferences. Most of these fields are also pushable org-wide via the managed-preferences API below and lockable via MDM.
| Field | Default | Notes |
|---|---|---|
| Check for updates | Daily | Hourly · Every 4 hours · Daily · Weekly · Manual only |
| Auto-install updates | Off | When on, installs detected updates on the next sync cycle |
| Auto-patch background apps | On | Only applies when Auto-install updates is on; updates apps that aren’t currently running so users aren’t interrupted |
| Scheduled updates | Off | Run installs only inside a recurring time-of-week window instead of as soon as updates land |
| Default schedule | unset | The recurring window — days of week, hour, minute |
| Notification frequency | Immediate | Immediate · Daily digest · Weekly digest · Critical only |
| Notification channels | Local | Any of Local · Slack · Microsoft Teams · Discord |
| Slack / Teams / Discord webhook URL | unset | Required when the matching channel is enabled |
| Show menu bar icon | On | |
| Show in Dock | On | Overridden by the MDM DisplayMode key |
| Hide apps without auto-update support | Off | Hides apps the agent can’t update from the Installed tab |
| Auto-update Installomator | On | Allow the agent to update its embedded Installomator script |
| Lock Installomator version | Off | When on, pin to a specific Installomator version |
| Notify your MDM after install | On | Pokes Jamf / Kandji / Addigy so its inventory updates without waiting |
| MDM notification target | Automatic | Automatic · Disabled · Jamf Pro only · Kandji only · Addigy only |
| Patch policy deadlines | Critical 7d · High 14d · Medium 30d · Low 90d | Per-severity deadlines and notification rules |
Via the API (org-wide or per-device)
Section titled “Via the API (org-wide or per-device)”Org-wide and per-device defaults are managed through the
managed-preferences API. There is no dedicated UI page in the admin
portal today — this is the canonical surface. Each preference is a
single key/value row scoped either to the entire org
(appliesTo: "ALL_DEVICES") or to a list of devices
(appliesTo: "SPECIFIC_DEVICES" with deviceIds).
Authentication is a Bearer token (PASETO v4 session token or an API
key starting with mngd_). The caller must have the org:manage
permission on the target org.
List the org’s current preferences
Section titled “List the org’s current preferences”curl https://api.mngd.app/api/v1/orgs/acme/managed-preferences \ -H "Authorization: Bearer $MNGD_API_KEY"Response:
{ "preferences": [ { "id": "8f20…", "key": "updateCheckFrequency", "value": "every_four_hours", "appliesTo": "ALL_DEVICES", "deviceIds": [], "note": "tightened for security review", "createdAt": "2026-04-22T10:11:12Z", "updatedAt": "2026-04-28T08:32:00Z" } ], "count": 1}Create or update a preference
Section titled “Create or update a preference”POST upserts by (org, key). There’s one POST per preference key
— the API doesn’t accept a single blob with many keys. Re-POSTing the
same key updates it in place.
curl -X POST https://api.mngd.app/api/v1/orgs/acme/managed-preferences \ -H "Authorization: Bearer $MNGD_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "key": "updateCheckFrequency", "value": "every_four_hours", "appliesTo": "ALL_DEVICES", "note": "tightened for security review" }'Scope a preference to specific devices
Section titled “Scope a preference to specific devices”curl -X POST https://api.mngd.app/api/v1/orgs/acme/managed-preferences \ -H "Authorization: Bearer $MNGD_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "key": "autoInstallUpdates", "value": "true", "appliesTo": "SPECIFIC_DEVICES", "deviceIds": [ "0a1b2c3d-4e5f-6789-abcd-ef0123456789", "11111111-2222-3333-4444-555555555555" ] }'A device receives a preference if either an ALL_DEVICES row matches
or a SPECIFIC_DEVICES row lists its UUID. If both apply, the
specific row wins.
Update the value of an existing preference
Section titled “Update the value of an existing preference”PUT to the preference’s ID. You don’t change the key after
creation; if you need to retire a key, DELETE it.
curl -X PUT https://api.mngd.app/api/v1/orgs/acme/managed-preferences/8f20… \ -H "Authorization: Bearer $MNGD_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "value": "daily", "note": "rolled back to daily after pilot" }'Remove a preference
Section titled “Remove a preference”curl -X DELETE https://api.mngd.app/api/v1/orgs/acme/managed-preferences/8f20… \ -H "Authorization: Bearer $MNGD_API_KEY"Values are always strings
Section titled “Values are always strings”The value column is text. The agent coerces them to the right type
on receipt. Use the formats below:
- Booleans as
"true"/"false"(or"1"/"0"). - Integers as decimal strings, e.g.
"240". - Arrays and objects as inline JSON, e.g.
"[{...}]"or'{"critical":0,"high":1,"medium":3,"low":5}'.
Pretty-printed for readability:
{ "key": "maintenanceWindows", "value": "[{\"day\":\"tue\",\"start\":\"02:00\",\"end\":\"04:00\"}]" }{ "key": "maxPostponesBySeverity", "value": "{\"critical\":0,\"high\":1,\"medium\":3,\"low\":5}" }Available preference keys
Section titled “Available preference keys”| Key | Value type | Description |
|---|---|---|
updateCheckFrequency | String | hourly, every_four_hours, daily, weekly, manual |
autoInstallUpdates | Boolean | Org-wide auto-install policy |
autoPatchIdleApps | Boolean | Update background apps only |
scheduledUpdatesEnabled | Boolean | Force scheduled-updates mode |
notificationSchedule | String | immediate, daily_digest, weekly_digest, critical_only |
slackWebhookURL / teamsWebhookURL / discordWebhookURL | String | Webhook URLs |
autoNotifyMDM | Boolean | Whether the agent pokes the local MDM after an install |
mdmNotificationPreference | String | automatic, disabled, jamf_only, kandji_only, addigy_only |
hideAppsWithoutAutoUpdate | Boolean | Hide unmanaged apps in the Installed tab |
installomatorVersionLocked | Boolean | Pin Installomator across the fleet |
installomatorLockedVersion | String | Specific Installomator version to pin |
syncIntervalMinutes | Integer | How often the agent calls /checkin. Clamped to a minimum of 1 (default 5) |
updateCheckIntervalMinutes | Integer | How often the agent runs Installomator-based update detection. Clamped to a minimum of 5 (default 60) |
maintenanceWindows | JSON array | Time windows when scheduled installs are allowed to fire |
maxPostponesBySeverity | JSON object | How many times a user can defer an install for a given severity (default {critical:0, high:1, medium:3, low:5}) |
criticalBypassSchedule | Boolean | When true, critical-severity installs ignore maintenanceWindows (default true) |
scheduledUpdateGracePeriod | Integer (minutes) | Soft countdown before a scheduled install runs (default 15) |
defaultBlockingPolicy | JSON object | What to do when an install’s destination app is running. {"mode":"defer"}, {"mode":"prompt"}, or {"mode":"force"} (default defer) |
Fields set on the patch policy, not via managed-preferences
Section titled “Fields set on the patch policy, not via managed-preferences”Two fields ride the same /checkin response but are stored in the
patch_policies table, not managed_preferences. Set them through
the patch-policy API instead:
| Field | Default | Description |
|---|---|---|
allowForceQuitAtDeadline | false | At a hard deadline, allow the agent to ask macOS to terminate the running app. Off by default |
nagIntervalHours | 4 | How often the user is re-nudged about a pending update. Clamped to 1–168 |
Via MDM (Configuration Profile)
Section titled “Via MDM (Configuration Profile)”Deploy a Configuration Profile to the com.mngd.agent domain
(preferred for new deployments) and com.mngd (legacy domain still
read for operational keys). Any key set here becomes the locked value
on every Mac that receives the profile. The
Jamf Pro deployment guide walks through
uploading a profile end-to-end; the keys themselves are the same on
Kandji, Addigy, and any other MDM that supports custom configuration
payloads.
<?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>EnrollmentToken</key> <string>mngd_K7X2-M9QR-4WPN</string> <key>ServerURL</key> <string>https://api.mngd.app</string> <key>OrgID</key> <string>acme</string>
<key>DisplayMode</key> <string>MenuBarOnly</string> <key>UpdateCheckFrequency</key> <string>every_four_hours</string> <key>AutoInstallUpdates</key> <true/>
<key>ForcedNotificationChannel</key> <string>#mngd-alerts</string> <key>ForcedQuietHoursStart</key> <integer>18</integer> <key>ForcedQuietHoursEnd</key> <integer>9</integer> <key>ForcedQuietOnWeekends</key> <true/> <key>ForcedMaxNudgesPerDay</key> <integer>3</integer></dict></plist>| Key | Domain | Type | Description |
|---|---|---|---|
EnrollmentToken | com.mngd.agent (fallback com.mngd) | String | Single-use token consumed on first launch to enroll the device silently. Issued under Settings → Enrollment in the admin portal. |
ServerURL | com.mngd.agent (fallback com.mngd) | String | Base URL for the mngd API. Defaults to https://api.mngd.app; override only for self-hosted deployments. |
OrgID | com.mngd.agent (fallback com.mngd) | String | Organization identifier. Required for silent enrollment. The legacy key OrganizationID is also read. |
DisplayMode | com.mngd | String | MenuBarOnly, DockOnly, or Both. Controls whether the agent shows up in the Dock, the menu bar, or both. |
UpdateCheckFrequency | com.mngd | String | Locks the update-check cadence. Same values as the local preference. |
AutoInstallUpdates | com.mngd | Boolean | Locks auto-install on or off across the org. |
ForcedNotificationChannel | com.mngd | String | Locks the Slack channel for nudge notifications. Settings UI shows Managed by your admin. |
ForcedQuietHoursStart | com.mngd | Integer (0–23) | Locks the start hour for quiet hours. Out-of-range values are ignored. |
ForcedQuietHoursEnd | com.mngd | Integer (0–23) | Locks the end hour for quiet hours. |
ForcedQuietOnWeekends | com.mngd | Boolean | Locks weekend-quiet behavior. |
ForcedMaxNudgesPerDay | com.mngd | Integer (1–10) | Locks the per-user nudge ceiling. Out-of-range values are ignored. |
CertificatePins | com.mngd | Array<String> | Override the SPKI hash list used for certificate pinning. Use only when the server cert rotates ahead of an agent release. |
PinnedDomains | com.mngd | Array<String> | Override which domains pinning applies to. |
What this looks like in the Activity Log
Section titled “What this looks like in the Activity Log”The activity feed lives at
GET /api/v1/orgs/{orgID}/activity, with optional filter params
device_udid, severity, before (RFC3339), and limit (max 100).
Each entry has the shape:
{ "id": "01HW…", "event_type": "device.enrolled", "title": "Device enrolled", "body": "MacBook Pro (14.7.1)", "severity": "info", "device_udid": "0A1B2C3D-…", "device_name": "Avery's MacBook Pro", "actor_id": null, "actor_name": null, "metadata": {}, "created_at": "2026-04-28T14:32:01Z"}Today the agent and server emit four event types that surface in the feed:
event_type | Title | Body |
|---|---|---|
device.enrolled | Device enrolled | <HardwareModel> (<OSVersion>) |
patch.cve_detected | <N> CVE(s) detected | <N> critical, <N> high |
patch.remediated | <AppName> patched | Updated to <Version> |
user.assigned | User assigned | Assigned to <email> |
There is no Activity Log entry today for a managed-preference push landing on a device, MDM overriding an org-pushed value, or a user changing a local setting in the agent’s Settings window. Those flows happen silently — to verify a config change reached a device, query the device directly:
ssh user@device "defaults read com.mngd.preferences"ssh user@device "defaults read com.mngd"A future release will emit a config.applied event so a managed-
preferences POST is auditable end-to-end through the activity feed.
This page will be updated when that ships.
Troubleshooting
Section titled “Troubleshooting”A setting is greyed out and shows “Managed by your admin”
Section titled “A setting is greyed out and shows “Managed by your admin””A Configuration Profile sets that key. Run
defaults read com.mngd.agent and defaults read com.mngd on the
Mac to see which keys are present, adjust the matching profile in
your MDM, and re-push it. The agent picks up the change on the next
sync cycle.
An org-policy change isn’t taking effect on a device
Section titled “An org-policy change isn’t taking effect on a device”The agent only reads org policy on a successful check-in. There is no Activity Log entry for managed-preference pushes today, so verify by inspecting the device directly:
- Click the sync icon in the popover header to force a check-in.
- On the device, run
defaults read com.mngd.preferencesand confirm the new value is present. - If the value isn’t there, list the org’s managed preferences with
GET /api/v1/orgs/{orgID}/managed-preferencesand confirm the row exists with the rightappliesTo/deviceIds. A row scoped toSPECIFIC_DEVICESonly reaches devices whose UUID is in the list. - If check-ins themselves are failing, the most common cause is certificate pinning blocking a rotated server certificate — see the troubleshooting guide for the recovery steps.
Auto-install is on but nothing installs
Section titled “Auto-install is on but nothing installs”Auto-install is one condition out of several. Most common reasons it doesn’t fire:
- A scheduled-update or maintenance window is gating the install. Verify the current time falls inside an allowed window, or turn off Scheduled updates to install on detection.
- The privileged background helper isn’t approved. On the Mac, open System Settings → General → Login Items & Extensions and turn on mngd. Without approval the agent refuses every install path.
- The device isn’t checking in. Click the sync icon in the popover header, then look in Devices → [Device] → Activity for the most recent check-in.
Settings changes don’t persist across launches
Section titled “Settings changes don’t persist across launches”The agent saves preferences to the user’s defaults under
com.mngd.preferences. Confirm the domain exists with
defaults read com.mngd.preferences. If it’s wiped on every login,
look for a profile-removal or device-management script that runs
defaults delete com.mngd.preferences and remove that step.
MDM is locking a field the user expects to control
Section titled “MDM is locking a field the user expects to control”This is by design. Anything in the com.mngd.agent or com.mngd
defaults domain wins over both the user’s UI choice and any org-wide
push. Remove the key from the Configuration Profile if the field
should be user-controlled.
Related
Section titled “Related”- Agent updates — how the agent self-updates and how to publish or pull a release.
- Notifications overview — channels, scheduling, and quiet hours.
- Jamf Pro deployment — end-to-end Configuration Profile delivery.
- Troubleshooting — install, enrollment, and check-in issues.