TensorCheck documentation.
TensorCheck reviews GitHub.com pull requests and posts its findings back to the pull request as a GitHub review and a Check Run. Run it hosted on TensorPlane, or run the daemon yourself against your own GitHub App.
What TensorCheck is.
TensorCheck watches a GitHub organization through a GitHub App. When an eligible pull request is opened or updated, it checks the change out into a sandbox, reviews it, and posts the result as a pull request review (a summary plus inline comments) and a Check Run. There are two ways to run it, and each runs the review differently: hosted on TensorPlane, where the platform centrally manages the GitHub App installation and runs the review for you on the platform, using the inference provider and model alias you select for the repository in the console; or self-hosted, where you build and run the daemon against your own GitHub App and it invokes a local CLI (for example codex) that you have logged in on your host. TensorCheck integrates with GitHub.com only; GitHub Enterprise Server is not supported, and no other source-control host is integrated.
Run TensorCheck without operating it.
On the hosted platform, TensorPlane centrally manages the GitHub App installation and enrolls your installation; reviews run on the platform. You configure everything from the console.
Create an account
Sign up with your email and complete email verification. You can add multi-factor authentication — an authenticator app (TOTP) or a WebAuthn security key or passkey.
Create an organization
Create a TensorPlane organization to hold your repositories, billing, and settings.
Install the GitHub App and select repositories
Install the centrally managed TensorPlane GitHub App on your GitHub organization and choose which repositories it may review. The installation is what lets TensorCheck read pull requests and post reviews and Check Runs.
Add a provider credential
Add an inference-provider API key in the console's provider-credential settings. After you save it, the console stores it sealed and shows only a fingerprint and the last four characters — the secret itself is never displayed again. You can replace or delete a credential later.
Set the repository's review provider and model
For each repository, select one review inference provider and one provider-scoped model alias in the repository's review configuration.
Open a pull request for an automatic review
Open a pull request on a selected repository and TensorCheck reviews it automatically, posting a review and a Check Run.
Rerun with a /review comment
To rerun a review on demand, comment
/reviewon the pull request. Manual reruns are authorized: the comment author must have GitHub repository permission ofwriteor higher (maintainandadminalso satisfy it);readandtriageare denied.See review history and operational status
The console lists your organization's review history and shows current operational status.
Trial and billing
New organizations get a 14-day trial with no card required. When you're ready, start a subscription through Stripe checkout, and manage your subscription and payment details in the Stripe billing portal from the console. The hosted MVP does not claim an availability SLA.
What is skipped: draft pull requests (until they are marked ready for review) and pull requests from forks. Automatic reviews can also be switched off per repository (automatic_trigger); with them off, an exact /review comment still requests a manual run.
Exact-head ownership: the hosted platform binds every review attempt to one exact head SHA. Immediately before publishing, it re-resolves the pull request's current eligible head; if the head has moved, the older attempt's findings do not become the current pull request review or the merge-gating Check Run — the newest eligible head SHA owns the canonical Check Run.
Build and run the daemon yourself.
The steps below stand up TensorCheck for development and evaluation against your own GitHub App. Production service activation is not documented here — there is no service unit or install recipe, and the standalone webhook endpoint is not a production ingress. Hosted production runs on TensorPlane.
Prerequisites
- A Linux host (also builds and runs on macOS for local testing).
- Rust ≥ 1.75 (rustup recommended).
gitonPATH.- The
claudeand/orcodexCLI installed and already logged in on the host, as the same OS user that will runtensorcheck. - A GitHub App installed on each organization you want to review.
- GitHub.com (this build targets
api.github.com; GitHub Enterprise Server is not supported).
1. Build
Clone the repository, then build the release binary. It is written to ./target/release/tensorcheck.
2. Create the GitHub App
In GitHub, under Settings → Developer settings → GitHub Apps → New GitHub App, set these repository permissions:
| Permission | Level | Why |
|---|---|---|
| Pull requests | Read & write | Fetch PR data, post the review and inline comments. |
| Checks | Read & write | Create and update the Check Run. |
| Contents | Read-only | Clone/fetch the PR head for the sandboxed checkout. |
| Metadata | Read-only | Mandatory baseline. |
Subscribe to two events: Pull request (drives open / reopen / ready-for-review / synchronize) and Issue comment (drives the /review command). For the webhook, use only an isolated development endpoint and a development webhook secret — keep the secret, GitHub won't show it again. Generate and download a private key (.pem), install the App on the org, and note the numeric App ID.
3. Confirm the CLIs are logged in
As the same OS user that will run the daemon, confirm the CLI you plan to use returns a JSON result rather than a login prompt:
4. Write a minimal config.toml
Config is layered TOML — secrets are referenced by env-var name or file path, never inlined. This minimal file defines one org:
[server] listen = "127.0.0.1:8080" work_dir = "/var/lib/tensorcheck" environment = "development" development_standalone = true [review] cli = "claude" # or "codex" [review.prompt] system = "You are a rigorous senior code reviewer. Be specific and actionable." [org.my-org] app_id = 123456 private_key_file = "/etc/tensorcheck/my-org.pem" webhook_secret_env = "MY_ORG_WEBHOOK_SECRET" # NAME of the env var holding the secret
Export the webhook secret the tool reads from the env var you named:
5. Validate the configuration
check-config loads and validates the config, prints the org count, and exits.
6. Try one pull request
review-once runs the full pipeline synchronously against one real PR and posts a review and Check Run — no webhooks needed. It's the fastest way to confirm auth, the CLI, and posting work end-to-end. (It does not use the queue or the audit log.)
7. Run the daemon
serve starts the webhook listener, the job scheduler, and the reconciliation poll. Point your GitHub App's webhook at the host and open or update a PR to have it reviewed. Health and metrics are served on the same address; log verbosity is set with RUST_LOG (for example RUST_LOG=tensorcheck=debug).
Every field, its default, and how layers merge.
Config is layered TOML, deep-merged global → [org.<name>] → [org.<name>.repo.<name>]; the most specific layer that sets a field wins. It is validated on load (check-config) and on startup. Secrets are referenced by env-var name or file path, never inlined. For max_diff_lines and daily_tokens, 0 means unlimited.
The [review] layer (global, org, or repo)
Every field below may appear in [review], [org.<o>.review], or [org.<o>.repo.<r>.review].
| Field | Type | Default | Meaning |
|---|---|---|---|
cli | "claude" | "codex" | claude | Which local CLI to invoke. |
model | string | (CLI default) | Passed to the CLI (--model for claude). |
timeout_secs | int | 1200 | Hard timeout for one CLI run; the child is killed on timeout. |
max_diff_lines | int | 4000 | Skip (don't review) diffs larger than this. 0 = no cap. |
severity_threshold | info | warning | error | info | Drop findings below this severity before posting. |
skip_draft | bool | true | Skip draft PRs until marked ready. |
author_denylist | [string] | [] | PR authors to skip (e.g. ["dependabot[bot]"]). |
path_exclude | [string] | [] | Glob patterns; matching files are dropped from the diff. If nothing remains, the review is skipped. |
daily_tokens | int | 0 | Per-org daily token budget. 0 = unlimited. |
prompt.system | string | (built-in) | The reviewer's system prompt (inline). |
prompt.system_file | path | — | Load the system prompt from a file instead. |
The [org.<name>] block (one per organization)
| Field | Type | Default | Meaning |
|---|---|---|---|
app_id | int | — | The GitHub App's numeric ID. |
private_key_file | path | — | Path to the App private key .pem (chmod 600, owned by the service user). |
webhook_secret_env | string | — | The NAME of an environment variable whose value is the webhook secret for this org's App. The daemon reads that env var at request time. |
Webhooks cover any repo the App is installed on. The reconciliation poll, however, only reconciles repos that appear under an [org.<o>.repo.<r>] block — add a (possibly empty) one to give a repo the self-healing poll.
Triggers, skips, and supersession.
Triggers
- opened / reopened / ready_for_review — a full review against the PR base branch.
- synchronize (new pushes) — an incremental review: the diff is taken against the last-reviewed commit, so the CLI only sees new commits.
- An exact
/reviewpull-request comment — reviews the PR's current head on demand. - The reconciliation poll re-enqueues any configured open PR whose head differs from the last-reviewed SHA — the safety net for missed webhook deliveries.
What is skipped
Draft PRs (until ready, skip_draft), forks (always), denylisted authors, and files matched by path_exclude globs (dropped before review; if nothing else changed, the review is skipped). Diffs larger than max_diff_lines are skipped (0 = no cap).
Dedup, supersession, and budget
Each finding carries a hidden fingerprint marker; on re-review, the tool skips findings already posted. When a newer head arrives for the same PR, the daemon supersedes older pending work: the older pending queue rows are dropped and the newest head is enqueued. The reconciliation poll re-enqueues any configured open PR whose head differs from the last-reviewed SHA. Findings below severity_threshold are dropped before posting. Once an org reaches its daily_tokens budget for the UTC day, further reviews are skipped and the Check Run is closed neutral with an explanation (0 = unlimited).
Health, metrics, logs, and the audit trail.
GET /healthz— liveness (200 once the process is up).GET /readyz— readiness.GET /metrics— Prometheus exposition:reviews_total(counter, attempts started),reviews_failed_total(counter, attempts that ended in error), andreview_seconds(histogram, end-to-end review time). Metrics register lazily — an idle daemon may not list a metric until the first review runs.- Logs — structured JSON, controlled by
RUST_LOG. Each review runs inside a span carryingorg/repo/pr. - Audit trail — every review attempt on the
servepath writes a row to theaudittable instate.db, with anoutcomeofreviewed,skipped(detail names the reason, e.g.fork,draft,denylisted_author,budget_exhausted), orfailed. Synchronousreview-onceruns are not audited.
Symptoms and fixes.
| Symptom | Likely cause / fix |
|---|---|
check-config warns private_key_file does not exist | Path or permission is wrong, or the key isn't provisioned yet. Validation only warns; the key is required at review time. |
webhook secret env not set | The env var named by webhook_secret_env isn't exported to the process. Webhooks for that org will 401 (fail-closed). Export it before starting the daemon. |
Webhook deliveries show 401 | Secret mismatch or unset; confirm the App's webhook secret equals the env var's value. |
Webhook deliveries show 200 but nothing happens | Draft, fork, denylisted author, all changed paths excluded, or over the daily budget — check the audit table for the skipped reason. |
Check Run stuck / review silently fails | Check the logs; the daemon closes the Check Run as failure on any pipeline error. Reproduce with review-once, which prints the error to your terminal. |
Reviews never parse / empty findings | The CLI's output format. Test the exact pre-auth command as the service user and confirm claude -p --output-format json returns a JSON envelope. |
A whole repo isn't reconciled | Add a [org.<o>.repo.<r>.review] block — the reconciliation poll only covers configured repos (webhooks still work regardless). |
Budgets never trigger | The CLI isn't reporting token usage for that mode; accounting is best-effort and logs when usage is absent. |
Duplicate comments after a deploy | Expected once after a binary upgrade — comment-dedup fingerprints are stable only within a binary build; they stabilize on the next review. |
Fastest end-to-end diagnostic: tensorcheck --config … review-once --org O --repo R --pr N — it exercises auth, checkout, the CLI, and posting synchronously, with the error printed to your terminal.
What this version does not do.
- GitHub.com only — the API base is
api.github.com; GitHub Enterprise Server is not supported, and no other source-control host is integrated. - Forks are not reviewed in this version, by design.
- Inline-comment placement — findings anchored to a line outside the PR diff would be rejected by GitHub, so the publisher falls back to posting them in the review body rather than failing the whole review.
codexoutput format — the JSONL handling is best-effort; verify it against your installedcodexversion with areview-oncerun. Theclaudepath is exercised end-to-end.- Single instance — one
serveprocess perstate.db; no multi-node or HA yet. - The
queue_depthmetric is not yet exported.
Get early access to the platform.
Every product is included in one platform subscription. Request early access and we'll onboard your team hands-on — free while we build toward launch.