Skip to content
Like what we’re building? Star on GitHub

Data model — forges, repositories and bots ​

Enabling a bot on a repository binds it in two documents — the webhook config that enforces the binding first, the integration row that records the repo's own choices second, with no transaction over the pair — and the bots they name are slugs a launch resolves through three tiers, never stored keys.

Drawn from the code at commit 61a305262 — main at v3.266.1, after #2391, which carries the launch rung; how this page is kept true: README.

Block 1 — Revi bound to a repository, inside a team ​

  • Six settings sit on both stores — hold labels, the label allowlist, overlap, the operator's launch vars (operator_launch_vars on the config), bot_ids and min_author_role. Which copy counts is a property of the lane, not of the store: every runtime reader of hold labels, the label allowlist and overlap takes the config's copy, while the zero-touch gate lane reads the INTEGRATION's auto_fix_on_gate_failure and its launch_vars[gate_context] pin. Nothing sets min_author_role on either store — the provision only carries the integration's existing value forward — so every lane reads it empty.
  • bot_ids and bot_rules[].bot_id are slugs, not keys: nothing in Mongo resolves them. A launch tries the launching TEAM's bot_sources row, then the row under tenant platform:, then the baked catalog on disk — hence the dotted edges, and why the same slug can mean different code for two teams.
  • The stored uniqueness is (tenant_id, connection_id, repo_full_name); the reverse (tenant_id, webhook_id) index is NOT unique, so one webhook per integration is a provisioning invariant rather than a constraint.

Block 2 — the inbound delivery lifecycle ​

  • The org| prefix of a quota row names a key shape, not an orgs document: the segment is the webhook config's tenant_id, a TEAM.
  • The debounce row's _id IS the subject key, so one push volley costs one review.
  • Only accepted, launched and a post-insert launch_error occupy the lane's key: the refusal statuses — invalid, filtered, and a launch_error the launch gate denied before the insert — are filed under a random uuid.

Block 3 — bot-definition tiers and team extensions ​

  • platform: is an ordinary row in the same collection under a sentinel tenant, not a second collection.
  • The baked tier is a FILESYSTEM: the tiered resolver reads the configured bot roots — by default bots/, examples/ and .botz/ under the work dir.
  • platform_settings holds one document per family and carries no tenant at all. Sovereign runner pools are a FAMILY, not a collection.
  • marketplace carries no tenant_id. org_id is where the tenant hides, and it holds the submitting TEAM: the viewer's reach is their own team id, so an org-scoped entry is visible to ONE team, never org-wide.

Block 4 — the board binding and the provisioning gate ​

  • The binding's _id IS the team id, so one board per team needs no unique index.
  • An approval row exists while the decision is pending.

Collections ​

CollectionPackageDocument structTenant field (values)Unique / TTL indexesTwin
forge_oauth_appspkg/forgeForgeOAuthApptenant_id — a team idunique (tenant_id, provider, forge_base_url, owner_login, security_read_only); the two legacy indexes are dropped by name firstnone (cloud-only)
forge_connectionspkg/forgeConnectiontenant_id — a team idnone unique; tenant_provider, token_expirynone (cloud-only)
repo_integrationspkg/forgeRepoIntegrationtenant_id — a team idtenant_conn_repo_unique on (tenant_id, connection_id, repo_full_name); tenant_webhooknone (cloud-only)
webhook_configspkg/webhooksConfigtenant_id — a team idtoken_hash_unique; tenant_created; no TTLnone (cloud-only)
webhook_deliveriespkg/webhooksDeliverytenant_id — a team ididempotency_unique on the key ALONE; TTL deliveries_ttl on received_at, 90 daysnone (cloud-only)
webhook_deferred_launchespkg/webhooksDeferredLaunchtenant_id, and the first _id segment — a team idnone unique; deferred_fire_at; TTL deferred_ttl on created_at, 7 daysnone (cloud-only)
webhook_quotaspkg/webhooksnone — MongoCounter writes {_id, count}none — the team is an _id segmentnone declared, no TTLnone (cloud-only)
bot_sourcespkg/botsourceBotSourcetenant_id — a team id, or platform:tenant_slug_unique on (tenant_id, slug)memory-only
bot_source_versionspkg/botsourceBotSource, _id rewritten to <row id>:<version>tenant_id — a team id, or platform:none unique; TTL created_at_ttl, 30 daysmemory-only
plugin_sourcespkg/pluginsourcePluginSourcetenant_id — a team idtenant_name_unique on (tenant_id, name); tenant_enablednone (cloud-only)
marketplacepkg/marketplaceEntryorg_id — the submitting TEAM id, stamped on every cloud submission (empty on a local or legacy entry); the owner when scope is orgnone unique; seven query indexes including text_search and moderation_queuefile marketplace.json
platform_settingspkg/platformcfg, pkg/usagecapone struct per family — BotRoles, RunnerPools, Sandbox, BotVars, PlatformCredentials, budgetfloor.Policy (the one family pkg/platformcfg stores whose type lives outside it), the usage capsnone — deployment-wide; the _id is the familynone declared, no TTLnone (cloud-only)
forge_board_bindingspkg/forgeBoardBindingthe _id is the team idnone unique (the _id is the key); board_binding_duenone (cloud-only)
forge_provision_approvalspkg/forgeProvisionApprovaltenant_id — the requesting team; org_id — the approving orgtenant_conn_repo_unique; org; no TTLnone (cloud-only)
teamspkg/identityTeamthe _id is the tenantstub heresee data-model-identity.md
orgspkg/identityOrgthe _id is the orgstub heresee data-model-identity.md
runspkg/store/mongostore.Runtenant_id — a team idstub heresee data-model-runs.md
generic_secretspkg/secretsGenericSecrettenant_id — a team idstub heresee data-model-credentials.md
bot_secret_bindingspkg/secretsBotSecretBindingtenant_id — a team idstub heresee data-model-credentials.md
"FS: baked catalog"pkg/botregistrynot a collection—not a collectionthe bundles shipped in the image, read from bots/, examples/ and .botz/ under the work dir; //go:embed carries four paths only
"external: git repository"not a collection——not a collectionthe repository a plugin source or a listing names