Tutorials
Tutorial: check a macOS workstation
A guided health and posture check of a Mac with Secronyx, covering hardware and battery, launchd and login items, FileVault, SIP, Gatekeeper and XProtect, Time Machine, extensions and sharing, plus the macOS-specific latency traps.
This walkthrough checks a macOS workstation end to end with Secronyx: is the hardware healthy, what runs at login, is the security posture what the fleet policy says it should be, and are backups actually happening. It is written for the case where a person hands you their Mac, or where you are checking a managed fleet member without an MDM agent's opinion in the way.
Everything runs locally over stdio. A workstation rarely wants an HTTP listener; the default transport is stdio and the default HTTP listen address is 127.0.0.1:8080, and the server refuses to start on a non-loopback address without authentication or TLS unless you pass --allow-unauthenticated. Leave that alone on a laptop.
For quick checks, --query is enough:
secronyx --query get_os_info --jsonFor anything with arguments, or for driving this from an AI client, use tools/call as described in the JSON-RPC API and wired up in Connect an AI client.
A naming trap, first
get_mac_status is not a macOS tool. It is registered under the sensitive scope and reports Mandatory Access Control status — SELinux and AppArmor on Linux. Most macOS-specific tools are prefixed get_macos_, but not all of them — get_homebrew_casks and get_podfile_lock are macOS-only too. Getting this wrong wastes a surprising amount of time, so check tools/list rather than guessing from a name.
Step 1: identify the machine
secronyx --query get_os_info --json
secronyx --query get_system_profile --jsonget_os_info (scope triage) returns types.OSInfoResult:
{
"name": "macOS",
"version": "15.3",
"build": "24D60",
"codename": "Sequoia",
"kernel_version": "24.3.0",
"kernel_arch": "arm64",
"platform": "darwin",
"platform_family": "darwin",
"platform_version": "15.3",
"hostname": "mbp-jrivera",
"timestamp": "2026-09-17T10:02:11Z"
}get_system_profile (also triage) wraps that with summaries rather than raw counters: an os object of the same shape, plus cpu (model, cores, logical_cores, usage_percent, frequency_mhz), memory (total_gb, used_gb, available_gb, usage_percent, swap_total_gb, swap_used_gb), disk and network. It is the right single call when you want one screenful before deciding what to dig into.
Step 2: hardware health
Battery health is the most common workstation complaint that has a measurable answer:
secronyx --query get_battery_health --jsonget_battery_health is scope hardware and returns types.BatteryHealthResult:
{
"batteries": [
{ "name": "InternalBattery",
"manufacturer": "SMP",
"technology": "Li-ion",
"cycle_count": 892,
"design_capacity": 8694,
"full_charge_capacity": 6981,
"capacity_unit": "mAh",
"health_percent": 80.3,
"charge_percent": 64.0 }
],
"count": 1,
"timestamp": "2026-09-17T10:02:24Z"
}health_percent is full_charge_capacity / design_capacity * 100, and capacity_unit tells you what the capacities are counted in — the macOS collector always reports mAh, the Windows one mWh, so check the field before comparing raw numbers across platforms. On macOS name is always InternalBattery and technology always Li-ion; neither is read from the hardware. A cycle_count near 1000 with health_percent in the low eighties is a battery at the end of its service life, which is a procurement answer, not a support one.
Storage, plus a thermal check that will disappoint you:
secronyx --query get_temperature --json
secronyx --query get_disk_info --json
secronyx --query get_macos_apfs_info --jsonget_temperature (scope core) returns sensors with name, temperature and optionally high and critical — but on macOS the collector is a stub that always returns an empty sensors array, because reading the SMC needs privileged IOKit access it does not have. That is a supported-but-unavailable result rather than a failure: collectors on platforms that cannot answer return empty results, not errors, by design. Do not plan a thermal investigation around this tool on a Mac.
get_macos_apfs_info (scope state) returns the real storage layout, which get_disk_info's mountpoint view hides: containers, each with reference, capacity_bytes, used_bytes, physical_stores and volumes. Each volume carries device, name, role, mount_point, encrypted and capacity_consumed_bytes. The encrypted flag per volume is the thing to read — a Mac with FileVault "on" still has unencrypted volumes in some configurations, and this is where you see it.
Step 3: what actually runs on this machine
secronyx --query get_macos_launchd_jobs --json
secronyx --query get_macos_login_items --json
secronyx --query get_macos_dock_apps --jsonAll three are scope state.
get_macos_launchd_jobs returns types.MacXLaunchdJobsResult: jobs (each label, pid, status, running, third_party), plus total, apple_count, third_party_count and truncated. The third_party flag is set when the label does not start with com.apple., which is a crude but effective filter — sort by it and you have the list of everything not shipped by Apple that is running on this machine. A status other than 0 on a job with running: false is a job that failed its last start.
get_macos_login_items returns items with name, path, source and third_party. source is the discriminator you want: launch_agents_system, launch_daemons, launch_agents_user or system_events. Something in launch_daemons runs as root before anyone logs in; something in system_events is a user's own login item. Treating those as the same category is how unexplained background CPU on a "clean" machine goes unnoticed.
If the complaint is "it is slow", the cross-platform tools from Tutorial: diagnose a slow Linux host apply here too — get_processes_sampled with sample_duration_ms, get_memory_info, get_thread_summary. get_pressure_stall_info is Linux-only and will report "supported": false; get_vmstat_summary does work on macOS.
Step 4: security posture
These four tools are the posture check, and all are scope security:
secronyx --query get_macos_filevault_status --json
secronyx --query get_macos_sip_status --json
secronyx --query get_macos_gatekeeper_status --json
secronyx --query get_macos_xprotect_status --jsontypes.MacOSFileVaultStatus:
{
"enabled": true,
"status": "On",
"encryption_percent": 100,
"encryption_type": "AES-XTS",
"has_recovery_key": true,
"has_institutional_key": false,
"deferred_enablement": false,
"users": ["jrivera"],
"timestamp": "2026-09-17T10:03:02Z"
}status is one of On, Off, Encrypting or Decrypting; a machine mid-Encrypting with encryption_percent below 100 is not yet protected, and deferred_enablement true means FileVault is armed but waiting for the user's next login — which reads as "compliant" on a lot of dashboards and is not.
types.MacOSSIPStatus returns enabled, status and configuration_flags. The flags array is what matters on a developer machine: SIP can be partially disabled, and enabled: false with a list of specific disabled protections is a different risk from a wholesale csrutil disable.
types.MacOSGatekeeperStatus returns enabled, assessment_enabled, developer_id_enabled, notarization_required and status, where status is the policy in words — App Store, App Store and identified developers, or Anywhere.
types.MacOSXProtectStatus returns xprotect_version, xprotect_bundle_version, mrt_version, gatekeeper_config_data and last_update. A last_update weeks old on a machine that is otherwise online means the update mechanism is broken, which is worth more attention than the version number itself.
Every one of these types carries an error field. If a value looks wrong, check whether error is set before you act on it — a permissions failure and a genuinely-off control look identical if you only read enabled.
Three more in the same scope round out the picture:
secronyx --query get_macos_mdm_profiles --json
secronyx --query get_macos_pf_rules --json
secronyx --query get_macos_security_log_events --jsonget_macos_pf_rules returns enabled, status, rule_count, rules and anchors — on macOS the packet filter is usually off and the application firewall is doing the work, so enabled: false here is not by itself a finding.
get_macos_tcc_permissions is the exception: it is registered under the sensitive scope, so it is absent unless the server was started with --enable-sensitive. That is deliberate — a TCC dump says which applications hold camera, microphone, screen recording and full-disk access, which is exactly the inventory an attacker would want. Tools outside the active scope policy are never registered, so without --enable-sensitive a tools/call for it returns code -32602, message Tool not found, with the tool name as data. The -32003 Forbidden error, whose data reads tool "get_macos_tcc_permissions" requires scope "sensitive", is the other case: the tool is registered, but the calling credential's own granted scopes exclude sensitive. See Scopes and authorization and the Security model for why that default exists.
Step 5: is it patched, and is it backed up
secronyx --query get_macos_software_update_config --json
secronyx --query get_macos_timemachine_status --jsonBoth are scope state.
types.MacXSoftwareUpdateConfigResult returns config_found, automatic_check_enabled, automatic_download, automatically_install_macos_updates, config_data_install, critical_update_install, last_successful_date and a raw_settings map of whatever else was in the preference domain. config_found: false means the preference file was not readable and every boolean below it is a default, not a reading — check that flag first.
types.MacXTimeMachineStatusResult returns configured, auto_backup, auto_backup_known and destinations (each name, kind of Local or Network, mount_point, url, id):
{
"configured": true,
"auto_backup": false,
"auto_backup_known": true,
"destinations": [
{ "name": "TimeCapsule", "kind": "Network",
"url": "afp://mbp-jrivera@timecapsule.local/Backups",
"id": "B2A1F0C4-9D3E-4B77-9C21-4E9A0D1F2B33" }
],
"timestamp": "2026-09-17T10:03:31Z"
}auto_backup_known exists because reading the setting can fail, and a false auto_backup with auto_backup_known: false means "we could not tell", not "backups are off". Reporting the first as the second is the classic false positive in fleet compliance checks.
get_macos_spotlight_status returns per-volume indexing_enabled with a raw_status string. A volume mid-reindex is a common explanation for sustained mds_stores CPU after an update.
Step 6: extensions, sharing and network services
secronyx --query get_macos_kernel_extensions --json
secronyx --query get_macos_system_extensions --json
secronyx --query get_macos_sharing_status --json
secronyx --query get_macos_network_services --jsonget_macos_kernel_extensions returns extensions (each bundle_id, version, non_apple), total, non_apple_count, truncated and source, where source is kmutil or kextstat. Modern macOS should have very few non-Apple kexts; a high non_apple_count is either legacy security software or something that should not be there.
get_macos_system_extensions is the modern replacement and returns richer entries: category, enabled, active, team_id, bundle_id, version, name and state. team_id is the field to check against your approved-vendor list — bundle identifiers can be chosen freely, team identifiers cannot.
get_macos_sharing_status is three booleans that answer a question people get wrong constantly: remote_login_enabled (sshd), screen_sharing_enabled and file_sharing_enabled. On a laptop that leaves the office, all three should normally be false.
get_macos_network_services returns services with name, enabled, order, hardware_port and device. order is the service order, which is what decides which interface wins when a machine is on Wi-Fi and a VPN and a dock's Ethernet simultaneously — the answer to a large fraction of "DNS is weird on my Mac" tickets.
get_macos_power_settings (scope state) returns sources, one per power source (AC Power, Battery Power, Currently in use), each with sleep, display_sleep, disk_sleep, hibernate_mode, power_nap and a settings map. A machine that never completes its overnight backup usually has sleep set aggressively on battery.
Step 7: the macOS latency trap
Several triage tools shell out to log show, which on macOS can take a very long time. The tool descriptions say so explicitly, and they are not exaggerating:
get_recent_kernel_eventsandget_recent_critical_eventscarryWARNING: High latency on macOS (1+ minutes, uses log show).get_recent_reboots,get_recent_service_failures,get_recent_resource_incidents,get_recent_config_changesandget_service_log_viewcarryNote: May be slow on macOS (uses log show).
If you are driving these from an AI client, expect a client-side timeout before the tool returns. Constrain them hard — all the get_recent_* tools take a limit, and get_service_log_view takes service (required) and lines — and prefer the state-scope macOS tools above for anything you can answer without touching the unified log.
Step 8: what you can hand back
secronyx --query get_macos_applications --jsonget_macos_applications is scope software and gives the installed application inventory, which together with the posture calls above is enough for a written machine report. For a single structured artefact, generate_system_report (scope report) collects in parallel; its section names are os, hardware, uptime, cpu, memory, gpu, processes, disks, network, listening_ports, dns, routes, arp, startup_items, programs and runtimes, with timeout_seconds defaulting to 30.
Audit logging is on by default, but it records tool calls that arrive through the MCP server — the --query shortcuts used above bypass the server and write no audit events. On macOS the default audit path /var/log/secronyx/audit.jsonl is usually not writable by a normal user account, in which case the audit provider falls back to stderr rather than failing the call — set --audit-output to somewhere under the user's own directory if you want the file. Audit logging has the details.
Where to go next
- Tool reference for every
get_macos_*tool and its arguments. - Connect an AI client to run this conversationally rather than by hand.
- Redaction for what is stripped from command lines and log messages before you ever see them.
- Compliance mapping if these posture checks need to line up with a control framework.
- Documentation home.
Built 2026-09-19. Source: levantar-ai/secronyx. Found a mistake? Tell us.