Command Palette

Search for a command to run...

UnylyUnyly
Browse all

Agent Plugin

FreeNot checked

Let your coding agent notify you, when you are needed. Smoke Signal Codex & Claude plugin.

GitHubEmbed

About

Let your coding agent notify you, when you are needed. Smoke Signal Codex & Claude 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.

Free every week: every account gets a credit allowance, 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 ABCDE-FGHIJ, to your agent:

Claude Code:

/smoke-signal pair ABCDE-FGHIJ

Codex, in plain language:

Pair smoke signal with code ABCDE-FGHIJ

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 ABCDE-FGHIJ   # 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
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 ABCDE-FGHIJ   # 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

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 spends a credit.

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 signal Plugin behavior
PermissionRequest Arms a permission alert
PreToolUse for request_user_input Arms an answer-needed alert
Matching PostToolUse Cancels an answered question or completed tool
UserPromptSubmit Cancels any pending alert, starts the turn timer
Stop after notify MCP wording Arms an intentional block alert
Stop after a long turn Arms a completion alert
SessionEnd Clears 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.

Configuration

Every send costs credits, one per subscriber, so the defaults are conservative and the plugin rate-limits itself. 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 -
Key Default What it does
grace_seconds 30 How long to wait for your reply before sending
trigger_ask_user_question true Notify when Claude asks you a question
trigger_exit_plan_mode true Notify when a plan waits for approval
trigger_permission_prompt true Notify on permission prompts
trigger_open_ended false Notify when Claude ends on an open question
trigger_task_complete longwork Notify when work finishes: longwork, everyturn, or off
long_work_threshold_seconds 90 What counts as long work
presence_mode gate off disables presence checks, leaving only the grace window
limit_max_per_hour 20 Never send more than this per hour
limit_min_seconds_between 60 Never 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_presence warn What request_decision does when you look present: send, warn, or refuse
decision_authority advice What a reply counts for: advice, or authorize to let the agent act on it directly
origin https://api.smokesignal.sh Where 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.

Key Default What it does
graceSeconds 30 How long to wait for your reply before sending
triggers.askUserQuestion true Notify when Codex asks you a question and waits
triggers.permissionPrompt true Notify when Codex routes an approval to you; Auto-review requests are ignored
triggers.inbandBlock true Notify when Codex flags a block via the notify tool
triggers.openEnded false Notify when Codex ends on an open question
triggers.taskComplete "longwork" Notify when work finishes: longwork, everyturn, or off
longWorkThresholdSeconds 90 What counts as long work
presence.mode "gate" "off" disables presence checks, leaving only the grace window
limits.maxPerHour 20 Never send more than this per hour
limits.minSecondsBetween 60 Never 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 ABCDE-FGHIJ
node ~/.codex/plugins/cache/smoke-signal/smoke-signal/*/bin/smoke-signal.mjs pair ABCDE-FGHIJ

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 and comes with free weekly credits and 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 there a free tier? Yes, a credit allowance every week; 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.

from github.com/smoke-signal-app/agent-plugin

Installing Agent Plugin

This server has no published package — it is built from source. Open the repository and follow its README.

▸ github.com/smoke-signal-app/agent-plugin

FAQ

Is Agent Plugin MCP free?

Yes, Agent Plugin MCP is free — one-click install via Unyly at no cost.

Does Agent Plugin need an API key?

No, Agent Plugin runs without API keys or environment variables.

Is Agent Plugin hosted or self-hosted?

Self-hosted: the server runs locally on your machine via the install command above.

How do I install Agent Plugin in Claude Desktop, Claude Code or Cursor?

Open Agent Plugin on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.

Related MCPs

Compare Agent Plugin with

Not sure what to pick?

Find your stack in 60 seconds

Author?

Embed badge for your README

Browse similar

All development MCPs