Files
paperclip-docs/docs/reference/api/connection-intents.md
c65bc9a9bf Release docs for paperclip v2026.916.0 (#125)
Brings **paperclip-docs** in line with paperclip **v2026.916.0**,
shipping the `v2026.831.1 → v2026.916.0` cycle drafted on `nightly`,
stamped to the release tag, with a documentation changelog entry.

This branch was cut from `nightly` **after** merging `origin/main` into
it, so it sits on top of the operator-first connectors catalog (#124)
rather than reverting it.

## Manifest

**New pages (4)**
- `docs/reference/api/connection-intents.md` — Connection Intents API
- `docs/reference/cli/connections.md` — `connections` command
- `docs/reference/cli/managed-agent.md` — `managed-agent` command
- `docs/reference/cli/test-drive.md` — `test-drive` command

**Updated pages (17)**
- Roles & Permissions + Company Administration — `tools:*` role-default
changes
- Connect an Agent to GitHub — managed GitHub connection (Connectors),
Option C
- Agents API — Managed/Remote Agent Profiles, `***REDACTED***` env
serialization
- Tool Gateway API — agent self-authorization (`start-authorization`,
`token`)
- Instance Admin API — instance-settings + task-drain routes
- Plugin SDK — `ctx.access` + `ctx.authorization` clients,
login-PTY/duplex streaming
- Environment Variables — Paperclip ID Connector block + HTTP adapter
allowlist var
- Adapters: Codex (`gpt-5.6-sol` default, Fast mode, auth cache), Claude
Code (Fable 5.1 + CLI floor), Grok Local (SuperGrok subscription auth),
HTTP (SSRF guard), Sandbox Providers (Daytona warm runner), OpenCode
(model pre-flight)
- CLI: `adapter detect-model`, `onboard` tool-action signing secret
- Command palette — recent tasks in sidebar
- `docs/reference/changelog.md` — new `v2026.916.0` accordion entry

All 21 touched pages stamped `paperclip_version: v2026.916.0`.

## Verification

**Tag-accuracy gate (Phase 5.7)** — `check-tag-accuracy.mjs --tag
v2026.916.0 --base main --head nightly` flagged 5 pages, **every one
verified present in the code at the release tag** and cleared as known
`verify-edit` false-positive classes. No content was quarantined; **no
post-tag leaks**:

| Page | Flagged claim(s) | Verified at tag |
|---|---|---|
| `cli/connections.md` | `PAPERCLIP_RUNTIME_TOOLS_*` (3) | present in
`cli/src/commands/client/connections.ts` (runtime-injected env) |
| `cli/managed-agent.md` | `--profile-key`, `--api-key-secret-id` |
present in `cli/src/commands/managed-agent.ts`
(`.requiredOption`/`.option`) |
| `cli/test-drive.md` | `--harness` | present in
`cli/src/commands/test-drive.ts` (`new Option`) |
| `deploy/environment-variables.md` | `PAPERCLIP_ID_CONNECTOR_*` (5) |
present in `.env.example` at tag |
| `plugins/sdk.md` | `PLUGIN_*` (6) | present in
`packages/plugins/sdk/src/index.ts` (exported constants) |

Rationale: nightly's drafts were authored from parent `af8439a`, **226
commits inside the tag**, so they document in-tag surfaces by
construction.

### ⚠ Drift
`check-drift.mjs --against v2026.916.0` returned 14 records — **all
verified present at the tag** (checker false positives), listed here for
the reviewer to confirm:

- **env-var (9, high-confidence in the tool, verified present):**
`PAPERCLIP_WORKSPACE_GIT_SCAN_{CONCURRENCY,QUEUE_CAPACITY,TIMEOUT_MS,CACHE_TTL_MS}`
and
`PAPERCLIP_ID_CONNECTOR_{BASE_URL,ENVIRONMENT,INSTANCE_ID,SIGN_PRIVATE_KEY,SEAL_PRIVATE_KEY}`
— all present in `.env.example` at the tag; the drift scanner's scoped
file scan missed them.
- **Verify: rest-route (5, medium-confidence):** `POST/PUT/GET
/api/companies/import/transfers*` — present at the tag in
`server/src/routes/companies.ts`, registered via the
`COMPANY_IMPORT_TRANSFERS_ROUTE_PATH` prefix constant (the documented
prefix/dynamic-registration blind spot).

### ⚠ Verification Failures
None. All tag-accuracy and drift flags above were verified present at
the tag.

### ↻ Renames detected
None. The connectors catalog (`docs/connectors/**`) arrived via the
`main` merge (#124), not as a renamed surface; no new top-level draft
directories were introduced this cycle.

## Screenshots
**238 of 342 screenshots** flagged stale across 50 routes (see
`SCREENSHOTS_PENDING.md`). This is a wide 16-day window touching ~921 UI
files, so most are dependency-touch flags rather than confirmed visual
changes. Recommend `npm run screenshots:refresh` on this release branch
as a dedicated follow-up before merge; PNGs go to a separate PR for
human review.

## Build gates (all green on this branch)
- `npm run docs:build` — 257 pages
- `npm run docs:test` — SEO metadata, crawlable-links (71,749 links
resolve), doc-link-resolution, skill-source-blocks, static-routes,
hierarchical-nav

## Post-merge checklist (Phase 9 — do NOT skip)
- [ ] Squash-merge this PR (repo is squash-only)
- [ ] `git checkout main && git pull`
- [ ] `git tag docs/v2026.916.0 && git push --tags`
- [ ] `node scripts/sync/realign-nightly.mjs release/v2026.916.0 --push`
(restore ancestry; keep nightly post-tag drafts)
- [ ] Flip `nightly` `.sync-state.json` back to `"branch_mode":
"nightly"` (leave `base_release_tag` at `v2026.916.0`)
- [ ] Verify `docs.paperclip.ing` serves the release: a new page
(`/reference/cli/test-drive/`), a changed page, and the changelog top
entry reads `Docs for v2026.916.0`
- [ ] If production is stale, republish: `npm run docs:build && npx
wrangler pages deploy .site --project-name paperclip-docs --branch main`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
Co-authored-by: DevRel Gemini <[email protected]>
Co-authored-by: Paperclip <[email protected]>
Co-authored-by: Dotta <[email protected]>
Co-authored-by: ClaudeCoder <[email protected]>
2026-09-17 11:15:48 +02:00

8.5 KiB
Raw Permalink Blame History

paperclip_version, seo_title, seo_description
paperclip_version seo_title seo_description
v2026.916.0 Connection Intents API When an agent needs a service it cannot reach, it opens a connection intent so the responsible person can connect the app and unblock the task.

Connection Intents

A connection intent is how an agent asks a human to hook up a service it can't yet reach. Say an agent is working a task and needs GitHub, but no usable GitHub connection is installed for it. Rather than fail, the agent opens a connection intent: Paperclip drops a connection card into the task thread addressed to the run's responsible person, the agent ends its run, and it waits. When the person connects the app (or declines), the intent resolves and the agent's heartbeat is woken so it can pick the task back up.

So an intent has a small lifecycle. An agent requests a service; that creates a pending connection_intent interaction on the issue. The addressed person can move it through phases (requested, authorizing, needs_retry) while they work, then complete it by choosing a connection, or decline it with an optional reason. Completing wires the chosen connection to the requesting agent — delegating the person's identity grant and installing the connection onto that agent — and marks the intent connected.

These endpoints are internal. They power two specific callers: the agent runtime (through a runtime-tools token) and the board UI where a person answers the connection card. They are not a general-purpose surface for direct API consumers — you would not normally script against them the way you might the Tool Gateway. They are documented here for completeness, and because the runtime side is exposed over MCP. If you are new to the API, read the API Overview first for base URL, authentication, and error conventions.

The surface splits cleanly in two: runtime tools the agent calls, and board routes the addressed person calls.


Runtime tools (agent-facing)

These routes are mounted at the server root — not under /api — and authenticate with a runtime-tools bearer token, the short-lived token bound to one heartbeat run. The token is revalidated against its run on every call, so a token from an ended run stops working. A missing, invalid, or expired token returns 401 Unauthorized with { "error": "Runtime tools token is missing, invalid, or expired" }.

Under the hood the token resolves to the run's company, agent, and responsible user, and to the task the run is bound to. A run with no bound task can't request connections (422 with Connection requests require a task-bound heartbeat run), and a task that is already done or cancelled is rejected too.

MCP endpoint

The tools are exposed as a small Model Context Protocol server:

GET  /mcp/runtime-tools
POST /mcp/runtime-tools

The GET is a discovery response: { "name": "paperclip-runtime-tools", "protocolVersion": "2025-03-26" }. The POST speaks JSON-RPC 2.0.

Method What happens
initialize Returns protocolVersion 2025-03-26, a capabilities.tools block with listChanged: false, and serverInfo naming paperclip-runtime-tools version 1.
notifications/initialized Acknowledged with 202 Accepted and no body.
tools/list Returns the two tools below, each with name, description, and inputSchema.
tools/call Runs a tool. Takes params.name and params.arguments.

An unknown params.name returns 404 with JSON-RPC error -32601, Unknown tool: <name>. Any other method returns 404 with -32601, Unknown method: <method>.

The two tools:

Tool Arguments Purpose
connections_search query (string, optional) List connectable services, filtered by a free-text query, with each one's readiness for this agent.
connection_request service (string, required) Ask for a specific service by slug; returns it ready if already usable, otherwise opens an intent.

REST convenience routes

The same two operations are also reachable as plain JSON, for callers that don't want to speak MCP:

POST /runtime-tools/connections/search
POST /runtime-tools/connections/request

search takes a body of { "query": <string> } — trimmed, up to 200 characters, defaulting to "" (which lists everything). It returns:

{
  "version": 1,
  "query": "github",
  "results": [
    {
      "service": "github",
      "name": "GitHub",
      "description": "...",
      "logoUrl": "...",
      "methods": [ { "key": "...", "label": "...", "auth": "..." } ],
      "state": "ready",
      "connectionId": "..."
    }
  ]
}

Each result's state is one of ready (a connection is connected and usable by this agent right now, with connectionId set), needs_user_action (a matching connection exists but isn't usable yet), available (the service can be connected but nothing exists), or unavailable (the service offers no connection methods).

request takes a body of { "service": <string> } — trimmed, 1–120 characters. A service that isn't available comes back 422 with Connection service <slug> is not available. Otherwise it returns:

{
  "version": 1,
  "service": "github",
  "state": "needs_user_action",
  "connectionId": null,
  "interactionId": "...",
  "instruction": "A connection card was sent to the responsible user. End this run and wait for continuation."
}

If the service is already connected, state is ready, connectionId is set, interactionId is null, and the instruction says the service is available in this run. Requests are idempotent per run and service, so calling twice won't spawn two cards.


Board routes (human-facing)

These are mounted under /api and answer the connection card. Every one is a board route: the caller must be on the board, have access to the intent's company, and — importantly — be the user the card was addressed to. Anyone else gets 403 Forbidden with { "error": "Only the addressed user can act on this connection request" }. The {interactionId} in each path is the connection-intent interaction on the issue.

Read setup options

GET /api/connection-intents/{interactionId}/setup-options

Returns what the person needs to answer the card: the interaction itself, the requested service (name, description, logo, and connection methods), any existingConnections for that service they're eligible to use, and the requestedAgentId. If the service is no longer offered, this responds 404 with Connection service is no longer available.

Update the phase

POST /api/connection-intents/{interactionId}/phase

Moves the intent through its working phases. Body:

Field Required Notes
phase yes One of requested, authorizing, or needs_retry.

Any other value returns 422 with { "error": "phase must be requested, authorizing, or needs_retry" }.

Complete the intent

POST /api/connection-intents/{interactionId}/complete

Connects the chosen connection to the requesting agent and resolves the intent as connected. Body:

Field Required Notes
connectionId yes A UUID for the connection to use. Must belong to the intent's service.

The chosen connection has to match the requested service (else 404, Connection does not match this intent) and be active and enabled (else 409, Finish and test this connection before using it for the task). An intent that's already resolved returns 409 with Connection intent is already resolved. Completing delegates the person's identity grant to the agent and installs the connection onto it; sharing a company-wide connection requires connection-management authority (tools:manage_connections). On success it logs an issue.connection_intent_connected activity and wakes the assigned agent's heartbeat.

Decline the intent

POST /api/connection-intents/{interactionId}/decline

Resolves the intent as declined. Body:

Field Required Notes
reason no Trimmed text, up to 4,000 characters.

Logs an issue.connection_intent_declined activity and, like complete, wakes the assigned agent so it can react.


Where to go next

  • Tool Gateway API — applications, connections, catalogs, and the policy engine a completed connection plugs into.
  • Issues API — connection intents live as interactions on an issue thread.
  • API Overview — base URL, authentication, company scoping, and the shared error-code table.