nudge 0.1.0 a CLI for macOS
Let your AI agent show you things.
curl -fsSL https://nudge.reintelligence.live/install.sh | sh
$ nudge -m "Here's the signup chart you asked for" chart.png
A preview window opens on the Mac. You look, press Download, close it.{"status":"saved","saved":["/Users/me/Downloads/chart.png"]}
$ some-tool --render-png | nudge -m "Latest traffic" -
You glance at it and close the window.{"status":"dismissed","saved":[]}
$
How it works
-
The agent runs nudge
An AI agent such as Claude Code, or any script, runs
nudge -m "why" file…on your Mac. Several files can go in one call. -
A window opens on your Mac
A native preview, with the agent's note on top. You can Download a copy, Save As… somewhere else, or Open it in its default app.
-
The agent reads the result
When you close the window, nudge prints one line of JSON: whether you kept a copy, and the absolute path of each one.
For AI agents
Add this to your agent's instructions file or system prompt.
To show the user a file (image, PDF, chart, report, HTML, …), run `nudge`:
- `nudge -m "<one line on why>" <file>...` opens a preview window on their desktop
and waits until they close it, then prints JSON like
`{"status":"saved","saved":["/Users/…/Downloads/x.png"]}`.
- Pipe generated content with `<cmd> | nudge --name result.png -`.
- If your shell tool has a timeout, add `--timeout 300`, or use
`--detach --result-file /tmp/nudge.json` and read that file later.
- status `saved` means they kept a copy; `dismissed` means they closed it.
- Run `nudge --list-sounds` once and add `--open-sound <name>` with the sound that
fits the moment (e.g. `done`, `need-your-input`).
Features
Any Quick Look format
Images, PDFs, text, code, Markdown, JSON, HTML, video, audio and Office files: anything Quick Look understands.
Save
Save As… picks a place. Download copies into ~/Downloads. Or drag the icon out of the title bar.
Sounds
Name your sound files done.mp3 or need-your-input.mp3, and agents pick the one that fits when a window opens.
Reads stdin
Pipe generated content in with -. nudge detects PNG, JPEG, GIF, WebP, HEIC, PDF, SVG, HTML, JSON and text.
$ curl -s https://example.com/chart.png \
| nudge -m "Latest traffic" -
Timeout and detach
--timeout closes the window on its own. --detach returns at once, and --result-file collects the outcome later.
$ nudge --detach --timeout 600 \
--result-file /tmp/r.json build/index.html
{"status":"shown","saved":[],"pid":6272}
Install
$ curl -fsSL https://nudge.reintelligence.live/install.sh | sh
Downloading nudge 0.1.0…
Installed nudge 0.1.0 to ~/.local/bin/nudge.
Added ~/.local/bin to your PATH in ~/.zshrc. Open a new terminal to use it.
Try it: nudge -m "Hello from nudge"
Installer
- Checks for macOS 13+ on Apple Silicon.
- Downloads the latest release and verifies its SHA-256.
- Installs to
~/.local/bin/nudge, without sudo. - Adds
~/.local/binto yourPATHif needed.
| Installer option | Effect |
|---|---|
NUDGE_INSTALL_DIR=<dir> | Install somewhere else |
NUDGE_NO_MODIFY_PATH=1 | Leave your shell profile alone |
NUDGE_VERSION=<version> | Install a specific version |
Uninstall
nudge --uninstall
Usage
nudge [options] <file>..., <command> | nudge [options] - or nudge --message <text>. By default nudge waits until the window closes.
# show a file and wait for the window to close
$ nudge report.pdf
# several files in one window, with a note on top
$ nudge -m "Which logo do you prefer?" logo-a.png logo-b.png logo-c.png
# content from stdin; the type is detected
$ curl -s https://example.com/chart.png | nudge -m "Latest traffic" -
# stdin with an explicit name
$ some-tool --svg | nudge --name diagram.svg -
# just a message, with an OK button
$ nudge -m "The deploy finished."
# return at once; collect the result later
$ nudge --detach --timeout 600 --result-file /tmp/r.json build/index.html
| Option | What it does |
|---|---|
-m, --message <text> | Note shown above the preview, e.g. why you're showing it |
-t, --title <text> | Window title (default: the file name) |
-d, --save-dir <dir> | Folder Download copies into (default: $NUDGE_SAVE_DIR, else ~/Downloads) |
-n, --name <name> | File name for stdin content (default: nudge-<time>.<type>, with the type detected from the content) |
--timeout <seconds> | Close the window automatically after this long |
--detach | Don't wait: print {"status":"shown","pid":…} and return |
--result-file <path> | Also write the final JSON result to this file (lets you collect the outcome after --detach) |
--open-sound <sound> | Play a sound when the window opens: a name from your sounds folder, a macOS sound like Glass, or the path to an audio file. Default: $NUDGE_OPEN_SOUND; none = off |
--list-sounds | List the sounds you can play by name |
--on-top | Keep the window above other windows |
--update | Update nudge to the latest version |
--uninstall | Remove nudge and the PATH line its installer added |
-h, --help | Show the help |
-v, --version | Show the version |
| In the window | Key |
|---|---|
| Download | ⌘S |
| Save As… | ⇧⌘S |
| Open in default app | ⌘O |
| Previous / next file | ⌘[ ⌘] |
| Close | Esc or ⌘W |
| Environment | Meaning |
|---|---|
NUDGE_SAVE_DIR | Folder Download copies into (default ~/Downloads) |
NUDGE_OPEN_SOUND | Sound for every window; --open-sound overrides it |
NUDGE_SOUNDS_DIR | Your sound folder (default ~/.config/nudge/sounds, or $XDG_CONFIG_HOME/nudge/sounds) |
Sounds
--open-sound plays a sound when the window opens: a name from your sound folder (~/.config/nudge/sounds), a built-in macOS sound, or the path to an audio file. --open-sound none silences one call.
$ nudge --list-sounds
Sounds in ~/.config/nudge/sounds (play one with --open-sound <name>):
done
need-your-input
Built-in: Basso, Blow, Bottle, Frog, Funk, Glass, Hero, Morse, Ping, Pop, Purr, Sosumi, Submarine, Tink
$ nudge --open-sound need-your-input -m "Which option should I go with?" a.pdf b.pdf
# in your shell profile: a sound on every nudge
export NUDGE_OPEN_SOUND=done
Result
When the window closes, nudge prints one line of JSON. With --result-file, the same line also goes to that file.
{"status":"saved","saved":["/Users/me/Downloads/chart.png"]}
{"status":"dismissed","saved":[]}
{"status":"timeout","saved":[]}
{"status":"interrupted","saved":[]}
{"status":"shown","saved":[],"pid":6272}
| status | Meaning |
|---|---|
saved | You downloaded or saved at least one copy, then closed the window |
dismissed | Closed without saving |
timeout | --timeout ran out |
interrupted | nudge received SIGINT, SIGTERM or SIGHUP |
shown | --detach: the window is open and nudge returned right away |
| Exit | Meaning |
|---|---|
0 | The window was shown, whatever the person did |
1 | Error: missing file, empty stdin, no desktop session, unplayable --open-sound |
2 | Bad usage |
savedlists every copy, Download and Save As… alike, as absolute paths. It's kept on timeout and interrupt too.- Opening the file in its default app isn't reported; status covers copies only.
- Errors print no JSON. The message goes to stderr, e.g.
nudge: no such file: /nope.png.