## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Slack setup connects a saved agent draft to a workspace. > - Workspace authorization can fail before the agent's Slack app exists. > - The error requested reconnection while its primary action said Continue. > - Older grants could also make retry provision instead of reopening authorization. > - This change names the recovery action and keeps it on the authorization path. > - People can reconnect from the same setup page and resume the saved agent. ## Linked Issues or Issue Description Refs: #18722. **What happened?** A managed Slack draft showed “Reconnect your Slack workspace to continue setting up this agent.” Its primary action was Continue. The reconnect label depended on a registration that might not exist, and a saved error or failed explicit authorization could be ignored when an older grant remained available. **Expected behavior:** Offer one enabled Reconnect Slack workspace action that opens ordinary Slack authorization and resumes the saved setup. **Steps to reproduce:** Resume a managed Slack draft before app creation with a saved manager reauthorization error, or fail an explicit workspace authorization request. Inspect the recovery action with zero, one or multiple older workspace grants. ## What Changed - Show Reconnect Slack workspace for saved and local authorization failures before app creation and for existing-app recovery. - Honor the saved manager error and retain explicit authorization intent, so retry authorizes rather than provisioning with an older grant. - Hide irrelevant workspace controls during recovery and allow authorization before choosing an old grant. Use one recovery action. - Cover zero, one and two older grants in component regressions. Update the existing browser test to use the explicit action; add production-wizard desktop/mobile recovery previews and provider guidance. The Slack provider UI owns this change. It uses the existing authorization endpoint and shared footer; API contracts and provider permissions are unchanged. Maps are unchanged. ## Verification - Final head: `02234bd1afc61d404841a9fc2b7e457b0dc021bf`. Full CI [41715544834](https://github.com/paperclipai/paperclip/actions/runs/41715544834) passed on attempt 2, including all browser, server/chat, Runner, typecheck, build, policy and canary checks. Greptile and Ponytail both give this exact head 5/5; all review threads are resolved. - All 20 managed setup tests and 276 related chat UI tests across 19 files passed. All 9 Slack provider browser cases passed on the final source in 1.3 minutes using Node 24.22.2 and unchanged Playwright configuration. Provider responses are mocked in those cases. - Full repository typecheck and build passed earlier; final UI typecheck/build, token gates and Storybook catalog checks passed after the source refinement. All 30 map/catalog Node checks passed. Catalog/map checks are structural. The full local server Vitest suite was not repeated for this UI-only change; full CI covered it. - Production-wizard browser previews covered saved recovery on desktop and at 320 × 568, older grants, and failed explicit authorization. On the final source, the visible retry with older grants returned to an error-free workspace chooser, where Continue requires a choice. Selecting a workspace and continuing was also exercised through the message step during the preceding refinement. All provider actions in these previews are simulated. - The existing recovery path was independently exercised live in staging through ordinary controls: Continue → Slack Allow → Success → Open Slack → real agent DM reply → Done → full reload. The new action label still needs deployed acceptance. No live grant was revoked or duplicate bot created to force the error. Failures retained through acceptance: - New regressions failed on the earlier sources for missing recovery labels, ignored saved errors with active grants, a duplicate action, disabled multi-workspace recovery, and lost explicit authorization intent. The final tests require enabled recovery, authorization navigation and no provisioning on that action. - The first preview assertion raced workspace-options loading; it now waits for the same enabled condition. A later multi-workspace return assertion incorrectly expected the message step; it now checks the required workspace choice and disabled Continue before selection. The fixture's authorization flag is reset by a normal full reload. An unsupported Testing Library `exact` option was caught by typecheck and replaced with an anchored name regex. Failure screenshots remain preserved. - Earlier CI [41707550300](https://github.com/paperclipai/paperclip/actions/runs/41707550300) found the existing browser test still clicking Continue and an npm canary-version collision. The locator was updated without removing authorization-count/redirect assertions; subsequent packaging checks passed. CI [41709833527](https://github.com/paperclipai/paperclip/actions/runs/41709833527) had runner shutdown/lost-communication interruptions; those earlier successes were not used to qualify the final head. - Final-head attempt 1 had a native Runner shutdown while unpacking its cache, plus a distinct Cursor Cloud Stop assertion failure in the package lane (4890 passed, 10 skipped). The Cursor Cloud case passed unchanged in isolation, with its source subtree matching the CI merge tree; the CI cause is not established. Both full Runner lanes then passed on retry of the same reviewed commit, with successful checks retained. - One local browser invocation timed out during server startup on Node 26 before assertions. The first Node 24 wrapper invocation failed a nested-npx package selector before assertions. Direct Playwright execution with that wrapper variable cleared and unchanged timeouts passed the final 9-case suite. - Greptile flagged a routine regression paragraph outside feature-map scope; it was removed. Ponytail then found the active-grant mismatch; it was reproduced and fixed at the authorization decision. Both reviewers now report 5/5. ## Risks Saved reauthorization errors and retries of explicit authorization requests now reopen existing Slack consent even when older grants remain. Provider availability or browser consent can still prevent reconnection. This change does not establish why the original workspace grant became unusable; simulated previews are not live Slack proof. ## Model Used OpenAI Codex, GPT-6 family, with reasoning, repository editing, browser use and command execution. The runtime does not expose a more precise model ID 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>
11 KiB
Slack app ownership and setup
Slack has one chat runtime and two provisioning paths. A saved connection's
slackSetupMethod selects provisioning; it does not change tools, scopes,
conversation routing, people permissions, or channel access.
| Method | App creation and installation | Default |
|---|---|---|
managed |
A personal Slack manager grant creates a child app; managed installation supplies its bot token. Slack consent/admin approval remains a fallback. | New drafts on qualified Cloud deployments only |
automatic |
A temporary app configuration access token creates a customer-owned app; the user approves its OAuth installation. | New self-hosted drafts and Cloud without managed availability |
manual |
User creates an app from the canonical manifest and enters credentials. | Legacy drafts with no saved method |
existing |
User supplies credentials for an existing app. | Explicit selection |
Existing drafts and active bots retain their method. Enabling managed setup never adopts existing apps. Choose agent offers Use your own app under Advanced, below Slash command, when the instance supports managed setup and creation has not started. The own-app flow retains Create manually and Use an existing app under Advanced. After creation dispatch, a managed draft cannot switch paths.
Managed setup has two visible stops: Choose agent and Connect. Continue starts manager authorization or installation in the saved workspace automatically. Multiple workspaces still require a selection. Recovery actions remain explicit; opening a failed or uncertain registration never retries creation automatically. Creation, installation, message waiting, and success use the same production components and server evidence as the own-app flow. A click or OAuth return does not constitute successful configuration.
Cloud deployment prerequisites
Managed setup is disabled by default. Qualification requires all of:
- The instance chat-connector rollout gate and connection-management permission.
- Verified Cloud runtime identity, connector broker signing/sealing configuration, and valid independently configured public board and webhook HTTPS origins.
PAPERCLIP_SLACK_MANAGED_SETUP_ENABLED=trueon the approved tenant deployment.- The companion Cloud broker deployment with the explicitly enabled
slack.managerprofile, approved Slack manager app, token rotation, and its client secret in the broker's secret store. No manager client secret belongs in the tenant.
The broker must advertise its manager app identity as well as the enabled profile. Previously saved grants from a different manager app are not reused. A broker without this capability leaves managed setup unavailable. Do not enable the tenant gate until real Slack qualification has passed; fixture coverage does not prove Marketplace eligibility or a workspace's approval policy.
Self-hosted instances do not need a Paperclip account, broker enrollment, manager credentials, or hosted-service calls. They continue using the own-app flow.
Personal workspace authorization
Manager grants belong to a company and one Paperclip user, and bind a verified Slack user, workspace, and manager app. Another company member must authorize their own account, even for the same workspace. Access and rotating refresh tokens are user-scoped vault entries. Refreshes serialize across connections, persist the new refresh token, and require fresh authorization after an ambiguous exchange. Managed provisioning resolves the submitted grant from the Slack manager-grant registry. Both provisioning and revocation check its company and current user; these IDs are separate from tool-connection grants.
Revoking a grant requests provider revocation, removes its local credentials, invalidates pending manager authorization, and prevents future provisioning with it. The local activity records whether provider revocation succeeded. Provider errors never restore local access. It does not uninstall apps or disable already-installed bots. Removing a bot deletes endpoint-specific secrets and pending setup attempts; a reusable personal manager grant survives. Provider-side app removal remains explicit through the saved Slack management URL.
Recovery
- A dispatched creation with an unknown result is uncertain. Never automatically create again. The user must inspect Slack and explicitly confirm that no app was created before a new request identity is accepted.
- Denied or pending installation retains the app. Resume with the same grant or complete the child app's state-bound OAuth approval; the installer must match the grant's Slack identity before personal linking.
- Returned bot credentials are vaulted before inventory or runtime configuration. Retry connecting reuses those credentials after network or inventory failures. Rejected or under-scoped bot credentials instead reinstall the saved app; they never trigger another app creation.
- Manifest updates finish before managed installation. Changes requiring updated permissions therefore pass through installation again before activation.
- Expired or revoked manager grants require reconnection. Losing managed availability pauses setup; it never changes the saved ownership method. A saved draft that needs workspace reauthorization shows Reconnect Slack workspace on Connect, even before its app has been created. This button opens Slack authorization and returns to the same saved agent setup.
- Slack rate limits are grouped by manager/workspace/method. Provider
Retry-Afteris persisted across matching grants in the company, survives restarts, and blocks early retries. Other tenant instances must observe Slack's limits independently; no background loop retries app creation.
All OAuth attempts bind company, actor/session, endpoint, registration revision, and configured origins, expire after ten minutes, and are claimed once before exchange. HTTP diagnostics redact manager tokens, refresh tokens, codes, and sealed handoffs. Local activity records contain only IDs and safe outcome codes. This adds no first-party telemetry.
Code and verification
Server provisioning lives in server/src/services/connectors/slack/setup/;
chat-slack-registration.ts remains the compatibility facade. Shared completion
owns credential binding, personal linking, welcome messages, and verification.
Removal cleanup stays independently callable. Slack wizard components and stage
selection live in ui/src/pages/apps/chat/slack/.
Inbound workspace checks and authenticated setup evidence resolve only the current signing secret. They do not read bot or app tokens for signature checks. Runtime setup still resolves its full credential set. Each check uses the saved company and connection, current secret version, and normal secret access audit path.
Production Storybook journeys: Connections / Slack / Managed setup and
Connections / Slack / Automatic setup (the persisted own-app automatic path).
Server integration cases cover personal grants, duplicate requests, uncertain
creation, approval fallback, refresh, revocation, removal, saved-credential recovery,
rate limits, and secret canaries. Browser cases are in
tests/e2e/chat-adapters-ui-providers.spec.ts; companion broker tests cover manager
user OAuth and the authenticated tenant handoff.
Before enabling a deployment, create two test agents in the authorized workspace. The second must reuse the personal grant without another configuration token or manager authorization. Verify avatars, identity linking, signed inbound events, and same-thread replies. Record real approval behavior separately from fixtures.
Managed setup during broker outages
Cloud deployments configured for managed Slack keep the managed default when the broker profile is temporarily unavailable. New drafts remain on Connect and offer Retry. Use your own app remains available under Advanced on Choose agent before creation. Discovery loading or failure never selects the configuration-token page. Self-hosted instances without managed configuration still use their independent own-app flow; saved draft methods do not change automatically. Provisioning continues to require current broker availability.
Local managed-bot qualification
Maintainers with an approved Slack manager app can exercise the real managed journey from an authenticated local test drive exposed through HTTPS (including TryCloudflare). This development transport talks directly to Slack and reuses the production manager-grant vault, state claims, provisioning, completion, and runtime. It does not exercise the Cloud broker's sealed handoff; qualify that separately on staging afterward.
Set NODE_ENV=development, PAPERCLIP_SLACK_MANAGED_SETUP_ENABLED=true, and
PAPERCLIP_SLACK_MANAGER_DEVELOPMENT_CONFIG to an absolute path outside the
checkout containing a mode-0600 JSON file with appId, clientId, and
clientSecret. Use only an authorized qualification manager app. No credentials
are shipped with Paperclip. Production ignores this development configuration,
and Cloud runtime identity continues to select the Cloud broker.
Configure the local instance for authenticated public access, with its public
URL and chat webhook URL pointing to the HTTPS tunnel. Add the exact public URL
plus /api/chat-slack/managed/oauth/callback to the manager app's OAuth redirect
URLs, preserving any existing redirects. Start a new Slack setup: saved
own-app drafts retain their selected method. Authorize the manager app normally;
do not copy user grants from another instance. The second bot should reuse the
same local user's vaulted grant. A changed tunnel requires updating public
origins and the manager redirect before starting fresh authorization.
Remove the temporary redirect when retiring the test drive and securely remove its development credential file. Removing a bot does not revoke a manager grant used by other bots.
Test messages from Settings
Send me a test message sends a DM to the signed-in connection manager, using their linked identity in this workspace. If this bot is not linked yet, Paperclip can reuse that user's verified manager grant or another bot's linked identity in the same company and workspace. Otherwise, the user selects their Slack account and receives a private connection invitation in Slack. They must open that invitation, sign in, and confirm before Paperclip links the account and sends the test DM. The account picker loads further workspace pages on request. Existing revoked or conflicting identity links are not overwritten. Direct messages must be enabled, and the user must be an active company operator.
The action records a durable request before sending. Repeating the same request returns its saved result; an uncertain delivery is never automatically resent. Open Slack configuration opens the saved app's OAuth & Permissions page. Legacy connections without an app ID open Slack's app list instead. Open Slack remains available after automatic setup completion and on the saved connection page. It opens the current user's bot DM when its workspace and channel are known and its linked owner matches the signed-in user. Another manager or an unknown identity uses the saved provider link or Slack instead.
An explicit managed reconnect reinstalls the saved app and verifies the replacement bot credentials. Its request ID is saved before dispatch, so a duplicate completed request does not reinstall again. Credential-configuration recovery still resumes the saved token after a downstream failure. No reconnect creates another Slack app.