AI Pulse is een softwarematige ambient-lichtstrip voor macOS, ontworpen om de actuele status van AI-coding agents te visualiseren. Het project is geïnspireerd op het SidePulse hardware-gadget en toont via acht virtuele ledlampjes naast de Dock of een agent bezig is, input nodig heeft, is voltooid of een fout heeft gegenereerd.
Belangrijkste statusindicatoren:
- Bezig (Working): Cyaan-kleurige komeet.
- Actie vereist (Needs you): Ademend oranje.
- Gefaald (Failed): Knipperend rood.
- Voltooid (Finished): Solide groen.
- Inactief/Uit: Aurora-effect of donker.
Technisch gezien is de app gebouwd met Swift (macOS 14+) en maakt het gebruik van een borderloze NSPanel om naast de Dock te zweven zonder private API's te gebruiken. De communicatie tussen AI-agents en de interface verloopt via een lokale HTTP-server op loopback-interface (127.0.0.1:7455) en een bijbehorende CLI tool genaamd aipulse.
De applicatie bevat een specifieke integratie voor Claude Code via hooks, waardoor sessies automatisch in de lichtstrip verschijnen. Privacy is een kernpunt: AI Pulse leest geen prompts of terminalinhoud, maar ontvangt enkel statusupdates.
AI Pulse: Ambient macOS-lichtstrip voor AI-coding agents
Statusindicatoren
- Bezig (Working) — een cyaan-kleurige komeet schiet voorbij terwijl een agent draait.
- Actie vereist (Needs you) — ademt oranje wanneer een agent wacht op input of goedkeuring.
- Gefaald (Failed) — knippert dubbel rood wanneer een sessie is onderbroken.
- Voltooid (Finished) — alle acht de lampjes worden solide groen.
- Inactief (Idle) — een langzame aurora drijft voorbij terwijl sessies stilstaan.
- Uit (Off) — donker wanneer er niets is verbonden.
De instelling 'Reduce Motion' vervangt elke animatie door een statische weergave. De oorspronkelijke per-agent iconen blijven beschikbaar via Settings → Appearance → Indicator style.
AI Pulse is niet ingebed in de Dock, aangezien macOS geen publieke API biedt voor Dock-accessoires. Het betreft een borderloze, niet-activerende NSPanel die naast de Dock wordt geplaatst op basis van publieke schermgeometrie (NSScreen.frame versus visibleFrame). Er wordt geen gebruik gemaakt van private API's, Accessibility/Screen Recording-machtigingen of injectie.
Installatie
Download AI-Pulse-<versie>.zip vanuit de nieuwste release, pak het bestand uit, verplaats AI Pulse.app naar /Applications en start de applicatie. Releases zijn nog niet genotariseerd; klik daarom bij de eerste lancering met de rechtermuisknop op de app → Open (op macOS 15+ moet dit daarna ook worden toegestaan onder Systeeminstellingen → Privacy & Beveiliging → Open Anyway).
De aipulse CLI is inbegrepen in het bundelbestand op: AI Pulse.app/Contents/Helpers/aipulse.
Releases worden automatisch aangemaakt wanneer een PR wordt samengevoegd: standaard als patch, of als minor of major wanneer de PR het label release:minor of release:major draagt.
Vereisten (bij bouwen uit broncode)
- macOS 14+
- Xcode 16+ / Swift 6 toolchain
Bouwen, testen en uitvoeren
swift build # bouw alles (app, CLI, kit)
swift test # unit + integratie tests (AIPulseKit)
swift run AIPulseApp # lanceer de pill (accessory app: geen Dock-icoon)
swift run AIPulseApp --snapshot DIR # render pill + hover card PNG's headlessly en sluit af
swift run aipulse health # CLI: controleer de lokale event service
./Scripts/make-app.sh # assembleer + signeer dist/AI Pulse.app
./Scripts/make-gifs.sh # regenereer docs/ GIFs vanuit headless frames (vereist ffmpeg)
docs/pulse-social.gif is een grotere, ondertitelde versie van dezelfde statuscyclus, bedoeld voor delen.
Voor dagelijks gebruik is het aanbevolen om de gebundelde app te gebruiken in plaats van het bare binary: het script signeert deze met jouw Apple Development identity, wat zorgt voor een stabiele code-signature zodat de Keychain de app vertrouwt na herbuilds (bare swift run binaries zijn ad-hoc gesigneerd en triggeren na elke rebuild een Keychain toestemmingsvraag — dit is ook de reden waarom AIPULSEDEVEPHEMERAL_TOKEN=1 bestaat voor dev loops). De CLI bevindt zich in AI Pulse.app/Contents/Helpers/aipulse. (Het app-product heet AIPulseApp omdat AIPulse en de aipulse CLI zouden conflicteren op case-insensitive bestandssystemen.)
Publiceren van agent-status
AI Pulse luistert op 127.0.0.1:7455 (configureerbaar in Settings). Bij lancering slaat het een bearer token op in de Keychain en schrijft het naar ~/Library/Application Support/AIPulse/cli.json (mode 0600), zodat de aipulse CLI kan authenticeren zonder dat tokens verschijnen in shell-commando's:
# Agent toevoegen of bijwerken
aipulse agent upsert \
--id "claude-code:$PWD:$SESSION_ID" \
--name "Claude Code" --provider anthropic \
--instance "$(basename "$PWD")" \
--state working --message "Implementing Dock placement"
# Status van agent bijwerken
aipulse agent update \
--id "claude-code:$PWD:$SESSION_ID" \
--state waitingForInput --message "Waiting for permission" --sequence 2
# Agent verwijderen
aipulse agent remove --id "claude-code:$PWD:$SESSION_ID"
# Lijst met alle bekende agents tonen
aipulse agents
Endpoints: POST /v1/agents/upsert, POST /v1/agents/{id}/event, DELETE /v1/agents/{id}, GET /v1/agents, GET /v1/health (alleen health is ongeauthenticeerd). De server bindt uitsluitend aan de loopback-interface, begrenst request-groottes, valideert elke payload (AgentReducer + RequestValidator), wijst onveilige URL-schema's af en voert nooit iets uit dat in een event is ontvangen.
Dev note: Het herbouwen van de app verandert de ad-hoc code signature, waardoor de Keychain per build opnieuw om toestemming vraagt; start tijdens ontwikkeling met AIPULSEDEVEPHEMERAL_TOKEN=1 om de Keychain over te slaan en een token per run te gebruiken.
Sluit de app af via het rechtermuisknopmenu van de pill → Quit AI Pulse (of beëindig het proces).
Structuur
Sources/AIPulseKit — AppKit-vrije, volledig unit-geteste kern:
- Domain/ —
Agent, AgentState, AgentAction (typed safe actions + URL scheme allowlist), AgentEventPayload (wire model), AgentIntegrationLevel, StatusPriority (urgency sort).
- Store/AgentStore — de enige bron van waarheid; alle interfaces renderen vanuit deze store.
- Placement/ —
ScreenSnapshot, best-effort DockGeometry inferentie, pure PlacementPolicy (gutter → adjacent → corner fallbacks, clamping).
Sources/AIPulse — de applicatie:
- Presentation/Pill/ — niet-activerende
AIPulsePanel, SwiftUI capsule, per-state iconen (glyph + badge + ring, nooit kleur alleen), hover card.
- Presentation/AgentList/, Presentation/Settings/ — conventionele, toetsenbord-toegankelijke vensters.
- Placement/DockPlacementController — debounced observatie van schermwijzigingen; geen polling.
Status en Mijlpalen
Mijlpaal 1–3 zijn voltooid:
- M1 — niet-activerend paneel, pill UI, mock agents, hover card, contextmenu.
- M2 — Dock-plaatsing onder/links/rechts, selectie van meerdere schermen via een Settings display picker, debounced observatie van scherm-/ruimtewijzigingen, off-screen clamping, optionele following van de auto-hidden-Dock (best-effort, via het publieke preference domein van de Dock — read-only, geen Dock-interactie).
- M3 —
AgentReducer event normalisatie (versioning, ID validatie, sequence/timestamp ordening, afwijzing van duplicaten, safe-action mapping), gecentraliseerde StalenessPolicy (werkende agents worden als 'stale' beschouwd na een configureerbare stilte, en daarna gedegradeerd naar disconnected; agents waarvan het achterliggende proces is beëindigd worden via een PID liveness check gedegradeerd; voltooide agents verlopen na een configureerbare vertraging; waiting, approval en failed states verlopen nooit op timers), en persistentie naar ~/Library/Application Support/AIPulse/agents.json met herstel na herstart: onopgeloste aandacht-statussen keren terug zoals ze waren, live-only statussen keren terug als disconnected tot hun bron opnieuw rapporteert.
M4 — loopback-only HTTP event service (LocalHTTPServer), Keychain bearer token + 0600 handshake-bestand voor de CLI, transportvalidatie, de aipulse publisher CLI en end-to-end integratietests. Geverifieerd live: CLI → HTTP → reducer → store → pill in circa 150 ms round-trip.
M5 — Claude Code adapter (ClaudeCodeAdapter + aipulse claude-hook), gebouwd tegen de gedocumenteerde hook-lifecycle: SessionStart→idle, UserPromptSubmit/PreToolUse→working, PermissionRequest en permission-prompt Notifications→approvalRequired, idle-prompt Notifications→waitingForInput, Stop→completed, StopFailure→failed, SessionEnd→removed. Eén pill-entry per sessie per project. Prompt-tekst, tool-inputs en assistant-output worden nooit gedecodeerd en kunnen dus nooit gepubliceerd worden. De hook exit altijd met 0 en print niets.
M6 — optioneel dynamisch Dock-icoon (standaard uit; Settings → Appearance). Aggregeert dezelfde AgentStore snapshot als de pill via DockTileAggregator: failure $>$ attention $>$ working $>$ neutral, met een NSDockTile custom content view voor de state treatment en badgeLabel dat het aantal niet-bevestigde urgente agents toont. De zwevende pill en het Dock-icoon kunnen onafhankelijk worden in- of uitgeschakeld; het icoon springt (bounce) nooit.
Alle zes de MVP-mijlpalen zijn voltooid, gevolgd door de pivot naar de "lights-first" presentatie (LightAggregator + LightStripView), waarbij het icon-pill behouden blijft als optie.
Claude Code integratie
Deze repository bevat .claude/settings.json waarin de aipulse claude-hook is geregistreerd voor de relevante hook events (via het debug build pad), zodat Claude Code sessies in deze repo automatisch in de pill verschijnen zodra de app draait. Voor systeembreed gebruik:
swift build -c release
sudo cp .build/release/aipulse /usr/local/bin/
Registreer vervolgens dezelfde hooks in ~/.claude/settings.json, waarbij het commando wordt vervangen door simpelweg aipulse claude-hook. Claude Code vraagt je om project hooks goed te keuren de eerste keer dat ze worden geladen.
Privacy
AI Pulse toont statussen die zijn verzonden door lokale agent-integraties. Het leest geen prompts, terminalinhoud, editorinhoud of applicatievensters.
Bijdragen
Bijdragen zijn welkom — zie CONTRIBUTING.md voor de ontwerpprincipes van het project, testverwachtingen en hoe je een nieuwe agent-integratie toevoegt. docs/DEBUGGING.md behandelt de debugging surface: omgevingsvariabelen, headless snapshots, log streaming, on-disk state en fixes voor veelvoorkomende foutmodi.
Licentie
MIT
AI Pulse: Ambient macOS-lichtstrip voor AI-coding agents
Statusindicatoren
- Bezig (Working) — een cyaan-kleurige komeet schiet voorbij terwijl een agent draait.
- Actie vereist (Needs you) — ademt oranje wanneer een agent wacht op input of goedkeuring.
- Gefaald (Failed) — knippert dubbel rood wanneer een sessie is onderbroken.
- Voltooid (Finished) — alle acht de lampjes worden solide groen.
- Inactief (Idle) — een langzame aurora drijft voorbij terwijl sessies stilstaan.
- Uit (Off) — donker wanneer er niets is verbonden.
De instelling 'Reduce Motion' vervangt elke animatie door een statische weergave. De oorspronkelijke per-agent iconen blijven beschikbaar via Settings → Appearance → Indicator style.
AI Pulse is niet ingebed in de Dock, aangezien macOS geen publieke API biedt voor Dock-accessoires. Het betreft een borderloze, niet-activerende NSPanel die naast de Dock wordt geplaatst op basis van publieke schermgeometrie (NSScreen.frame versus visibleFrame). Er wordt geen gebruik gemaakt van private API's, Accessibility/Screen Recording-machtigingen of injectie.
Installatie
Download AI-Pulse-<versie>.zip vanuit de nieuwste release, pak het bestand uit, verplaats AI Pulse.app naar /Applications en start de applicatie. Releases zijn nog niet genotariseerd; klik daarom bij de eerste lancering met de rechtermuisknop op de app → Open (op macOS 15+ moet dit daarna ook worden toegestaan onder Systeeminstellingen → Privacy & Beveiliging → Open Anyway).
De aipulse CLI is inbegrepen in het bundelbestand op: AI Pulse.app/Contents/Helpers/aipulse.
Releases worden automatisch aangemaakt wanneer een PR wordt samengevoegd: standaard als patch, of als minor of major wanneer de PR het label release:minor of release:major draagt.
Vereisten (bij bouwen uit broncode)
- macOS 14+
- Xcode 16+ / Swift 6 toolchain
Bouwen, testen en uitvoeren
swift build # bouw alles (app, CLI, kit)
swift test # unit + integratie tests (AIPulseKit)
swift run AIPulseApp # lanceer de pill (accessory app: geen Dock-icoon)
swift run AIPulseApp --snapshot DIR # render pill + hover card PNG's headlessly en sluit af
swift run aipulse health # CLI: controleer de lokale event service
./Scripts/make-app.sh # assembleer + signeer dist/AI Pulse.app
./Scripts/make-gifs.sh # regenereer docs/ GIFs vanuit headless frames (vereist ffmpeg)
docs/pulse-social.gif is een grotere, ondertitelde versie van dezelfde statuscyclus, bedoeld voor delen.
Voor dagelijks gebruik is het aanbevolen om de gebundelde app te gebruiken in plaats van het bare binary: het script signeert deze met jouw Apple Development identity, wat zorgt voor een stabiele code-signature zodat de Keychain de app vertrouwt na herbuilds (bare swift run binaries zijn ad-hoc gesigneerd en triggeren na elke rebuild een Keychain toestemmingsvraag — dit is ook de reden waarom AIPULSEDEVEPHEMERAL_TOKEN=1 bestaat voor dev loops). De CLI bevindt zich in AI Pulse.app/Contents/Helpers/aipulse. (Het app-product heet AIPulseApp omdat AIPulse en de aipulse CLI zouden conflicteren op case-insensitive bestandssystemen.)
Publiceren van agent-status
AI Pulse luistert op 127.0.0.1:7455 (configureerbaar in Settings). Bij lancering slaat het een bearer token op in de Keychain en schrijft het naar ~/Library/Application Support/AIPulse/cli.json (mode 0600), zodat de aipulse CLI kan authenticeren zonder dat tokens verschijnen in shell-commando's:
# Agent toevoegen of bijwerken
aipulse agent upsert \
--id "claude-code:$PWD:$SESSION_ID" \
--name "Claude Code" --provider anthropic \
--instance "$(basename "$PWD")" \
--state working --message "Implementing Dock placement"
# Status van agent bijwerken
aipulse agent update \
--id "claude-code:$PWD:$SESSION_ID" \
--state waitingForInput --message "Waiting for permission" --sequence 2
# Agent verwijderen
aipulse agent remove --id "claude-code:$PWD:$SESSION_ID"
# Lijst met alle bekende agents tonen
aipulse agents
Endpoints: POST /v1/agents/upsert, POST /v1/agents/{id}/event, DELETE /v1/agents/{id}, GET /v1/agents, GET /v1/health (alleen health is ongeauthenticeerd). De server bindt uitsluitend aan de loopback-interface, begrenst request-groottes, valideert elke payload (AgentReducer + RequestValidator), wijst onveilige URL-schema's af en voert nooit iets uit dat in een event is ontvangen.
Dev note: Het herbouwen van de app verandert de ad-hoc code signature, waardoor de Keychain per build opnieuw om toestemming vraagt; start tijdens ontwikkeling met AIPULSEDEVEPHEMERAL_TOKEN=1 om de Keychain over te slaan en een token per run te gebruiken.
Sluit de app af via het rechtermuisknopmenu van de pill → Quit AI Pulse (of beëindig het proces).
Structuur
Sources/AIPulseKit — AppKit-vrije, volledig unit-geteste kern:
- Domain/ —
Agent, AgentState, AgentAction (typed safe actions + URL scheme allowlist), AgentEventPayload (wire model), AgentIntegrationLevel, StatusPriority (urgency sort).
- Store/AgentStore — de enige bron van waarheid; alle interfaces renderen vanuit deze store.
- Placement/ —
ScreenSnapshot, best-effort DockGeometry inferentie, pure PlacementPolicy (gutter → adjacent → corner fallbacks, clamping).
Sources/AIPulse — de applicatie:
- Presentation/Pill/ — niet-activerende
AIPulsePanel, SwiftUI capsule, per-state iconen (glyph + badge + ring, nooit kleur alleen), hover card.
- Presentation/AgentList/, Presentation/Settings/ — conventionele, toetsenbord-toegankelijke vensters.
- Placement/DockPlacementController — debounced observatie van schermwijzigingen; geen polling.
Status en Mijlpalen
Mijlpaal 1–3 zijn voltooid:
- M1 — niet-activerend paneel, pill UI, mock agents, hover card, contextmenu.
- M2 — Dock-plaatsing onder/links/rechts, selectie van meerdere schermen via een Settings display picker, debounced observatie van scherm-/ruimtewijzigingen, off-screen clamping, optionele following van de auto-hidden-Dock (best-effort, via het publieke preference domein van de Dock — read-only, geen Dock-interactie).
- M3 —
AgentReducer event normalisatie (versioning, ID validatie, sequence/timestamp ordening, afwijzing van duplicaten, safe-action mapping), gecentraliseerde StalenessPolicy (werkende agents worden als 'stale' beschouwd na een configureerbare stilte, en daarna gedegradeerd naar disconnected; agents waarvan het achterliggende proces is beëindigd worden via een PID liveness check gedegradeerd; voltooide agents verlopen na een configureerbare vertraging; waiting, approval en failed states verlopen nooit op timers), en persistentie naar ~/Library/Application Support/AIPulse/agents.json met herstel na herstart: onopgeloste aandacht-statussen keren terug zoals ze waren, live-only statussen keren terug als disconnected tot hun bron opnieuw rapporteert.
M4 — loopback-only HTTP event service (LocalHTTPServer), Keychain bearer token + 0600 handshake-bestand voor de CLI, transportvalidatie, de aipulse publisher CLI en end-to-end integratietests. Geverifieerd live: CLI → HTTP → reducer → store → pill in circa 150 ms round-trip.
M5 — Claude Code adapter (ClaudeCodeAdapter + aipulse claude-hook), gebouwd tegen de gedocumenteerde hook-lifecycle: SessionStart→idle, UserPromptSubmit/PreToolUse→working, PermissionRequest en permission-prompt Notifications→approvalRequired, idle-prompt Notifications→waitingForInput, Stop→completed, StopFailure→failed, SessionEnd→removed. Eén pill-entry per sessie per project. Prompt-tekst, tool-inputs en assistant-output worden nooit gedecodeerd en kunnen dus nooit gepubliceerd worden. De hook exit altijd met 0 en print niets.
M6 — optioneel dynamisch Dock-icoon (standaard uit; Settings → Appearance). Aggregeert dezelfde AgentStore snapshot als de pill via DockTileAggregator: failure $>$ attention $>$ working $>$ neutral, met een NSDockTile custom content view voor de state treatment en badgeLabel dat het aantal niet-bevestigde urgente agents toont. De zwevende pill en het Dock-icoon kunnen onafhankelijk worden in- of uitgeschakeld; het icoon springt (bounce) nooit.
Alle zes de MVP-mijlpalen zijn voltooid, gevolgd door de pivot naar de "lights-first" presentatie (LightAggregator + LightStripView), waarbij het icon-pill behouden blijft als optie.
Claude Code integratie
Deze repository bevat .claude/settings.json waarin de aipulse claude-hook is geregistreerd voor de relevante hook events (via het debug build pad), zodat Claude Code sessies in deze repo automatisch in de pill verschijnen zodra de app draait. Voor systeembreed gebruik:
swift build -c release
sudo cp .build/release/aipulse /usr/local/bin/
Registreer vervolgens dezelfde hooks in ~/.claude/settings.json, waarbij het commando wordt vervangen door simpelweg aipulse claude-hook. Claude Code vraagt je om project hooks goed te keuren de eerste keer dat ze worden geladen.
Privacy
AI Pulse toont statussen die zijn verzonden door lokale agent-integraties. Het leest geen prompts, terminalinhoud, editorinhoud of applicatievensters.
Bijdragen
Bijdragen zijn welkom — zie CONTRIBUTING.md voor de ontwerpprincipes van het project, testverwachtingen en hoe je een nieuwe agent-integratie toevoegt. docs/DEBUGGING.md behandelt de debugging surface: omgevingsvariabelen, headless snapshots, log streaming, on-disk state en fixes voor veelvoorkomende foutmodi.
Licentie
MIT