GNU watch, supercharged with notifications.
Know the instant your command output changes — in the terminal, your inbox, or a live GitHub Gist.
Quickstart · Examples · Flags · Configuration
You're already running watch to keep an eye on things. But you can't stare at a terminal forever.
watch+ is a drop-in replacement for GNU watch that adds email alerts via Resend and live output to GitHub Gists. Same flags, same behavior — plus --email and --gist flags that change everything.
flowchart TD
Command["🐚 Your Shell Command"] -->|runs every N seconds| WatchPlus["⚡ watch+"]
WatchPlus --> Terminal["🖥️ Terminal<br/>fullscreen with diff highlight"]
WatchPlus -->|output changed?| Email["📧 Resend<br/>email alert"]
WatchPlus -->|every update| Gist["📝 GitHub Gist<br/>live output"]
style Command fill:#1e293b,stroke:#475569,color:#e2e8f0
style WatchPlus fill:#2d1f4e,stroke:#7c3aed,color:#e2e8f0
style Terminal fill:#164e63,stroke:#06b6d4,color:#e2e8f0
style Email fill:#4c1d95,stroke:#a78bfa,color:#e2e8f0
style Gist fill:#1a3a2a,stroke:#34d399,color:#e2e8f0
# Install dependencies
bun install
# Build a standalone binary
bun run build # → ./watch+
# Or run directly
bun run src/index.ts -n 1 dateCross-compile for Linux:
bun build --compile --target=bun-linux-x64 src/index.ts --outfile watch+-linux-amd64
# 🕐 Live-updating clock
watch+ -n 1 date
# 🔍 Highlight changes to a file
watch+ -d -n 1 "cat /tmp/test.txt"
# 🚪 Exit as soon as output changes
watch+ -g -n 1 "date +%S"
# 📧 Email yourself when an API response changes
watch+ --email me@example.com \
--from noreply@mydomain.com \
--cooldown 30s \
-n 2 \
"curl -s https://api.example.com/status"
# 📝 Publish live output to a GitHub Gist
watch+ --gist -n 5 "kubectl get pods"
# 📝 Update an existing Gist
watch+ --gist-id abc123def456 -n 5 "kubectl get pods"
# 📊 Count errors in a log file
watch+ -n 5 -- grep -c ERROR /var/log/app.logAll the flags you know. Fully compatible — swap watch for watch+ in your scripts.
| Flag | Description |
|---|---|
-n, --interval <secs> |
Seconds between updates (default: 2) |
-d, --differences [permanent] |
Highlight changes between updates |
-e, --errexit |
Exit on non-zero return code |
-g, --chgexit |
Exit when output changes |
-c, --color |
Pass through ANSI color sequences |
-C, --no-color |
Strip ANSI color sequences |
-t, --no-title |
Suppress header |
-w, --no-wrap |
Truncate long lines |
-x, --exec |
Pass command to exec instead of sh -c |
-p, --precise |
Attempt precise timing |
-b, --beep |
Beep on change |
| Flag | Description |
|---|---|
--email <address> |
Email address to notify on change |
--from <address> |
Sender email address (required with --email) |
--cooldown <duration> |
Min time between emails — e.g. 30s, 5m, 1h (default: 1m) |
--subject <text> |
Custom email subject |
--api-key <key> |
Resend API key |
Changes that occur during the cooldown period are queued and sent as a single email once the cooldown expires — no changes are dropped.
| Flag | Description |
|---|---|
--gist |
Create a new private Gist and push output to it on every update |
--gist-id <id> |
Push output to an existing Gist |
Requires the GitHub CLI (gh auth login). Output is written to output.md in the Gist, alongside a statistics.txt file with uptime, iteration count, and change count.
| Key | Action |
|---|---|
| Space | Force an immediate re-run |
| q | Quit |
| Ctrl+C | Quit |
graph LR
CLI["CLI<br/><small>commander</small>"] --> Config["Config<br/><small>~/.watch+/config.json</small>"]
Config --> Watch["Watch Loop<br/><small>execute → compare → render</small>"]
Watch --> Terminal["Terminal<br/><small>fullscreen + diff highlight</small>"]
Watch -->|output changed?| Email["Email<br/><small>Resend API + cooldown</small>"]
Watch -->|every update| Gist["Gist<br/><small>GitHub API</small>"]
style CLI fill:#1e293b,stroke:#475569,color:#e2e8f0
style Config fill:#1e293b,stroke:#475569,color:#e2e8f0
style Watch fill:#2d1f4e,stroke:#7c3aed,color:#e2e8f0
style Terminal fill:#164e63,stroke:#06b6d4,color:#e2e8f0
style Email fill:#4c1d95,stroke:#a78bfa,color:#e2e8f0
style Gist fill:#1a3a2a,stroke:#34d399,color:#e2e8f0
| Module | Responsibility |
|---|---|
| index.ts | CLI parsing with Commander, flag validation |
| config.ts | Loads ~/.watch+/config.json, merges CLI + env + config with correct priority |
| watch.ts | Core loop — executes command, diffs output, renders fullscreen terminal UI |
| diff.ts | Change detection, unified diff generation, HTML formatting for emails |
| email.ts | Sends notifications via Resend with cooldown throttling and queuing |
| gist.ts | Creates/updates GitHub Gists via the GitHub API with statistics tracking |
Create ~/.watch+/config.json to set defaults so you don't have to pass flags every time:
{
"resendApiKey": "re_...",
"defaultTo": "alerts@example.com",
"defaultFrom": "watch+@mydomain.com",
"defaultCooldown": "5m",
"defaultInterval": 2
}The Resend API key can also be set via the RESEND_API_KEY environment variable.
Priority: CLI flags > environment variables > config file > defaults
Built with Bun + TypeScript