Hwip Docs
CLI & SDK

Command Reference

Every hwip command, its flags, exit codes, and environment variables.

# Send a notification
hwip notify --title "Deploy done" --body "v2.1.0 shipped"

# Send with priority
hwip notify --title "Build failed" --priority high --url https://ci.example.com/123

# Send to a channel you own
hwip channel list
hwip notify --channel Releases --title "v2.1.0" --body "shipped"

# List recent pushes
hwip list
hwip list --limit 10 --type note

# Dismiss a push
hwip dismiss push_01JXY...
hwip dismiss --all

# Rename the current agent session (shows in the app's Agents list)
hwip rename "Prod deploy"
hwip rename --clear                # reset to the default name

# Type a message into another agent session, here or on another computer
hwip agent send dev_listener_ab12cd34:hwip-api "Build is green — rerun the e2e suite"
hwip agent send hwip-api "…"       # a name or alias works when it names one session

# See which agent sessions run on THIS computer, and what one did last
hwip agent list                    # KEY  AGENT  STATE  NAME; --json for scripts
hwip agent read hwip-api           # its last 3 turns: prompt, the agent's text, tool names

# Drop an ended session from this machine's record
hwip forget --ended

# Test connection
hwip test

# Run an agent in a named tmux session, so the listener can reach it
hwip cc                       # claude
hwip codex                    # codex
hwip gemini                   # gemini
hwip pi                       # pi
hwip opencode                 # opencode
hwip cc --wt feat/x           # claude in a new git worktree + branch

# Start an agent session on a timer (the listener starts it)
hwip schedule add cc --at 09:00 --days weekdays --prompt "Triage the open issues"
hwip schedule

# Run the resident listener (foreground; background it as you like)
hwip listener
hwip listener --ws-url wss://...   # override config

# JSON output
hwip notify --title "Hello" --json

Commands

CommandDescription
loginBrowser sign-in: fetches the API key and hook into ~/.hwip/config.json over a localhost loopback (--web-url, --timeout, --allow-host). No copy-paste. Over SSH it prints the URL and the ssh -L line that forwards the callback port, so a browser on your own machine can finish the login
install (alias: setup)One-command setup: detect agents, save config, install rules, hooks, and MCP. With no saved config it opens browser login automatically. --only claude,cursor,… skips the picker (cc = claude; an unknown id is a usage error). With no terminal for the picker it is a usage error, so pass --key for a scripted install
uninstallRemove Hwip from each detected agent and stop the listener (--dry-run, --purge). Asks first when stdin is a terminal; --yes skips the question
verifyCheck installation health across detected agents (--ping for a live API call, --json for one JSON object). Reports whether tmux is on PATH and whether the listener is running, the resolved WebSocket URL and where it came from, and the last failed push, if any
check-updateCheck whether a newer Hwip version is on npm
notifySend a push notification. --channel <id or name> sends to a channel you own
channel listList the channels you own and follow, each marked yours or following. Only an owner can send
askAsk the phone a question and wait for the answer, for hooks that cannot call the MCP hwip_ask tool. --title (required), --body, --actions id:Label,…, --timeout <s> (default 60), --accepts-exit. Prints one JSON line: {"answered":true,…} or {"answered":false,"reason":"cancelled"|"timeout"|"error"}. Exit 0 if answered, 1 if not. The question and the answer travel sealed
ask-context [status|on|off|show] [--global]The switch for the git diff and terminal lines a sealed question carries. On unless turned off, per project or with --global
file-view [status|on|off|log] [--global]The switch for the app browsing this computer's session files. On unless turned off. log prints the last 50 reads the app made
listList recent push notifications. An encrypted push this host cannot open reads [encrypted]
dismiss <id>Dismiss a push, or --all
rename <name>Set the current agent session's display name in the app. Run it inside a hwip cc session, or name one with --session <name>; --clear resets. It auto-detects the tmux session and this machine's listener device id (--device <id> picks another machine)
agent send <target> <message…>Type a message into another agent session, on this machine or another, as if you sent it from the app. target is a <deviceId>:<session> key or a name or alias that names exactly one session. The message is always sealed, and a - as the message reads it from stdin. Exit 0 means the server stored it, not that it was typed
agent list [--json]List the agent sessions running on this machine: key, agent, state (working, blocked, idle, unknown) and name. Local only: no server, no API key
agent read <session> [--turns <n>] [--json]Print what a session on this machine did last: its last <n> turns (1–20, default 3). Prompts, the agent's text, and tool names with their target, never tool output. Secret-looking strings are masked, best effort. Works for agents with a transcript reader (Claude Code, Codex, Gemini CLI, pi, OpenCode)
send <target> <message…>The older name of agent send
forget <session>Drop an ended session from this machine's record so it leaves the app's past list. Refuses a running session. --ended forgets every remembered session tmux no longer has
testSend a test push to confirm the API key and connection work. Your devices actually buzz
trust [deviceId]Show this computer's key fingerprint and the pinned devices; with a deviceId, pin the key the account now lists for it; --reset forgets every pin. See Encryption
cc · codex · gemini · cursor · hermes · pi · opencode · kimi · grok · agy · qwen · auggie · kilo · copilot · kiro-cli · droidRun the agent in a hwip-<project> tmux session, reattaching a detached session of that project when there is one, else auto-suffixing -2, -3, …. Auto-spawns the background listener on first invocation. Trailing arguments pass through to the agent. --detach / --label <x> / --wt <name> go at the front of the args. cursor launches cursor-agent, not the IDE
worktree [clean]List the git worktrees --wt made, and what keeps each. clean removes the ones nothing keeps; --dry-run removes nothing
scheduleStart an agent session on a timer. schedule add <agent> (--at HH:MM | --every <N>m|<N>h) [-- <agent args…>], schedule [list] (--json), schedule rm <id>. Options: --days, --prompt, --label, --wt, --max-runtime. See Remote control
shOpen (or reattach) hwip-<project>-sh, a login shell the app may type into. See Remote control
mcpRun the MCP server on stdio, in this process. What agent MCP configs launch; hwip install registers it and you never type it
listenerUsually unnecessary, since hwip cc autospawns it. Resident daemon: subscribes via WebSocket, reports tmux session inventory, injects agent.command pushes into the matching session
remote-hook <agent>Not run by hand. The prompt-submit hook that hwip install wires into Codex, Gemini and pi calls it to flag a message as app-injected. See Remote control

Notify options

FlagDescription
--title <text>Push title (default: "Task done")
--body <text>Push body (default: "<project> · <branch>" if cwd is a git repo, else "<project>")
--url <url>URL to include
--type <type>Push type: note, link, file, hook
--priority <p>Priority: low, normal, high, urgent
--device <id>Target device ID
--session <id>Agent session ID, so the push threads into that session's chat (or the HWIP_SESSION_ID env var)
--channel <id|name>Send to a channel you own. A channel push is plain text and needs --title or --body; it does not combine with --auto, --device or --session. The API key needs the channel:read and push:write scopes
--autoApply the push gate before sending. Honors the /hwip-mode quiet and /hwip-mode loud push-mode dial, per project or machine-wide with --global. A gated-out push exits silently with code 0
--pushmode-default <m>The mode --auto assumes when the project has no dial: quiet (built-in), normal, or loud. A dial the user set always wins
--marker <m>Push Signal marker for --auto: skip, push, high
--tools <n>, --nonreadonly <n>Turn tool counts feeding --auto's heuristic (the defaults assume real work)

The defaults are tuned for hook-driven invocations, for example a Stop hook calling hwip notify --title "Task done" with no body. You see which project and branch finished without writing per-IDE wrappers. Pass --body "" explicitly to suppress it.

Listener options

FlagDescription
--ws-url <url>WebSocket endpoint for this run only; the lasting setting is wsUrl in ~/.hwip/config.json. It must be a ws:// or wss:// URL
--key <api-key>API key (or the HWIP_API_KEY env var)
--base-url <url>REST API base URL (or the HWIP_BASE_URL env var, or baseUrl in ~/.hwip/config.json)
--stopStop the running daemon and clear its PID and version stamps
--restartStop it and relaunch detached, logging to ~/.hwip/listener.log
--install-service · --uninstall-service · --service-statusStart the listener at every login (launchd on macOS, a systemd user unit on Linux). See Remote control
--no-keep-awakeDon't hold the Mac awake on AC power. Lasting form: "keepAwake": false in ~/.hwip/config.json
--no-turn-historyDon't upload session conversations for the app's history. Lasting form: "turnHistory": false in ~/.hwip/config.json

The listener reconnects with exponential backoff plus jitter, from 1 second to a 30-second cap. On an authentication failure close (4001, 4002, 4003) it exits with code 3 instead of looping forever: fix the key and restart.

List options

FlagDescription
--limit <n>Number of pushes (1–20, default 5)
--type <type>Filter by push type

Global options

A flag that takes a value takes the next word whatever it looks like, so text nobody typed (a command to approve, a model's message) cannot set a flag of hwip's. -- ends hwip's flags. After an agent subcommand such as hwip cc, the words go to the agent untouched.

FlagDescription
--key <api-key>API key (or the HWIP_API_KEY env var)
--base-url <url>API base URL (or the HWIP_BASE_URL env var)
--jsonOutput JSON format
--versionPrint version
--help, -hPrint usage. With a command (hwip notify --help, or hwip help notify) it prints that command's own usage

Mute and push mode

Both live as state files under ${XDG_STATE_HOME:-~/.local/state}/hwip, keyed by a cksum hash of the project directory. Claude Code's /hwip-mode mute, /hwip-mode quiet, /hwip-mode loud, and /hwip-mode normal write them; the CLI reads them: mute on every notify, push mode on --auto.

Notifications are silently skipped when a mute file exists for the current project:

STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/hwip"
HASH=$(printf '%s' "$PROJECT_DIR" | cksum | cut -d' ' -f1)

# Mute (created by /hwip-mode mute in the Claude Code plugin)
mkdir -p "$STATE_DIR" && touch "$STATE_DIR/muted-$HASH"

# Unmute
rm -f "$STATE_DIR/muted-$HASH"

Push mode is a one-word file (quiet, loud, or normal) resolved in this order, first hit wins:

OrderFileSet by
1$STATE_DIR/pushmode-<hash>/hwip-mode quiet · /hwip-mode loud · /hwip-mode normal
2/tmp/hwip-pushmode-<hash>Older versions, honored only when you own the file
3$STATE_DIR/pushmode-defaultThe --global form of any dial, the machine-wide default
4--pushmode-default <mode>The calling hook (the installed ones pass normal)
5(nothing above)quiet

Row 4 sits below the state files on purpose: the flag names a default, it does not override a dial you set. A dial file that exists but reads empty resolves to normal, not to row 5.

Mute has no -default form on purpose: it is keyed on presence, not content, so a global mute could never be lifted for a single project.

Quiet while away

quiet silences routine pushes because you are watching the pane. When you have walked away, notify --auto under quiet still sends the push (normal priority). It decides you are away when no tmux client is attached, or when input has been idle longer than HWIP_AWAY_SEC seconds (default 300; 0 turns detection off). Anything it cannot read counts as present.

The CLI checks CLAUDE_PROJECT_DIR, CURSOR_PROJECT_DIR, and WINDSURF_PROJECT_DIR, and falls back to the cwd.

Last push failure

Installed hooks run hwip notify … 2>/dev/null || true, so a failed push leaves nothing on screen. hwip notify, hwip test, and the test push hwip install sends therefore record the last failure in ${XDG_STATE_HOME:-~/.local/state}/hwip/last-notify-failure.json and delete it once a push goes through. kind is one of no-key, auth, quota, rate-limit, client, server, timeout, network, no-app, unsealed. No message text, key or push content is stored. hwip verify shows it under Push delivery.

Exit codes

CodeMeaning
0Success
1General error. Also: ask got no answer, verify has a failed check, install has a failed step, uninstall answered no
2Quota exceeded. Also a usage error (agent send, agent list, agent read, rename, forget, bad agent-subcommand flags, install with no terminal for the picker)
3Authentication failed, or no API key (also: listener auth close 4001, 4002, 4003)
127A required external binary such as tmux or claude was not found on PATH

Environment variables

VariableDescription
HWIP_API_KEYAPI key, used when --key is not provided
HWIP_HOOK_IDHook ID for the MCP server's two-way tools (hwip_ask and friends); hookId in ~/.hwip/config.json does the same
HWIP_BASE_URLAPI base URL (default: https://api.hwip.app/v1). With the key from ~/.hwip/config.json it must be on the same origin as that file's baseUrl, otherwise set HWIP_API_KEY too
HWIP_WS_URLDeprecated. WebSocket endpoint. wsUrl in ~/.hwip/config.json wins over it; it is read only when the file has none, and it will stop being read
HWIP_TMUX_SOCKETExplicit tmux socket path for the listener, skipping auto-discovery. Use it when your tmux runs with -L <name> or a custom -S <path>
HWIP_SESSION_IDAgent session ID, used when --session is not provided
HWIP_ASK_CONTEXT0, false, off or no switches off the question context for that run
HWIP_FILE_VIEW0, false, off or no, in the listener's environment, switches off the app's access to session files for that run
HWIP_AWAY_SECSeconds of idle input before quiet counts you as away (default 300, 0 = off)
HWIP_NO_UPDATE_CHECKSkip the once-a-day npm update check that hwip cc makes (also skipped when CI is set)
HTTPS_PROXY · HTTP_PROXY · NO_PROXYRoute API calls and the listener's socket through a proxy. A listener installed as a service does not see the shell's variables; it reads "httpsProxy", "httpProxy" and "noProxy" from ~/.hwip/config.json instead. The environment wins, one setting at a time

On this page