Back to Discover

agent-plugin

connector

smoke-signal-app

Phone notifications and phone-answered questions for AI agents: notify and decision-request tools.

View on GitHub
0 starsSynced Aug 12, 2026

Install to Claude Code

/plugin marketplace add smoke-signal-app/agent-plugin

README

Smoke Signal

Smoke Signal agent plugins
Phone notifications from Claude Code, Codex, and any agent that can call a webhook.

What this is

Your agent stops. Your phone tells you.

Claude Code and Codex go silent the moment they need you: a permission prompt, a question, a plan waiting on a yes, a long job that just finished. Smoke Signal puts that on your phone, so stepping away costs nothing.

At your desk it stays quiet. Reply inside the grace window and the alert is cancelled, unsent and unspent.

  • See permission prompts on your phone, not when you come back to a stalled session.
  • Decisions, on Claude Code. Your agent asks a real question and waits. You tap a choice on your phone and it carries on.
  • afk on when you step away. Straight through, no waiting.
  • MCP tools included. notify on both, plus the three Decision tools on Claude Code.
  • Remote control. Pair a computer and start, follow, and interrupt Claude Code or Codex tasks from the app's Remote tab.

Everything is free for individuals; see smokesignal.sh/free. Alerts land in the Smoke Signal app on your phone.

Install

Claude Code:

claude plugin marketplace add smoke-signal-app/agent-plugin
claude plugin install smoke-signal@smoke-signal

Codex:

codex plugin marketplace add smoke-signal-app/agent-plugin
codex plugin add smoke-signal@smoke-signal

Codex has one extra step: restart the app or start a new CLI task, open /hooks, and trust the Smoke Signal hooks.

Connect it

In the Smoke Signal app, open your channel, tap Connect, and under Connect an agent tap Get a pairing code. Hand the code it shows you, something like NXXXX-XXXXX, to your agent:

Claude Code:

/smoke-signal pair NXXXX-XXXXX

Codex, in plain language:

Pair smoke signal with code NXXXX-XXXXX

No terminal, no long secret. Subscribe to your own publisher while you are in the app, or there is nobody to deliver to.

Then see it land:

/smoke-signal test

or ask Codex to test your Smoke Signal notification. /smoke-signal doctor explains anything that comes back wrong. Other ways to connect, including a webhook URL, are further down.

Everyday commands

Claude Code
/smoke-signal pair NXXXX-XXXXX   # connect this machine (code from the app)
/smoke-signal               # overview: health, settings, what you can ask for
/smoke-signal test          # send a real notification now
/smoke-signal pause 2h      # mute everything (default 1h, expires on its own)
/smoke-signal resume        # unmute early
/smoke-signal afk on        # away from keyboard: ping immediately, no waiting
/smoke-signal afk off       # back: grace window and presence checks again
/smoke-signal here off      # never notify for this project (here on undoes it)
/smoke-signal status        # pause state, credit balance, recent sends
/smoke-signal show          # current settings, credentials masked
/smoke-signal presence      # print the current presence verdict
/smoke-signal doctor        # check the whole setup
/smoke-signal update        # update the bridge binary and check the plugin
/smoke-signal remote install    # set up phone-to-computer remote control
/smoke-signal remote on|off     # resume or pause remote control
/smoke-signal remote add-workspace  # register another project folder
/smoke-signal remote resume     # pick up a phone task at the keyboard
/smoke-signal remote uninstall  # remove the bridge completely
/smoke-signal help          # list every argument
Codex

Invoke the skill with /skills, by typing $smoke-signal in the composer, or by asking in plain language ("pause smoke signal for 2 hours"). Every operation is also a CLI command you can run yourself, where SMOKE_SIGNAL is ~/.codex/plugins/cache/smoke-signal/smoke-signal/*/bin/smoke-signal.mjs:

node $SMOKE_SIGNAL pair NXXXX-XXXXX   # connect this machine (code from the app)
node $SMOKE_SIGNAL             # usage
node $SMOKE_SIGNAL test        # send a real notification now
node $SMOKE_SIGNAL pause 2h    # mute everything (default 1h, expires on its own)
node $SMOKE_SIGNAL resume      # unmute early
node $SMOKE_SIGNAL afk on      # away from keyboard: ping immediately, no waiting
node $SMOKE_SIGNAL afk off     # back: grace window and presence checks again
node $SMOKE_SIGNAL here off    # never notify for this project (here on undoes it)
node $SMOKE_SIGNAL status      # pause state, credit balance, recent sends
node $SMOKE_SIGNAL show        # current settings, credential masked
node $SMOKE_SIGNAL doctor      # check the whole setup
node $SMOKE_SIGNAL help        # list every argument

Ask "update Smoke Signal" to check the bridge binary and the plugin for a newer release and walk through updating either.

Remote control is set up by asking Codex itself ("set up Smoke Signal remote control"); the skill installs and drives the smokesignal-codex-bridge daemon, and "remote off", "remote on", "add this workspace to smoke signal", "pick up my phone task", and "remote uninstall" work the same way in plain language.


How it decides when to notify you

  1. The agent blocks: a pending alert is armed, nothing is sent yet.
  2. You reply within the grace window (default 30s): the alert is cancelled.
  3. The grace window runs out, and a presence check decides:
    • screen locked or idle: send now
    • still in the agent's window: cancel, you are already looking at it
    • active elsewhere on the machine: wait, check again in 2 minutes
  4. Only a send reaches your phone.

As long as you are active the window keeps extending, so the alert fires only once you are away. If presence cannot be read at all, the plugin errs on the side of sending: a broken probe never silences a real alert. afk on skips all of this and sends immediately until you run afk off.

Triggers, grace window, presence, and rate limits are all configurable per agent. See Configuration.

Codex: how its lifecycle maps to alerts
Codex signalPlugin behavior
PermissionRequestArms a permission alert
PreToolUse for request_user_inputArms an answer-needed alert
Matching PostToolUseCancels an answered question or completed tool
UserPromptSubmitCancels any pending alert, starts the turn timer
Stop after notify MCP wordingArms an intentional block alert
Stop after a long turnArms a completion alert
SessionEndClears pending state

What the notification says

A plain notification cannot answer the agent, so it tells you what is stalled rather than repeating the question:

my-project · needs an answer Deploy is on hold until you approve the release plan (14:22)

The wording comes from the agent itself via the bundled notify MCP tool, or from the question text as written, or from a fixed fallback. No extra model call is made unless you turn on open-ended stops.

Decisions: reply to your agent

On Claude Code the plugin does more than notify you. A Decision puts a real question on your phone and blocks the agent until you answer it:

my-project · needs a decision Deploy is on hold. Ship now, or hold for the failing test? [ Ship ] [ Hold ]

Where your platform shows notification action buttons, tap one on the notification itself; on iPhone, tap through to the decision screen. The agent picks up where it left off, and an unanswered question expires so it can carry on without you.

The agent drives this with three MCP tools: request_decision to ask, await_decision to block on the answer, cancel_decision to withdraw the question. Codex has none of them yet.

Replies are anonymous, anyone subscribed to the Channel can send one, and the first answer wins. Because of that, questions deserve their own Channel: create one, press Subscribe this Account so you are its only subscriber, and give its key as decision_key. Without one, questions go to your notification Channel and its whole audience.

How much a reply counts for is decision_authority. The default, advice, means the agent takes your answer as input but still re-confirms anything sensitive with you at the keyboard. authorize means it acts on your answer directly, which is the honest setting when you are the only subscriber.

Questions need node; /smoke-signal doctor reports whether the tools loaded.

Remote control: start your agent from your phone

Works with Claude Code and Codex. A small daemon (the bridge) runs on your computer, and the Smoke Signal app's Remote tab can then start a task in a project folder you registered, follow the transcript, reply, and interrupt it while you are away from the machine. Each agent has its own bridge (smokesignal-claude-bridge / smokesignal-codex-bridge), and one computer can run both side by side.

Before a new task starts, the phone shows the models and effort levels offered by that computer. Codex discovers them from its authenticated local App Server and refreshes them daily or after a real reconnect. Claude Code has no truthful machine-readable catalogue, so its setup asks which qualified model IDs and effort levels to offer and installs that stopped-daemon local definition. The selected values are encrypted between the phone Device and bridge, validated again immediately before dispatch, and shown in task history.

Custom Remote integrations use the same select, input, and textarea contract without pretending every integration has a model or effort setting. See the Remote integration guide.

You do not install anything by hand; pick your agent below and it does the rest.

Get started with Claude Code

In Claude Code, run:

/smoke-signal remote install

Get started with Codex

In Codex, just ask: "set up Smoke Signal remote control".

What happens next (both agents)

The agent downloads the right bridge binary for your platform from this repo's releases, verifies its checksum, and walks you through the rest. The binary is not code-signed, so macOS or Windows may warn before letting it run; the verified checksum is what vouches for it, and the agent says so during install. Your part is three things: on your phone open Remote, tap Pair this computer, choose the agent, and read out the code it shows; say which project folders the phone may use; and say yes if you want it to keep running across reboots. Remote codes start with R; notification codes start with N. The agent uses that prefix to select the right pairing flow before it contacts Smoke Signal.

Afterwards (in Claude Code as /smoke-signal remote ..., in Codex in plain language):

remote                 # health and next steps
remote off             # pause remote control (pairing stays)
remote on              # resume it
remote add-workspace   # register another project folder
remote uninstall       # remove the bridge and its pairing completely
update                 # update the bridge binary; checks the plugin too

The phone can only start tasks in folders you registered. The Claude bridge runs Claude with the permission mode and budget caps in its own config file; the Codex bridge runs Codex under the sandbox mode and turn-time cap in its config (Codex reports token counts, not cost, so there is no spend cap -- doctor says so rather than pretending otherwise). Each bridge's doctor reports the whole setup: where the binary is, whether the daemon is running, autostart, pairing, and workspaces.

If the relay pauses remote control

Pairing a computer is free for individuals. Should the relay ever refuse a pairing's entitlement, remote control pauses instead of breaking: the bridge parks itself, polls slowly (the relay tells it how often, normally every 15 minutes), writes one clear line to its log, and doctor shows an entitlement line saying it is parked. A task that was already running gets 24 hours to report its final state. Starting a new task from the phone is refused in the app with the same reason. Nothing needs a restart: once the relay allows the pairing again the bridge resumes on its next poll.

Bridges from v0.4.0 or older do not know this state by name; they retry lapsed claims on their generic backoff (safe, but chattier and with no doctor line). Update the bridge to get the first-class behavior.

Configuration

The defaults are conservative and the plugin rate-limits itself, so your phone is not flooded. Lowering the limits is always safe.

Claude Code

Settings live in ~/.claude/smoke-signal.conf, where every default is documented inline. Change one with /smoke-signal set <key> <value>, or edit the file. For the two credentials, send_key and decision_key, pass - and pipe the value in on stdin so it never reaches a command line or a transcript:

printf '%s' "$DECISION_KEY" | ~/.claude/plugins/cache/smoke-signal/smoke-signal/*/bin/smoke-signal set decision_key -
KeyDefaultWhat it does
grace_seconds30How long to wait for your reply before sending
trigger_ask_user_questiontrueNotify when Claude asks you a question
trigger_exit_plan_modetrueNotify when a plan waits for approval
trigger_permission_prompttrueNotify on permission prompts
trigger_open_endedfalseNotify when Claude ends on an open question
trigger_task_completelongworkNotify when work finishes: longwork, everyturn, or off
long_work_threshold_seconds90What counts as long work
presence_modegateoff disables presence checks, leaving only the grace window
limit_max_per_hour20Never send more than this per hour
limit_min_seconds_between60Never send two alerts closer than this
project_allow / project_deny(empty)Comma-separated path fragments. An empty allow list means every project; deny always wins
decision_key(empty)Channel API key for request_decision; falls back to the notify key when empty
decision_presencewarnWhat request_decision does when you look present: send, warn, or refuse
decision_authorityadviceWhat a reply counts for: advice, or authorize to let the agent act on it directly
originhttps://api.smokesignal.shWhere sends go. Hand-edited only; set origin is refused. See Use your own endpoint

decision_presence: warn sends anyway but tells the agent to prefer asking you in-session, because presence is a heuristic and a false "present" must not eat the question. An unknown reading never gates; it is treated as away, the same rule notify uses.

Codex

Settings live in ~/.codex/smoke-signal.json. Change one with node $SMOKE_SIGNAL set <dotted-key> <value> (the same cache path as in Everyday commands), or read them all with show.

KeyDefaultWhat it does
graceSeconds30How long to wait for your reply before sending
triggers.askUserQuestiontrueNotify when Codex asks you a question and waits
triggers.permissionPrompttrueNotify when Codex routes an approval to you; Auto-review requests are ignored
triggers.inbandBlocktrueNotify when Codex flags a block via the notify tool
triggers.openEndedfalseNotify when Codex ends on an open question
triggers.taskComplete"longwork"Notify when work finishes: longwork, everyturn, or off
longWorkThresholdSeconds90What counts as long work
presence.mode"gate""off" disables presence checks, leaving only the grace window
limits.maxPerHour20Never send more than this per hour
limits.minSecondsBetween60Never send two alerts closer than this
projectAllow / projectDeny[]JSON arrays of path fragments. An empty allow list means every project; deny always wins
origin"https://api.smokesignal.sh"Where sends go. Hand-edited only; set origin is refused. See Use your own endpoint

Other ways to connect

Pairing is the path. These still work.

Prefer your own terminal?
~/.claude/plugins/cache/smoke-signal/smoke-signal/*/bin/smoke-signal pair NXXXX-XXXXX
node ~/.codex/plugins/cache/smoke-signal/smoke-signal/*/bin/smoke-signal.mjs pair NXXXX-XXXXX

The * glob resolves to the installed version, so the command survives updates. From a checkout of this repository, run bin/smoke-signal or codex/plugins/smoke-signal/bin/smoke-signal.mjs directly.

Pasting a webhook URL instead

Copy a credential by hand if you would rather. In your publisher's Sources, create a source named claude-code or codex and copy its webhook URL; a dedicated source can be rotated or revoked without touching your other senders.

That URL is a live credential, so run setup with no argument. It prompts with your typing hidden, which keeps the key out of the session transcript, out of ps, and out of your shell history:

~/.claude/plugins/cache/smoke-signal/smoke-signal/*/bin/smoke-signal setup
node ~/.codex/plugins/cache/smoke-signal/smoke-signal/*/bin/smoke-signal.mjs setup

On Claude Code it then offers the optional decision key described in Decisions; press Enter to skip.

Passing the URL as an argument also works, for scripts, at the cost of it being visible in ps while the command runs and written to your history file afterwards.

A webhook URL for a host this machine does not already send to is refused. See Use your own endpoint.

Use your own endpoint

The server is a setting, not a constant. By default it is Smoke Signal's hosted service, which needs no setup, is free for individuals, and comes with the phone app. Point the plugins at infrastructure you control by editing one line.

No command changes it: set origin is refused and there is no --origin flag. The origin decides which server receives a pairing code and every notification after it, and notifications are composed from your session transcripts. That is a decision you make at a keyboard, not one an agent makes mid-session on the say-so of something it read.

In ~/.claude/smoke-signal.conf:

origin = https://your-server.example

or in ~/.codex/smoke-signal.json:

{ "version": 1, "origin": "https://your-server.example" }

Pairing keeps that origin and fills in the rest; every other setting takes its default until you add it. On a machine that is already paired, change the line and pair again. Pairing prints a [warn] naming the host whenever the origin is not the default, so a file you did not edit yourself is visible the moment it is used.

A pasted webhook URL is held to the same rule. Its host never becomes the origin, so a URL for your own host is refused until the config file says so. A bare smk_ key carries no host and keeps whichever origin is already set.

The origin must be https://; plain http:// is allowed only on localhost and 127.0.0.1. Your server implements the same small API the hosted service exposes, documented at smokesignal.sh/docs:

  • POST {origin}/api/v1/agent-setup/exchange trades a pairing code for a key. Unauthenticated, since the code is the credential: body {"code": "..."}, answer {"origin", "api_key", "webhook_url", "channel_name"}, and 404 for a code that is unknown, expired, or already spent.
  • POST {origin}/webhooks/v1/notifications/{key} sends a notification.
  • POST {origin}/api/v1/decisions creates a question.
  • POST {origin}/api/v1/decisions/{id}/reply/claim?wait={seconds} long-polls for the answer and claims it. The hosted service bounds wait to 25 seconds and the client loops, so a long wait is many claims, not one long request.
  • DELETE {origin}/api/v1/decisions/{id} cancels a question.

Credentials go in the last path segment (webhook) or an Authorization: Bearer header (Decisions), and the client only accepts keys starting with smk_, so mint yours in that shape. One key serves both, which is why pairing can settle the whole configuration in one answer. Everything else runs on your machine and works identically against any origin.

Requirements

Every install needs a pairing code from the app, or a webhook URL, plus a subscription to your own publisher on your phone.

Claude Code
  • bash and curl. That is all the hooks need.
  • jq (optional) for better question extraction.
  • node (optional) enables the notify MCP tool for the best wording, and is required for request_decision, await_decision, and cancel_decision, which have no fallback.
  • claude on PATH (optional), used only for open-ended stops.

/smoke-signal doctor reports what is present and what each absence costs.

Codex
  • Node.js 18 or newer. The plugin uses only the standard library.
  • Codex CLI 0.145.0 or the matching desktop app, with plugin and hook support enabled.

Dependencies (Linux only)

macOS and Windows need nothing extra. On Linux, presence detection reads idle time with xprintidle (X11 only) and lock state with loginctl (part of systemd, already on most distros):

sudo apt install xprintidle   # or your distro's equivalent

Without it the plugin still works, in the louder direction: a probe that cannot read presence never suppresses an alert.

Known limitations

  • After a phone reboot, nothing arrives until you open the Smoke Signal app. The send succeeds all the way through, but iOS shows nothing.
  • No retraction. Answered alerts stay on your phone until you dismiss them. Each carries a timestamp so a stale one looks stale.
  • Two sessions in one directory can mix up MCP wording. That source is matched by working directory and dropped after 120 seconds; all other sources are per session.
  • Presence detection works best on macOS. Linux needs xprintidle (X11 only) and loginctl; Windows uses PowerShell probes. A failed probe never suppresses an alert.
Claude Code
  • On Windows the watcher cannot verify the session is still alive, so a hard kill mid grace window can produce one notification for a dead session.
  • Claude Code's notification_type values are not a stable enum. Unknown types are logged, not acted on, and show up in doctor.
  • No node, no Decision tools, no fallback. notify degrades gracefully without node; the three Decision tools do not exist at all. doctor reports the absence without echoing the decision key.
Codex
  • Approving a slow command can still ping you. Codex has no "approval answered" event, so the plugin cancels when the approved tool finishes. A command that outruns the grace window can notify about a prompt you already answered.
  • Plugins work in the Codex desktop app and CLI, not the Codex IDE extension.

FAQ

Does Smoke Signal work with Claude Code and Codex? Yes, as separate plugins installed from this one marketplace.

Is it free? Everything is free for individuals. Paid plans will come later, for teams and large channels only. See smokesignal.sh/free.

Is it safe to type a pairing code in front of my agent? Yes, that is what it is for. A code works once and expires in minutes, so it is worthless the moment it is redeemed. It buys a key this machine keeps to itself, written to ~/.claude/smoke-signal.conf (Codex: ~/.codex/smoke-signal.json) and never displayed. A refused code has been used or has timed out; mint a fresh one rather than retrying it.

Can I reply to my agent from my phone? On Claude Code, yes: that is what a Decision is. The agent calls request_decision, your phone shows the question with its choices, and the first answer wins. Codex support is not there yet.

Will it notify me while I am at my desk? No. The grace window plus a presence check suppress alerts while you are active on the machine.

Do I have to use Smoke Signal's servers? No. See Use your own endpoint.

Does it send my code anywhere? No. Only a short notification title, body, and link. Your credential is passed to curl through a config file on stdin, never on a command line, so it stays out of ps and your shell history.

License

MIT. See LICENSE.

Rendered live from smoke-signal-app/agent-plugin's GitHub README — not stored, always reflects the source repo.

1 Install Method

NameDescriptionCategorySource
mcpb packageInstall via mcpb (stdio transport)mcp-serverhttps://github.com/smoke-signal-app/agent-plugin/releases/download/v0.4.2/smoke-signal.mcpb

0 Comments

Login required
Log in to post a comment or update on this repo.

No comments yet — be the first to share an update.