Skip to content

Configuration

Configuration is read from environment variables (see .env.example). Short names (AI_*, REVIEW_*, WEBHOOK_*, ...) are explicit aliases; every other thrillhousebot.* key is settable through the standard Quarkus env-var mapping — uppercase with ./- replaced by _ (e.g. thrillhousebot.review.ignored-filesTHRILLHOUSEBOT_REVIEW_IGNORED_FILES). The AI variables are the ones you will change per provider:

VariablePurposeDefault
AI_API_KEYAPI key for the AI provider(required)
AI_BASE_URLOpenAI-compatible base URLhttps://api.deepseek.com/v1
AI_MODELChat model namedeepseek-chat
AI_PROVIDERProvider label for telemetry (gen_ai.provider.name); derived from AI_BASE_URL when unset(derived)
AI_TIMEOUTPer-request timeout300s
AI_REASONING_ENABLEDSend a reasoning hint to reasoning-capable models; when false no reasoning parameter is sent and the provider default appliesfalse
AI_REASONING_EFFORTEffort sent while enabled: none/low/medium/high (none explicitly asks the model not to reason); reasoning tokens are billed as output tokenslow
GITHUB_APP_IDGitHub App ID(required)
GITHUB_PRIVATE_KEYGitHub App private key (PEM)(required)
GITHUB_WEBHOOK_SECRETWebhook HMAC secret(required)
GITHUB_BOT_LOGINSComma-separated bot account login(s) the bot skips to avoid replying to itself; override when deployed under a different App slug (<app-slug>[bot])thrillhousebot[bot],thrillhouse-bot[bot]
WEBHOOK_DEDUP_TTLWebhook deduplication time-to-live for GitHub redeliveries24h
THRILLHOUSEBOT_REVIEW_MANUAL_TRIGGER_ALLOWED_LOGINSComma-separated allowlist of logins permitted to trigger manual /review without repo access(empty)
MANUAL_TRIGGER_AUTH_TIMEOUTUpper bound on the manual-trigger write-access check on the webhook ACK thread; fails closed (denies) if GitHub is slower5s
ACK_REACTION_TIMEOUTUpper bound on the 👀 command-ack reaction on the webhook ACK thread; the wait is abandoned (reaction may land late) if GitHub is slower3s
AUTO_REVIEW_MIN_INTERVALMinimum interval between automatic reviews of the same PR — pushes within the window are skipped silently, even on a new head SHA (in-memory, per replica). A manual /review always bypasses; unset or 0 reviews every push0 (disabled)
WEBHOOK_SKIP_DRAFTSSkip auto-review while a PR is a draft (reviewed once marked ready / on later pushes)false
WEBHOOK_REQUIRED_LABELSComma-separated labels; only auto-review PRs carrying at least one (case-insensitive)(empty — no gate)
WEBHOOK_EXCLUDED_LABELSComma-separated labels; skip auto-review of PRs carrying any (wins over required)(empty)
WEBHOOK_BASE_BRANCHESComma-separated globs; only auto-review PRs whose base branch matches one (e.g. main,release/*). Globs are gitignore-style: * does not cross /, so use ** to span slashes (** alone matches every branch)(empty — all branches)
WEBHOOK_IGNORED_BASE_BRANCHESComma-separated globs; skip auto-review of PRs whose base branch matches one (wins over allowlist; same */** rule — match nested branches with **, e.g. dependabot/**)(empty)
REVIEW_VERIFIER_ENABLEDSecond, skeptical AI pass that re-checks each finding against the diff before posting, dropping or downgrading what it can't confirm (see AI call budget); fails open — a verifier error keeps the original findingstrue
REVIEW_CONVERSATIONAL_REPLIES_ENABLEDAnswer @thrillhousebot mentions in PR threads (including finding replies) with an AI replytrue
REVIEW_ADD_DOCS_ENABLEDAllow the on-demand /add-docs command to generate docstrings as committable suggestionstrue
REVIEW_DIAGRAM_ENABLEDInclude an opt-in Mermaid control-flow diagram in the PR summaryfalse
REVIEW_MAX_INPUT_TOKENSPer-call input-token budget for review calls; large PRs are split into batches that each fit it. Bounded by the active model's input cap (see Per-model AI settings). 0 disables token budgeting48000
REVIEW_OUTPUT_BUFFER_TOKENSTokens reserved out of the input budget for the model's response8192
REVIEW_MAX_AI_CALLSCap on AI calls per review (batch calls plus the final summary call); files that still don't fit are reported by name as omitted6
REVIEW_TOKEN_SAFETY_MARGINFraction of the input budget actually used, absorbing token-estimate error0.9
REVIEW_MAX_DIFF_LINESLine cap on single-call diff renders (/describe, /changelog, /add-docs, replies, budgeting-disabled review). Token-budgeted reviews ignore it (planner owns coverage by tokens); 0 disables the cap5000
THRILLHOUSEBOT_REVIEW_MAX_REVIEW_COMMENTSMaximum inline comments posted per review; findings over the cap are surfaced in the summary instead of dropped50
THRILLHOUSEBOT_REVIEW_MAX_AI_RETRIESAttempts per failed AI call before the review errors out5
THRILLHOUSEBOT_REVIEW_AI_RETRY_BASE_DELAY_MSBase delay of the exponential retry backoff, in milliseconds2000
THRILLHOUSEBOT_REVIEW_AI_TIMEOUT_SECONDSClient-side wait per AI streaming attempt; keep it >= AI_TIMEOUT so timed-out attempts don't leave orphaned provider streams300
THRILLHOUSEBOT_REVIEW_INSTRUCTIONS_FILERepo-relative path of the per-repo instructions file read on each review.github/thrillhousebot.md
THRILLHOUSEBOT_REVIEW_IGNORED_FILESComma-separated gitignore-style globs excluded from review — lockfiles, generated code, build output. * does not cross /; use ** to span directories. Replaces (not extends) the default list, so re-include the defaults you still want**/pom.xml,**/package-lock.json,**/*.lock,**/*.generated.*,**/target/**
REVIEW_LABELS_ENABLEDOpt in to context-aware PR labels (see PR labels)false
REVIEW_LABELS_APPLYWhen labels are enabled, add them to the PR instead of only suggesting them in a commentfalse
REVIEW_LABELS_ALLOW_CREATEAllow the bot to create suggested labels that don't exist yetfalse
REVIEW_LABELS_MAXMaximum labels applied or suggested per PR3
GITHUB_CLIENT_ID / GITHUB_CLIENT_SECRETOAuth credentials for dashboard login(required for dashboard)
DASHBOARD_URLPublic dashboard URL (OAuth callback base)http://localhost:8080
DATASOURCE_DB_KINDh2 or postgresqlh2 (dev), postgresql (%prod)
HTTP_CONNECT_TIMEOUTOutbound HTTP connect timeout (GitHub API, OAuth)10s
HTTP_REQUEST_TIMEOUTOutbound HTTP request timeout (GitHub API, OAuth)10s
WEBSOCKET_KEEPALIVE_MSDashboard WebSocket keepalive interval in ms; 0 or negative disables it (and stale replay-buffer eviction)25000

A review that reports findings makes two model calls by default, not one: the review call itself plus a verification call that re-sends the diff and the candidate findings, so budget roughly 2× tokens per flagged review. On large PRs under token-aware budgeting this becomes N batch review calls + N per-batch verification calls + one summary call. Set REVIEW_VERIFIER_ENABLED=false to skip only the AI verifier — cheaper, at the cost of more false positives; a deterministic hedging guard still runs, and a verifier failure never blocks the review (it fails open, keeping the original findings).

The app validates configuration at startup and fails fast if a required value (GITHUB_APP_ID, GITHUB_PRIVATE_KEY, GITHUB_WEBHOOK_SECRET, AI_API_KEY) is missing or — for the private key — not a valid PEM RSA key, naming every offending variable in one message instead of surfacing later on the first webhook or review. Dashboard OAuth (GITHUB_CLIENT_ID / GITHUB_CLIENT_SECRET) is optional: leave both unset and the dashboard login is simply disabled.

Cost tracking uses per-model pricing keyed by the model name, for example:

thrillhousebot.ai.pricing.deepseek-chat.input-per-1k=0.00014
thrillhousebot.ai.pricing.deepseek-chat.output-per-1k=0.00028

If you switch to a different AI_MODEL, add a matching thrillhousebot.ai.pricing.<model>.* pair so the dashboard can compute cost. Without an entry the bot still records tokens, but warns once and flags sessions as "no pricing" instead of showing $0.

Model-specific settings live under thrillhousebot.ai.models.<model>.*, keyed by the model name (the AI_MODEL value) like the pricing map. Only the active model's entry is read, so you can keep entries for every model you use and switch AI_MODEL freely:

# Input hard cap (the model's context window). The effective review budget is
# min(REVIEW_MAX_INPUT_TOKENS, cap); models without an entry get a 128000 cap.
thrillhousebot.ai.models.deepseek-chat.max-input-tokens=64000
# Per-model overrides of REVIEW_OUTPUT_BUFFER_TOKENS / REVIEW_TOKEN_SAFETY_MARGIN
thrillhousebot.ai.models.deepseek-chat.output-buffer-tokens=8192
thrillhousebot.ai.models.deepseek-chat.token-safety-margin=0.9
# Generation parameters, sent on every chat call when set
thrillhousebot.ai.models.deepseek-chat.temperature=0.2
thrillhousebot.ai.models.deepseek-chat.top-p=0.95
thrillhousebot.ai.models.deepseek-chat.max-output-tokens=8192

Notes:

  • max-input-tokens is a cap, not the budget. REVIEW_MAX_INPUT_TOKENS stays the spend knob; the per-model value keeps it from overshooting the model's real window. To use a large-context model beyond 128k, raise both. Startup logs a warning whenever the cap lowers your configured budget.
  • Quote keys with . or / (thrillhousebot.ai.models."gpt-5.5".…), the same rule as the pricing map. Override via env — hyphen-only keys use underscores (THRILLHOUSEBOT_AI_MODELS_DEEPSEEK_V4_PRO_MAX_INPUT_TOKENS=1000000); dotted keys use the quoted-key form (THRILLHOUSEBOT_AI_MODELS__GPT_5_5__MAX_INPUT_TOKENS=256000). application.properties ships empty stubs for known models so SmallRye can disambiguate hyphenated keys — Quarkus env mapping. For a model without a stub, add an empty thrillhousebot.ai.models."<model>".max-input-tokens= line (external application.properties or -D) alongside the env var.
  • top_k is not available on the OpenAI-compatible wire; it becomes relevant only with native provider integrations.
  • Generation-parameter validation happens at boot: temperature must be in [0, 2], top-p in (0, 1], token counts positive — a typo in any entry (even an inactive model's) fails startup with a message naming the key.

ThrillhouseBot can suggest context-aware labels (area, change type, risk) drawn from the diff. The feature is off by default; turn it on with REVIEW_LABELS_ENABLED=true.

When enabled, the model is shown the repository's existing labels and picks the few that best describe the PR — it only ever chooses from labels that already exist, so it respects whatever label scheme the repo already uses. What happens next depends on REVIEW_LABELS_APPLY:

  • false (default): the suggestions are posted as a one-line comment on the first review, leaving the decision to a maintainer.
  • true: the labels are added to the PR automatically.

Set REVIEW_LABELS_ALLOW_CREATE=true to let the bot create a suggested label that doesn't exist yet (off by default, so it never invents labels), and REVIEW_LABELS_MAX to cap how many labels it applies or suggests (default 3). Labelling is best-effort — a failure here never blocks or fails the review.