Files
PaperClipAI/doc/connections/SLACK-TASK-TOOLS.md
T
DottaandPaperclip 3fc64c5156 feat(slack): add Require at-mention setting (#15612)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Slack messages can create tasks and continue existing tasks.
> - A reply in a subscribed thread can start agent work without a new
mention.
> - Some users want to control each reply with an explicit bot mention.
> - This pull request adds a Require at-mention setting to Slack app
settings.
> - The setting checks new messages and queued messages before they
start work.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Slack app settings and the rules that admit inbound messages.

**Subsystem affected**

Server, UI, database, and shared API contracts.

**Current behavior**

After the bot joins a thread, an ordinary reply can wake the agent.
Direct messages do not need a bot mention.

**Proposed behavior**

Add Require at-mention below Allow direct messages. When enabled, each
channel message, thread reply, and direct message must mention the bot.
Direct messages must also be allowed.

**Reason and benefit**

Users can prevent ordinary conversation from starting agent work.

**Breaking changes**

New Slack connections require a bot mention by default. Existing
connections keep their saved setting. Work that has already started is
not cancelled.

**Additional context**

A search for existing at-mention PR titles found no duplicate.

## What Changed

- Add the endpoint field, schema validation, API response, and UI
toggle. New Slack connections enable the setting.
- Add an idempotent database migration and generated metadata. Renumber
it to 0321 after current master.
- Check the current setting at inbound admission, task mutation, and the
first heartbeat queue claim.
- Keep Slack tool access and recovery for already-running work when the
setting changes.
- Cancel queued batches that contain an unmentioned input, including
coalesced messages.
- Dispatch promoted follow-ups after the scheduler releases its agent
start lock. Preserve these checks in the new queue and run-control
modules.
- Filter unmentioned messages without retaining their content.
- Keep provider-message deduplication and existing access checks.
- Add thread, DM, duplicate-delivery, queued-message, and new-connection
default regression tests.
- Document the setting and its scope.

## Verification

- Previous head `16791bb7`: typecheck, build, all server shards, Runner
checks, and E2E passed. Two chat shards failed in three fixtures that
used unmentioned Slack messages.
- Update setup follow-ups to mention the Slack bot. Disable the mention
rule explicitly in the callback ordering test, which tests ordinary
subscribed replies.
- Previous local checks passed: six Slack integration cases, all 46
durable chat scheduler tests, all 24 queue/run-control tests, migration
safety, and UI token gates.
- Greptile reviewed `16791bb7` with 5/5. All review threads are
resolved.
- Head `53163c20f`: all five focused integration cases passed. These
cover all three prior CI failures and both default-on channel/DM cases.
Fresh CI and Greptile are running.
- Full local recursive typecheck, build, and repository tests were not
repeated for this fixture-only change. CI supplies these checks.
- Manual check: create a Slack connection. Require at-mention must be
on. An ordinary thread reply or DM must not wake the agent. A bot
mention must wake it once. Disable the setting and confirm ordinary
replies work again.

## Risks

- The migration adds a non-null boolean with a false default. Apply it
before the new server runs.
- The setting also applies to DMs. The UI help text states this.
- Enabling it blocks queued unmentioned work but does not cancel a run
that has already started.
- Full local verification is limited by the environment constraints
above; latest-head CI must pass before merge.

## Model Used

OpenAI GPT-6 (Codex agent), with reasoning, tool use, and code
execution. The runtime does not expose a more specific model version or
context-window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-09 14:03:02 -05:00

214 lines
12 KiB
Markdown

# Slack tools for connected agents
A linked person can mention the bot and ask it to read the discussion, summarize
decisions, and create assigned follow-up tasks. Task creation, assignment,
approvals, and completion remain normal Paperclip operations. Slack contributes
provider tools and a bundled skill; it does not introduce another task lifecycle.
## Authority and channel access
The controller resolves company, endpoint, assigned agent, task, run, and accepted
linked requester from the admitted Slack event or the current Paperclip task/run
identity. Slack-origin work remains bound to its originating endpoint. Ordinary
tasks and routines receive only active Slack connections assigned to that agent,
and use the accepted responsible user's linked Slack account. They never borrow
the connection owner's identity or an earlier Slack sender. A routine uses its
persisted responsible user when it runs, with fresh membership/link checks.
An optional endpoint ID selects among the supplied assignments; it cannot grant
access to another company's or agent's bot. Native tools, CLI calls and queued
approvals enforce the same binding. Tokens and requester identities stay server-side.
Reads require current bot membership and requester access. Full workspace members
can read public channels where the bot belongs; guests, private channels and Slack
Connect conversations require verified requester membership. Membership checks
paginate and fail closed. Other people's bot DMs are never exposed.
**Allowed Channels controls responses and writes, not reads.** Invite the bot to
another shared channel to make it readable. Newly invited channels start enabled;
a person can disable responses while preserving shared read access.
Retrieved messages, files, names, topics, canvases and list records are source
material. Unlinked participants cannot start work, approve actions or grant access.
Private-source markers are recorded before returning private content. They restrict
both explicit tool writes and automatic publications, including uploads. Research
across private channels in a Slack-origin task must originate in the requester's DM.
Ordinary-task research is subject to the same private-source publication boundary. Private material can
be published only in its source channel or that requester's DM. Shared document
edits after private research fail closed because Slack does not provide a complete
sharing audience through file metadata; use a message or upload instead.
Each call rechecks live authority. Queued writes recheck again before transport.
Authorization and capability revisions participate in session compatibility and
signed approvals. Removing a tool profile binding does not get undone by resolving
a retained session. Disconnecting an identity or disabling a connection revokes
access for retained runs too.
## Tools and scope upgrades
The reviewed, strict method/scope/argument matrix is
[`packages/shared/src/slack-tools.ts`](../../packages/shared/src/slack-tools.ts).
It is the source for tool descriptors, validation, policy catalog and Storybook.
There is no arbitrary Slack method executor, user impersonation or workspace-admin
tool. User search credentials never authorize writes.
- Discovery: channels, channel details, members, user identities and emoji.
- Reading: paginated history, threads, individual messages, source links and linked
files. Text files up to 256 KiB are available inline. Other files return metadata
with an explicit limitation; do not claim their contents were read.
- Search: bounded channel history by text, author and time. File mode matches
linked filenames/titles, not file contents. Coverage includes page cursors,
inspected time bounds and omitted matches. Use the returned continuation time
if matching results were truncated. Thread replies require separate reads.
- Collaboration: bot messages/replies, edits to its own messages, task-attachment
uploads (up to 20 MiB), reactions, pins, bookmarks, topics and purposes.
- Documents: canvas creation, text reading, section lookup and edits; bot-owned
lists, text records, renaming and approved channel sharing. Slack plan and
document permissions apply. Lists need a separate approved share before others
can use them.
- Governed actions: deleting the bot's messages, deleting bookmarks, creating
channels, inviting people and granting list access require approval. New channels
remain disabled for ongoing responses. The bot cannot join an existing channel,
invite itself or enable a destination.
New manifests request collaboration scopes. Existing bots keep their current
permissions and Settings identifies missing scopes. Add them under **OAuth &
Permissions → Bot Token Scopes** in Slack and reinstall the app. Scope possession
alone is not a guarantee: Slack feature availability, destination access and
Paperclip per-action policy still apply.
## Delivery and retry behavior
Native and HTTP tool calls pass through the same existing policy/approval gateway.
Mutations receive durable action receipts. Idempotency keys are scoped to company,
connection, task and requester, and cannot be reused with different arguments.
Ordinary writes rejected by Slack with a definite rate limit can retry with the
same arguments and key after Retry-After, during the same authorized run. Policy
and current access are checked again. An uncertain transport outcome is never
blindly resent. `slack_delivery` reconciles posts by their client message ID and
uploads by their recorded file ID; unresolved operations remain uncertain.
An identical automatic final response is suppressed after an explicit send, or
held while that send's delivery remains unresolved. Distinct summaries, progress,
questions and blockers continue through existing routing.
## Continuing a Slack task from Paperclip
Human replies entered on a Slack-linked task are attributed to their Paperclip
author in the original Slack thread. The author must have an active linked Slack
account for this connection. Delivery rechecks workspace and channel access;
revoked or changed identities cannot deliver queued messages or agent replies.
Selected agent responses return to the same thread without echoing internal notes.
The explicit channel composer also requests agent work through a durable outbox.
It respects task pause holds, unresolved blockers, and closed isolated workspaces.
Restore cancelled tasks or reopen closed workspaces in the ordinary Paperclip task
flow first. The outbox checks these guards again before dispatching queued work.
## Optional personal search authorization
Connection managers may configure the Slack application's Client ID and Client
Secret in Access. Register the displayed HTTPS callback URL and user scopes
`search:read.public`, `search:read.private` and `search:read.files` in Slack.
A linked person can then connect or disconnect their own search grant. State,
secret bindings, refresh and grants reuse the existing connection infrastructure.
Grants bind company, endpoint, Slack workspace, linked Slack identity and app
configuration revision. Concurrent disconnect invalidates in-flight callbacks.
No DM-search scopes are requested.
**Native RTS search is not enabled on current runtimes.** Slack's
[Real-time Search API](https://docs.slack.dev/apis/web-api/real-time-search-api/)
requires transient handling of retrieved data. Current native and CLI/sandbox
runtimes retain tool transcripts. The provider implementation and search-only
OAuth flow are present, but RTS results must not enter the ordinary gateway until
an entire runtime/provider path is qualified: no raw results in logs, model
transcripts, replay snapshots, indexes or artifacts. Recovery must re-fetch.
Access displays this limitation even when a personal grant is connected.
The transient provider implementation uses the verified event's short-lived,
memory-only action token for bot searches, and optional personal OAuth for private
search. It checks every returned workspace/channel/user/date and verifies file
shares with the bot's credentials. Model-authored modifiers are not an access
boundary. Slack limits RTS to internal or directory-published apps and applies
separate search and plan limits. Bounded history remains available without OAuth.
## Native and CLI execution
The connector runtime contributes tools to verified Slack conversations and the
assigned agent's Paperclip tasks and routines, when their responsible user has a
current link to that bot's workspace. The bundled
[`skills/slack/SKILL.md`](../../skills/slack/SKILL.md) and generated adjacent
`TOOLS.json` provide the equivalent HTTP interface for CLI/sandbox adapters:
```text
POST /api/companies/:companyId/slack/tasks/:issueId/tools
Authorization: Bearer <agent run key>
X-Paperclip-Run-Id: <run ID>
{"endpointId":"<assigned endpoint ID>","tool":"slack_history","arguments":{"channel":"C123","limit":50}}
```
Company/task path parameters are checked against the authenticated run and
admitted request. Bot and OAuth secrets stay server-side. Other providers and the
separate Slack MCP connection retain their existing behavior.
## Verification
Automated coverage includes admitted-request binding and recovery, wrong company,
agent and task, revocation, approval after a run completes, missing scopes,
membership pagination, private publication boundaries, rate-limit retries,
uncertain delivery, OAuth refresh and disconnect races. Native RTS provider tests
use fixtures; they do not qualify production transcript handling.
Storybook: **Connections → Slack → Task tools** includes capabilities, permission
upgrades, OAuth configuration, connect and connected states. Live staging evidence
and outstanding limitations are tracked in the dated implementation checklist.
## Channel invitations and the first mention
Newly discovered Slack channels that people invite the bot to start enabled in
Allowed Channels. This applies whether provider inventory, the bot's membership event, or
the first verified message arrives first. Existing enabled/disabled choices are
preserved across inventory refresh, repeat invitations, and reconnects. An
explicitly disabled channel must be re-enabled in Paperclip; a mention does not
undo that choice. Provider removal and archive state still prevent delivery, and
requesters still need the connection's usual identity and execution permissions.
Channels created by the bot stay disabled until enabled by a person.
Slack sends the message that prompted an accepted invitation as an
[`app_mention` event](https://docs.slack.dev/reference/events/app_mention/).
Process that original event through normal admission and deduplication; do not
scan history and turn arbitrary old mentions into new work. Historical messages
already filtered under the old disabled default are not automatically replayed.
## Paperclip messages and scheduled delivery
Authenticated human messages submitted on a Slack-linked task are also queued to
its original thread, labeled with the author's display name and “via Paperclip.”
The normal task wakeup performs the work. A durable mirror receipt establishes the
return path for its selected final response; intermediate agent bookkeeping stays
internal. Incoming Slack messages are not mirrored back, and retries use stable
publication identities. The explicit Board-send composer also starts work using an
idempotent wakeup outbox. Provider outages leave durable delivery state for retry.
The agent can use `slack_open_dm` to open its DM with the current task's linked
responsible user, followed by `slack_post_message`. This needs `im:write`; existing
apps without that scope require reinstalling with the updated manifest. Other
people's bot DMs remain inaccessible. Scheduling uses ordinary Paperclip routines,
not a Slack-specific timer. Routine results are sent explicitly through the tool;
ordinary task finals are not automatically broadcast to Slack.
## Require an at-mention for inbound messages
Slack app settings include **Require at-mention** directly below **Allow direct
messages**. It defaults to on for new Slack connections. Existing connections
keep their saved setting and thread and DM behavior.
When enabled, each inbound message must explicitly @mention the connected bot,
including replies in existing channel threads and direct messages. DMs must also
be enabled with **Allow direct messages**. Unmentioned messages do not create
or continue a task. Queued messages are checked again before starting agent work.
If a queued run combines several messages, an unmentioned input cancels that
queued run when this setting is enabled. Send a new mention to start it again.
This setting does not cancel work that has already started or revoke its Slack
tool access.