diff --git a/apps/gittensory-ui/src/routes/docs.self-hosting-ai-providers.tsx b/apps/gittensory-ui/src/routes/docs.self-hosting-ai-providers.tsx index f9af1045a8..fb694c42f6 100644 --- a/apps/gittensory-ui/src/routes/docs.self-hosting-ai-providers.tsx +++ b/apps/gittensory-ui/src/routes/docs.self-hosting-ai-providers.tsx @@ -69,6 +69,28 @@ function SelfHostingAiProviders() { ANTHROPIC_API_KEY= ANTHROPIC_AI_MODEL=claude-sonnet-4-6`} /> +

+ ANTHROPIC_AI_BASE_URL defaults to https://api.anthropic.com — set + it only to route through a gateway or proxy in front of the real Anthropic API. +

+ +

OpenAI API

+

+ Distinct from OpenAI-compatible below: this is the native OpenAI API path ( + AI_PROVIDER=openai), for when you have an OpenAI account key rather than a + gateway or local endpoint. +

+ +OPENAI_AI_BASE_URL=https://api.openai.com/v1 +OPENAI_AI_MODEL=gpt-5.5`} + /> +

+ OPENAI_AI_BASE_URL and OPENAI_AI_MODEL already default to the + values shown — set them only to override the endpoint or model. +

OpenAI-compatible endpoint

+

Ollama (dedicated provider)

+

+ AI_PROVIDER=ollama is a separate provider id from routing Ollama through{" "} + openai-compatible above — use whichever matches how you want + fallback/dual-review chains to identify it. Defaults to a local Ollama at{" "} + http://localhost:11434/v1 with no API key. +

+ +

+ Set OLLAMA_AI_BASE_URL to http://ollama:11434/v1 when using the + compose ollama profile; OLLAMA_AI_API_KEY is normally left blank + for a local, unauthenticated Ollama instance. +

+

Fallback and dual review

A comma-list is a fallback chain by default. Use this for subscription CLIs when you want diff --git a/apps/gittensory-ui/src/routes/docs.self-hosting-configuration.tsx b/apps/gittensory-ui/src/routes/docs.self-hosting-configuration.tsx index 86c5dd4358..501d4a1af6 100644 --- a/apps/gittensory-ui/src/routes/docs.self-hosting-configuration.tsx +++ b/apps/gittensory-ui/src/routes/docs.self-hosting-configuration.tsx @@ -65,6 +65,41 @@ function SelfHostingConfiguration() { ]} /> +

Precedence

+

+ Where policy for a given repo can live is one question; which layer wins when more than one + is set is another. Most specific wins, in this order: +

+
    +
  • + the repo's .gittensory.yml (public repo config, or the mounted private + per-repo config file below if GITTENSORY_REPO_CONFIG_DIR is set), then +
  • +
  • the per-repo database settings (the dashboard), then
  • +
  • built-in safe defaults.
  • +
+

+ Within .gittensory.yml itself, the typed gate: block is an alias + for the gate-related fields and wins over the generic settings: block for those + same fields — so a value written under both gate.duplicates and{" "} + settings.duplicates resolves to whatever gate.duplicates says. One + exception to the whole precedence chain: hard path guardrails ( + settings.hardGuardrailGlobs) are config-as-code only — omitted or empty means + no path guardrails, never a hidden engine fallback, regardless of what the database row or + defaults would otherwise imply. +

+

+ This page covers the environment layer and the shape of the config file. For the full field + list — every gate: and settings: key, its default, and what it + does — see Tuning your reviews, and for a complete, + commented, copy-pasteable manifest see{" "} + + .gittensory.yml.example + {" "} + in the repo — the authoritative reference for every field, including several documented only + in its comments (see below). +

+

Required baseline env

`} Any FOO_FILE is loaded into FOO at startup. Explicit{" "} FOO wins over the file variant.

+

+ Every command example on these docs pages hardcodes :8787 — that's the + default, not a fixed port. Set PORT to listen on something else; update your + compose port mapping and any curl/health-check commands to match. +

GITTENSORY_MCP_TOKEN is a shared, end-user-obtainable CLI credential (the normal alternative to gittensory-mcp login), so it must not implicitly stage @@ -109,6 +149,33 @@ MCP_ACTUATION_REPO_ALLOWLIST=owner/repo-one, owner/repo-two contributor/operator tools.

+

Data paths

+
    +
  • + MIGRATIONS_DIR (default migrations) — where the self-host + runtime looks for SQL migration files to auto-apply at boot. Only relevant for a custom + build that ships migrations somewhere other than the default in-image location. +
  • +
  • + REVIEW_AUDIT_DIR — when set, persists visual-review screenshot PNGs to this + filesystem path so they're served from cache instead of re-rendered on every request. + Unset means each screenshot is re-rendered on demand. Only relevant when{" "} + BROWSER_WS_ENDPOINT (see{" "} + REES enrichment) is also set — visual review is + fully inert without it. +
  • +
  • + CODEX_HOME — do not set this for the app container. The Codex provider + rejects a container-set CODEX_HOME outright (fails closed with{" "} + codex_credential_isolation_required) because codex exec reads + attacker-controlled PR title/body/diff text, and a mounted OAuth home on the same + filesystem could otherwise leak into review output via prompt injection. This is why the + Codex subscription path additionally requires the explicit{" "} + GITTENSORY_ENABLE_UNSAFE_CODEX_REVIEWER=1 opt-in — see{" "} + AI providers. +
  • +
+

GitHub API cache

Redis backs shared caching for stable GitHub GET responses, including repeated installation, @@ -132,6 +199,101 @@ GITHUB_METADATA_CACHE_TTL_SECONDS=600`} self-host Grafana dashboard includes the hit/miss/coalesced/error breakdown. +

Queue cadence and startup

+

+ CRON_INTERVAL_MS (default 120000, ~2 minutes) is the tick that + drives the maintain/sweep and sync cadence — contributor evidence, burden forecasts, RAG + re-indexing, drift scans, and notifications all fan out from it.{" "} + QUEUE_BACKGROUND_CONCURRENCY (default 1) caps how many + low-priority background jobs may occupy a QUEUE_CONCURRENCY slot at once, + independent of live webhook/review work. +

+

+ QUEUE_STARTUP_JITTER_MIN_JOBS (default 8) sets the pending-job + count below which the queue skips its startup jitter delay — useful on a small instance + where you'd rather a handful of jobs start processing immediately after boot than wait out a + jitter window meant to stagger many instances restarting at once. +

+ +

Maintenance and installation backpressure

+

+ Two independent, opt-out admission checks run at queue-claim time, on top of GitHub + rate-limit deferral, so background work never starves live PR review or overloads the host. + Both grew out of real production incidents — an un-jittered cron enqueue and an unbounded + per-installation background fan-out — and every value below is optional with a sane default. +

+ +

+ Tune MAINTENANCE_ADMISSION_MAX_LIVE_PENDING (default 5),{" "} + MAINTENANCE_ADMISSION_MAX_LIVE_AGE_MS (default 120000),{" "} + MAINTENANCE_ADMISSION_MAX_PENDING (default 15),{" "} + MAINTENANCE_ADMISSION_MAX_HOST_LOAD (default 1.5, a 1-minute + load-average-per-core ceiling), and{" "} + MAINTENANCE_ADMISSION_MAX_BACKLOG_CONVERGENCE_PENDING (default 10) + if you register many repos or run a busy instance and see maintenance sweeps lagging behind + where you'd like. A denial backs off by MAINTENANCE_ADMISSION_DEFER_MS (default{" "} + 180000, 3 minutes) before jitter, but two escape hatches stop a deferral from + becoming a starve: MAINTENANCE_ADMISSION_MAX_DEFER_AGE_MS (default{" "} + 14400000, 4 hours) force-admits any maintenance job that has waited this long + regardless of pressure, and the shorter MAINTENANCE_ADMISSION_DRAIN_AGE_MS{" "} + (default 600000, 10 minutes, clamped to the 4-hour ceiling) specifically drains + the oldest jobs in a backed-up maintenance_pending_high lane so it can actually + shrink instead of denying every claim for hours. Set{" "} + MAINTENANCE_ADMISSION_ENABLED=false to fully disable the policy and return to + the old always-run behavior. +

+

+ GITHUB_INSTALLATION_CONCURRENCY_LIMIT (default 2) is the per- + installation ceiling; GITHUB_INSTALLATION_CONCURRENCY_DEFER_MS (default{" "} + 15000, 15 seconds) is its base backoff before jitter. Raise the limit if a + single large installation's background work is being throttled and you have GitHub + rate-limit and host headroom to spare; set{" "} + GITHUB_INSTALLATION_CONCURRENCY_ENABLED=false to disable the check entirely. + This check only applies to background jobs that call GitHub — live PR review ( + github-webhook/agent-regate-pr) is never subject to it. +

+ + Where the two backpressure checks above defer background work, foreground liveness protects + live PR-review work FROM unbounded rate-limit deferral (its own worst case is up to ~65 + minutes per defer under sustained pressure, e.g. right after a deploy floods a shared REST + budget). A periodic sweep force-releases any foreground-priority job that has genuinely + waited past FOREGROUND_LIVENESS_MAX_DEFER_MS (default 600000, 10 + minutes), checked every FOREGROUND_LIVENESS_CHECK_INTERVAL_MS (default{" "} + 60000, 1 minute — deliberately not the 1-second poll tick, so a job that is + still genuinely rate-limited waits for the next sweep instead of busy-looping), releasing at + most FOREGROUND_LIVENESS_MAX_RELEASE_PER_SWEEP jobs per tick (default{" "} + 25, oldest first, so a large inherited backlog ramps up gradually instead of + every released job re-tripping the same rate-limit bucket at once). It also runs once at + boot, so a restart self-heals inherited over-deferral. Set{" "} + FOREGROUND_LIVENESS_ENABLED=false to disable the sweep. + + +

Tracing and telemetry env

+

+ OTEL_EXPORTER_OTLP_ENDPOINT overrides the OpenTelemetry collector target only + if you're routing to an external collector instead of the bundled one (default{" "} + http://otel-collector:4318 under the observability profile).{" "} + OTEL_SERVICE_NAME (default gittensory-selfhost) is the service + name traces and metrics are tagged with — set a distinct value per instance if you run more + than one and want to tell them apart in Grafana/Tempo. OTEL_TRACES_SAMPLER{" "} + (default parentbased_traceidratio) picks the sampling strategy for app + job/provider traces; pair it with OTEL_TRACES_SAMPLER_ARG (for example{" "} + 0.05 to sample 5% of root traces). +

+

Generated env reference

This table is generated from process.env.NAME reads in{" "} @@ -199,12 +361,212 @@ features: rag: false reputation: false`} /> +

+ The features: block above overrides a deployment-wide{" "} + GITTENSORY_REVIEW_* flag (rag, reputation, unifiedComment, safety) for this one + repo, with three states per key: true forces the capability on for this repo + (still subject to the env flag itself being enabled — it can never turn on a capability the + operator has fully disabled at the deployment level); false forces it off for + this repo regardless of the env flag; and omitting the key entirely falls back to the{" "} + GITTENSORY_REVIEW_REPOS allowlist default, i.e. today's behavior for an + operator who hasn't set anything here. See{" "} + Tuning your reviews for the full{" "} + GITTENSORY_REVIEW_* flag list this overrides. +

+ +

Config-as-code blocks with no dashboard equivalent

+

+ Everything above has a dashboard row it mirrors. The fields below exist{" "} + only in .gittensory.yml — there is no DB column or dashboard + toggle for them, so a self-host operator who never reads the example file may not know they + exist. +

+

gate.checkMode

+

+ Controls only whether/how the required Gittensory Orb Review Agent check-run is + published — it never affects gate evaluation, comments, labels, audit records, or autonomous + merge/close, all of which run identically in every mode. Takes precedence over the legacy{" "} + gate.enabled boolean when both are set. +

+ + + Before switching to disabled, remove Gittensory Orb Review Agent{" "} + from this repo's branch-protection or ruleset required-status-checks list — Gittensory + cannot do this on your behalf, and leaving it required with nothing to satisfy it means + GitHub shows a pending status forever. Keep your real CI/Codecov/security checks required; + this setting only ever affects Gittensory's own check-run. + +

+ For a repo that has never been configured, the default is disabled; an + already-configured repo keeps its current effective behavior. Self-hosters running + high-volume autonomous review should prefer visible or disabled{" "} + over required — Gittensory's own merge/close decisions never depend on + this check either way. +

+ +

Other gate-only fields

+
    +
  • + gate.cla — sub-object for the CLA gate (gate.claMode, documented + on Tuning your reviews): consentPhrase (a + case-insensitive substring gittensory looks for in the PR description),{" "} + checkRunName (an existing CLA-bot check-run name that also satisfies + consent), and checkRunAppSlug (the trusted App slug required to have produced + that check-run, so a contributor-controlled same-name check can't satisfy a blocking + legal gate). Either detection method is enough; both may be set. All default to{" "} + null (not configured). +
  • +
  • + gate.expectedCiContexts — CI check/status context names to treat as required + when GitHub branch protection returns no readable required-status-checks (unconfigured, or + a 403 from a token lacking administration:read — common for GitHub App + installations, especially self-host). Merged with branch-protection contexts when both are + readable; used alone when branch protection is null/empty. Default: not configured, which + keeps the fold-all fail-closed behavior when branch protection is also unreadable. +
  • +
  • + gate.premergeContentRecheck — when true, a PR touching{" "} + migrations/** gets a fresh GitHub read of the base branch's current + migration filenames immediately before an agent-driven merge, catching a different PR that + merged a same-numbered migration in the meantime. A live collision holds the PR instead of + merging blind. Default false — costs one extra GitHub API call per + migrations-touching PR. +
  • +
  • + gate.requireFreshRebaseWindow — when the base branch has advanced within this + many minutes of the actual merge decision, forces an update_branch + fresh CI + recheck before merging, instead of trusting a possibly-stale{" "} + mergeable_state: clean read. A bounded retry cap prevents a fast-moving base + from live-locking the PR. Default null (never force). +
  • +
  • + gate.dryRun — when true, the posted check conclusion remains the + real non-enforcing verdict while comments/check text may also show the would-be stricter + verdict for AI-review blocker mode. It does not disable downstream merge/close planning + for failures from already-enforced gates. Default false. +
  • +
  • + gate.firstTimeContributorGrace — reserved and currently inert: parsed and + stored, but the gate does not read it. A first-time contributor with a real blocker is + one-shot closed the same as a repeat contributor. Kept for potential future use. +
  • +
+ +

settings.closeOwnerAuthors and blockedPaths

+

+ settings.closeOwnerAuthors — by default, the repo owner's own PRs (and{" "} + ADMIN_GITHUB_LOGINS fleet-operator PRs) are never auto-closed; they may still + auto-merge when clean and passing, or fall to a manual hold. Set true to make + owner/admin-authored PRs eligible for auto-close like a contributor's, still gated by + the close autonomy class and adverse-signal conditions. Automation-bot PRs stay exempt + regardless of this setting. Default false. +

+

+ blockedPaths (top-level, alongside wantedPaths) — globs off-limits + to contributors. Touching one yields a manifest_blocked_path finding, + enforceable when gate.manifestPolicy: block is set. Default []{" "} + (nothing blocked). +

-

Instance-wide write switches

+

settings anti-abuse block

+

+ A cluster of contributor-abuse guardrails, all config-as-code only, all off/unset by + default: +

+
    +
  • + Open-item capscontributorOpenPrCap and{" "} + contributorOpenIssueCap bound how many PRs/issues a single non-owner/ + non-admin/non-bot contributor may have open at once; a contributor's newest item + above the cap is closed with a clear reason, their oldest items up to the cap stay open. + Both are unset (no cap) by default. contributorCapLabel (default{" "} + over-contributor-limit) is the label applied on close — set it to explicit{" "} + null to close silently. contributorCapCancelCi cancels in-flight + CI runs on a cap-triggered close (requires the actions: write App permission; + degrades gracefully without it) and falls back to the{" "} + CONTRIBUTOR_CAP_CANCEL_CI_DEFAULT env var when unset. +
  • +
  • + Review-nag cooldownreviewNagPolicy (off/ + hold/close, default off) throttles a contributor + who repeatedly pings @gittensory for review on the same PR/issue, once they + exceed reviewNagMaxPings (default 3) within{" "} + reviewNagCooldownDays (default 5). reviewNagLabel{" "} + (default review-nag-cooldown) is applied alongside the hold/close action.{" "} + reviewNagMonitoredMentions extends the same cooldown to specific maintainer + logins a contributor keeps tagging directly instead of (or in addition to){" "} + @gittensory. +
  • +
  • + Exemptions and account ageautoCloseExemptLogins is a + shared, repo-scoped list of logins never throttled or closed by these deterministic + mechanisms, on top of the standing owner/admin/bot exemption.{" "} + accountAgeThresholdDays (default null, off) applies{" "} + newAccountLabel (default new-account) to a PR from a + below-threshold-age account — friction/visibility only, never an automatic close on + account age alone, and never for the owner, admins, or bots. +
  • +
  • + Command rate limitcommandRateLimitPolicy ( + off/hold, default off) generalizes the review-nag + pattern to every @gittensory command, not just review-request pings.{" "} + commandRateLimitMaxPerWindow (default 20) bounds cheap, + cache-only commands; commandRateLimitAiMaxPerWindow (default 5) + is the tighter limit for AI-cost-bearing commands (ask/blockers/preflight/etc.);{" "} + commandRateLimitWindowHours (default 24) is the rolling window + both limits count against. +
  • +
+ +

contentLane

+

+ Lets a self-hosted maintainer point Gittensory at their own structured registry (a + subnet/plugin/package catalog, for example) without a Gittensory code change — reviewing + additions to a data file the same way it reviews code. Unconfigured by default; uncomment + and set at least entryFileGlob and collectionField (both required + — the whole block is ignored with a warning if either is missing). +

+ + +

Instance-wide write switches (SELFHOST_DEPLOYMENT_MODE)

+

+ SELFHOST_DEPLOYMENT_MODE forces write suppression for the whole instance, + regardless of per-repo autonomy — useful for running a self-host in parallel with the live + cloud App on the same webhooks, provably posting nothing until an explicit cutover. +

GitHub App and Orb, then add optional context through AI providers,{" "} REES, or{" "} - RAG. + RAG. For the full gate-mode and per-repo settings + reference — including the AI-review combine modes and a complete worked manifest — see{" "} + Tuning your reviews.

); diff --git a/apps/gittensory-ui/src/routes/docs.self-hosting-github-app.tsx b/apps/gittensory-ui/src/routes/docs.self-hosting-github-app.tsx index cd94fa5160..92311b00b0 100644 --- a/apps/gittensory-ui/src/routes/docs.self-hosting-github-app.tsx +++ b/apps/gittensory-ui/src/routes/docs.self-hosting-github-app.tsx @@ -175,7 +175,7 @@ GITHUB_WEBHOOK_SECRET=`} { title: "What's never exported", description: - "Repo/owner/PR names, commit SHAs, source code, diffs, comments, or logins. Repo/PR identifiers are HMAC-anonymized with a per-instance secret gittensory's own collector never holds.", + "Repo/owner/PR names, commit SHAs, source code, diffs, comments, or logins. Repo/PR identifiers are HMAC-anonymized by default with a per-instance secret gittensory's own collector never holds.", }, { title: "Disabling it", @@ -184,6 +184,22 @@ GITHUB_WEBHOOK_SECRET=`} }, ]} /> + + Repo/PR identifiers are HMAC-anonymized by default ( + ORB_ANONYMIZE=true), not unconditionally — an operator can set{" "} + ORB_ANONYMIZE=false to export raw repo/PR names instead. There's no scenario + where gittensory's own hosted collector needs raw names; the toggle exists for an operator + running their own collector (see ORB_COLLECTOR_URL below) who + wants readable identifiers in their own infrastructure. Leave this at the default unless you + control the collector end. + +

+ ORB_COLLECTOR_URL overrides the export endpoint — default gittensory's hosted + collector, or point it at your own private collector if you're aggregating telemetry + yourself instead of sending it to gittensory. ORB_COLLECTOR_TOKEN is the bearer + credential for that private collector; leave it unset when using gittensory's own hosted + collector, which accepts unauthenticated, rate-limited, aggregate-only exports. +

Brokered Orb env

`} ORB_BROKER_URL=https://gittensory-api.aethereal.dev ORB_RELAY_MODE=pull # or omit for push (the default) -- see "Choosing a relay mode" below`} /> +

+ ORB_APP_ID overrides the seed used to derive this instance's stable, + anonymous instance_id in telemetry exports — normally derived from{" "} + GITHUB_APP_ID. A brokered instance holds no App ID of its own (it uses the + broker's tokens instead), so its identity falls back to the export secret unless you + set ORB_APP_ID explicitly. Most operators never need to set this; it exists so + a brokered instance's telemetry identity can be pinned independent of any App ID. +

Choosing a relay mode: pull vs. push

diff --git a/apps/gittensory-ui/src/routes/docs.self-hosting-operations.tsx b/apps/gittensory-ui/src/routes/docs.self-hosting-operations.tsx index 7800038b54..d1b3f3b389 100644 --- a/apps/gittensory-ui/src/routes/docs.self-hosting-operations.tsx +++ b/apps/gittensory-ui/src/routes/docs.self-hosting-operations.tsx @@ -133,6 +133,42 @@ docker compose --profile postgres --profile observability --profile backup up -d watching for.

+

Two different Discord/Slack integrations

+

+ Don't confuse these — they're unrelated features that happen to share the same two chat + platforms: +

+ +

+ DISCORD_WEBHOOK_URL is a global fallback Discord channel for any repo without + its own webhook. DISCORD_REPO_WEBHOOKS is a per-repo override — a JSON map of{" "} + owner/repo to a webhook URL — for routing different repos' notifications to + different channels. Both are unset (no Discord notifications) by default. +

+ +

+ SLACK_WEBHOOK_URL posts the same per-action events (merged/closed/manual) as a + Block Kit section to one Slack channel. Unlike Discord there is no per-repo map today — + every repo shares this one webhook. Unset means no Slack notifications. +

+

Resource profiles

Measured rows below come from a real production instance running the full @@ -420,6 +456,14 @@ volumes: runner-work-2:`} /> +

Sentry server name

+

+ SENTRY_SERVER_NAME sets a clean, human name for this instance in Sentry (for + example gittensory-us-east). Unset defaults to the OS hostname — never the + public-origin URL. Set this explicitly if you run more than one instance and want to tell + their Sentry events apart at a glance instead of matching container hostnames. +

+

Sentry tracing

Leave SENTRY_TRACES_SAMPLE_RATE unset or blank to disable trace export, or set diff --git a/apps/gittensory-ui/src/routes/docs.self-hosting-rag.tsx b/apps/gittensory-ui/src/routes/docs.self-hosting-rag.tsx index 7da7216b19..d3e459a661 100644 --- a/apps/gittensory-ui/src/routes/docs.self-hosting-rag.tsx +++ b/apps/gittensory-ui/src/routes/docs.self-hosting-rag.tsx @@ -53,6 +53,17 @@ function SelfHostingRag() { ]} /> +

Choosing a vector backend

+

+ SQLite vectors are the default and need no extra service — fine for a small instance or + getting started. Qdrant (QDRANT_URL, --profile qdrant) is the + preferred dedicated vector store for review context at scale. A third option,{" "} + PGVECTOR_ENABLED=true, uses the Postgres pgvector table instead — only relevant + if you're already running the postgres profile and want to avoid standing up a + separate Qdrant service. Leave it false (the default) when{" "} + QDRANT_URL is set; Qdrant remains preferred for RAG at scale. +

+

Qdrant and Ollama example

mxbai-embed-large. If a Qdrant collection already exists, recreate it before changing dimensions.

+

+ AI_EMBED_API_KEY is the bearer credential for AI_EMBED_BASE_URL, + if that endpoint requires one — a local Ollama typically doesn't, but a hosted + OpenAI-compatible embeddings endpoint usually does. Setting AI_EMBED_MODEL{" "} + alone does nothing without AI_EMBED_BASE_URL also set; unset, embeddings use + the same provider as the rest of the review chain. +

Indexing

diff --git a/apps/gittensory-ui/src/routes/docs.tuning.tsx b/apps/gittensory-ui/src/routes/docs.tuning.tsx index 98608f20d4..79c3f92f8e 100644 --- a/apps/gittensory-ui/src/routes/docs.tuning.tsx +++ b/apps/gittensory-ui/src/routes/docs.tuning.tsx @@ -1,4 +1,4 @@ -import { createFileRoute } from "@tanstack/react-router"; +import { createFileRoute, Link } from "@tanstack/react-router"; import { DocsPage } from "@/components/site/docs-page"; import { CodeBlock, Callout } from "@/components/site/primitives"; @@ -58,6 +58,13 @@ function Tuning() { algorithm and never reveal review direction, so a contributor cannot read them and game the gate.

+

+ This page covers those fields in depth, for the cloud service or a self-host alike. If + you're running your own instance, see{" "} + Self-host configuration for the + environment layer (deployment-wide flags, secrets, and where config files can live) that + sits underneath everything below. +

Every feature flag ships OFF. A repo with no settings and no{" "} @@ -494,7 +501,10 @@ settings:

For the privacy guarantees behind these surfaces, see{" "} Privacy & security. For the maintainer install and - trust flow, see Install & trust. + trust flow, see Install & trust. If you're + self-hosting, see Self-host configuration{" "} + for the environment layer these settings sit on top of, plus the config-precedence rules and + a link to the fully-commented .gittensory.yml.example.

);