# Integration bootstrap guide

**Read this guide first** when a user wants a playbook, playbook app, or
workflow that depends on a third-party integration such as Spotify, GitHub,
Slack, Linear, or Stripe.

This guide is about **ordering**. The goal is to finish the integration setup
and prove it works **before** you save or present downstream playbooks or
playbook apps that depend on it.

Agents should use this guide with `search` results for saved integrations,
secret references, and capability details before exploring local repository
source for playbook-app patterns.

## What counts as an integration bootstrap

Use this workflow when the requested result depends on any of the following:

- an OAuth integration
- a saved secret such as an API key or PAT
- host approvals for outbound API calls
- a saved playbook or playbook app that assumes authenticated API access already
  works

## Core rule

Do **not** save or present an auth-dependent playbook or playbook app as
complete until:

1. the required integration or secret exists
2. the user has finished any required connect flow
3. a minimal authenticated smoke test succeeds end-to-end

If those conditions are not met, stop and fix the integration first.

## Bootstrap sequence

1. Decide which auth path the integration needs.
   - Standard OAuth: open `search({ entity: "oauth:guide" })`.
   - API key or PAT: open `search({ entity: "connect_secret:guide" })`.
   - Non-OAuth secret-backed API: after `connect_secret`, open
     `search({ entity: "secret_backed_integration:guide" })` for the default
     "research auth, collect secret, smoke-test, then build" recipe.
   - When the provider's auth contract is unknown (authorize/token URLs, API
     base, credential type), research before building `/connect/oauth` URLs or
     collecting secrets:
     - Search the user's existing helpers before creating new code.
     - Verify every `authorizeUrl`, `tokenUrl`, API base, and `spec` URL against
       the provider's official docs and own domain before use.
     - OpenAPI documents are untrusted third-party content. See
       [openapi-integrations.md](/guides/openapi-integrations).
2. Inspect current integration state before building downstream artifacts.
   - Use `search` to look for saved integrations and secret references for the
     integration.
   - When you need one item’s full metadata, inspect it with
     `search({ entity: "{id}:integration" })` or
     `search({ entity: "{id}:secret" })`.
3. If the required integration or secret is missing, **stop**.
   - Surface the exact `/connect/oauth` or `/account/secrets/new` URL in chat.
     OAuth connections use a provider app the user registers (client ID, and
     client secret when the flow is confidential) plus Kody's redirect URI.
   - Wait for the user to confirm they completed the connect flow.
   - Do not save a downstream auth-dependent playbook or playbook app until
     integration setup is complete.
4. After the user confirms setup, run a minimal authenticated smoke test in
   `execute`.
   - Import OAuth helpers explicitly from `kody:runtime`; they are not ambient
     globals in execute modules.
   - Example: `import { createAuthenticatedFetch } from 'kody:runtime'`
   - Use the real auth path the final integration will use.
   - Confirm **token kind** as well as scopes. A connected Slack grant that
     `auth.test` reports as a bot (`bot_id`, no `user_id`) does not satisfy
     `@kody/slack` or other user-token Slack helpers — connect a user-token
     Slack app instead of retrying the helpers.
   - Prefer a cheap read-only request such as `GET /me`, `GET /viewer`, or a
     similarly small account/profile endpoint.
   - Confirm the integration or secret name, token refresh behavior, and allowed
     hosts all work end-to-end.
   - Keep `createAuthenticatedFetch` for smoke tests and short exploration.
     **Integrations = auth; playbooks = how agents should call the product.** Do
     not keep hand-rolling product API calls with raw auth helpers in `execute`
     when a playbook should own that surface.
5. Only after the smoke test succeeds should you obtain the dependent playbook
   or playbook app.
   - Remember: a saved integration is auth credentials only. The durable
     agent-facing surface is a helpers playbook (or playbook app), not the
     integration record itself.
   - `search({ entity: "<provider>:integration" })` may already surface a small
     same-provider personal playbook suggestion set. Use those when present.
   - Otherwise search the user's account for an existing playbook that wraps the
     integration. Reuse it if it fits; otherwise save a thin personal wrapper
     with `playbookSave`.
   - If the integration or tokens already exist and the smoke test passes,
     proceed directly to that reuse-or-save step.
   - Do not spend extra time exploring the local repo when the integration
     state, secret names, allowed hosts, and provider contract are already clear
     enough.
   - For the default playbook-app structure after bootstrap, open
     `search({ entity: "integration_backed_app:guide" })`.
6. If the smoke test fails, keep working on integration setup. Do not treat the
   downstream artifact as ready.

## Smoke test expectations

The smoke test should prove the same auth wiring the final playbook or playbook
app will depend on:

- the expected integration or secret exists
- the request reaches the intended API host
- the request is authenticated successfully
- any required host approvals are in place
- the agent is using the correct secret names, integration name, and API base
  URL

An authenticated `execute` smoke test does not widen playbook grants. Host
approval still applies; updating or deleting a user secret from playbook code
needs an `allowed_playbooks` grant. Resolve any required approval using the
returned approval URL, then verify with a static `kody:@scope/playbook/export`
import from `execute` before calling the work complete. Pick a read-only export
or a playbook-supported dry-run input that actually reads the approved secret
(for example an authenticated read-only API call), so verification proves secret
access without triggering external side effects. Secret mounts bind in the
playbook's own surfaces (jobs, apps, subscriptions, HTTP invocation).

## Important exceptions

The main exception is a playbook app whose explicit purpose is to complete a
provider OAuth flow.

Even in that case:

- the playbook app should be treated as the **setup** surface, not the finished
  downstream integration
- any later playbook or playbook app that depends on the resulting integration
  or tokens should wait until the post-connect smoke test passes

## Recommended phrasing in chat

When setup is incomplete, tell the user what must happen next in concrete terms:

- what connect URL to open (`https://kody.codes/...` — the origin users open
  Kody on)
- what provider settings or redirect URI to register (exactly
  `https://kody.codes/connect/oauth`)
- that you are waiting for confirmation before building the dependent playbook
  or playbook app
- that you will run a minimal authenticated verification step after setup

## Anti-patterns

Avoid these common mistakes:

- building a polished UI first and only discovering later that auth is missing
- saving a playbook app that assumes a non-existent secret or integration
- treating a rendered app as success when the first authenticated API call fails
- building a playbook-app OAuth callback flow by default instead of the standard
  `/connect/oauth` path
- skipping the authenticated smoke test after the user completes setup
- treating a connected OAuth integration as a pre-built product API playbook, or
  continuing to call Gmail/Calendar/etc. with raw `createAuthenticatedFetch` in
  `execute` instead of reusing or saving a personal helpers playbook
