@easypush/plush
v0.1.3
Published
SDK, CLI, and MCP server for the Plush push notification API.
Maintainers
Readme
easypush
SDK, CLI, and MCP server for Plush.
npm install @easypush/plush
export PLUSH_API_KEY="push_..."
plush login "$PLUSH_API_KEY"
plush send "Build passed" --title "Deploy done" --thread deploy-mainimport { PlushClient } from "@easypush/plush";
const plush = new PlushClient();
await plush.send({
title: "Deploy done",
body: "main is live",
thread_id: "deploy-main",
});
const answer = await plush.askQuestion({
title: "Ship it?",
body: "The build passed. Choose the next step.",
question: { kind: "select", options: ["Ship", "Hold"] },
}, { wait: true });Select questions include an open-ended Other text reply by default, so Codex can offer quick choices while still letting you type a custom answer. Use allowTextResponse: false only for strict fixed-choice prompts.
JSX dashboards:
import { Badge, Progress, Row, Text, Widget } from "@easypush/plush/jsx";
export default function DeployWidget({ progress = 0.68 }) {
return (
<Widget
id="deploy-main"
action="update"
title="Deploy"
family="systemMedium"
families={["systemSmall", "systemMedium", "systemLarge"]}
>
<Row>
<Text weight="bold">Production deploy</Text>
<Badge tone="success">healthy</Badge>
</Row>
<Progress value={progress} label="Rollout" />
</Widget>
);
}Scripted widgets:
--file renders TSX locally and sends JSON. --script registers the TSX source plus a compiled JavaScriptCore bundle and a rendered fallback, so the iOS app/widget extension can re-render it locally with scoped localStorage, optional scoped keychain, fetch, Web API primitives, console, and process runtime info.
plush widget --file .plush/deploy-widget.tsx --props-json '{"progress":0.68}'
plush widget --script .plush/codex-dashboard.tsx --id codex-dashboard --group-id codex --props-json '{"progress":0.72}'
plush live --file .plush/deploy-live.tsx --props-json '{"progress":0.42}'
plush ask --title "Need input" --body "Ship this? Pick one, or type another answer." --option Ship --option Hold --wait
plush send "Work is ready" --title "Codex finished" --thread codex --app-name Codex --app-icon-url https://chatgpt.com/favicon.icoMCP:
[mcp_servers.plush]
command = "npx"
args = ["-y", "@easypush/plush", "mcp"]Run plush login <api-token> once before using plush mcp. MCP requires the saved login and can list devices, send notifications, ask/wait for questions, update/end Live Activities, create/update/delete widgets from JSON or JSX template files, and register_widget_script from JS/TS/JSX/TSX files. Keep agent-authored templates in .plush/ and git-ignore that directory.
Codex Stop hook:
{
"type": "command",
"command": "plush codex-hook",
"statusMessage": "Sending Plush notification",
"timeout": 10
}plush codex-hook reads the Stop-hook JSON from stdin, uses the saved login, sends with app.name = "Codex" plus the Codex icon, uses the Codex thread title as the notification title, keeps the workspace name out of the visible body, deduplicates repeats, and exits quietly if not configured. iOS communication-notification metadata is enabled by default so the Codex avatar can render; set PLUSH_CODEX_COMMUNICATION=0 if you want plain APNs presentation with a normal subtitle instead.
Claude Code Stop hook:
plush install-claude-hookThe installer adds an asynchronous native Stop hook to ~/.claude/settings.json without replacing existing hooks. plush claude-hook reads Claude Code's final assistant message, uses the latest custom session title when available, groups the thread by Claude session, and sends with app.name = "Claude Code" plus the Claude icon. Communication metadata is enabled by default so the Claude avatar can render; set PLUSH_CLAUDE_COMMUNICATION=0 for plain presentation or PLUSH_CLAUDE_ENABLED=0 to disable delivery. Remove it with plush uninstall-claude-hook.
Reply from your phone:
plush patch-codex-appPhone replies are opt-in. Set both PLUSH_CODEX_REPLY=1 and PLUSH_CODEX_FOLLOWUP_SYNC=1 after validating the local watcher on your Mac. When enabled, the local watcher caches the answer locally, sends it through Codex desktop's background thread-follower IPC, and only consumes the Plush queue item after Codex accepts the follow-up. codex://plush/followup remains available after plush patch-codex-app, but the watcher does not consume replies through that fallback path.
Docs: https://easypush.app/doc.md
Claude Code setup: https://easypush.app/claude.md
