Iru deployment
Iru/Kandji deploys the same universal AgentKeeper PKG used by Jamf and Intune. The PKG reconciles seven local IDE/CLI surfaces; Cowork and MCP Gateway remain separate deployments.
Universal signed PKG · Custom App
Iru/Kandji deploys the same universal AgentKeeper PKG used by Jamf and Intune. The PKG reconciles seven local IDE/CLI surfaces; Cowork and MCP Gateway remain separate deployments.
Current package versions and checksums are published with the release artifacts. See Download artifacts.
Before deployment, subscribe to installer updates.
1. Create the AgentKeeper profile
Create the macOS Enterprise Installer token first. Select Iru / Kandji and use the same deployment ID in the token and profile. Copy the token when it appears. It is a secret and must not go in the readable profile, logs, screenshots, or support messages.
The token is reusable for Macs in this scoped deployment until it expires or is revoked. Keep it only in the restricted Kandji Library Item script. Rotate it immediately after exposure and revoke it when the deployment ends.
This deployment uses two artifacts: the computer-level com.agentkeeper.runtime
profile carries api_url, org_id, mdm_provider, and mdm_deployment_id,
and the Custom App's Post-Install Script carries the enrollment token over
standard input.
In Library > Add Library Item > Custom Profile, upload the following as
AgentKeeper.mobileconfig. Edit only the <string> value that follows each
key. The <key> names are fixed; renaming one removes that setting and leaves
the profile incomplete.
| Key (do not edit) | Value in the <string> below it |
|---|---|
api_url | Your AgentKeeper app origin |
org_id | Replace YOUR_AGENTKEEPER_ORG_ID with your AgentKeeper organization ID |
mdm_provider | Keep kandji |
mdm_deployment_id | Replace YOUR_AGENTKEEPER_DEPLOYMENT_ID with the deployment ID entered on the token |
The deployment ID in the profile must match the token. A placeholder left in place is a real value that does not match, and enrollment is rejected.
<?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>PayloadContent</key>
<array>
<dict>
<key>PayloadType</key>
<string>com.apple.ManagedClient.preferences</string>
<key>PayloadIdentifier</key>
<string>com.agentkeeper.runtime.preferences.kandji</string>
<key>PayloadUUID</key>
<string>2D7B26D5-FE8E-4BB4-A172-936F3F9235C5</string>
<key>PayloadVersion</key>
<integer>1</integer>
<key>PayloadEnabled</key>
<true/>
<key>PayloadContent</key>
<dict>
<key>com.agentkeeper.runtime</key>
<dict>
<key>Forced</key>
<array>
<dict>
<key>mcx_preference_settings</key>
<dict>
<key>api_url</key>
<string>https://agentkeeper.dev</string>
<key>org_id</key>
<string>YOUR_AGENTKEEPER_ORG_ID</string>
<key>mdm_provider</key>
<string>kandji</string>
<key>mdm_deployment_id</key>
<string>YOUR_AGENTKEEPER_DEPLOYMENT_ID</string>
</dict>
</dict>
</array>
</dict>
</dict>
</dict>
</array>
<key>PayloadDisplayName</key>
<string>AgentKeeper Runtime</string>
<key>PayloadIdentifier</key>
<string>com.agentkeeper.runtime.kandji</string>
<key>PayloadOrganization</key>
<string>AgentKeeper</string>
<key>PayloadScope</key>
<string>System</string>
<key>PayloadType</key>
<string>Configuration</string>
<key>PayloadUUID</key>
<string>8F0C81DF-86D2-40A9-AF4C-4A6A3CD21777</string>
<key>PayloadVersion</key>
<integer>1</integer>
</dict>
</plist>
Assign the profile before the app. An existing Kandji Assigned User can remain for inventory or device ownership; AgentKeeper neither requires nor reads it. Do not put the Assigned User value, a local account name, or a username variable in the AgentKeeper profile. This is a device-scoped deployment, and machine enrollment can complete at the login window. Confirm the profile is installed before assigning the Custom App:
#!/bin/bash
set -euo pipefail
PROFILE="/Library/Managed Preferences/com.agentkeeper.runtime.plist"
if [[ ! -f "$PROFILE" || -L "$PROFILE" ]]; then
echo "AgentKeeper profile is missing or invalid" >&2
exit 1
fi
for key in api_url org_id mdm_provider mdm_deployment_id; do
sudo /usr/bin/plutil -extract "$key" raw -o - "$PROFILE" 2>/dev/null \
| /usr/bin/grep -q '[^[:space:]]' || exit 1
done
if [[ "$(sudo /usr/bin/plutil -extract mdm_provider raw -o - "$PROFILE")" != "kandji" ]]; then
echo "AgentKeeper profile has the wrong MDM provider" >&2
exit 1
fi
if sudo /usr/bin/plutil -extract enrollment_token raw -o - "$PROFILE" >/dev/null 2>&1; then
echo "Remove enrollment_token from the AgentKeeper profile" >&2
exit 1
fi
echo "AgentKeeper device profile ready"
Sharing one Blueprint does not prove delivery order. Never add
enrollment_token to the profile.
2. Add the Custom App
- Verify the PKG against
checksums.txt, its Developer ID Installer signature, stapler, and Gatekeeper. - In the Library, add a Custom App.
- Under Installation, choose Installer Package and upload the PKG.
- Use Install once per device.
- Add this Post-Install Script, replacing the token placeholder:
#!/bin/bash
set -euo pipefail
set +x
AGENTKEEPER_ENROLLMENT_TOKEN='PASTE_ENTERPRISE_INSTALLER_TOKEN'
trap 'unset AGENTKEEPER_ENROLLMENT_TOKEN' EXIT
BIN="/Library/Application Support/AgentKeeper/bin/agentkeeper"
REMEDIATE="/Library/Application Support/AgentKeeper/helpers/agentkeeper-macos-remediate.sh"
if [[ "$(id -u)" -ne 0 || ! -x "$BIN" || ! -x "$REMEDIATE" ]]; then
echo "AgentKeeper PKG is not ready for enrollment" >&2
exit 1
fi
printf '%s' "$AGENTKEEPER_ENROLLMENT_TOKEN" | "$BIN" \
stage-managed-enrollment \
--token-stdin \
--program-data "/Library/Application Support/AgentKeeper" \
--install-dir "/Library/Application Support/AgentKeeper"
unset AGENTKEEPER_ENROLLMENT_TOKEN
"$REMEDIATE"
- Assign the Library Item to the target Blueprint or Assignment Map.
Record the AgentKeeper version and SHA-256 in the notes. Do not put the PKG in an Audit or Remediation Script, and do not build a fleet package from the source ZIP. The Custom App installs the package; its Post-Install Script stages the token over standard input and starts enrollment.
If you add Audit and Remediation scripts, keep them thin. Audit the package receipt, the LaunchDaemon, and the installed status helper. Remediate with the package-matched repair helper, after token staging. A remediation script that installs anything has become a second installer, and the two will drift.
3. Verify the deployment
pkgutil --pkg-info dev.agentkeeper.runtime
sudo launchctl print system/com.agentkeeper.runtime
sudo "/Library/Application Support/AgentKeeper/helpers/agentkeeper-macos-status.sh"
Status must show enrollment_state="enrolled",
managed_profile_state="ready", hook_matrix.config_json=true, and
credential_state="valid". Then restart one selected AI agent and confirm
one live Activity event in AgentKeeper.
Run that action in a session on the Mac itself, such as the Claude Code CLI or another selected local agent. The PKG reconciles local IDE and CLI hooks, so this check covers agent activity that executes on the Mac. A Claude session running in the cloud is outside its scope.
The universal PKG does not install Cowork, managed browser extensions, or MCP Gateway. Before reporting missing MCP or connector coverage, confirm Claude Desktop is signed in to the enterprise workspace that received those separate deployments, not a personal account.
The runtime enrolls the machine before login without a per-device user mapping.
After a regular non-root user signs in, it resolves the active console account
through macOS Directory Services and reconciles that account automatically. It
repeats this after a user switch and never scans /Users. Before sign-in,
targeting_mode="active_console_user" with no active_console_user and
maintenance_state="waiting_for_user" is expected.
An Audit Script may report package, LaunchDaemon, and status-helper state. A
Remediation Script may call the installed repair helper,
agentkeeper-macos-remediate.sh. Neither should download another installer or
rewrite customer hook files.
Troubleshooting
| Symptom | Fix |
|---|---|
| Custom App is installed, but no Workstation appears | Check enrollment_state and managed_profile_state. Correct missing or invalid profile metadata. If enrollment_state=managed_token_missing, rerun the Custom App so its Post-Install Script stages the token. The service checks changes each minute; network failures retry with backoff. |
| Enrolled before login, but no user hooks appear | Sign in with a regular account, then wait for the one-minute maintenance tick or run the installed remediation helper. Do not add a username to the profile. |
| Audit keeps reinstalling AgentKeeper | Remove installer logic from the script; keep installation in the Custom App. |
Kandji reruns a Custom App at the next agent check-in when its Post-Install Script fails. Do not replace the package with a separate installer script.
See Kandji's Custom Apps guide, Validate deployment, and Uninstall and rollback.