# Integration bootstrap

**Read this guide first** when a user wants a package, package 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 packages or package
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 package-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 package or package app that assumes authenticated API access already
  works

## Core rule

Do **not** save or present an auth-dependent package or package 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:
     - Prefer `communitySearch` for a close helpers package, then fork it.
     - For registry lookup (canonical domain, credential types, spec URLs),
       `communityFork` `@kody/integrations-sh` and call `search` / `discover`.
     - 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](/docs/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 package or package 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; packages = how agents should call the product.** Do
     not keep hand-rolling product API calls with raw auth helpers in `execute`
     when a package should own that surface.
5. Only after the smoke test succeeds should you obtain the dependent package or
   package app.
   - Remember: a saved integration is auth credentials only. The durable
     agent-facing surface is a helpers package (or package app), not the
     integration record itself.
   - If the user just finished `/connect/oauth`, read `nextSteps` from the
     connect success payload/UI first: it already includes same-provider
     community helpers suggestions (listing name, kody id, or tags must mention
     the connected provider) and a create-helpers prompt.
   - `search({ entity: "<provider>:integration" })` may already surface a small
     same-provider package suggestion set (user packages first, else community
     listings). Use those when present.
   - Otherwise search the user's account for an existing package that wraps the
     integration, then call `communitySearch` for the provider or workflow. If a
     listing is close to the user's goal, fork or point them at one-click
     install, then adapt — do not reimplement from scratch.
   - Create or save a thin helpers package only when no suitable community
     listing exists.
   - If the integration or tokens already exist and the smoke test passes,
     proceed directly to that fork-or-create 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 package-app structure after bootstrap, open
     `search({ entity: "package_apps:guide#after-an-integration-smoke-test" })`.
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 package or package
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** grant package secret access
for unadopted community-forked packages. Self-authored packages and adopted
forks (`communityForkAdopt` after source review) get automatic read/use access
to user secrets (host approval still applies; updating or deleting a user secret
from package code still needs an `allowed_packages` grant). After you save or
publish a secret-using package, read `pending_secret_package_approvals`; when it
is non-null (unadopted community forks), either adopt after review or surface
`bulk_approval_url`, wait when required, and verify with a static
`kody:@scope/package/export` import from `execute` before calling the work
complete. Pick a read-only export or a package-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 package's own surfaces (jobs, apps,
subscriptions, HTTP invocation).

## Important exceptions

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

Even in that case:

- the package app should be treated as the **setup** surface, not the finished
  downstream integration
- any later package or package 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 package or
  package 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 package app that assumes a non-existent secret or integration
- treating a rendered app as success when the first authenticated API call fails
- building a package-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 package, or
  continuing to call Gmail/Calendar/etc. with raw `createAuthenticatedFetch` in
  `execute` instead of searching for / forking / creating a helpers package
