Agent Plugin
FreeNot checkedLet your coding agent notify you, when you are needed. Smoke Signal Codex & Claude plugin.
About
Let your coding agent notify you, when you are needed. Smoke Signal Codex & Claude plugin.
README
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 onwhen you step away. Straight through, no waiting.- MCP tools included.
notifyon 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
- The agent blocks: a pending alert is armed, nothing is sent yet.
- You reply within the grace window (default 30s): the alert is cancelled.
- 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
- 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/exchangetrades a pairing code for a key. Unauthenticated, since the code is the credential: body{"code": "..."}, answer{"origin", "api_key", "webhook_url", "channel_name"}, and404for a code that is unknown, expired, or already spent.POST {origin}/webhooks/v1/notifications/{key}sends a notification.POST {origin}/api/v1/decisionscreates a question.POST {origin}/api/v1/decisions/{id}/reply/claim?wait={seconds}long-polls for the answer and claims it. The hosted service boundswaitto 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 thenotifyMCP tool for the best wording, and is required forrequest_decision,await_decision, andcancel_decision, which have no fallback.claudeon 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.0or 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) andloginctl; 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_typevalues are not a stable enum. Unknown types are logged, not acted on, and show up indoctor. - No node, no Decision tools, no fallback.
notifydegrades gracefully without node; the three Decision tools do not exist at all.doctorreports 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.
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-pluginFAQ
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
GitHub
PRs, issues, code search, CI status
by GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
by mcpdotdirectCompare 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
