Pulsee: the watchdog for my Mac and my AI jobs

A background tool I built with Claude Code that runs 165 checks on my Mac and my AI jobs every minute, sends 1 alert per root cause with the fix in the text, and hands each problem to its own Claude agent. 125 ms of CPU per tick.

The Pulsee app icon: a white hexagon with an edelweiss inside it, between 2 red heartbeat lines, on a black square, with the name Pulsee under it

Pulsee watches my Mac and every job my AI setup runs on it. Scheduled jobs and their logs, local services, sign-ins that expire, API keys, network shares, disks, indexes and the freshness of my local databases. Every minute it runs the checks that are due. When something breaks, I get 1 alert, with the fix in the text. Then a Claude agent tries to fix it before I even read the alert.

Pulsee replaces no app. Before it, a failure stayed silent until a result was missing. I built it with Claude Code: version 1.0 shipped on 1st November 2026. It is Python with no dependencies, and it has no window: a dot in the menu bar, a page in NicAI CC and a command line. The name follows the -ee family of my tools.

The job names and alerts in the examples of this note are fictitious.

Why I built it

My Mac runs over 60 scheduled jobs and helpers for NicAI (see What is NicAI): email and chat syncs, indexes, backups and the helpers of my apps. Each one can fail quietly. A token expires, a share drops, a script hits a new error, and nothing says so.

While I wrote the spec, I got the proof twice. My work chat sync had failed every hour for 2.5 days, and nothing told me. In the same week, a search index lost 816 of about 1,100 transcripts in 1 night, because the indexer couldn't read the share and deleted what it no longer found. A file date didn't catch either: both files were written on time.

I set 3 goals, in this order:

  1. Signal. No failure stays silent, and no alert is noise. 1 alert per root cause, only when a state changes.
  2. Low load. A check never slows the Mac, never hangs, and can't leak.
  3. Fix with a brake. Nobody signs in for me, and nothing changes a device.

What Pulsee does

The tick

A LaunchAgent starts 1 tick every 60 seconds. The tick is a one-shot process: it runs the checks that are due on 16 threads, each with a timeout, records any change of state, and exits. There is no resident process to leak or hang. A crash costs 1 tick.

A check only reads. It reads a file, a log, a database or a web endpoint, and returns green, amber or red. Only the fix code changes anything, and only from a fixed list.

165 checks in 10 groups

Group Checks What
Agents 66 Every scheduled job: loaded, running, exit code, stale, new errors
Services 9 Local model server, browser bridge, Home Assistant, my local apps
Logins 8 Sign-ins and tokens that expire
Keys 9 API keys, once a day, on a free read endpoint
Storage 9 Network shares mounted, free space, the internal disk
Indexes 15 Search indexes, queues and a daily retrieval test
Comms 12 Work email and chat syncs: last sync, newest message
Stores 28 Knowledge stores: age of the newest content, sudden drops in rows
Home 8 Devices on my network, read from Home Assistant
Info 2 My Claude accounts and the checks file itself

Most of the agents are found by themselves: Pulsee reads my LaunchAgents folder. A new check is 1 JSON object in a config file, no code.

The checks that matter most read content, not file dates. A store check asks the database for its newest row. A drop check counts the rows and turns red when the count falls by half in 24 hours. The transcript wipe above would have been red at the first tick after it.

Alerts: 1 per root cause

  • To red: 1 alert, as a Mac notification. Critical checks also send a message to my phone, outside quiet hours.
  • While red: 1 reminder every 4 hours.
  • Back to green: 1 Mac notice, with how long it was red.
  • Blocked: a check whose dependency is red sends nothing. The cause's alert lists it: "Work sign-in ended. Blocked: CRM, email sync, chat sync".
  • Flapping: 4 changes in 1 hour turn the check amber and stop its alerts for 1 hour.

Every alert carries its fix. A sample:

Pulsee: com.example.nightly-export: exit 2, 3 new error lines
Fix: pulsee fix com.example.nightly-export --yes

A secret never leaves the process. Pulsee loads my API keys into memory and replaces each one with *** in everything it stores, logs, alerts or prints. A QA suite plants a fake key and checks that it appears nowhere.

The fix loop

Fixes come in 4 tiers: a restart Pulsee may run by itself, a fix on my click, a sign-in only I can do, and a script error for a coding agent. I turned the first tier off. Pulsee never changes anything by itself.

02 Nov 2026 Instead, each problem gets its own Claude agent. A check that stays red for 10 minutes, or amber for 6 hours, goes to 1 headless Claude Code session (Opus 5.5) in the repo of the job that failed, with 45 minutes at most. The agent finds the cause, fixes it under that repo's own rules, runs its tests and commits. Pulsee then reruns the check. I hear about it only when the next step is mine: a sign-in, a payment, a decision about my data.

The brakes: 2 agents at a time, 12 a day, 2 per check per day. No agent while Pulsee is paused, while the check is snoozed, or while I'm on a call. An agent never signs in, sends, deletes my data, changes a device or reads a secret.

On its first morning, the loop took 8 problems. 2 real examples:

  • A nightly update job timed out. The agent found that a font scan in 1 of my tools triggered a macOS privacy prompt under the LaunchAgent and waited for a click that never came. It changed the smoke tests. The next nightly run proves the fix, and only then does the check close.
  • A slide index looked stale. The agent found that a run with no changed decks wrote nothing, so the file date stayed old. It made the index stamp the database after a clean run. The check was wrong, not the index.

1 problem came back to me: a macOS permission that only I can grant.

Where I see it

  • The menu bar dot. The NicAI logo with no dot when all is green, an amber or red dot, or a grey one when Pulsee itself stopped. The menu lists every check that isn't green, worst first, with its fix.
  • NicAI CC. A Health page lists every check, and a red sign-in lands in Needs you. It leaves by itself when the check turns green (see NicAI CC: the command centre for my Claude Code sessions).
  • Agents. Before a task, an agent asks Pulsee whether its tools work.

The menu, with sample data:

Pulsee   2 red · 2 amber · 101 green              checked 18:42
-----------------------------------------------------------------
● com.example.reports: 2 new errors           red since 09:40
● Music streaming sign-in                     red since 08:15
◌ login.crm                                    blocked by work sign-in
◐ queue.inbox: 32 files                        amber
-----------------------------------------------------------------
Fixed today: restarted com.example.web at 07:12 (1st attempt)

All features

Checks

  • 18 check types. LaunchAgent, log, TCP, HTTP, process, mount, disk, file age, token, count, command, SQLite, Home Assistant and more.
  • Auto-discovery. Every LaunchAgent of mine and of my apps, each with its log.
  • Log reading. New error lines since the last read, with ignore patterns and log rotation handled.
  • Content age. A read-only SQL query for the newest row of a database.
  • Silent wipes. A row count that falls 10% is amber, 50% is red.
  • Trends. A queue that stops falling for 24 hours turns amber.
  • Retrieval tests. A daily test of my search indexes, red when the score drops.
  • Dependencies. A check under a red cause is blocked, shown under it, and silent.
  • Checks in 1 file. JSON with comments, validated at every tick; a bad file keeps the last good copy.

Alerts

  • On change only. Red, back to green, amber; reminders every 4 hours.
  • Phone for critical checks. Mac notices for the rest.
  • Quiet hours. 22:00 to 06:00, then 1 morning summary if still red.
  • Flapping rule. A check that keeps changing goes quiet for 1 hour.
  • Snooze and pause. Snooze 1 check for 4 hours, or pause every alert and fix.
  • Secret mask. Every key value replaced with *** everywhere.

Fixes

  • 4 tiers. Restart, on click, sign-in, code.
  • Allow-list in code. A check can pick a fix from the list; it can't run any command it likes.
  • Proof. A fix counts only when the check passes again.
  • Fix log. Every attempt with its time, trigger and result.
  • The fix loop. 02 Nov 2026 1 Claude agent per problem, with caps, reporting only the steps I must do.

Where it shows

  • Menu bar dot in Hammerspoon.
  • Health page and Needs you in NicAI CC.
  • Home Assistant heartbeat. Every tick posts a heartbeat, so Home Assistant can tell my phone when the Mac or Pulsee stops. Ready, waiting for my go.

For agents

  • CLI with JSON. status, check, explain, history, fixes and agents read; fix, ack, pause and dispatch write, and refuse without --yes.
  • pulsee need. Exit 0 when the tools a task needs work, else 1 with the causes and the fixes.

Speed and footprint

Pulsee must never be the thing that slows my Mac. The spec set budgets, and QA fails when one breaks. Measured on my Mac on 1st November 2026:

Metric Budget Measured
Tick wall time < 2 s 124 ms
CPU per tick < 0.2 s 125 ms
Memory per tick < 50 MB 27 MB
pulsee status --json < 100 ms 90 ms

The rules that keep it there:

  1. 1 short process per minute. Nothing stays in memory between ticks.
  2. Only the checks that are due. About 70 of the 165 run every minute; the rest run hourly or daily.
  3. An idle tick writes 2 small files. The database gets a row only when a state changes, plus 1 sample per check per hour.
  4. Hard timeouts. A check that hangs 3 times is red with "timed out", and the tick is capped at 10 seconds.
  5. Long checks in the background. The retrieval test takes about 1 minute, so a later tick reads its result.

How it's built

  • Python 3.9 or later, standard library only. No dependency.
  • SQLite in WAL mode for the history and the fix log, and 1 JSON state file written atomically for the dot, NicAI CC and the CLI.
  • A Hammerspoon script for the menu bar dot. No app bundle, no signing, no build.
  • Claude Code in headless mode for the fix loop, with a JSON schema for the agent's answer.
  • Databases opened read-only, with a 1-second timeout on every query.

The agent interface

Every command takes --json and prints 1 JSON object:

pulsee need login.crm service.browser --json   # exit 0: go. Exit 1: the causes and their fixes
pulsee status --json                           # counts, failing, blocked, paused
pulsee explain <id> --json                     # why it is red: masked lines, the fix, dependencies
pulsee fix <id> --yes --json                   # run the fix, confirmed by a rerun
pulsee agents --json                           # what each Claude agent works on

How it was built

Pulsee followed my appee process for apps:

  1. Usage review: my LaunchAgents, logs, sign-ins, local services and network devices, on 27th October 2026. A test during the spec found my music streaming sign-in failing for a day already.
  2. Questions: 32 in round 1, 17 in round 2, each with a recommended answer. My main answers: no automatic fixes, and Home Assistant watches the Mac from outside.
  3. Spec, build and QA: version 1.0 in 1 session on 1st November. An independent review found 15 defects; 13 are fixed. The first real run, with alerts off, found 7 problems, among them the chat sync and an API key that the provider refused.
  4. Changes from use: the same afternoon, the fix loop. On 2nd November, the state file says whether the LaunchAgent or a person ran the tick.

QA today: 34 unit tests and 116 end-to-end checks in 9 suites, on Python 3.9 and 3.15. QA runs on a scratch home folder with fake system tools, stub servers and a fake Claude. It never touches my real Mac.

Next

1 dot for everything, new devices on my network, a weekly report, a Stream Deck key and backup freshness.

Further reading

The tool I built it with:

The menu bar dot runs in:

The outside watcher:

NicAI
Written by NicAI, Nic's AI assistant, for his personal knowledge base. Researched and drafted by the model, not hand-written by Nic. Verify anything you plan to act on.