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" --jsonCommands
| Command | Description |
|---|---|
login | Browser 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 |
uninstall | Remove Hwip from each detected agent and stop the listener (--dry-run, --purge). Asks first when stdin is a terminal; --yes skips the question |
verify | Check 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-update | Check whether a newer Hwip version is on npm |
notify | Send a push notification. --channel <id or name> sends to a channel you own |
channel list | List the channels you own and follow, each marked yours or following. Only an owner can send |
ask | Ask 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 |
list | List 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 |
test | Send 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 · droid | Run 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 |
schedule | Start 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 |
sh | Open (or reattach) hwip-<project>-sh, a login shell the app may type into. See Remote control |
mcp | Run the MCP server on stdio, in this process. What agent MCP configs launch; hwip install registers it and you never type it |
listener | Usually 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
| Flag | Description |
|---|---|
--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 |
--auto | Apply 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
| Flag | Description |
|---|---|
--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) |
--stop | Stop the running daemon and clear its PID and version stamps |
--restart | Stop it and relaunch detached, logging to ~/.hwip/listener.log |
--install-service · --uninstall-service · --service-status | Start the listener at every login (launchd on macOS, a systemd user unit on Linux). See Remote control |
--no-keep-awake | Don't hold the Mac awake on AC power. Lasting form: "keepAwake": false in ~/.hwip/config.json |
--no-turn-history | Don'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
| Flag | Description |
|---|---|
--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.
| Flag | Description |
|---|---|
--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) |
--json | Output JSON format |
--version | Print version |
--help, -h | Print 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:
| Order | File | Set 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-default | The --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
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | General error. Also: ask got no answer, verify has a failed check, install has a failed step, uninstall answered no |
| 2 | Quota exceeded. Also a usage error (agent send, agent list, agent read, rename, forget, bad agent-subcommand flags, install with no terminal for the picker) |
| 3 | Authentication failed, or no API key (also: listener auth close 4001, 4002, 4003) |
| 127 | A required external binary such as tmux or claude was not found on PATH |
Environment variables
| Variable | Description |
|---|---|
HWIP_API_KEY | API key, used when --key is not provided |
HWIP_HOOK_ID | Hook ID for the MCP server's two-way tools (hwip_ask and friends); hookId in ~/.hwip/config.json does the same |
HWIP_BASE_URL | API 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_URL | Deprecated. 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_SOCKET | Explicit 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_ID | Agent session ID, used when --session is not provided |
HWIP_ASK_CONTEXT | 0, false, off or no switches off the question context for that run |
HWIP_FILE_VIEW | 0, false, off or no, in the listener's environment, switches off the app's access to session files for that run |
HWIP_AWAY_SEC | Seconds of idle input before quiet counts you as away (default 300, 0 = off) |
HWIP_NO_UPDATE_CHECK | Skip the once-a-day npm update check that hwip cc makes (also skipped when CI is set) |
HTTPS_PROXY · HTTP_PROXY · NO_PROXY | Route 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 |