--- name: build-integration metadata: version: "1.0" description: "Build, develop, and publish GitBook integrations — apps that run inside GitBook to add custom blocks, react to events, connect external services via OAuth, and extend the editor. Use this skill whenever a task involves the GitBook integrations platform: scaffolding an integration with the GitBook CLI (`gitbook new`), writing or editing an integration's code (`createIntegration`, `createComponent`, ContentKit TSX), configuring `gitbook-manifest.yaml` (scopes, blocks, configurations, secrets), building custom editor blocks or link unfurlers, handling GitBook events like `space_content_updated`, setting up an integration's OAuth flow, running `gitbook dev`, or publishing an integration (private/unlisted/public, marketplace submission). Trigger this even if the user just says they want to 'build an app for GitBook', 'add a custom block', or 'connect to GitBook' without saying the word 'integration'." --- # Build a GitBook Integration A skill for building integrations on GitBook's developer platform: apps that run inside GitBook itself. An integration can render custom blocks in the editor, show configuration UI, listen to events (content updated, Git sync completed, space viewed), authenticate against external services with OAuth, and talk to anything over HTTP. This skill covers the integration lifecycle — scaffold, code, develop, publish. For creating or restructuring the docs *site* an integration might be installed into, defer to `configure-site`; for authoring page content, defer to `write-docs`. ## What an integration is (mental model) An integration is a small TypeScript app executed by GitBook's runtime — not a script injected into pages, and not code running on the user's server. Three consequences shape everything else: 1. **Rendering happens on GitBook's backend.** Your component's `render` function runs server-side on every interaction and returns ContentKit markup (a JSX-like UI description). There is no client-side React tree you control, no DOM access, and UI updates flow through the action → new state → re-render loop. 2. **You cannot inject JavaScript into a site.** The `site:script:inject` and `site:script:cookies` scopes you'll see in GitBook-owned integrations are internal-only. If the user's plan amounts to "add a script tag to their docs", stop and say so early — the supported paths are custom blocks, webframes, and events. 3. **Local development is a proxy, not a server you visit.** `gitbook dev` routes the *installed* integration's traffic to your machine. You never open the dev server's port in a browser; you interact with the integration inside app.gitbook.com. ## The project `gitbook new` scaffolds this shape: ``` my-integration/ ├── gitbook-manifest.yaml # identity, scopes, blocks, configuration schema ├── .gitbook-dev.yaml # local dev config (generated by `gitbook dev`) ├── package.json └── src/ └── index.tsx # entry file — default-exports createIntegration() ``` The entry file (whatever `script:` in the manifest points to) default-exports `createIntegration({ fetch, components, events })`: ```tsx import { createIntegration, createComponent } from '@gitbook/runtime'; const helloBlock = createComponent({ componentId: 'hello-world', // must match a block id in the manifest initialState: { message: 'Say hello!' }, action: async (element, action, context) => { switch (action.action) { case 'say': return { state: { message: 'Hello world' } }; default: return {}; } }, render: async (element, context) => (