Docs

Connectors

Plug Bcontext into GitHub, Slack, Linear, or Notion. Each connector implements the same 4-method interface (authorize / fullSync / handleWebhook / toContextNode), runs on the shared job queue, and upserts nodes idempotently by (source, external_id).

Overview

A connector is a workspace-scoped install of an external system. Install state lives in connector_installs; jobs (full sync, webhook ingest, push-back) flow through connector_jobs with a 30s → 24h retry ladder and a dead-letter status after five attempts.

Secrets never sit in the install row itself. They're stored in Supabase Vault and referenced via secret_ref (formats: vault:<id>, env:<NAME>, or inline:<b64> — the last only valid in dev).

GitHub

A GitHub App per Bcontext deployment, with one installation per workspace. Webhooks signed with the App's secret arrive at /api/webhooks/github and are verified with HMAC-SHA256 (header X-Hub-Signature-256).

Install
POST /api/connectors/github/install
{ "workspace_id": "<uuid>" }

# 200
{ "install_id": "<uuid>", "redirect_url": "https://github.com/apps/<slug>/installations/new?state=<install_id>" }

After the user installs the App, GitHub redirects to /api/connectors/github/callback?installation_id=<n>&state=<install_id>. The callback exchanges the App JWT for an installation access token and persists it via the Vault. Tokens are refreshed before every full sync and push because GitHub installation tokens are short-lived.

Pull side. fullSync backfills the install's repo READMEs (kind=doc) and open issues/PRs (issues → task, PRs → adr).

Push side. Updating a skill node fires pushSkillExports which commits AGENTS.md, CLAUDE.md, .cursor/rules/bcontext.mdc, and .clinerules to every repo in config.repo_allowlist[] on the default branch.

Required env vars: GITHUB_APP_ID, GITHUB_APP_SLUG, GITHUB_APP_PRIVATE_KEY (PKCS8 PEM), GITHUB_WEBHOOK_SECRET.

Minimum repository permissions: Contents read/write (README pull plus explicit rules push), Issues read, and Pull requests read. Subscribe only to Issues, Pull request, Push, and Installation events; the last keeps suspend, unsuspend, and uninstall state aligned locally.

Slack

A Slack App with the user-installable OAuth flow. Scopes intentionally exclude im:* and mpim:* — DMs are off-limits by default for compliance.

OAuth scopes
channels:history,groups:history,users:read,commands,reactions:read
No DM/MPIM scopes. Channel allowlist on connector_installs.config.channels[].

Events arrive at /api/webhooks/slack. The v0 signature scheme (HMAC-SHA256 over v0:<ts>:<body>) is verified with a 5-minute replay window. The URL-verification handshake responds inline.

Slash command. /bcontext search <query> ephemeral-responds with the top-3 RAG hits via the standard retrieve() path. The signature is verified before the response is computed.

Reaction. A :bcontext: reaction on any message in an allowlisted channel creates a doc node, keyed by (channel, ts) so re-reacts upsert.

Required env vars: SLACK_CLIENT_ID, SLACK_CLIENT_SECRET, SLACK_SIGNING_SECRET.

Linear

OAuth against linear.app/oauth/authorize with scopes read,write,issues:create. Webhook payloads arrive at /api/webhooks/linear and are verified via HMAC-SHA256 against the per-install config.webhook_secret (env fallback: LINEAR_WEBHOOK_SECRET).

Pull side. fullSync issues GraphQL viewer.assignedIssues (backlog/unstarted/started) → task nodes. Comments → doc children. State + priority are mapped to Bcontext's backlog/todo/in_progress/done shape.

Push side. Updating a Bcontext task that carries data.linear_id fires pushBcontextStatusToLinear (GraphQL issueUpdate) — fire-and-forget. No-op when the status is unchanged or the connector install is missing.

Required env vars: LINEAR_CLIENT_ID, LINEAR_CLIENT_SECRET, LINEAR_WEBHOOK_SECRET.

Notion (bulk import only)

Notion's webhook surface is unreliable for bulk-import use cases, so this connector is intentionally one-shot. Two paths:

OAuth path. Standard authorize redirect (Notion uses Basic auth on the token endpoint). fullSync crawls /v1/search with cursor pagination persisted in connector_jobs.payload.cursor so the worker can resume after rate-limit pauses.

ZIP path. Drop a Notion export zip on the workspace sidebar. Markdown pages become semantic nodes; every enclosing directory and legacy category frontmatter becomes a reusable tag. Directories never become synthetic nodes.

Required env vars: NOTION_CLIENT_ID, NOTION_CLIENT_SECRET.

Worker

Inline runJob is fast-path for the install + immediate-sync flow. For retried + background work, run the cron:

Vercel Cron
{
  "crons": [
    { "path": "/api/cron/connector-worker", "schedule": "* * * * *" },
    { "path": "/api/cron/webhook-worker",  "schedule": "* * * * *" }
  ]
}
Both crons auth via Bearer CRON_SECRET when set in production.

Build your own

The connector SDK is a 4-method interface. Implement authorize, fullSync, handleWebhook, and toContextNode; call registerConnector(c) at module load. See src/lib/connectors/types.ts for the contract and github/index.ts for the most complete reference.