Stetrel

Docs

Install, then let the margin speak.

The Git app is the primary path. The API is for custom gates. Worked comments below are the voice Stetrel actually writes.

01

Install

  1. Open app.stetrel.xyz and sign in with GitHub or GitLab.
  2. Choose the org and the repos Stetrel may read.
  3. Wait for the first index on the default branch. A 2 GB Python service usually finishes in under 20 minutes.
  4. Open a pull request. Comments appear as the Stetrel bot on the hunk.

GitLab uses a group-level app with the same scopes. Self-hosted GitLab needs a reachable webhook URL; VPC customers get that URL inside the perimeter.

Permissions

The GitHub app asks for:

  • contents:read on selected repos, so the indexer can clone.
  • pull_requests:write, so comments and suggested patches can post.
  • checks:write if you turn on a required status named stetrel/review.
  • metadata:read for org and repo names.

We never ask for contents:write on the default branch. Stetrel comments. Required reviewers still merge.

Languages

Strong comments

Python, JavaScript, TypeScript, Go, Java, C, C++, C#, Rust, Swift, PHP, Elixir.

Indexed, thinner comments

Ruby, Kotlin, Scala, Haskell, Lua, Shell, SQL, Terraform, and other trees we can parse enough to embed. Live coverage sits in the org dashboard after the first index.

Tuning

Org settings expose three knobs:

  • Severity: quiet, standard, or strict. Same control as the product tuner.
  • Ignore paths: glob list, for example vendor/** and **/*.generated.ts.
  • Learning: off by default. On Floor and Press you can let dismissed comments update house voice.

Guidelines files

Commit .stetrel/guidelines.md at the repo root, or point the org at a single file. The reviewer must obey every imperative sentence.

# .stetrel/guidelines.md
Prefer the helper in packages/auth/session.py over new token minting.
Never log raw Authorization headers.
Deleting an exported Go function requires a caller search in cmd/ and internal/.

VPC

Press customers receive a container image, an index worker, and pinned model weights. You provide a GPU or CPU pool, object storage for the graph, and a GitHub/GitLab app registered in your tenant. After first boot there is no required outbound call. Book the walkthrough from contact.

API

Base URL: https://api.stetrel.xyz. Authenticate with a bearer token from app.stetrel.xyz. Primary path is still the Git app.

POST /v1/ask
POST /v1/review
GET  /v1/index/status

Review a patch

curl -s https://api.stetrel.xyz/v1/review \
  -H "Authorization: Bearer $STETREL_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "org": "ledger-north",
    "repo": "payments-api",
    "base_sha": "9c1e0a2b",
    "head_sha": "b7f4d91c",
    "severity": "standard"
  }'

Response (abridged)

{
  "review_id": "rvw_1842",
  "index_id": "idx_payments_api_9c1e",
  "comments": [
    {
      "path": "auth/session.py",
      "line": 41,
      "kind": "suggest",
      "body": "admin scope was struck in billing/webhooks.py:88. Restore read, or update apps/api/permissions.py and apps/api/tenants.py together.",
      "citations": ["billing/webhooks.py:88", "apps/api/permissions.py:120"]
    },
    {
      "path": "auth/session.py",
      "line": 44,
      "kind": "stet",
      "body": "log extra matches observability/logfmt.py. Keep this line."
    }
  ]
}

Ask the index

curl -s https://api.stetrel.xyz/v1/ask \
  -H "Authorization: Bearer $STETREL_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "org": "ledger-north",
    "repo": "payments-api",
    "question": "Where do we mint session tokens, and which scopes are legal?"
  }'

Index status

GET /v1/index/status?org=ledger-north&repo=payments-api

{
  "state": "ready",
  "bytes": 147829331,
  "files": 1842,
  "default_branch": "main",
  "refreshed_at": "2026-08-13T10:04:00Z"
}

PR review snippets

These are the comments Stetrel would post on a real hunk. Paths are from a sample payments service.

Auth scope drift

auth/session.pykind: suggest
41scopes=["read"]
41scopes=["admin"]
suggest stetrel

grant_all() is used in billing/webhooks.py for invoice retries. Callers in apps/api/permissions.py expect scoped tokens. A full admin grant here would let a forged role claim skip the tenant check in apps/api/tenants.py:load_tenant.

Deleted helper, live callers

packages/http/retry.pykind: suggest
12def with_backoff(fn, tries=3):
suggest stetrel

Callers remain in billing/webhooks.py:141 and apps/api/outbox.py:67. Deleting with_backoff will raise at invoice retry and at outbox flush. Move those two sites to packages/http/retry_v2.py in this PR, or restore the helper.

stet on a log line

auth/session.pykind: stet
44log.info("session issued", extra={"uid": user.id})
stet stetrel

The extra field matches observability/logfmt.py. A style bot may want this line gone. Keep it. The leak is the scope on line 41.