Files
PaperClipAI/doc/plans/2026-09-22-slack-origin-tools.md
DottaandPaperclip a10702a878 feat(slack): add governed tools for Slack-origin tasks (#13828)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Chat connectors let people start and continue agent tasks from other
services.
> - A Slack conversation needs access to its surrounding discussion and
Slack collaboration tools.
> - The agent must use the linked requester's access and keep private
material within its permitted audience.
> - This pull request adds Slack tools through the existing connector
contribution and approval framework.
> - People can ask an invited bot to read a discussion, create follow-up
tasks, and collaborate in Slack.

## Linked Issues or Issue Description

**Subsystem affected**

Chat connectors, connector runtime, tool gateway, and connection
Settings/Access.

**Problem or motivation**

Slack-origin tasks can receive messages but cannot inspect the rest of a
channel or act through the originating bot. People must paste context or
configure a separate integration.

**Proposed solution**

Supply typed Slack tools and a bundled skill only to the originating
task and assigned agent. Resolve the linked requester on the server.
Check bot and requester access before reads and writes. Use existing
durable actions and approvals. Retrieved messages remain source
material.

**Alternatives considered**

Slack's user-OAuth MCP server does not replace the customer-created chat
bot. An unrestricted Web API proxy would not provide suitable permission
or publication boundaries.

**Roadmap alignment**

This extends the existing MCP Tool Gateway & Apps work with a provider
contribution. It does not add a task dispatcher or a separate Slack task
lifecycle. Related: #11144 covers generic per-user MCP grant execution;
this change binds Slack bot operations to chat-origin tasks.

## What Changed

- Add 39 typed Slack tools, a method/scope matrix, a bundled skill, and
shared native/HTTP execution.
- Bind tools to company, endpoint, task, run, assigned agent, and
admitted linked requester. Check membership and revocation on each call
and before queued writes.
- Add paginated reads, bounded history search, source links, messages,
file uploads, reactions, pins, bookmarks, topics, canvases, lists, and
approved channel operations.
- Restrict private-source publication, including automatic replies and
uploaded deliverables. Keep other people's bot DMs inaccessible.
- Reuse action receipts, idempotency, approvals, and reconciliation.
Suppress an identical explicit-send/final-reply duplicate. Return
governed results through their verified originating conversation.
- Add endpoint-bound personal search OAuth storage and lifecycle. Keep
native real-time search disabled until a runtime meets Slack's
transient-result requirements. Current runtimes use bounded history
search.
- Show capabilities, scope upgrades, and personal search authorization
in Settings/Access and Storybook. Document provider and runtime limits.

## Verification

- Current head `0eb21cba4`: CI checks pass and Greptile is 5/5 with no
unresolved findings. One unchanged rapid-callback timing test passed on
a single CI retry.
- Approval presentation regressions cover board-comment precedence and
exact Slack publication; the expanded database assertion passed in CI.
The local PostgreSQL startup probe later became unavailable, so that
final assertion was verified in CI. Slack setup and failed-run retry
browser tests also passed locally.

- Full workspace typecheck and build passed. Server typecheck/build
passed again after the approval routing fix.
- Broad local suites passed in separate groups: server 12,958 tests, UI
6,555, shared 770, skills catalog 20, and other workspace packages
2,652. CLI and serialized server checks passed after environment/timeout
retries. These are composite results, not one uninterrupted green
full-suite invocation.
- PostgreSQL authority regression covers admitted identity,
cross-company/task/agent rejection, recovery, retained-session
revocation, OAuth refresh/disconnect races, approval execution, exact
publication lineage, retries, uncertain sends, and duplicate
suppression.
- Gateway/response regressions cover separate-origin approval batches
and durable continuation. Focused provider, access, search, native
runtime, route, and AgentMail regressions pass.
- Storybook capability, missing-scope, OAuth configuration,
authorization, and disconnect states were inspected in the browser.
- Live staging: read a channel decision and full thread, create exactly
two assigned backlog tasks, add a reaction, paginate discovery to
exhaustion, and return bounded search matches with source links and
coverage.
- Live staging: create/edit/read a canvas and list, inspect the canvas
in Slack, post/edit one message, and create a channel only after
approval. New channels remain disabled for responses.
- Live staging: read a response-disabled channel from the requester's
DM; writes to that channel were denied. The test setting was restored.
- Final live retest passed: explicit file upload and exact content
read-back; approved deletion of only the disposable bot message;
continuation confirmation returned to the original Slack thread without
repeating the action.
- Optional OAuth, private multi-user boundaries, native RTS, and CLI
provider execution are not fully live-qualified. The staging agent
initially supplied malformed tool arguments; valid arguments succeeded,
and the tool/skill descriptions now emphasize UUID write keys.

## Risks

- Existing Slack apps must add scopes and reinstall for new
capabilities. Provider plans and document permissions can still restrict
operations.
- Instances need an independent `PAPERCLIP_TOOL_ACTION_SIGNING_SECRET`
for governed tool actions. The staging instance was configured with
explicit operator approval; fleet provisioning is a separate gap.
- Native RTS is not exposed on current transcript-retaining runtimes.
Bounded history scans are deliberately reported as incomplete. Inline
file reads support text/canvas content up to 256 KiB; other types return
metadata.
- Private document edits fail closed when the full audience cannot be
verified. Uncertain effects other than posts/uploads require inspection
instead of blind retries.
- Shared approval-delivery code now separates outcomes by source run to
preserve origin boundaries. No database migration is required.
- A separate completion-validator gap remains when the agent cites a
prior run's registered artifact during finalization. It asked for
registration again even though Slack delivery was confirmed. This change
does not add a connector-specific task-completion policy.

## Model Used

OpenAI GPT-6 through Codex, with repository tools, code execution, and
browser testing. The exact deployed model identifier and context-window
size were not exposed in the session.

## 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-22 15:29:07 -05:00

7.4 KiB

Slack tools for Slack-origin agent tasks

Implement the approved Slack contribution through the existing connector runtime. The authority is the verified originating connection and accepted linked sender; retrieved messages are data, never instructions or authorization.

Work and verification

  • Typed tool/method/scope matrix and bundled skill; no arbitrary Web API execution.
  • Task/run/endpoint/accepted-user binding, live membership, revocation and session compatibility.
  • Paginated reads, files, bounded history search, source links and honest coverage.
  • Durable governed writes, approval, retries, delivery reconciliation and duplicate prevention.
  • Private-source publication restrictions, including automatic replies and attachments.
  • Optional endpoint-bound personal search OAuth, credentials, refresh and disconnect.
  • Native search only with qualified transient runtime delivery; no stored search responses.
  • Native and authenticated CLI operations, preserving AgentMail restrictions.
  • Settings capabilities, Access search authorization, scope upgrades and Storybook states.
  • Focused security/provider tests, full checks and live Leaf staging proof.

Allowed Channels governs replies and writes. Reads require current bot membership and requester access. Other users' bot DMs remain inaccessible. Ordinary writes use existing action policy; destructive actions, channel creation and invitations require approval. The agent cannot join existing channels or enable destinations.

Provider references: Slack Web API method documentation and https://docs.slack.dev/apis/web-api/real-time-search-api/ . Native search requires an event action token for bot calls, optional personal OAuth for private search, and explicit runtime retention qualification. Unsupported runtime/provider states must be reported accurately and retain bounded history search.

Current verification

  • Full workspace typecheck and build passed on the initial implementation.
  • 39 focused access, provider, native authority and guidance tests passed.
  • PostgreSQL integration passes admitted-event binding, cross-company/task/agent rejection, CLI route validation, ordinary writes, rate-limit retries, uncertain send reconciliation, approval after run completion, recovery, OAuth refresh, disconnect race and removed-profile/identity revocation.
  • Storybook capability and upgrade screens inspected visually. OAuth fields, disabled save, secret clearing and connected/disconnect state inspected.
  • Full checks after staging fixes: pnpm -r typecheck and pnpm build pass.
  • General server suite: 679 files / 12,958 tests passed. UI retry: 626 files / 6,555 tests passed. CLI passed in two groups after using canonical macOS TMPDIR. Shared: 770 tests; skills catalog: 20 tests; remaining source-only workspace packages: 184 files / 2,652 tests passed (19 skipped).
  • Serialized server checks passed after a process-start timeout retry. The remaining route-test timeout passed on rerun; new Slack routes now have exact OpenAPI coverage. These are composite results, not one uninterrupted green run.
  • Staging-fix checks: 89 transport/API/route tests and the PostgreSQL authority integration test pass. The latter now holds the endpoint lock concurrently and verifies resolution waits, then retains identity/revocation enforcement.
  • Live staging on 4e00210da: a linked Slack request read the channel decision, cited its source, created exactly two assigned backlog tasks through normal Paperclip tools, and added an eyes reaction. The quoted malicious task request was ignored. This fixture was posted by the linked tester; a live unlinked participant is not yet qualified (automated coverage uses unlinked sources).
  • Bounded search scanned 35 top-level messages, returned four matches with source links, and reported its incomplete coverage. Thread reading completed with hasMore: false. Initial invalid search arguments were rejected before retrieval; the exact typed contract succeeded. The skill now includes a concrete example.
  • Live canvas creation, append and read-back passed. The canvas was opened in Slack and contained the expected text. List creation, record insertion, update and read-back passed; the bot correctly reported that channel sharing needs approval.
  • Initial staging defects (JSON transport, missing native source-channel guidance, endpoint lock race) are fixed and retested. Channel discovery subsequently found a listed channel returning channel_not_found; d23bb857a omits only definite access denials. Its unit/PG regressions, full typecheck and build pass. Deployment and live discovery retest passed on 653c9ad2b: two pages exhausted, both accessible channels returned, and the natural-language search succeeded.
  • Live disabled-response boundary passed: from the requester's bot DM, channel reading succeeded while a write was denied. The channel's original enabled setting was restored afterward.
  • Explicit posting and editing passed without a duplicate send. Governed channel creation executed only after approval; the new channel remained disabled for responses and no invitations were sent. Leaf's independent signing secret was configured through its managed environment with explicit operator permission.
  • Approval continuation exposed a missing return path: its result appeared in Paperclip but not Slack. The fix verifies the durable tool-review wake and every referenced action's source before authorizing publication, and separates wakes from different source runs. Authority/dedup integration and 81 gateway/response tests pass. Live retest on bef1a0fad passed: an approved deletion executed once, read-back found the disposable message absent, and the continuation's final answer appeared in the original Slack thread.
  • Explicit upload with valid arguments delivered the registered text attachment; the agent read back its exact content from Slack. Initial malformed arguments were rejected before execution. Write schemas and the skill now emphasize UUID idempotency keys because ordinary artifact tools also accept descriptive keys.
  • A separate completion-validator gap appeared when the agent tried to cite an earlier run's registered artifact during finalization: it requested registration again. The file was already delivered and no duplicate upload was made. This is an underlying artifact-reuse workflow gap, not a Slack transport failure.
  • Optional OAuth, private multi-user boundaries, and CLI execution currently have automated coverage, not complete live qualification.

Explicit runtime/provider limitations

Native RTS provider transport and OAuth are implemented but not connected to the ordinary tool gateway: no current native/CLI runtime qualifies for Slack's transient search-result retention requirement. Current tasks use bounded history and filename/title search. Do not claim native public/private search passed live.

Inline file reading is limited to supported text/canvas downloads up to 256 KiB; other files return metadata and an explicit limitation. Canvas/list writes depend on Slack plan/scopes and cannot carry private research into an unverifiable shared document audience. Uncertain effects other than posts/uploads need operator inspection rather than an automatic resend. New approvals are needed to retry failed approval-required operations. Ordinary rate-limit retries are limited to the same still-authorized run.