Skip to main content

launchd-audit

MCP server for macOS that lists launchd jobs, cron entries, and brew services in plain English, flags the ones that are failing or stale, and can act on them without rm or sudo.

Ask an agent: what's running in the background on this Mac, and is anything broken?

totals: {"jobs": 31, "running": 8, "disabled": 0, "failing": 1, "stale": 1}
[failing] com.example.drift-check | exit=1
[stale]   com.example.backup      | daily at 03:00, no evidence for 41 days

macOS only. Python 3.11+. MIT.

Why

A machine that has been alive for a while accumulates agents from apps you uninstalled, cron lines from a test, brew services that log megabytes a day. launchctl list is a wall of PIDs. Plists are XML. Answering "is anything wrong?" means reading a dozen files by hand.

Four of the five tools are read-only. Mutation is one tool, dry-run by default. Design notes live in PHILOSOPHY.md. Tool contracts live in SPEC.md.

Tools

Tool Role
job_health The audit. Failing, stale, or writing huge logs, with totals and reasons. Start here.
list_scheduled_jobs Every launchd job, cron entry, and brew service. Schedules as "every 15 minutes", "daily at 03:00", "keep alive (respawn)".
job_detail One job: plist (secrets masked), live launchctl state, log tails.
search_job_logs Regex search in that job's output files, optional since date.
job_action The only mutating tool. Dry-run unless confirm=true.

Sources scanned: ~/Library/LaunchAgents, /Library/LaunchAgents, /Library/LaunchDaemons, crontab -l plus /etc/cron.d and /etc/crontab. Brew services are recognised by their homebrew.mxcl.* plists in ~/Library/LaunchAgents; brew itself is never called. /System/Library is skipped on purpose.

Safety

Guardrails are in the server, not in a companion skill or prompt.

  • Dry-run by default. Without confirm=true, job_action only reports what it would run: commands, files, warnings, and an undo recipe.
  • System daemons are listable and never modified. Anything in /Library/LaunchDaemons is refused, whatever it is called.
  • Nothing is deleted. remove unloads the plist and moves it to Trash. Every applied action returns an undo recipe.
  • No sudo. A plist the current user cannot move is refused up front, not half-removed.
  • Secrets are masked at parse time. EnvironmentVariables values never leave the process. Secret-looking ProgramArguments (--token=…, API_KEY=…, --password …) are redacted too. Masking is a heuristic: a secret hidden in a plain positional argument or inside a script the job runs is not covered.
  • Every applied action is appended to ~/.launchd-audit/actions.jsonl.

Install

Requires macOS, Python 3.11+, and uv. No clone needed: uvx fetches and runs the server straight from GitHub.

Claude Code

claude mcp add launchd-audit -- uvx --from git+https://github.com/aka-kika/launchd-audit launchd-audit

Claude Desktop, Cursor, and other JSON-configured clients

{
  "mcpServers": {
    "launchd-audit": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/aka-kika/launchd-audit", "launchd-audit"]
    }
  }
}

Pin a release with git+https://github.com/aka-kika/launchd-audit@v0.3.0.

From a local checkout

git clone https://github.com/aka-kika/launchd-audit.git
cd launchd-audit
uv sync
uv run pytest -q
uv run python scripts/smoke.py   # spawns the server over stdio and calls the read-only tools

Then point the client at the checkout:

{
  "mcpServers": {
    "launchd-audit": {
      "command": "uv",
      "args": ["--directory", "/path/to/launchd-audit", "run", "launchd-audit"]
    }
  }
}

Use

Ask the client something like:

  • "What scheduled jobs are on this Mac?"
  • "Is anything quietly failing?"
  • "Did the backup run yesterday?"
  • "Preview disabling com.vendor.sync."

Worked conversations are in EXAMPLES.md.

Limitations

  • /System/Library launchd items are not scanned.
  • Full system/ domain runtime state needs root. Refused by design, so system daemon state shows as not-loaded and last_exit is unknown.
  • Stale detection uses log-file mtimes. Jobs with no declared output logs are not flagged stale.
  • last_exit in listings comes from launchctl list, which reports 0 for a job that has never run. job_detail uses launchctl print and reports null in that case.
  • Cron entries have no live state (macOS cron does not expose one). Only remove is supported for them.
  • Not Windows Task Scheduler. Not Linux systemd.

Docs

File Contents
PHILOSOPHY.md Why it exists
SPEC.md Inputs, outputs, safety rules
EXAMPLES.md Five example sessions
CHANGELOG.md Version history

License

MIT.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

launchd_audit-0.3.0.tar.gz (76.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

launchd_audit-0.3.0-py3-none-any.whl (22.0 kB view details)

Uploaded Python 3

File details

Details for the file launchd_audit-0.3.0.tar.gz.

File metadata

  • Download URL: launchd_audit-0.3.0.tar.gz
  • Upload date:
  • Size: 76.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for launchd_audit-0.3.0.tar.gz
Algorithm Hash digest
SHA256 4ed70d66e0b3e5b659efb5bbe98a1336b4da5ba6349270cbaa1402165880ea82
MD5 7b2e1961a9852f31b1e556d014efdbc1
BLAKE2b-256 1b8f47e2753c395beda2bfe606e03e62b48e2fbfb93d4fa52c09ec0c62c740c2

See more details on using hashes here.

Provenance

The following attestation bundles were made for launchd_audit-0.3.0.tar.gz:

Publisher: publish.yml on aka-kika/launchd-audit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file launchd_audit-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: launchd_audit-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 22.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for launchd_audit-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2cad168e1d81cb767a041529f445b72ef2e4f9e46860bee700446764a1cd6236
MD5 ee1daecff6af0627a691a6d253be8efa
BLAKE2b-256 b2217afdb6673ac1ec1dcac956c72542b4983c8dd12177197963156c53d2a492

See more details on using hashes here.

Provenance

The following attestation bundles were made for launchd_audit-0.3.0-py3-none-any.whl:

Publisher: publish.yml on aka-kika/launchd-audit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page