Back to Rules
πŸ“‹

Nudgy CLAUDE.md

Native macOS menu bar app that notifies you when AI coding agents (Claude Code) finish tasks, need permissions, or ask questions. Privacy-first, zero dependenci

Hamma111

by @Hamma111

Sourced from Hamma111/nudgy β€” MIT

View profile
CLAUDE.md
> Sourced from [Hamma111/nudgy](https://github.com/Hamma111/nudgy) β€” [MIT](https://github.com/Hamma111/nudgy/blob/1466637c940ccb4ba5aeade454d159fc7247bcae/CLAUDE.md).

# Nudgy

Native macOS menu bar app that notifies you when AI coding agents need attention. Currently supports Claude Code.

## Build & Run

```bash
make build          # release build
make debug          # debug build
make test           # run tests
make run            # debug build + launch
make package        # create .app bundle
make release        # full pipeline: test β†’ sign β†’ dmg
```

Requires: Swift 5.9+, macOS 14.0+ (Sonoma). Zero external dependencies β€” only Apple system frameworks.

## Architecture

```
Sources/Nudge/
β”œβ”€β”€ App/        # NudgeApp.swift (@main), AppDelegate.swift (lifecycle + notification pipeline)
β”œβ”€β”€ Models/     # AppState, AgentSession, HookEvent, NotificationItem, RingBuffer, AnyCodable
β”œβ”€β”€ Server/     # HTTPServer (NWListener on 127.0.0.1:9847, token-authenticated)
β”œβ”€β”€ Services/   # SessionManager, HookInstaller, SmartSuppressor, TranscriptParser,
β”‚               # WindowFocuser, SoundManager, UsageQuotaManager, KeychainHelper, Logger
└── UI/         # MenuBarManager, MenuBarView, PopupWindowController, PopupContentView,
                # SettingsView, NudgyIcon
```

## Event Flow

```
Claude Code hook β†’ HTTP POST /event?token=... β†’ HTTPServer (responds 200 immediately)
  β†’ AppDelegate.httpServer(_:didReceive:)
  β†’ SessionManager.handleEvent() [actor-isolated, updates session state]
  β†’ SmartSuppressor.evaluate() β†’ show / suppress / escalate / batch
  β†’ PopupWindowController.show(item) + SoundManager + MenuBarManager.updateIcon()
```

## Key Patterns

- **AppState** is `@Observable @MainActor` β€” the single source of truth for all UI
- **SessionManager** is a Swift `actor` β€” always `await` its methods
- **UserDefaults keys** use `nudgy.*` prefix (e.g. `nudgy.soundEnabled`, `nudgy.notify.success`)
- **HTTP responses** are sent immediately; event processing is async
- **Auth token** stored in Keychain, generated on first launch

## Session States

States in priority order (highest first):

| State | Priority | Style | Auto-dismiss |
|---|---|---|---|
| waitingPermission | 100 | warning (orange) | no |
| error | 90 | error (red) | 3s |
| waitingInput | 80 | question (yellow) | no |
| active | 50 | β€” | β€” |
| idle | 10 | success (teal) | 3s |
| stopped | 0 | β€” | β€” |

## Notification Styles

Five styles used throughout: `success`, `warning`, `question`, `error`, `info`. Each has color, gradient, icon, and a user toggle (`nudgy.notify.<style>`).

## Hook System

HookInstaller manages `~/.claude/settings.json`:
- Installs HTTP hooks for: Stop, Notification, StopFailure, SessionStart, PermissionRequest, SessionEnd
- Creates timestamped backups before modifying (keeps max 5)
- Idempotent β€” detects existing Nudgy hooks by URL pattern
- Cleans up on quit (unless user explicitly uninstalled)

## Tests

```bash
swift test
```

Tests in `Tests/NudgyTests/`: SessionManager, HTTPServer, HookInstaller, SmartSuppressor, RingBuffer, AppState, HookEvent, WindowFocuser, SoundManager, Integration.

## Style Notes

- SwiftUI for views, AppKit for window management (NSPanel, NSStatusItem)
- No external dependencies β€” Network.framework for HTTP, Keychain for secrets
- Popup presets: Minimal, Pill, Glass (default), Card, Banner
- Sound effects mapped per notification style, user-configurable
- Smart suppression avoids notification fatigue (3+ events in 10s = suppress idle completions)
- Logger writes to `~/Library/Logs/Nudgy/nudgy.log` (rotates at 5MB)

Add to your project

Paste into your project's CLAUDE.md or ~/.claude/CLAUDE.md for global rules.