Slack notifications plugin for Paperclip - posts to Slack when issues are created, completed, or need approval
TypeScript
55
83 commits
updated Sep 10, 2026
Slack Chat OS plugin for Paperclip. Turns Slack into a bidirectional agent command center - notifications, approvals, multi-agent threads, voice-to-task pipelines, custom workflow commands, and proactive agent suggestions.
Built on the Paperclip plugin SDK and the domain event bridge (PR #909).
Multiple Paperclip users asked for notifications on the same day the plugin system shipped (2026-03-14):
"is there a way to have codex/claude check paperclip to see when tasks are done without me prompting it?" - @Choose Liberty, Discord #dev
"basically to have it 'let me know when its done'" - @Choose Liberty, Discord #dev
"can claude code check paperclip to see when tasks are done" - @Nascozz, Discord #dev
@dotta (maintainer) responded: "we're also adding issue-changed hooks for plugins so when that lands someone could [make notifications]." The event bridge (PR #909) shipped that same day. @dotta also asked for "someone to make a plugin that's a totally separate package" to validate the DX. @Ryze said "Really excited by the plugins. I had developed a custom plugin bridge that I will now deprecate and migrate over to the new supported plugin system."
This is that plugin.
Notifications (rich Block Kit formatting)
Interactive approvals
slack:{user_id})Issue-thread confirmations
request_confirmation issue interactions to Slack with Accept/Reject buttonsHITL escalation
escalate_to_human tool for agentsPer-type channel routing
Daily digest
cost_event.created events throughout the daymaxAgentsPerThread (default 5) agents in a single Slack thread via /clip acp spawn <agent> [display_name]handoff_to_agent tool lets one agent request a handoff to another with Approve/Reject buttons in-threaddiscuss_with_agent tool starts a back-and-forth conversation between two agents with configurable max turns/clip acp status - Show all active agents in the current thread/clip acp close [name] - Close a specific agent or the most recently active onewhisper-transcriber agent for speech-to-textprocess_media tool - Agents can programmatically trigger media processing with an optional briefAgentIdfile_shared events trigger the pipeline automatically!command syntax - Type !deploy staging or !triage bug-123 in any thread to trigger registered workflowsinvoke_agent, post_message, create_issue, wait_approval$1, $2, or $args in step templates to pass user argumentsregister_command tool - Agents or admins can register new commands at runtimewait_approval steps pause execution with Approve/Reject buttons/clip commands - List all registered custom commands with descriptions and usageregister_watch tool sets up a trigger: when an event matching a pattern fires, an agent is invoked with a templated promptissue.created) or wildcards (agent.run.*)${event.payload.key} in watch prompts to inject event datanew-lead-follow-up, deal-stalled, high-value-issue, budget-warning, agent-error-diagnosislist_watch_templates tool - Browse available templatesremove_watch tool - Remove watches by ID/clip watches - List all active watches with trigger counts/clip status - Show active agents and recent completions/clip agents - List all agents with status badges/clip issues [open|done] - List issues filtered by status/clip approve <id> - Approve a pending approval/clip acp spawn <agent> [display] - Add an agent to this thread/clip acp status - Show all agents in this thread/clip acp close [name] - Close a specific agent (or most recent)/clip commands - List registered custom commands/clip watches - List active event watches/clip help - Show this help messagenpm install paperclip-plugin-slack
Or register with your Paperclip instance directly:
curl -X POST http://127.0.0.1:3100/api/plugins/install \
-H "Content-Type: application/json" \
-d '{"packageName":"paperclip-plugin-slack"}'
[!NOTE] Company-scoped activation (#9557, first stable in
v2026.720.0): the host now resolves plugin secret references under a company scope. This plugin is deliveries-only: it reads no configuration and resolves no secrets at startup, and builds its runtime from the host's company-scoped configuration delivery (onConfigChanged). Onv2026.817.0+ it activates out of the box; onv2026.720.0/722.0save the plugin configuration once through the settings panel after installing, to trigger the first delivery. The earlier temporary secret-ref kill switch (#5429) was removed upstream in #9557 — no host pinning is needed any more.
If the plugin looks broken, first confirm which Paperclip host it's actually talking to. Run paperclipai plugin target (#8575) — it prints the resolved API URL plus the server's status, version, deploymentMode, and deploymentExposure before anything is installed. A server version older than this plugin expects is the most common cause of activation failures and secret-resolution errors (e.g. slackTokenRef not resolving) that look like plugin bugs but aren't. If the URL or version is wrong, retarget Paperclip — or update the server — before opening an issue.
Create a Slack app at https://api.slack.com/apps
Add the required bot scopes:
chat:write for posting notifications and command responsescommands for the /clip slash commandfiles:read if you want voice/file ingestionapp_mentions:read and the relevant message history scopes if you want Slack message events routed to agentsChoose one inbound mode:
connections:write, and store that token as a Paperclip secret. Socket Mode is the easiest local setup because Slack sends events and interactive payloads over the WebSocket instead of requiring a public Request URL.For webhook mode, configure these Slack app URLs:
| Slack setting | Request URL |
|---|---|
| Event Subscriptions | <paperclip base URL>/api/plugins/paperclip-plugin-slack/webhooks/slack-events |
Slash Commands (/clip) | <paperclip base URL>/api/plugins/paperclip-plugin-slack/webhooks/slash-command |
| Interactivity & Shortcuts | <paperclip base URL>/api/plugins/paperclip-plugin-slack/webhooks/slack-interactivity |
Install the app to your workspace and copy the Bot OAuth Token
In Paperclip, create a company secret holding the Bot OAuth Token, by either:
slack-bot-oauth-token) and the Bot OAuth Token as the value, then click Create / Seal. The secret is created at the company level (not bound to that agent — despite the agent-context UI) and the returned UUID can be used from any plugin in the company.POST /api/companies/{companyId}/secrets with body {"name": "slack-bot-oauth-token", "value": "<your-bot-oauth-token>", "provider": "local_encrypted"}. The response contains the secret's UUID.Copy the resulting secret UUID — you'll paste it into slackTokenRef in the next step.
Install the plugin and configure the Bot token secret UUID in slackTokenRef, the app-level token secret UUID in slackAppTokenRef when using Socket Mode, the signing secret reference in slackSigningSecretRef, and your default channel ID. The host-delivered company owns all inbound commands and confirmation state. Leave slackAppTokenRef empty to keep webhook mode only.
| Setting | Description |
|---|---|
slackTokenRef | Secret reference for the Slack Bot OAuth token |
slackAppTokenRef | Optional secret reference for the Slack app-level xapp-... token used by Socket Mode |
paperclipApiKeyRef | Secret reference for a Paperclip API key; required when enabling issue-thread confirmations |
defaultChannelId | Default Slack channel ID (e.g. C01ABC2DEF3) |
approvalsChannelId | Dedicated channel for approvals (optional) |
errorsChannelId | Dedicated channel for agent errors (optional) |
pipelineChannelId | Dedicated channel for agent lifecycle events (optional) |
notifyOnIssueCreated | Post when issues are created (default: true) |
notifyOnIssueDone | Post when issues are completed (default: true) |
notifyOnApprovalCreated | Post when approvals are requested (default: true) |
notifyOnRequestConfirmationCreated | Post pending issue-thread confirmations (default: false; requires paperclipApiKeyRef) |
notifyOnAgentError | Post when agent runs fail (default: true) |
notifyOnAgentConnected | Post when agents connect/disconnect (default: true) |
notifyOnBudgetThreshold | Post when agents hit budget limits (default: true) |
enableDailyDigest | Send daily activity summary at 9am (default: false) |
escalationChatId | Dedicated channel for agent escalations (optional) |
escalationTimeoutMs | Timeout before default action fires (default: 900000 / 15 min) |
escalationDefaultAction | Action on timeout: defer, dismiss, or auto_reply (default: defer) |
escalationHoldMessage | Message sent to customer while waiting (default: "Your request has been escalated to a human agent. Please hold.") |
paperclipBaseUrl | Base URL for the Paperclip API (default: http://localhost:3100) |
maxAgentsPerThread | Max concurrent agents in a single thread (default: 5) |
The plugin registers these tools that agents can call:
| Tool | Phase | Description |
|---|---|---|
escalate_to_human | 1 | Escalate to a human operator with conversation context and optional suggested reply |
handoff_to_agent | 2 | Request a handoff from one agent to another with approval buttons |
discuss_with_agent | 2 | Start a turn-based discussion loop between two agents |
process_media | 3 | Process an audio/video file - transcribe and optionally brief |
register_command | 4 | Register a custom !command with workflow steps |
register_watch | 5 | Register an event watch that triggers an agent on matching events |
remove_watch | 5 | Remove a registered event watch |
list_watch_templates | 5 | List built-in watch templates for common use cases |
The slackTokenRef field now declares format: "secret-ref", which is required for Paperclip to collect and resolve secret references at activation time. Previously, the field was a plain string with no format annotation, causing plugin activation to fail with Invalid secret reference.
If you installed v2.0.0: you must re-configure the plugin. Create a company secret holding the Slack Bot OAuth Token using one of the paths in the Setup section above (UI or REST API), then paste the resulting secret UUID into the slackTokenRef field in the plugin configuration. Raw token strings are no longer accepted in this field.
npm install
npm run typecheck
npm test
npm run build
Tests cover notifications, approvals, escalation, session registry, media pipeline, custom commands, proactive suggestions, Block Kit formatting, Socket Mode, and slash commands.
For full local verification, run npm run verify. For the standalone diagnostic script only, set SLACK_APP_TOKEN and run npm run smoke:socket to verify that Slack returns a Socket Mode WebSocket URL. Installed plugin workers use slackAppTokenRef and paperclipApiKeyRef; they do not read host environment credentials or package .env files.
Issues and PRs welcome at github.com/mvanhorn/paperclip-plugin-slack.
Auto-publishes to npm on push to main via OIDC trusted publishing.
@MatB57 - Escalation channel concept, "Chat OS" vision for turning chat plugins into bidirectional agent command centers, and the HITL suggested-reply flow.
MIT
TypeScript
99.5%
Slack notifications plugin for Paperclip - posts to Slack when issues are created, completed, or need approval
TypeScript
55
83 commits
updated Sep 10, 2026
Slack Chat OS plugin for Paperclip. Turns Slack into a bidirectional agent command center - notifications, approvals, multi-agent threads, voice-to-task pipelines, custom workflow commands, and proactive agent suggestions.
Built on the Paperclip plugin SDK and the domain event bridge (PR #909).
Multiple Paperclip users asked for notifications on the same day the plugin system shipped (2026-03-14):
"is there a way to have codex/claude check paperclip to see when tasks are done without me prompting it?" - @Choose Liberty, Discord #dev
"basically to have it 'let me know when its done'" - @Choose Liberty, Discord #dev
"can claude code check paperclip to see when tasks are done" - @Nascozz, Discord #dev
@dotta (maintainer) responded: "we're also adding issue-changed hooks for plugins so when that lands someone could [make notifications]." The event bridge (PR #909) shipped that same day. @dotta also asked for "someone to make a plugin that's a totally separate package" to validate the DX. @Ryze said "Really excited by the plugins. I had developed a custom plugin bridge that I will now deprecate and migrate over to the new supported plugin system."
This is that plugin.
Notifications (rich Block Kit formatting)
Interactive approvals
slack:{user_id})Issue-thread confirmations
request_confirmation issue interactions to Slack with Accept/Reject buttonsHITL escalation
escalate_to_human tool for agentsPer-type channel routing
Daily digest
cost_event.created events throughout the daymaxAgentsPerThread (default 5) agents in a single Slack thread via /clip acp spawn <agent> [display_name]handoff_to_agent tool lets one agent request a handoff to another with Approve/Reject buttons in-threaddiscuss_with_agent tool starts a back-and-forth conversation between two agents with configurable max turns/clip acp status - Show all active agents in the current thread/clip acp close [name] - Close a specific agent or the most recently active onewhisper-transcriber agent for speech-to-textprocess_media tool - Agents can programmatically trigger media processing with an optional briefAgentIdfile_shared events trigger the pipeline automatically!command syntax - Type !deploy staging or !triage bug-123 in any thread to trigger registered workflowsinvoke_agent, post_message, create_issue, wait_approval$1, $2, or $args in step templates to pass user argumentsregister_command tool - Agents or admins can register new commands at runtimewait_approval steps pause execution with Approve/Reject buttons/clip commands - List all registered custom commands with descriptions and usageregister_watch tool sets up a trigger: when an event matching a pattern fires, an agent is invoked with a templated promptissue.created) or wildcards (agent.run.*)${event.payload.key} in watch prompts to inject event datanew-lead-follow-up, deal-stalled, high-value-issue, budget-warning, agent-error-diagnosislist_watch_templates tool - Browse available templatesremove_watch tool - Remove watches by ID/clip watches - List all active watches with trigger counts/clip status - Show active agents and recent completions/clip agents - List all agents with status badges/clip issues [open|done] - List issues filtered by status/clip approve <id> - Approve a pending approval/clip acp spawn <agent> [display] - Add an agent to this thread/clip acp status - Show all agents in this thread/clip acp close [name] - Close a specific agent (or most recent)/clip commands - List registered custom commands/clip watches - List active event watches/clip help - Show this help messagenpm install paperclip-plugin-slack
Or register with your Paperclip instance directly:
curl -X POST http://127.0.0.1:3100/api/plugins/install \
-H "Content-Type: application/json" \
-d '{"packageName":"paperclip-plugin-slack"}'
[!NOTE] Company-scoped activation (#9557, first stable in
v2026.720.0): the host now resolves plugin secret references under a company scope. This plugin is deliveries-only: it reads no configuration and resolves no secrets at startup, and builds its runtime from the host's company-scoped configuration delivery (onConfigChanged). Onv2026.817.0+ it activates out of the box; onv2026.720.0/722.0save the plugin configuration once through the settings panel after installing, to trigger the first delivery. The earlier temporary secret-ref kill switch (#5429) was removed upstream in #9557 — no host pinning is needed any more.
If the plugin looks broken, first confirm which Paperclip host it's actually talking to. Run paperclipai plugin target (#8575) — it prints the resolved API URL plus the server's status, version, deploymentMode, and deploymentExposure before anything is installed. A server version older than this plugin expects is the most common cause of activation failures and secret-resolution errors (e.g. slackTokenRef not resolving) that look like plugin bugs but aren't. If the URL or version is wrong, retarget Paperclip — or update the server — before opening an issue.
Create a Slack app at https://api.slack.com/apps
Add the required bot scopes:
chat:write for posting notifications and command responsescommands for the /clip slash commandfiles:read if you want voice/file ingestionapp_mentions:read and the relevant message history scopes if you want Slack message events routed to agentsChoose one inbound mode:
connections:write, and store that token as a Paperclip secret. Socket Mode is the easiest local setup because Slack sends events and interactive payloads over the WebSocket instead of requiring a public Request URL.For webhook mode, configure these Slack app URLs:
| Slack setting | Request URL |
|---|---|
| Event Subscriptions | <paperclip base URL>/api/plugins/paperclip-plugin-slack/webhooks/slack-events |
Slash Commands (/clip) | <paperclip base URL>/api/plugins/paperclip-plugin-slack/webhooks/slash-command |
| Interactivity & Shortcuts | <paperclip base URL>/api/plugins/paperclip-plugin-slack/webhooks/slack-interactivity |
Install the app to your workspace and copy the Bot OAuth Token
In Paperclip, create a company secret holding the Bot OAuth Token, by either:
slack-bot-oauth-token) and the Bot OAuth Token as the value, then click Create / Seal. The secret is created at the company level (not bound to that agent — despite the agent-context UI) and the returned UUID can be used from any plugin in the company.POST /api/companies/{companyId}/secrets with body {"name": "slack-bot-oauth-token", "value": "<your-bot-oauth-token>", "provider": "local_encrypted"}. The response contains the secret's UUID.Copy the resulting secret UUID — you'll paste it into slackTokenRef in the next step.
Install the plugin and configure the Bot token secret UUID in slackTokenRef, the app-level token secret UUID in slackAppTokenRef when using Socket Mode, the signing secret reference in slackSigningSecretRef, and your default channel ID. The host-delivered company owns all inbound commands and confirmation state. Leave slackAppTokenRef empty to keep webhook mode only.
| Setting | Description |
|---|---|
slackTokenRef | Secret reference for the Slack Bot OAuth token |
slackAppTokenRef | Optional secret reference for the Slack app-level xapp-... token used by Socket Mode |
paperclipApiKeyRef | Secret reference for a Paperclip API key; required when enabling issue-thread confirmations |
defaultChannelId | Default Slack channel ID (e.g. C01ABC2DEF3) |
approvalsChannelId | Dedicated channel for approvals (optional) |
errorsChannelId | Dedicated channel for agent errors (optional) |
pipelineChannelId | Dedicated channel for agent lifecycle events (optional) |
notifyOnIssueCreated | Post when issues are created (default: true) |
notifyOnIssueDone | Post when issues are completed (default: true) |
notifyOnApprovalCreated | Post when approvals are requested (default: true) |
notifyOnRequestConfirmationCreated | Post pending issue-thread confirmations (default: false; requires paperclipApiKeyRef) |
notifyOnAgentError | Post when agent runs fail (default: true) |
notifyOnAgentConnected | Post when agents connect/disconnect (default: true) |
notifyOnBudgetThreshold | Post when agents hit budget limits (default: true) |
enableDailyDigest | Send daily activity summary at 9am (default: false) |
escalationChatId | Dedicated channel for agent escalations (optional) |
escalationTimeoutMs | Timeout before default action fires (default: 900000 / 15 min) |
escalationDefaultAction | Action on timeout: defer, dismiss, or auto_reply (default: defer) |
escalationHoldMessage | Message sent to customer while waiting (default: "Your request has been escalated to a human agent. Please hold.") |
paperclipBaseUrl | Base URL for the Paperclip API (default: http://localhost:3100) |
maxAgentsPerThread | Max concurrent agents in a single thread (default: 5) |
The plugin registers these tools that agents can call:
| Tool | Phase | Description |
|---|---|---|
escalate_to_human | 1 | Escalate to a human operator with conversation context and optional suggested reply |
handoff_to_agent | 2 | Request a handoff from one agent to another with approval buttons |
discuss_with_agent | 2 | Start a turn-based discussion loop between two agents |
process_media | 3 | Process an audio/video file - transcribe and optionally brief |
register_command | 4 | Register a custom !command with workflow steps |
register_watch | 5 | Register an event watch that triggers an agent on matching events |
remove_watch | 5 | Remove a registered event watch |
list_watch_templates | 5 | List built-in watch templates for common use cases |
The slackTokenRef field now declares format: "secret-ref", which is required for Paperclip to collect and resolve secret references at activation time. Previously, the field was a plain string with no format annotation, causing plugin activation to fail with Invalid secret reference.
If you installed v2.0.0: you must re-configure the plugin. Create a company secret holding the Slack Bot OAuth Token using one of the paths in the Setup section above (UI or REST API), then paste the resulting secret UUID into the slackTokenRef field in the plugin configuration. Raw token strings are no longer accepted in this field.
npm install
npm run typecheck
npm test
npm run build
Tests cover notifications, approvals, escalation, session registry, media pipeline, custom commands, proactive suggestions, Block Kit formatting, Socket Mode, and slash commands.
For full local verification, run npm run verify. For the standalone diagnostic script only, set SLACK_APP_TOKEN and run npm run smoke:socket to verify that Slack returns a Socket Mode WebSocket URL. Installed plugin workers use slackAppTokenRef and paperclipApiKeyRef; they do not read host environment credentials or package .env files.
Issues and PRs welcome at github.com/mvanhorn/paperclip-plugin-slack.
Auto-publishes to npm on push to main via OIDC trusted publishing.
@MatB57 - Escalation channel concept, "Chat OS" vision for turning chat plugins into bidirectional agent command centers, and the HITL suggested-reply flow.
MIT
TypeScript
99.5%