Files
PaperClipAI/doc/connections/SLACK-TASK-TOOLS.md
T
DottaandPaperclip b0155a681a feat(slack): connect Paperclip conversations and scheduled messages (#13920)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Slack conversations use the same tasks and agents as the Paperclip
board.
> - A board reply must reach that Slack conversation and let the agent
continue the work.
> - An assigned agent also needs its Slack tools during normal tasks and
scheduled routines.
> - Both paths must keep the linked user's authority, delivery rules,
and conversation history.
> - This pull request adds those paths and reduces setup friction for
Slack bots.

## Linked Issues or Issue Description

**Subsystem affected**

Server orchestration, Slack connector tools, shared contracts, and chat
setup UI.

**Problem or motivation**

Replies entered in Paperclip did not provide a complete round trip to
the linked Slack thread. Slack and board wakeups could select different
model sessions for the same task. Agents also lacked their assigned
Slack tools outside Slack-origin work, which prevented a routine from
sending its responsible user a briefing. Inviting a bot could leave the
new channel disabled.

**Proposed solution**

Mirror human board messages with author attribution and route the agent
result to the same thread. Use the same session key across both entry
points. Supply Slack tools to the connection's assigned agent in normal
tasks and routines, using the current responsible user's verified link.
Enable newly invited channels while preserving explicit disabled
choices. Add a browser-agent setup prompt to the Slack wizard.

**Alternatives considered**

A separate Slack scheduler or task dispatcher would duplicate existing
Paperclip workflows. Reusing the connection owner's identity would grant
the wrong authority. Replaying old channel history could start
unintended work. This change uses ordinary task wakeups, routine
dispatch, and Slack's original invitation mention event instead.

**Roadmap alignment**

Extends the shipped Scheduled Routines and governed Apps capabilities.
It does not add a separate task lifecycle. Related work: #13828 and
#13809. Related test stabilization: #13877. The existing plugin
Slack-control proposals are separate from this built-in connector
change.

## What Changed

- Queue human Paperclip messages for the original Slack thread with
display-name attribution and stable delivery identities. Require the
author’s current linked Slack identity and recheck access before
delivering messages or agent replies.
- Apply pause, dependency, cancellation, and closed-workspace guards
before explicit Board sends request work and again when the durable
outbox dispatches it.
- Route agent results back to Slack and preserve model-session
continuity, including replies that reopen completed tasks.
- Resolve assigned Slack connections for normal agent tasks and
routines. Recheck the responsible user's link, membership, and
permissions at execution.
- Add `slack_open_dm` for the responsible user's bot DM and request the
`im:write` scope.
- Enable newly discovered invited channels. Keep explicit OFF choices
and normal admission and deduplication rules.
- Add a copyable Slack setup prompt for a computer-use agent, with
Storybook coverage. Share the prompt-button component with GitHub.
- Update Slack tool documentation and runtime instructions.
- Stabilize the mobile project browser test by waiting for the final
canonical route before editing, preserving all persistence assertions.

## Verification

- Live staging: invited the bot after the first mention. The channel
became enabled and the bot answered that original mention.
- Live staging: a normal Paperclip reply appeared in Slack with author
attribution. The agent completed the calculation and replied once in the
original thread and in Paperclip.
- Live staging: a codeword entered in Slack was recalled from Paperclip.
A following Slack calculation used the result from the Paperclip turn.
Run metadata confirmed the same model session for both entry points.
- Live staging: a scheduled routine used `slack_open_dm` and
`slack_post_message` to deliver one DM. The existing app was reinstalled
with `im:write`. The test routine was paused after verification.
- Before the master merge: 397 focused feature tests passed. The
continuity fix passed all 76 issue comment/update route tests and six
focused route/integration cases. Typecheck, build, and token gates
passed.
- Review fixes: 47 focused integration cases passed, covering link
revocation/replacement, private membership removal, guarded outbox
dispatch, concurrent workers, lost scheduler responses, a real
one-connection pool, exact reply provenance, and attachment retries. All
99 issue-comment route tests and the Slack catalog browser test passed.
- Full local typecheck, production build, token gates, and
module-boundary checks passed. The full local test command passed 25,915
tests before a 15-second timeout in
`issue-thread-interaction-routes.test.ts`; that entire suite passed on
isolated rerun (81 tests). Remaining serialized coverage is provided by
the current-head CI shards.
- An unchanged Cursor adapter test hit its 10-second limit in CI; all
five tests in that file passed on a local rerun in 3.11 seconds, and the
failed CI shard passed on its single retry.
- The preview-server readiness test passed a local rerun (28 tests). The
mobile-project readiness fix passed three repetitions of both browser
tests (6/6).
- Final commit `64ac0d9897f4353375996f1b1b38e5040bdeb0a0`: all CI gates
passed, including all eight browser shards, all server/chat suites,
typecheck, build, runner checks, and security checks. Greptile reviewed
this exact commit at 5/5; all review threads are resolved.

## Risks

- Human messages on a Slack-linked task now publish to its Slack thread.
The task banner states this behavior. Incoming Slack messages and
internal agent bookkeeping must not echo back.
- Normal tasks and routines can now use the assigned bot. Authority
remains bound to the current responsible user's link; it does not fall
back to the connection owner. Revocation, private-context limits, and
queued-write checks still apply.
- Existing Slack apps need `im:write` and a reinstall to open DMs. Other
existing capabilities remain available without that scope.
- New invited channels default to enabled. Explicit disabled choices
remain disabled. Channels created by bot tools still require a person to
enable responses.
- No database migration or new provider credentials are required.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, code execution, GitHub CLI,
and browser tools. The runtime does not expose a more specific model
build identifier 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
- [x] 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-09-24 10:51:45 -05:00

12 KiB

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. 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 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 and generated adjacent TOOLS.json provide the equivalent HTTP interface for CLI/sandbox adapters:

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. 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.