diff --git a/README.md b/README.md index a7b6293..eb573ce 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,10 @@
--- @@ -25,36 +24,93 @@ jigai watch claude --- +## Table of Contents + +- [Prerequisites](#prerequisites) +- [The Problem](#the-problem) +- [How JigAi Is Different](#how-jigai-is-different) +- [How It Works](#how-it-works) +- [Quick Start](#quick-start) +- [Supported Tools](#supported-tools) +- [Notification Setup](#notification-setup) +- [Known Issues and Caveats](#known-issues-and-caveats) +- [Configuration](#configuration) +- [Commands](#commands) +- [Architecture](#architecture) +- [Development](#development) +- [Publishing to PyPI](#publishing-to-pypi) +- [Roadmap](#roadmap) +- [Contributing](#contributing) +- [License](#license) + +--- + +## Prerequisites + +- **macOS** — notifications use macOS APIs. Linux and Windows support is planned. +- **Python 3.10 or later** +- **[terminal-notifier](https://github.com/julienXX/terminal-notifier)** (strongly recommended) — required for banner popup notifications. Without it, notifications land silently in Notification Center. + +```bash +brew install terminal-notifier +``` + +--- + ## The Problem You kick off Claude Code on a big refactor, switch to your browser to research something, and come back 20 minutes later to find it asked a clarifying question in the first 30 seconds. You just wasted 20 minutes. -Every AI coding tool has this problem. None of them have a universal solution. Hook-based approaches require per-tool configuration that breaks across versions. Cloud notification services require accounts, subscriptions, or trusting a third party with your terminal output. +Every AI coding tool has this problem. Existing solutions all have significant limitations: + +- **Hook-based tools** (Claude Code Notifier, ntfy integrations) require per-tool configuration that breaks across versions and doesn't work with tools that don't have hooks. +- **Cloud notification services** (Pushover, ntfy.sh) require accounts, subscriptions, or sending your terminal output to a third-party server. +- **Terminal replacements** (cmux) require abandoning your existing terminal setup. **JigAi** fixes this with a single transparent PTY proxy that watches any terminal output, detects idle patterns, and notifies you — locally, privately, instantly. --- +## How JigAi Is Different + +| Feature | ntfy / Pushover | Claude Code Notifier | cmux | JigAi | +|---|:---:|:---:|:---:|:---:| +| Works with **any** AI tool | ❌ manual wiring | ❌ Claude Code only | ✅ via hooks | ✅ auto-detect | +| **No per-tool config** needed | ❌ | ❌ | ❌ hooks required | ✅ | +| **Auto-detects** idle state | ❌ | ❌ hook-triggered | ❌ | ✅ | +| macOS notifications | ✅ | ✅ | ✅ | ✅ | +| **LAN mobile push** (no cloud) | ❌ cloud | ❌ | ❌ | ✅ | +| Works in **any terminal** | ✅ | ✅ | ❌ is the terminal | ✅ | +| **Free and open source** | ✅ ntfy | ❌ | ❌ | ✅ | +| **Privacy-first** (LAN only) | ❌ cloud | ✅ | ✅ | ✅ | + +--- + ## How It Works -JigAi wraps your AI tool in a **PTY (pseudo-terminal) proxy**. Your tool runs exactly as normal — same colors, same interactivity, same behavior. JigAi intercepts the output stream silently: +JigAi wraps your AI tool in a **PTY (pseudo-terminal) proxy**. Your tool runs exactly as normal — same colors, same interactivity, same behavior. JigAi intercepts the output stream silently in the background: ``` You type: jigai watch claude - │ - ▼ - ┌──────────────────┐ - │ JigAi Watcher │ ← sits here transparently - │ (PTY proxy) │ - └────────┬─────────┘ - │ passes all I/O through unchanged - ▼ - ┌──────────────────┐ - │ Claude Code │ ← behaves exactly as if launched directly - └──────────────────┘ + │ + ▼ + ┌──────────────────────┐ + │ JigAi Watcher │ ← sits here transparently + │ (PTY proxy) │ + └──────────┬───────────┘ + │ all I/O passed through unchanged + ▼ + ┌──────────────────────┐ + │ Claude Code │ ← behaves as if launched directly + └──────────────────────┘ ``` -When idle is detected (via pattern match or timeout), JigAi fires: +Idle detection uses three layers in order: +1. **Pattern match** — recognizes the idle prompt for known tools instantly +2. **Timeout fallback** — no output for N seconds = idle (works with any tool) +3. **Cooldown** — suppresses repeated notifications during a single idle period + +When idle is detected, JigAi fires: 1. A **macOS notification** with the last meaningful output line 2. A **WebSocket push** to the JigAi server (if running) 3. Your phone receives the notification via the LAN server *(mobile app coming in v0.2)* @@ -67,15 +123,10 @@ When idle is detected (via pattern match or timeout), JigAi fires: ```bash pip install jigai +brew install terminal-notifier # recommended — enables banner popups ``` -For richer notifications (banner popups instead of silent NC delivery): - -```bash -brew install terminal-notifier -``` - -> See [Notification Setup](#notification-setup) for macOS configuration steps. +See [Notification Setup](#notification-setup) for the one-time macOS configuration required. ### 2. Watch a tool @@ -95,28 +146,28 @@ jigai watch aider # Any arbitrary command jigai watch -- python my_agent.py -# Override tool detection (for custom prompts) +# Override tool name (custom idle prompts) jigai watch --tool my_agent -- python agent.py ``` ### 3. (Optional) Start the server for LAN mobile push ```bash -# Terminal 1 — keep the server running +# Terminal 1 — keep the server running in the background jigai server start # Terminal 2 — watch your tool as normal jigai watch claude ``` -That's it. When Claude Code goes idle, you get notified. +That's it. When your AI tool goes idle, you get notified. --- ## Supported Tools -| Tool | Detection Method | Status | -|------|-----------------|--------| +| Tool | Detection | Notes | +|------|-----------|-------| | Claude Code | Pattern + timeout | Built-in | | OpenAI Codex CLI | Pattern + timeout | Built-in | | Gemini CLI | Pattern + timeout | Built-in | @@ -124,87 +175,84 @@ That's it. When Claude Code goes idle, you get notified. | OpenCode | Pattern + timeout | Built-in | | Any custom tool | User-defined regex | Via `~/.jigai/patterns.yaml` | -JigAi also has a **timeout fallback**: if no output is received for `timeout_seconds` (default: 30s), it fires regardless of pattern matching. This means it works with any tool, even ones not in the list above. +The **timeout fallback** (default: 30s of silence = idle) means JigAi works with any tool out of the box, even ones not listed above. --- ## Notification Setup -JigAi uses two delivery mechanisms. Both are attempted in order: +JigAi tries two delivery mechanisms in order: -### 1. `terminal-notifier` (Recommended — banner popups) +### 1. `terminal-notifier` — Recommended -Install via Homebrew: +Enables proper banner popup notifications. ```bash brew install terminal-notifier ``` -Then configure macOS to show banners: +**One-time macOS configuration:** 1. Open **System Settings → Notifications → terminal-notifier** -2. Enable **Allow Notifications** -3. Check **Desktop** (required for banner popups) -4. Set **Alert Style** to **Persistent** (stays until dismissed) or **Temporary** (auto-dismisses) -5. Enable **Play sound for notification** +2. Toggle **Allow Notifications** ON +3. Check **Desktop** *(required for the popup to appear on screen)* +4. Set **Alert Style** → **Persistent** (stays until dismissed) or **Temporary** (auto-dismisses after a few seconds) +5. Toggle **Play sound for notification** ON -### 2. `osascript` (Fallback — no installation required) +### 2. `osascript` — Fallback -If `terminal-notifier` is not installed, JigAi falls back to macOS's built-in `osascript`. Notifications will appear in **Notification Center** but may not show as banner popups, depending on your macOS version and Script Editor's notification settings. - -> **Recommendation:** Install `terminal-notifier` for the best experience. +No installation required. Notifications appear in **Notification Center** but may not show as popup banners on macOS Sequoia (15.x). See [Known Issues](#known-issues-and-caveats). --- ## Known Issues and Caveats -Read this section before filing a bug report — most common issues are documented here. +Read this before filing a bug — most common issues are documented here. + +--- -### Focus Mode blocks banner notifications +### Focus Mode silences banner popups -**Symptom:** Notifications appear in Notification Center but the banner popup never shows, even with correct settings. +**Symptom:** Notification appears in Notification Center, but the banner popup never shows — even with all settings correct. -**Cause:** macOS Focus Mode (Do Not Disturb, Work, Personal, etc.) silences notification banners from apps not explicitly allowed. +**Cause:** macOS Focus (Do Not Disturb, Work, Personal, etc.) blocks notification banners from apps not on the allow list. **Fix:** -1. Open **System Settings → Focus** -2. Select your active Focus profile -3. Under **Allowed Notifications → Apps**, add **terminal-notifier** +1. **System Settings → Focus** → select your active Focus profile +2. **Allowed Notifications → Apps** → add **terminal-notifier** -This is a one-time setup per Focus profile. Once allowed, banners will appear even when Focus is active. +One-time setup per Focus profile. This is the most common reason banners don't show. --- ### `terminal-notifier` on macOS Sequoia (15.x) -**Symptom:** Notifications appear in Notification Center but never pop as banners, or `terminal-notifier` produces no output at all. +**Symptom:** Notifications appear in Notification Center but never pop as banners, or no notifications appear at all. -**Cause:** `terminal-notifier` has known compatibility issues on macOS Sequoia 15, particularly on M-series chips ([issue #312](https://github.com/julienXX/terminal-notifier/issues/312)). The binary is not updated for the newer UserNotifications framework in Sequoia. +**Cause:** `terminal-notifier` has a [known compatibility issue on macOS 15](https://github.com/julienXX/terminal-notifier/issues/312), particularly on M-series chips. It predates the UserNotifications framework changes in Sequoia. -**Workarounds:** -- Try resetting the notification registration: - ```bash - /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -kill -r -domain local -domain system -domain user - ``` - Then re-open System Settings → Notifications → terminal-notifier and re-enable. -- If still broken, notifications will still land in Notification Center via the `osascript` fallback — you just won't get the popup banner. -- A native Swift notification backend is planned for v0.2 that will resolve this permanently. +**Workarounds (try in order):** ---- +1. Make sure Focus mode isn't blocking it (see above) — this is the cause 90% of the time. -### Display mirroring / screen sharing +2. Reset the notification registration cache: + ```bash + /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister \ + -kill -r -domain local -domain system -domain user + ``` + Then re-open System Settings → Notifications → terminal-notifier and re-enable. -**Symptom:** Notifications don't show on the desktop while screen sharing or mirroring. +3. If banners still don't appear, notifications will still land in **Notification Center** via the `osascript` fallback — you won't get the popup, but the sound will still play. -**Fix:** System Settings → Notifications → enable **"Allow notifications when mirroring or sharing the display"** +A native Swift notification backend is planned for v0.2 which will resolve this permanently. --- ### Notifications fire while you're at the terminal -By default, JigAi will fire a notification even if you're actively looking at the terminal. This is intentional — the sound alone can be useful as a cue. +**By default this is intentional** — the sound cue is useful even when you're looking at the screen. -To suppress notifications when a terminal window is focused: +To suppress notifications when any terminal window is focused: ```yaml # ~/.jigai/config.yaml @@ -212,36 +260,42 @@ notifications: only_when_away: true ``` -JigAi checks the frontmost macOS application. If it's Terminal, iTerm2, Warp, Ghostty, Alacritty, Kitty, or similar, the notification is skipped. Supported terminal app names are: `terminal`, `iterm2`, `warp`, `hyper`, `alacritty`, `kitty`, `ghostty`, `tabby`, `rio`. +JigAi checks the frontmost macOS application. If it is Terminal, iTerm2, Warp, Ghostty, Alacritty, Kitty, Hyper, Tabby, or Rio, the notification is skipped. + +--- + +### Display mirroring or screen sharing + +**Symptom:** Notifications don't appear while screen sharing or using a mirrored display. + +**Fix:** System Settings → Notifications → enable **"Allow notifications when mirroring or sharing the display"** --- ### Idle fires too early or too often -**Cause:** Pattern matching may trigger on output lines that superficially resemble idle prompts, especially for tools with rich TUI output. +**Cause:** A pattern may match on output that looks like an idle prompt but isn't. -**Fix:** Adjust the cooldown (minimum gap between notifications) and timeout: +**Fix:** Raise the cooldown (minimum gap between notifications) or the timeout: ```yaml # ~/.jigai/config.yaml detection: - timeout_seconds: 45 # how long to wait before timeout-based idle - cooldown_seconds: 10 # minimum seconds between notifications + timeout_seconds: 45 # wait longer before timeout-based idle + cooldown_seconds: 10 # minimum seconds between consecutive notifications ``` -Or test which lines trigger detection: +Debug which lines trigger detection: ```bash -jigai config test "some terminal output line" +jigai config test "the output line you want to test" ``` --- -### Pattern detection for Claude Code - -Claude Code renders a rich TUI with box-drawing characters and animated spinners. JigAi strips all ANSI codes and decorative Unicode before matching, and the idle prompt (`>`) is the primary pattern matched. +### Pattern detection reliability for Claude Code -If you find detection is unreliable, set a longer timeout: +Claude Code renders a rich TUI with box-drawing characters and animated spinners. JigAi strips all ANSI codes and decorative Unicode before matching. If detection feels unreliable, fall back to a longer timeout: ```bash jigai watch --timeout 60 claude @@ -249,49 +303,45 @@ jigai watch --timeout 60 claude --- -### iOS / Android mobile notifications (LAN) +### Mobile notifications (iOS / Android) — not yet available -The mobile app is planned for **v0.2**. Currently, `jigai server start` runs a WebSocket server that a future React Native app will connect to. +The mobile app is planned for **v0.2**. `jigai server start` runs the WebSocket server that the React Native app will connect to — the server-side is already live. -iOS note: iOS aggressively terminates background WebSocket connections. When the mobile app is built, foreground/background behavior will be documented. Users on iOS may want to keep the app in the foreground or use a notification relay for reliable background delivery. +**iOS note:** iOS aggressively suspends background WebSocket connections. The v0.2 mobile app will document foreground/background behavior in detail. For fully reliable background delivery on iOS, a push notification relay option will be offered as an opt-in. --- ## Configuration -### Config file: `~/.jigai/config.yaml` - -Initialize with defaults: +Initialize the config file with defaults: ```bash jigai config init ``` -Full reference: +### `~/.jigai/config.yaml` — full reference ```yaml server: port: 9384 # LAN server port - bind: "0.0.0.0" # Bind address + bind: "0.0.0.0" # Bind address (0.0.0.0 = all interfaces) notifications: macos: true # Enable macOS notifications - only_when_away: false # Skip if a terminal is the frontmost app - sound: "Ping" # macOS sound name (Ping, Basso, Funk, etc.) - group_by_session: true # Group notifications per session - show_last_output: true # Include last output in notification body - output_lines: 3 # Lines of output to include - redact_patterns: # Auto-redact sensitive info from notifications + only_when_away: false # Skip notification if a terminal is focused + sound: "Ping" # macOS sound name: Ping, Basso, Funk, Glass, etc. + group_by_session: true # Group notifications per session in NC + show_last_output: true # Include last meaningful output line in body + output_lines: 3 # Lines of terminal context to capture + redact_patterns: # Patterns auto-redacted from notification body - '(?i)(token|password|secret|key|api_key)=\S+' detection: - timeout_seconds: 30 # Timeout-based idle threshold - cooldown_seconds: 5 # Minimum gap between notifications + timeout_seconds: 30 # Silence threshold for timeout-based idle + cooldown_seconds: 5 # Minimum gap between consecutive notifications ``` -### Custom patterns: `~/.jigai/patterns.yaml` - -Add your own tools or override built-in patterns: +### `~/.jigai/patterns.yaml` — custom tool patterns ```yaml custom_tools: @@ -303,7 +353,7 @@ custom_tools: - '(?i)what would you like' overrides: - timeout_seconds: 45 # Override global timeout + timeout_seconds: 45 ``` --- @@ -311,26 +361,26 @@ overrides: ## Commands ```bash -# Watch commands +# Watching jigai watch