## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Agents need a governed way to request app connections during issue work. > - The catalog now describes the available providers and setup methods. > - A request must become a durable, company-scoped intent before an operator acts on it. > - This pull request adds that intent runtime across server, agent, CLI, and shared contracts. > - The benefit is a safe bridge from agent need to operator-approved setup. ## Linked Issues or Issue Description Refs #11965 This is stack 7 of 11. It depends on stack 6 and replaces another reviewable part of #11965. ## What Changed - Add connection intent types, validation, service logic, and routes. - Add agent runtime tools and CLI support for connection requests. - Add issue-thread interaction support for connection intents. - Add runtime, route, adapter, and contract tests. - Hold the final resolved-continuation row lock through asynchronous adapter preparation until an actual process spawn, so parking or reassignment cannot cross that boundary. - Report Hermes Gateway's first remote run request through the shared dispatch hook so the resolved-intent lock is released at the true dispatch boundary. - Revalidate the addressed user's live non-viewer membership and connection-management authority for every intent mutation, including OAuth completion. ## Verification - `pnpm --filter @paperclipai/server typecheck` - `pnpm --filter @paperclipai/server exec vitest run src/__tests__/tool-access-service.test.ts` - Result: 176 tests passed. - `pnpm build` - `pnpm --filter @paperclipai/server exec vitest run src/__tests__/heartbeat-stale-queue-invalidation.test.ts` (32 passed; includes non-process dispatch lock-release coverage) - `pnpm exec vitest run --project @paperclipai/server server/src/__tests__/connection-intents-service.test.ts -t "addressed-user mutation"` (1 passed) - `pnpm exec vitest run --project @paperclipai/server server/src/__tests__/tool-access-service.test.ts -t "binds OAuth callback completion to the initiating board session"` (1 passed) - `pnpm --filter @paperclipai/hermes-paperclip-adapter test -- src/gateway/server/execute.test.ts` (23 passed; includes dispatch-hook ordering and exactly-once coverage) - `pnpm --filter @paperclipai/hermes-paperclip-adapter typecheck` ## Risks - A malformed intent could create an unusable operator request. - Validators and company checks reject invalid or cross-company requests. - The final continuation gate holds the issue row lock through adapter preparation until process or remote dispatch; later operator changes use the normal active-run interruption path. - The change does not add a database migration. > I checked `ROADMAP.md`. This stack continues the existing app connection work from #11965 and does not duplicate another planned item. ## Model Used OpenAI Codex, GPT-5. The runtime model ID and context window were not exposed. The model used reasoning, tool use, and code execution. ## 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 linked the public source pull request with `Refs #` - [x] I have not referenced internal or instance-local Paperclip issues or links - [x] My branch name describes the change 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>
3.6 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.
Agent tools
Every active heartbeat with a responsible user receives two run-bound tools:
connections_search({ query })searches first-party connectable definitions 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 end the run pending continuation.
Claude and Codex receive the tools through a native 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.
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 runtime token and stored heartbeat context.
- Tokens are scoped to connection intents, expire after one hour, and are rejected when the heartbeat is no longer running.
- The thread payload contains only service identity, requesting-agent identity, and a safe phase. 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.
- Task-hosted setup locks install reach to the requesting agent; the store host retains its normal broader access choices.
- The intent resolves only after the connection, grant/delegation, profile access, and install succeed. Failures remain pending with
needs_retry. - Closing the task, a newer run requesting the same service, or a newer human task comment expires the intent and deletes linked OAuth state.
- Success and decline wake the assignee once using an interaction-and-status idempotency key and force a fresh continuation session.
Legacy request_confirmation.payload.connectionAuthorization interactions remain readable and resolvable. New agent requests use connection_intent exclusively.