Task-hosted tool setup kept requester-only defaults, and audience edits could leave runtime installations restricted after permission bindings were widened. Large provider catalogs could also fail before creating an access card. Use the normal agent audience defaults for new tool setup, preserve explicit selections through verified OAuth and draft resumption, and synchronize permission bindings and runtime installations atomically. Enforce agent-edit authority and preserve existing access during additive account reuse. Validation: 915 focused regression tests, typechecks, and builds passed. All 54 CI checks passed and Greptile Apex scored the reviewed head 5/5 with no unresolved threads. Broad local test failures, recoveries, and incomplete heartbeat coverage are documented in the PR. Co-Authored-By: Paperclip <[email protected]>
11 KiB
Connection intents
Connection intents let an agent ask the responsible user for a known service connection without leaving the task thread. The user can reuse an eligible connection or run the normal provider setup in a dialog. A successful resolution grants and installs the connection for the requesting agent, then wakes the task assignee in a fresh run.
Shared setup flow
ui/src/features/connections/ConnectionSetupFlow.tsx is the only connection setup implementation. It owns provider selection, method and identity choices, provider fields, validation, OAuth, access, catalog setup, installs, retry states, and completion. It has two presentation hosts:
ui/src/pages/apps/AppsConnect.tsxsupplies full-page routing and breadcrumbs.ui/src/features/connections/ConnectionIntentInteractionBody.tsxsupplies the task dialog, intent resolution, query invalidation, and focus return.
Provider-specific setup must stay in the shared feature and AppDefinition metadata. Do not add provider forms or connection mutations to either host.
When a task connection needs Paperclip Cloud enrollment, the shared dialog opens enrollment in a separate window. The task keeps its access selection and interaction ID. A new-tab link is available if the window does not open. The dialog reads server enrollment status and refreshes the provider catalog after approval; enrollment alone does not mark the app connected. OAuth retains the interaction ID even if setup resumes in the page host, so the verified callback can resolve the task card and queue its continuation.
Agent tools
Every active heartbeat with a responsible user receives two run-bound tools:
connections_search({ query })searches catalog names and descriptions, plus authorized configured MCP connections and indexed tool descriptions and returnsready,needs_user_action,available, orunavailablefrom the requesting agent's perspective.connection_request({ service })returns immediately when the service is already usable. Otherwise it creates or reuses aconnection_intentand instructs the agent to finish independent work, then yield pending continuation.
The native Paperclip Runner advertises both tools through its server-owned tool authority even with an empty MCP assignment. It captures the current responsible identity at each call. Legacy Claude and Codex receive the tools through a managed MCP server. Local/process adapters receive PAPERCLIP_RUNTIME_TOOLS_* environment variables and CLI guidance. Cloud, HTTP, gateway, and external adapters receive the typed runtime descriptor in their invocation context; compatible adapters may also project it into their remote environment.
Legacy delivery uses the same intent service, setup card, and fresh-session resolution wake. Environment and descriptor delivery require the receiving harness to consume them; they do not establish support in every third-party runtime. The default legacy prompt includes the canonical discovery guidance. A custom promptTemplate replaces that default and should retain the connection guidance if proactive discovery is desired.
The equivalent CLI helpers are:
paperclipai connections search notion
paperclipai connections request notion
The manually configured Paperclip MCP server also advertises connections_search and connection_request. Both helper surfaces require the narrow runtime token and fail outside an active heartbeat.
Security and lifecycle
- Company, agent, run, task, and responsible user come only from the signed legacy runtime token or the native server-owned binding and stored execution identity.
- Tokens are scoped to connection intents, expire after one hour, and are rejected when the heartbeat is no longer running.
- The thread payload contains service identity, requesting-agent identity, a safe phase, and an optional human-selected audience bound to an OAuth draft. It never contains credentials or authorization URLs.
- OAuth state is linked to the interaction. The same-origin callback finalizes the existing connection pipeline, posts only interaction ID/outcome to its opener, and redirects back to the task if there is no opener.
- Personal OAuth defaults to the addressed user and creates an explicit delegation to the requesting agent. Reuse and installs are additive.
- New tool setup uses the same all-agents default and audience controls in Apps and task dialogs. Broadening the audience requires current connection-management authority. AI authentication and inbox setup remain agent-scoped.
- The intent resolves only after the connection, grant/delegation, profile access, and install succeed. Failures remain pending with
needs_retry. - Closing or reassigning the task expires pending intents and deletes linked OAuth state. Ordinary comments and later runs preserve the pending card. Requests reuse the same task, requester, addressed user and service; a different addressed user supersedes an older request for that service.
- Success and explicit decline atomically persist a continuation delivery with resolution. A leased startup/periodic worker dispatches through heartbeat with a unique
connection-intent:<interaction>:<outcome>wake key. It checks assignment, status, membership and current executable access, retries paused/suppressed delivery, and recovers a crash after enqueue without creating a second wake. The continuation forces a fresh provider session; heartbeat queues it behind active execution.
Legacy request_confirmation.payload.connectionAuthorization interactions remain readable and resolvable. New agent requests use connection_intent exclusively.
Model evaluations
The companion paperclip-evals repository owns the connection cases in
evals/runner-api-tools/connection-cases.json. They use the existing real-server
API-tool eval controller and scripts/runner-api-eval-worker.ts, with this
checkout's production tool definitions, connection guidance, and authority.
Natural prompts measure discovery and request selection; explicit contract probes
measure deduplication, readiness, and denied targets. The fixture helper supplies
isolated company records and retains initial and final connection interaction
state. Scoring requires observed calls/results and persisted state, not an
assistant's claim of having connected.
These tool evals do not perform live provider OAuth or establish browser quality. The native and legacy connection browser suites separately cover setup and continuation, while the live-provider journey report records actual authorization and data-read coverage.
Custom targets, readiness and recovery
Catalog slugs remain stable. Search also returns connection:<uuid> for configured custom connections whose active identity grants authorize the responsible person, their company, or the requesting agent. Identifiers are never interpreted as URLs. Configured metadata and tool descriptions, including catalog-provider descriptions, are read only after the company and identity audience checks. Setup choices expose only display and selection metadata; they never include connection configuration, transport settings, or credential fields. Discovery reads the stored index without refreshing providers. Search is ranked with exact provider matches first and capped at 20 results.
ready requires an installed, enabled, healthy executable connection, permitted catalog tools, and a usable runtime identity. An installed connection with denied actions is administrative denial rather than a request to reauthenticate. Runtime calls continue enforcing access after a historical card resolves. If access is ready but the native provider's pinned tool snapshot is older, connection_request queues a fresh session without another authorization card.
New tool setup uses the normal Apps identity and audience choices, including access for all agents. Before OAuth navigation, the addressed human saves the selected audience bound to the draft connection. This save grants no access. The callback prepares the catalog, and intent completion rechecks task ownership, membership and sharing authority before applying the audience and resolving the request atomically. Older clients without a saved audience retain requester-only completion. Reusing an existing account keeps access additive. Callback messages do not establish authorization: the card reloads the durable server result. A blocked popup offers a new-tab fallback; closing or declining provider sign-in keeps the request retryable. Only the card's Not now action declines the request. Decline continuations are told to pursue alternatives and cannot immediately request the same service again.
Saving a tool connection's agent audience updates its permission profile and installations in the same transaction. This includes GitHub credential admission and newly hired agents. Explicitly narrowing or clearing the audience removes the corresponding installations. An access request without exact tool names can review an indexed catalog of up to 500 tools; explicit model-selected tool lists remain limited to 20. Existing action blocks still apply, and write tools granted by an access card require approval.
New task setup must include the requesting agent, even when the human chooses a broader audience. The form and authorization phase save reject an omitted requester before provider sign-in. Save & exit persists the audience on the interaction without granting access; an incomplete draft can still have no agents selected. Resuming OAuth with hidden audience controls retains the saved audience rather than submitting form defaults; gateway draft setup restores the saved selection into its visible controls.
Agent installation changes made by finishing setup use the same agent-edit checks as direct installation changes. Explicit task audiences are checked when saved and again at OAuth completion. Additive completion retains existing installations, including agents using a separate narrow profile; retaining an installation does not add those agents to the app's broader permission profile.
Verification
Service and native-authority tests cover discovery, current identity, company boundaries, cross-run deduplication, additive grants and installs, permission denial, resolution atomicity, restart delivery and stale assignment. tests/e2e/in-feed-native/playwright.config.ts starts source test-drive instances with fresh data directories and a deterministic fake Codex provider plus MCP server. It exercises the real native runner and gateway; it is fixture proof, not live Notion or GitHub proof. Run with pnpm exec playwright test -c tests/e2e/in-feed-native/playwright.config.ts.
Offline Storybook examples live in ui/storybook/stories/connection-setup/in-feed-connections.stories.tsx. Build with pnpm --filter @paperclipai/ui build-storybook, then run pnpm exec playwright test -c tests/storybook-visual/in-feed-connections.config.ts. The suite checks every independently addressable story in both themes, catches play-function failures, and saves screenshots. Live provider acceptance additionally requires a model credential and a test workspace/account; do not describe fixture results or local-trusted testing as authenticated/cloud acceptance.