# Connectors (https://docs.vitrinka.ai/operator/connectors)



## Which side owns the setting [#owner]

Environment variables supply deployment defaults ([Configuration](/operator/configuration#integrations)). Administrators bind workspaces and projects to external systems through the relevant settings or API. These integrations are optional.

## GitHub App [#github]

One GitHub App per deployment powers commit pills on sets, the per-workspace repository connect, and pull-request and check-suite webhooks that attach references to tasks and paint each pull request's check state (subscribe the App to Pull requests, Pushes and Check suites). The App installation is the workspace's credential; **which repositories belong to which project** is declared per project under Settings → Projects → repositories (the first one is the default that commit pills, the code viewer and release sweeps resolve to when a card carries no set of its own; `vitrinka setup` binds the checkout's origin remote when the project has none yet, and a pushed set still stamps its own repo as the fallback). Set `GITHUB_APP_ID`, `GITHUB_APP_PRIVATE_KEY`, `GITHUB_APP_SLUG`, `GITHUB_APP_CLIENT_ID`, `GITHUB_APP_CLIENT_SECRET` and `GITHUB_WEBHOOK_SECRET`; point the App's webhook at `POST /api/v1/github/webhook` — the App's one URL for every workspace: a delivery is routed to the workspace that connected the installation it names, then verified against the webhook secret. A workspace admin then installs the App on the organization and binds it — the binding requires proof that the installing user owns the installation. A workspace may connect several GitHub accounts (an organization and a personal account, several organizations); each installation serves its own account's repositories, and an installation belongs to exactly one workspace. Settings → GitHub lists what each account reaches, and the repositories rows under Settings → Projects complete from that grant and warn on a `github.com` repository no connected account can read — a caution, never a block, so a self-hosted remote or a repository declared before its account is connected still saves. `GITHUB_TOKEN` is the deployment-wide fallback for commit pills when no App is configured, and `GITHUB_LOGIN=1` adds **Continue with GitHub** to the sign-in pages.

Under `AIR_GAP=1` everything GitHub is blanked ([Air-gapped deployment](/security/airgap#switch)).

## Jira mirror [#jira]

A project can mirror its tasks into Jira. Connect the workspace's Jira in **Settings → Trackers** (or `PUT /api/v1/connectors/jira`) — the same one tracker connection that promoted reports use — then bind the project at `PUT /api/v1/projects/{project}/mirror`. The binding selects the source of truth (`local` or `remote`) and a state map. A sync overwrites conflicts from the other side and records a `mirrored` event. Request a sync with `POST /api/v1/projects/{project}/mirror/sync`. `VITRINKA_CONNECTOR_POLL` controls polling for tickets linked to promoted reports, not this project task mirror.

Binding a mirror and running a sync are admin-and-above operations. A connection a workspace admin saves reaches public internet addresses only; a Jira on a private, loopback or internal address works once deployment authority has saved the connection ([Outbound targets](#outbound)). In an air-gapped deployment such a connection reaches internal addresses only, so only an in-network Jira Server or Data Center works, and a connection nobody with deployment authority saved reaches nothing ([Air-gapped deployment](/security/airgap#stays)).

## Plane [#plane]

`PLANE_API_URL`, `PLANE_API_TOKEN` and `PLANE_WORKSPACE` together turn on the Plane integration: each published set that references an issue gets one comment on it, updated in place on every push. There is no mirror for Plane.

## AI backend [#ai]

`AI_BACKEND_URL` and `AI_BACKEND_TOKEN` configure the backend used by chat and the run view through `/api/v1/eve/`. Mutating requests to the managed backend draw on the organization's AI credits (**Settings → Organization → Plan & billing**); reads remain available, and a workspace's own backend uses its own compute without managed credits. A workspace admin can point one workspace at its own backend under **Settings → Workspace → AI → Backend**, overriding `AI_BACKEND_URL` — on a public address; a backend on a private, loopback or internal address takes deployment authority's save ([Outbound targets](#outbound)). The backend `AI_BACKEND_URL` names is yours as the operator and is not affected. The provider behind @mentions and review passes is chosen per organization under **Settings → Organization → AI**, and an endpoint of its own (`base_url`) follows the same rule. `EVE_URL` and `EVE_SECRET` configure the separate HMAC-signed channel for board mentions and AI reviews.

## Meeting transcription [#stt]

Snap transcribes a meeting on the Mac. A deployment can transcribe on the server instead with one whisper.cpp sidecar beside vitrinka: the enterprise bundle carries it as the optional `stt` profile, on the internal compose network with no published port, so the audio never leaves it. No model ships in any image.

Turn the profile on and point the server at it in `.env`, download a model into the `vitrinka-stt-models` volume once (about 1.6 GB), then bring it up; the sidecar loads the model at start, which can take up to two minutes.

```bash
# .env
COMPOSE_PROFILES=stt
VITRINKA_STT_URL=http://vitrinka-stt:8080

docker compose --profile stt run --rm --entrypoint sh vitrinka-stt -c \
  'curl -fL -o /models/ggml-large-v3-turbo.bin https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-large-v3-turbo.bin'
docker compose up -d
```

`VITRINKA_STT_MODEL` names the model file (default `ggml-large-v3-turbo.bin`, multilingual, so Czech works) and `VITRINKA_STT_THREADS` the decode threads (default `4`; match the cores you give the sidecar). Air-gapped, fetch the model file and the pinned sidecar image on a connected machine, load the image into your registry and point `VITRINKA_STT_IMAGE` at it, then copy the model into the volume with `docker compose --profile stt cp ggml-large-v3-turbo.bin vitrinka-stt:/models/`.

Each organization then opts in: an organization admin turns on **Settings → Organization → AI → server transcription**, which is off by default. From then on, a meeting that arrives without a transcript is filled on the server. `AIR_GAP=1` leaves the sidecar on, because it is an internal endpoint. Meetings on the person's side: [meetings](/use/day#meetings).

## Outbound targets [#outbound]

Three settings make the server dial an address an admin chose: a workspace's issue tracker (**Settings → Trackers**), a workspace's AI backend (**Settings → Workspace → AI → Backend**) and an organization's own AI endpoint (the `base_url` under **Settings → Organization → AI**). Where anyone can sign up, every account administers a workspace and an organization of its own, so an admin's save never decides what your network exposes: a target an ordinary admin saves reaches public internet addresses only — checked when it is saved and again on every request, each redirect included, with no environment proxy. A target on a private, loopback or internal address works only once [deployment authority](/security/identity#deployment) has saved it: a platform admin, or an admin of the organization named by `VITRINKA_OPS_ORG`, who also holds the admin seat the setting needs (an admin of that workspace, or of that organization). That save marks the target; beside a marked tracker or AI backend, Settings reads “saved by deployment authority — may reach your internal network”. An ordinary admin may still edit what it files — project key, issue type, sync mode, model — but changing where it connects (the URL, or the token, key or email that decides how) clears the mark and the target is public-only again. The token deployment authority stored stays with the target it was saved for: an ordinary admin who changes a marked tracker's URL or email must enter a token of their own, and one who re-points a marked AI backend leaves its token behind. Every target's URL must be https, or http to loopback only, because its token or key rides every request; a tracker follows a redirect only to the same host and never to plain http, and an organization's AI endpoint follows none. Under `AIR_GAP=1` a marked target reaches your internal network — loopback, private, link-local, CGNAT and class E, never a cloud metadata or credential endpoint — and never the public internet; an unmarked one reaches nothing, and neither does a provider's public default endpoint. The settings API reports the mark as `deploymentManaged` (organization AI: `deployment_managed`).

A refusal says what to change or whom to ask, and never names an address the host resolved to. A save the rule refuses answers `403` — `422` for a public host under `AIR_GAP=1` — and stores nothing; a request to a target that may not reach its address, such as an internal one nobody re-saved after the upgrade, answers `502` with the code `not_configured`, and retrying does not help.

**After upgrading**, every tracker, AI backend and AI endpoint saved before this rule is unmarked. For each one that points at your internal network — every one, on an air-gapped install — have deployment authority save it once, signed in with the admin seat it needs:

* **Settings → Trackers** → **save**; an empty token keeps the stored one.
* **Settings → Workspace → AI → Backend** → click into the backend URL and press Enter, or send `PUT /api/v1/workspace/ai-backend` with the current `url`.
* **Settings → Organization → AI** → save the provider unchanged.

The readback then shows `deploymentManaged: true` (organization AI: `deployment_managed: true`), and a tracker or AI backend shows the line above in Settings.

## Agents over OAuth [#oauth]

Hosted AI assistants that speak MCP over HTTP connect through OAuth 2.1 with PKCE: metadata at `/.well-known/oauth-authorization-server` and `/.well-known/oauth-protected-resource`. Clients register with a client-ID metadata document (preferred) or dynamically at `POST /oauth/register` — the only way under `AIR_GAP=1`, which fetches no metadata document — and the resource is `/mcp`. A consent covers every team workspace you belong to in the organization it was approved in, checked on each request. Users and workspace admins each see a live list of connections with one-click revocation. Local agents — Claude Code, Codex, Cursor — register the same door and sign in through the same OAuth flow ([MCP clients](/dev/mcp/clients)). The token model is on [Identity and access](/security/identity#agents).
