doc/connections/CONNECTOR-PLAYBOOK.md
This playbook is the repeatable template for adding a vendor to the Apps catalog as data, not as a plugin. It follows the accepted connections framework in PAP-13211, the first-30 rollout matrix in PAP-2432, and the production validation scope in PAP-12373.
Use it when Paperclip acts on an external system through a governed connection: a stored credential, a capability catalog, access profiles and policy rules, and audit. Inbound integrations, such as an external client acting on Paperclip, use gateway or webhook guidance instead.
A complete connector proposal produces:
company_secrets; never raw env values.Default to a catalog entry when the vendor can be represented as metadata plus a transport:
Use a plugin only when the integration needs code that cannot fit inside the common connection model:
A plugin may bundle one or more catalog entries, but it must still create normal applications, connections, credential refs, catalog entries, profiles, policies, and audit events. Plugin code must not bypass the gateway, policy engine, company_secrets, changed-action quarantine, or call-event audit log.
Classify the vendor before writing metadata. Use the PAP-2432 matrix terms so rollout planning, security review, and QA can compare providers consistently.
| Reuse path | Use when | Typical transport | Examples from the matrix |
|---|---|---|---|
| MCP-direct | The vendor exposes an official or stable MCP server whose tools map cleanly to Paperclip grants. | remote_http; local_stdio only for approved trusted templates. | Linear, Notion, Sentry, Vercel, Exa, Apify, Context7. |
| OpenAPI-shim | The vendor has a documented REST/OpenAPI surface but no stable MCP server, and a generated/thin shim can expose safe actions. | Shim service or approved template that presents an MCP-compatible catalog to Paperclip. | Datadog, Apollo, QuickBooks, Ramp/Brex, Zendesk. |
| Vendor-deep-wrapper | The vendor boundary depends on app-installation tokens, event validation, rich domain semantics, resource grants, or high-risk writes. | Vendor-specific wrapper behind the same connection model. | GitHub, Slack, Google Workspace writes, Atlassian, Microsoft 365, Cloudflare, Figma, Stripe, Salesforce, HubSpot, Intercom, PagerDuty. |
Record the classification in the proposal along with the transport and the reason a lighter path is or is not enough.
Choose one auth mode:
company_secrets ref.Credentials always live in company_secrets with redacted metadata and versioned material. The catalog entry records the secret binding shape, not the secret value:
{
"credentialSecretRefs": [
{
"configPath": "credentials.authorization",
"label": "Linear OAuth access token",
"required": true
}
],
"credentialRefs": [
{
"name": "Authorization",
"placement": "header",
"key": "Authorization",
"prefix": "Bearer ",
"secretId": "<resolved at connect time>"
}
]
}
Do not add durable vendor credentials to agent env, project env, runtime env, adapter config, issue comments, screenshots, logs, fixture JSON, or plugin config. Agents receive a run-scoped gateway token; Paperclip resolves the vendor credential server-side and audits the call.
The manifest must explain what the operator gets without exposing protocol details in prosumer surfaces. Developer docs can mention transport, MCP, shim, and gateway terms; the Apps gallery copy should use plain app/action language.
Capture:
key: stable lowercase app key, e.g. linear.name, logoUrl, tagline, description: user-facing metadata.authKind: oauth, api_key, or none.transportTemplate: remote_http URL, approved local_stdio template key, or shim template key once available.credentialFields: labels, vendor-call placement, header key, prefix, help URL, and required state. User-facing labels should be sanitized by the Apps UI copy layer. The saved value is always a company_secrets ref, not an env entry.oauth: provider key, scopes, authorization URL, token URL, metadata URL if applicable.urlPatterns: URLs that can identify this app during paste/import flows.recommendedDefaults: access and risk defaults, especially ask-first risk levels.availability: whether the connector is generally available, gated by deployment config, or needs vendor registration.Keep manifest metadata deterministic and company-scoped at install time. Global catalog data names capabilities; company connection rows hold the configured instance, secret refs, resource filters, status, health, and audit history.
Every connector proposal needs resource filters before write actions are enabled. Filters are part of the connection configuration and must be enforced by the gateway or wrapper, not only by UI affordances.
Common filter dimensions:
The connection health and catalog discovery steps should fail or warn when required filters are absent for S3/S4 providers.
List each initial action before implementation. Do not rely on vendor tool names alone; Paperclip needs normalized metadata for review, policy, and audit.
For each action, capture:
Risk classes:
| Risk | Examples | Default |
|---|---|---|
read | Search, list, fetch metadata/content inside allowed resources. | Active when profile includes the app or read risk level. |
write | Create issue, add comment, update status, append block, trigger redeploy. | Ask-first unless the default profile or a reviewed policy narrows it further. New/changed write tools start quarantined when discovered after initial review. |
destructive | Delete, refund, cancel production deployment, send external message, broad tenant mutation. | Quarantined. Requires explicit operator review and usually a require_approval policy even after review. |
Changed-action quarantine is mandatory: if catalog refresh finds a new or schema-changed write/destructive action, the entry stays hidden from agents until an operator reviews and re-enables it. Do not mark a changed action active just because a previous action with a similar name was active.
The wizard path comes from auth mode and transport:
| Auth mode | Operator path | Stored result |
|---|---|---|
| OAuth | Gallery card -> Connect -> vendor consent -> callback -> configure filters -> health/catalog -> access defaults. | OAuth token material in company_secrets; connection metadata redacted. |
| API key | Gallery card -> paste key -> configure filters -> health/catalog -> access defaults. | Key material in company_secrets; no raw key returned after save. |
| App-installation | Gallery card -> install app/bot -> callback or paste installation identifier -> configure filters -> health/catalog -> access defaults. | Installation credential in company_secrets; installation account metadata redacted. |
| None | Gallery card -> configure allowed resources -> health/catalog -> access defaults. | No vendor secret; connection row still carries config and audit scope. |
The operator should see Apps, Connections, and Review language. Keep protocol language behind Developer/Advanced copy.
Governance is automatic because every catalog entry becomes a normal tool-access object:
disabled and quarantined deny immediately.Recommended defaults for a new catalog entry:
recommendedDefaults.askFirstRiskLevels to ["write", "destructive"] unless the connector is read-only.PAP-12373 owns real-vendor gallery smoke evidence and connector validation. Do not duplicate that issue's screenshot/evidence matrix in this playbook. A connector proposal should instead state exactly how it will be validated there:
If a gallery card cannot pass this path against a real vendor, de-list it or mark it unavailable until the missing auth, transport, or governance dependency is fixed.
Copy this section into a connector proposal or implementation issue.
## Vendor
- App key:
- App name:
- Owner:
- First-30 classification: MCP-direct / OpenAPI-shim / vendor-deep-wrapper
- Reason for classification:
- Security tier: S1 / S2 / S3 / S4
- Plugin needed? No / Yes, because:
## Transport And Auth
- Transport:
- Endpoint or approved template:
- Auth mode: OAuth / API key / app-installation / none
- OAuth scopes or key scope:
- Credential owner: company / user-delegated / app-installation
- Secret storage: company_secrets refs only
- Revocation behavior:
## Resource Filters
- Required filters:
- Optional filters:
- Write-enabling filters:
- Filters enforced by:
## Manifest
- key:
- name:
- tagline:
- authKind:
- transportTemplate:
- credentialFields:
- oauth:
- urlPatterns:
- recommendedDefaults:
- availability:
## Actions
| Tool | Risk | Default status | Filters | Approval default | Audit fields | Negative case |
| --- | --- | --- | --- | --- | --- | --- |
| | read/write/destructive | active/quarantined/disabled | | allow/ask-first/block | | |
## Wizard Path
- User path:
- Configuration steps:
- Error states:
- Redacted metadata shown:
## Governance Defaults
- Default profile:
- Profile bindings:
- Policies:
- Quarantine rules:
- Rate limits:
## Validation Hook
- Real-vendor smoke issue:
- Connect evidence:
- Catalog evidence:
- Allowed read:
- Ask-first write:
- Denied/quarantined case:
- Revoke:
- Audit:
This dry run applies the template to Linear, one of the PAP-2432 Batch A providers.
linearremote_httphttps://mcp.linear.app/mcpread and write initially, with writes governed by profiles and ask-first policies.company_secrets refs; no token in agent env, project env, comments, logs, or screenshots.{
"key": "linear",
"name": "Linear",
"tagline": "Create, update and read tickets.",
"authKind": "oauth",
"transportTemplate": {
"transport": "remote_http",
"url": "https://mcp.linear.app/mcp"
},
"credentialFields": [],
"oauth": {
"provider": "linear",
"scopes": ["read", "write"],
"authorizationUrl": "https://linear.app/oauth/authorize",
"tokenUrl": "https://api.linear.app/oauth/token"
},
"urlPatterns": ["https://mcp.linear.app/*"],
"recommendedDefaults": {
"access": "all_agents",
"askFirstRiskLevels": ["write", "destructive"]
}
}
| Tool | Risk | Default status | Filters | Approval default | Audit fields | Negative case |
|---|---|---|---|---|---|---|
linear.search_issues | read | active after catalog review | workspace, team, project, label, status | allow when profile includes Linear reads | query summary, team/project ids, result count | Granted agent cannot search a disallowed team. |
linear.get_issue | read | active after catalog review | workspace, team, issue id | allow when profile includes Linear reads | issue id, team/project ids | Ungranted agent cannot list or invoke the tool. |
linear.create_issue | write | active only after review; changed versions quarantined | workspace, team, project, label | ask-first by default | team/project ids, title hash, created issue id | Missing project/team filter denies. |
linear.comment_issue | write | active only after review; changed versions quarantined | workspace, team, issue id | ask-first by default | issue id, comment body redaction summary | Agent cannot comment on a disallowed issue. |
linear.update_issue_status | write | active only after review; changed versions quarantined | workspace, team, issue id, allowed statuses | ask-first unless a trust rule covers exact shape | issue id, old/new status if returned | Revoked connection blocks retry. |
No destructive Linear action should ship in the first pass. If a future delete/archive/bulk-update action appears during catalog refresh, it starts quarantined and needs explicit SecurityEngineer review before any policy can expose it.
company_secrets and shows redacted workspace/account metadata.quarantineReason: "pending_review" and are hidden from agent tool lists.Linear's real-vendor evidence belongs in PAP-12373. The smoke pass should prove:
linear.create_issue opens ask-first review and only executes after approval.