Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ GITTENSORY_REVIEW_DRAFT=false
# # /setup returns 400; with it, enter the token in the browser form
# # or send an x-setup-token / Bearer header. Never put this token in
# # the URL; query strings leak to logs, proxies, and browser history.
# SETUP_OUTPUT_PATH=/data/gittensory-app.env # overrides where the first-run setup wizard writes the generated
# # GitHub App credentials file. Default: /data/gittensory-app.env.
# ADMIN_GITHUB_LOGINS=your-github-login # REQUIRED for control-panel ("operator") access. A comma- or
# # whitespace-separated allowlist of GitHub logins, case-insensitive.
# # FAIL-CLOSED: unset/empty means NOBODY can sign into the dashboard,
Expand Down Expand Up @@ -220,6 +222,9 @@ REDIS_URL=redis://redis:6379 # REQUIRED for the self-host review
# BROWSER_WS_ENDPOINT= # ws:// URL of a browserless/chrome instance for visual-review
# # screenshot capture. Unset = visual review is fully inert (no
# # screenshots, no error) — this feature is entirely optional.
# REVIEW_AUDIT_DIR= # persist visual-review screenshot PNGs to this filesystem path
# # instead of re-rendering on demand. Unset = re-render each time.
# # Only relevant when BROWSER_WS_ENDPOINT above is set.
# DISCORD_WEBHOOK_URL= # one Discord channel for per-action notifications (merged/closed/
# # manual) on ANY repo you review. Unset = no Discord notifications.
# # Collection and schema are auto-created at startup. Off when unset.
Expand Down Expand Up @@ -253,6 +258,9 @@ REDIS_URL=redis://redis:6379 # REQUIRED for the self-host review
# LITESTREAM_SECRET_ACCESS_KEY=
# LITESTREAM_ENDPOINT= # e.g. s3.us-west-002.backblazeb2.com (omit for AWS S3)
# LITESTREAM_REGION=us-east-1
# BACKUP_ACKNOWLEDGED=false # silences the boot-time warning about running SQLite with no
# acknowledged backup once you've wired Litestream (or an
# equivalent) above. Default false (warning shown).

# --- Queue worker (#977/#1201) ---
# QUEUE_CONCURRENCY=4 # max concurrent job-processing loops per instance. Default 4; set 1
Expand Down Expand Up @@ -399,6 +407,11 @@ REDIS_URL=redis://redis:6379 # REQUIRED for the self-host review
# DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/... # global fallback for any repo without its own
# DISCORD_REPO_WEBHOOKS={"owner/repoA":"https://discord.com/api/webhooks/...","owner/repoB":"https://..."} # per-repo
#
# Slack notifications: the same per-action events (merged/closed/manual) as Discord above, posted as a Block
# Kit section to one Slack channel. Unset = no Slack notifications. Unlike Discord there is no per-repo map
# today — every repo shares this one webhook.
# SLACK_WEBHOOK_URL=https://hooks.slack.com/services/...
#
# Sentry error tracking. OFF when SENTRY_DSN is unset. Official self-host release images bake
# GITTENSORY_VERSION=gittensory-selfhost@<version>; initSentry uses that as the release id unless
# SENTRY_RELEASE is set explicitly (useful for custom/local images).
Expand Down Expand Up @@ -480,6 +493,12 @@ REDIS_URL=redis://redis:6379 # REQUIRED for the self-host review
# AI_EMBED_MODEL=nomic-embed-text:latest # embedding model for RAG (openai-compatible /embeddings). Its output
# # dimension must match QDRANT_DIM. Used only when RAG is enabled
# # (GITTENSORY_REVIEW_RAG + allowlist).
# AI_EMBED_BASE_URL= # route embeddings to a SEPARATE openai-compatible endpoint instead
# # of the review chain's own AI provider — e.g. a dedicated local
# # Ollama for embeddings while Claude/Codex handle review. Unset =
# # embeddings use the same provider as everything else; setting
# # AI_EMBED_MODEL above alone does nothing without this.
# AI_EMBED_API_KEY= # bearer credential for AI_EMBED_BASE_URL, if it requires one.

# --- Gittensory Orb (#1255; ALWAYS-ON fleet-calibration telemetry) ---
# TELEMETRY NOTICE: running this self-hosted image contributes anonymized gate-calibration data to
Expand All @@ -498,8 +517,13 @@ REDIS_URL=redis://redis:6379 # REQUIRED for the self-host review
# ORB_AIR_GAP=false # air-gapped/OFFLINE deployments only: compute locally, never send
# ORB_ANONYMIZE=true # HMAC-hash repo/PR before export (default true; false = raw names)
# ORB_COLLECTOR_URL=https://gittensory-api.aethereal.dev/v1/orb/ingest # gittensory's hosted collector (default; override for your own)
# ORB_COLLECTOR_TOKEN= # bearer credential for a private/self-hosted collector (ORB_COLLECTOR_URL
# # above). Unset when using gittensory's own hosted collector.
#
# Token broker (optional): get GitHub tokens from the central Orb (you installed the Orb App) instead of running
# your own GitHub App. Set the enrollment secret the operator issued for your install; unset = use your own App key.
# ORB_ENROLLMENT_SECRET= # one-time enrollment secret (a secret — keep it out of version control)
# ORB_BROKER_URL=https://gittensory-api.aethereal.dev # the Orb broker base (default; override for a private deployment)
# ORB_RELAY_MODE=push # push | pull. push registers a public relay URL the broker calls;
# # pull is the right fit behind NAT/tailnet — your instance drains
# # events outbound instead of exposing an inbound endpoint. Default: push.
30 changes: 30 additions & 0 deletions .gittensory.yml.example
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,13 @@ settings:
# Bool. Default: false.
includeMaintainerAuthors: false

# Standing rule: the repo OWNER's own PRs (and ADMIN_GITHUB_LOGINS fleet-operator PRs, #2133) are NEVER
# auto-closed by default -- they may still auto-merge when clean + 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 below + adverse-signal conditions). Automation-bot PRs stay exempt regardless
# of this setting. Bool. Default: false.
closeOwnerAuthors: false

# Require a linked issue on every PR (dashboard equivalent of the toggle that
# can auto-promote gate.linkedIssue to block). Bool. Default: false.
requireLinkedIssue: false
Expand Down Expand Up @@ -512,3 +519,26 @@ settings:
# commandRateLimitMaxPerWindow: 20 # Positive integer. Per-command invocation limit for a CHEAP command (cache-only, no AI call) within the window. Default: 20.
# commandRateLimitAiMaxPerWindow: 5 # Positive integer. Tighter limit for an AI-cost-bearing command (ask/blockers/preflight/reviewability/packet/duplicate-check/next-action/repo-fit). Default: 5.
# commandRateLimitWindowHours: 24 # Positive integer. Rolling window (hours) both limits above count against. Default: 24.

# Per-repo activation overrides for the converged review features that ship behind a deployment-wide
# GITTENSORY_REVIEW_* env kill-switch (rag/reputation/unifiedComment/safety). Each key is `true` (force on
# for this repo, subject to the env flag still being enabled), `false` (force off), or omitted (falls back
# to the GITTENSORY_REVIEW_REPOS allowlist default -- an operator who sets nothing keeps today's behavior).
# features:
# rag: true
# reputation: false
# unifiedComment: true
# safety: true

# Registry-review lane (#2435): lets a self-hosted maintainer point gittensory at their OWN structured
# registry (e.g. a subnet/plugin/package catalog) without a gittensory code change -- reviewing additions
# to a data file the same way it reviews code. Uncomment and set at least entryFileGlob + collectionField
# (both required; the block is ignored with a warning if either is missing).
# contentLane:
# entryFileGlob: registry/*.json # Glob for the structured entry files this lane reviews. Required.
# collectionField: entries # The JSON field holding the collection this lane diffs. Required.
# providerFileGlob: providers/*.ts # Optional glob for source files the entries are validated against.
# artifactGlob: dist/registry.json # Optional glob for a generated/build artifact to cross-check.
# maxAppendedEntries: 1 # Positive integer cap on new entries per PR. Default: unbounded.
# duplicateKeyFields: [slug] # Field name(s) used to detect a duplicate entry. Default: [] (no dedup check).
# validatorId: my-registry-validator # Optional identifier for a custom per-entry validator. Default: none.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ Gittensory CI and gittensory review score, gate, and comment on pull requests. T
- **Unified review comment** — renders the public PR feedback as one in-place comment instead of multiple panels.
- **Per-repo activation** — capabilities roll forward (and back) one flag and one repo at a time via the `GITTENSORY_REVIEW_REPOS` allowlist.

**Check-run and comment surfaces, disambiguated** (a common point of confusion — these are three independent, separately-configured things, not layers of the same feature):

- **`Gittensory Orb Review Agent`** (`gate.*` / `settings.gateCheckMode` / `settings.reviewCheckMode`, off by default) — the authoritative GitHub Check Run carrying the gate's pass/fail verdict. This is the one worth making a required status check.
- **`Gittensory Context`** (`settings.checkRunMode` / `settings.checkRunDetailLevel`, off by default) — a separate, purely advisory Check Run. At its default `checkRunDetailLevel: minimal` it publishes no findings at all; even at `standard`/`deep` it only re-renders content already shown elsewhere. Never make this one required.
- **Inline review comments** (`GITTENSORY_REVIEW_INLINE_COMMENTS` + `.gittensory.yml`'s `review.inline_comments`, off by both by default) — real, reply-able line-anchored PR review comment threads (CodeRabbit-style). This is the ONLY one of the three that posts an interactive per-line thread; the two check runs above never do.

See [Tuning your reviews](https://gittensory.aethereal.dev/docs/tuning) for the full flag, setting, and `.gittensory.yml` reference.

## Start Here
Expand Down
65 changes: 35 additions & 30 deletions apps/gittensory-ui/src/lib/selfhost-env-reference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ export const SELFHOST_ENV_REFERENCE_ROWS: SelfHostEnvReferenceRow[] = [
},
{
name: "AI_EMBED_API_KEY",
firstReference: "src/server.ts:428",
firstReference: "src/server.ts:445",
},
{
name: "AI_EMBED_BASE_URL",
firstReference: "src/server.ts:425",
firstReference: "src/server.ts:442",
},
{
name: "AI_EMBED_MODEL",
Expand Down Expand Up @@ -43,7 +43,7 @@ export const SELFHOST_ENV_REFERENCE_ROWS: SelfHostEnvReferenceRow[] = [
},
{
name: "BACKUP_ACKNOWLEDGED",
firstReference: "src/server.ts:367",
firstReference: "src/server.ts:384",
},
{
name: "BROWSER_WS_ENDPOINT",
Expand Down Expand Up @@ -79,7 +79,7 @@ export const SELFHOST_ENV_REFERENCE_ROWS: SelfHostEnvReferenceRow[] = [
},
{
name: "CRON_INTERVAL_MS",
firstReference: "src/server.ts:904",
firstReference: "src/server.ts:921",
},
{
name: "DATABASE_PATH",
Expand Down Expand Up @@ -111,11 +111,11 @@ export const SELFHOST_ENV_REFERENCE_ROWS: SelfHostEnvReferenceRow[] = [
},
{
name: "GITHUB_CACHE_TTL_SECONDS",
firstReference: "src/server.ts:496",
firstReference: "src/server.ts:513",
},
{
name: "GITTENSORY_REPO_CONFIG_DIR",
firstReference: "src/server.ts:284",
firstReference: "src/server.ts:289",
},
{
name: "GITTENSORY_VERSION",
Expand All @@ -127,11 +127,11 @@ export const SELFHOST_ENV_REFERENCE_ROWS: SelfHostEnvReferenceRow[] = [
},
{
name: "MAINTENANCE_ADMISSION_ENABLED",
firstReference: "src/selfhost/maintenance-admission.ts:129",
firstReference: "src/selfhost/maintenance-admission.ts:126",
},
{
name: "MIGRATIONS_DIR",
firstReference: "src/server.ts:380",
firstReference: "src/server.ts:397",
},
{
name: "OBSERVABILITY_SMOKE_POLL_MS",
Expand Down Expand Up @@ -191,7 +191,7 @@ export const SELFHOST_ENV_REFERENCE_ROWS: SelfHostEnvReferenceRow[] = [
},
{
name: "ORB_BROKER_URL",
firstReference: "src/server.ts:953",
firstReference: "src/server.ts:970",
},
{
name: "ORB_COLLECTOR_TOKEN",
Expand All @@ -207,7 +207,7 @@ export const SELFHOST_ENV_REFERENCE_ROWS: SelfHostEnvReferenceRow[] = [
},
{
name: "ORB_RELAY_MODE",
firstReference: "src/server.ts:955",
firstReference: "src/server.ts:972",
},
{
name: "OTEL_EXPORTER_OTLP_ENDPOINT",
Expand Down Expand Up @@ -243,7 +243,7 @@ export const SELFHOST_ENV_REFERENCE_ROWS: SelfHostEnvReferenceRow[] = [
},
{
name: "PORT",
firstReference: "src/server.ts:703",
firstReference: "src/server.ts:720",
},
{
name: "PUBLIC_API_ORIGIN",
Expand All @@ -259,19 +259,19 @@ export const SELFHOST_ENV_REFERENCE_ROWS: SelfHostEnvReferenceRow[] = [
},
{
name: "QDRANT_URL",
firstReference: "src/server.ts:515",
firstReference: "src/server.ts:532",
},
{
name: "QUEUE_BACKGROUND_CONCURRENCY",
firstReference: "src/selfhost/queue-common.ts:102",
firstReference: "src/selfhost/queue-common.ts:120",
},
{
name: "REDIS_URL",
firstReference: "src/selfhost/preflight.ts:144",
},
{
name: "REVIEW_AUDIT_DIR",
firstReference: "src/server.ts:560",
firstReference: "src/server.ts:577",
},
{
name: "SELFHOST_BUNDLE_ALL",
Expand Down Expand Up @@ -307,23 +307,27 @@ export const SELFHOST_ENV_REFERENCE_ROWS: SelfHostEnvReferenceRow[] = [
},
{
name: "SETUP_OUTPUT_PATH",
firstReference: "src/server.ts:820",
firstReference: "src/server.ts:837",
},
{
name: "SLACK_WEBHOOK_URL",
firstReference: "src/services/notify-discord.ts:173",
},
];

export const SELFHOST_ENV_REFERENCE_MARKDOWN = [
"| Name | First reference |",
"| --- | --- |",
"| `AI_COMBINE` | `src/selfhost/ai.ts:936` |",
"| `AI_EMBED_API_KEY` | `src/server.ts:428` |",
"| `AI_EMBED_BASE_URL` | `src/server.ts:425` |",
"| `AI_EMBED_API_KEY` | `src/server.ts:445` |",
"| `AI_EMBED_BASE_URL` | `src/server.ts:442` |",
"| `AI_EMBED_MODEL` | `src/selfhost/ai.ts:832` |",
"| `AI_ON_MERGE` | `src/selfhost/ai.ts:938` |",
"| `AI_PROVIDER` | `src/selfhost/ai-config.ts:43` |",
"| `ANTHROPIC_AI_BASE_URL` | `src/selfhost/ai.ts:836` |",
"| `ANTHROPIC_AI_MODEL` | `src/selfhost/ai.ts:57` |",
"| `ANTHROPIC_API_KEY` | `src/selfhost/ai.ts:835` |",
"| `BACKUP_ACKNOWLEDGED` | `src/server.ts:367` |",
"| `BACKUP_ACKNOWLEDGED` | `src/server.ts:384` |",
"| `BROWSER_WS_ENDPOINT` | `src/selfhost/stubs/puppeteer.ts:11` |",
"| `CLAUDE_AI_EFFORT` | `src/selfhost/ai.ts:108` |",
"| `CLAUDE_AI_MODEL` | `src/selfhost/ai.ts:49` |",
Expand All @@ -332,20 +336,20 @@ export const SELFHOST_ENV_REFERENCE_MARKDOWN = [
"| `CODEX_AI_MODEL` | `src/selfhost/ai.ts:53` |",
"| `CODEX_AI_TIMEOUT_MS` | `src/selfhost/ai.ts:112` |",
"| `CODEX_HOME` | `src/selfhost/ai.ts:274` |",
"| `CRON_INTERVAL_MS` | `src/server.ts:904` |",
"| `CRON_INTERVAL_MS` | `src/server.ts:921` |",
"| `DATABASE_PATH` | `src/server.ts:250` |",
"| `DATABASE_URL` | `src/selfhost/preflight.ts:201` |",
"| `DISCORD_REPO_WEBHOOKS` | `src/services/notify-discord.ts:41` |",
"| `DISCORD_WEBHOOK_URL` | `src/services/notify-discord.ts:78` |",
"| `FOREGROUND_LIVENESS_ENABLED` | `src/selfhost/foreground-liveness.ts:41` |",
"| `GITHUB_APP_ID` | `src/selfhost/orb-collector.ts:59` |",
"| `GITHUB_APP_PRIVATE_KEY` | `src/selfhost/orb-collector.ts:166` |",
"| `GITHUB_CACHE_TTL_SECONDS` | `src/server.ts:496` |",
"| `GITTENSORY_REPO_CONFIG_DIR` | `src/server.ts:284` |",
"| `GITHUB_CACHE_TTL_SECONDS` | `src/server.ts:513` |",
"| `GITTENSORY_REPO_CONFIG_DIR` | `src/server.ts:289` |",
"| `GITTENSORY_VERSION` | `src/selfhost/health.ts:29` |",
"| `HOME` | `src/selfhost/ai.ts:274` |",
"| `MAINTENANCE_ADMISSION_ENABLED` | `src/selfhost/maintenance-admission.ts:129` |",
"| `MIGRATIONS_DIR` | `src/server.ts:380` |",
"| `MAINTENANCE_ADMISSION_ENABLED` | `src/selfhost/maintenance-admission.ts:126` |",
"| `MIGRATIONS_DIR` | `src/server.ts:397` |",
"| `OBSERVABILITY_SMOKE_POLL_MS` | `scripts/smoke-observability-traces.mjs:8` |",
"| `OBSERVABILITY_SMOKE_TIMEOUT_MS` | `scripts/smoke-observability-traces.mjs:6` |",
"| `OLLAMA_AI_API_KEY` | `src/selfhost/ai.ts:829` |",
Expand All @@ -360,11 +364,11 @@ export const SELFHOST_ENV_REFERENCE_MARKDOWN = [
"| `ORB_AIR_GAP` | `src/selfhost/orb-collector.ts:161` |",
"| `ORB_ANONYMIZE` | `src/selfhost/orb-collector.ts:174` |",
"| `ORB_APP_ID` | `src/selfhost/orb-collector.ts:59` |",
"| `ORB_BROKER_URL` | `src/server.ts:953` |",
"| `ORB_BROKER_URL` | `src/server.ts:970` |",
"| `ORB_COLLECTOR_TOKEN` | `src/selfhost/orb-collector.ts:205` |",
"| `ORB_COLLECTOR_URL` | `src/selfhost/orb-collector.ts:172` |",
"| `ORB_ENROLLMENT_SECRET` | `src/selfhost/orb-collector.ts:165` |",
"| `ORB_RELAY_MODE` | `src/server.ts:955` |",
"| `ORB_RELAY_MODE` | `src/server.ts:972` |",
"| `OTEL_EXPORTER_OTLP_ENDPOINT` | `src/selfhost/otel.ts:47` |",
"| `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` | `src/selfhost/otel.ts:45` |",
"| `OTEL_SERVICE_ENVIRONMENT` | `src/selfhost/otel.ts:60` |",
Expand All @@ -373,14 +377,14 @@ export const SELFHOST_ENV_REFERENCE_MARKDOWN = [
"| `OTEL_TRACES_SAMPLER` | `src/selfhost/otel.ts:74` |",
"| `OTEL_TRACES_SAMPLER_ARG` | `src/selfhost/otel.ts:76` |",
"| `PGVECTOR_ENABLED` | `src/server.ts:230` |",
"| `PORT` | `src/server.ts:703` |",
"| `PORT` | `src/server.ts:720` |",
"| `PUBLIC_API_ORIGIN` | `src/selfhost/preflight.ts:192` |",
"| `QDRANT_API_KEY` | `src/selfhost/qdrant-vectorize.ts:50` |",
"| `QDRANT_DIM` | `src/selfhost/qdrant-vectorize.ts:71` |",
"| `QDRANT_URL` | `src/server.ts:515` |",
"| `QUEUE_BACKGROUND_CONCURRENCY` | `src/selfhost/queue-common.ts:102` |",
"| `QDRANT_URL` | `src/server.ts:532` |",
"| `QUEUE_BACKGROUND_CONCURRENCY` | `src/selfhost/queue-common.ts:120` |",
"| `REDIS_URL` | `src/selfhost/preflight.ts:144` |",
"| `REVIEW_AUDIT_DIR` | `src/server.ts:560` |",
"| `REVIEW_AUDIT_DIR` | `src/server.ts:577` |",
"| `SELFHOST_BUNDLE_ALL` | `scripts/build-selfhost.mjs:13` |",
"| `SELFHOST_SERVICE` | `scripts/smoke-observability-traces.mjs:5` |",
"| `SELFHOST_SETUP_TOKEN` | `src/selfhost/preflight.ts:186` |",
Expand All @@ -389,5 +393,6 @@ export const SELFHOST_ENV_REFERENCE_MARKDOWN = [
"| `SENTRY_RELEASE` | `src/selfhost/otel.ts:62` |",
"| `SENTRY_SERVER_NAME` | `src/selfhost/sentry.ts:383` |",
"| `SENTRY_TRACES_SAMPLE_RATE` | `src/selfhost/sentry.ts:171` |",
"| `SETUP_OUTPUT_PATH` | `src/server.ts:820` |",
"| `SETUP_OUTPUT_PATH` | `src/server.ts:837` |",
"| `SLACK_WEBHOOK_URL` | `src/services/notify-discord.ts:173` |",
].join("\n");
Loading
Loading