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.

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.

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 — the existing markdown importer round-trips the tree. The Notion connector then tags rows with source='notion' so re-runs upsert instead of duplicating.

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.