Set up Tessl Code Review
Set up Tessl Code Review on GitHub pull requests, choose when reviews run, and decide whether findings are advisory or block merging.
Tessl Code Review is in beta. Behavior and output formats may change in upcoming releases.
Tessl Code Review reviews the exact head of a pull request and publishes one native GitHub review. It anchors findings to changed lines where GitHub can place them, keeps earlier findings in context when a review runs again, and distinguishes required changes from optional suggestions.
The supported integration is the tesslio/code-review-action GitHub Action. Your repository owns a thin caller workflow: when reviews run, which permissions the job holds, the runner, the timeout, the token secret, and whether findings block merging. The Action owns pull request resolution, checkout of the exact head, Tessl CLI setup, failure notices, its own check run, and result artifacts. The Tessl CLI the Action installs runs the review and publishes it, which includes stale-head protection and idempotent retries.
What appears on a pull request
Every completed review publishes three things:
A native GitHub review carrying a short judgment, a severity summary, and findings anchored to files and lines where GitHub can place them.
A check run named
Tessl Code Review, reported against the pull request head that was actually reviewed. The Action reports this check on every trigger, including comment-driven and manually dispatched runs.A result artifact on the workflow run, containing the decision, findings, selected configuration, duration, and publication receipt.
Two configuration problems, covered later in this guide, change that list: without checks: write the Action completes the review but reports no check run, and in gate mode a repository setting that refuses the review event means the review is published as a comment instead.
Every completed review reaches one of two public outcomes:
Changes approved
The review found no changes that the author is required to make. Optional suggestions may still be present.
Changes requested (N required, M advisory)
The review found N findings that require changes and M advisory findings. The heading omits the advisory part when M is zero: Changes requested (N required).
Not every run reaches one of those. A run can also finish having deliberately reviewed nothing: no configured lens matched the changed files, or a comment asked Tessl to approve the pull request and the commenter may not. Those runs publish no review and reach neither outcome. Both are covered under Check conclusions.
The reviewer assesses consequence severity, likelihood, confidence, and relationship internally. Tessl derives a stable published severity from consequence and likelihood. requestChangesAt sets the minimum consequence eligible to block, while review mode controls how much blocking strength the finding needs.
The repository selects reviewMode: strict, standard, or relaxed in a YAML profile, covered under Route reviews with YAML. Standard is the default. requestChangesAt sets the consequence baseline and defaults to Major.
When a review runs again on the same pull request, it also accounts for replies, resolved threads, and findings from earlier Tessl reviews. An unresolved earlier finding remains visible for continuity, but its current assessment can make it non-blocking. An incremental review omits fresh optional findings.
Before you start
You need:
a GitHub repository whose pull requests come from branches in that repository rather than from forks;
permission to create repository secrets and GitHub Actions workflows;
a Tessl API key to store as a repository secret named
TESSL_TOKEN;the Action reference you want:
@v1, which tracks the newest 1.x release, or the full commit SHA of a release, taken from that release's notes.
Cross-repository pull requests are not supported. The Action rejects them before review execution, on every trigger. Do not use a more privileged event such as pull_request_target to work around this boundary: it runs a privileged token in the base repository's context against untrusted head code, which is the trust boundary the Action is built to keep.
Set up with an agent
The setup-code-review skill in the tessl/code-review plugin sets up Code Review for you. How you reach it depends on the agent:
Tessl Agent already has it. A current Tessl CLI ships the skill, so there is nothing to install.
Any other agent, such as Claude Code or Cursor, needs the skill installed into the project first:
Installing places the skill under .tessl/plugins/ and records it as a dependency in tessl.json. Teammates get the same skill by running tessl install in their own clone, and adding --global installs it for every repository on your machine instead. Recording the dependency is worth doing even when you use Tessl Agent, since the project copy then wins over whatever the CLI ships.
From a checkout of the repository you want reviewed, and signed in to the Tessl CLI, ask your agent:
Set up Tessl Code Review for this repository. Start in advisory mode and review a pull request when it becomes ready.
The agent reads the repository's existing workflows first, asks the two policy questions below, proposes the change, and writes the caller workflow only after you approve it. It then tells you which secret to add and which repository settings to change. It cannot create the secret for you, so you still need Step 1 either way.
The two questions it asks are the two decisions this guide covers:
When reviews run. Manual only, once when the pull request becomes ready plus requested rounds, or on every commit.
Whether findings block. Advisory or gate.
The rest of this guide describes the workflow the agent writes, so you can audit it, operate it, and change it by hand. Reading it is worthwhile either way: the workflow is your repository's, and the gate and branch protection steps are yours to make.
Step 1: Add the Tessl token
Create a Tessl API key with access to the workspace and plugins the review will use. For example:
See the tessl api-key create reference for expiry and role options. In the GitHub repository, go to Settings > Secrets and variables > Actions, create a repository secret, and name it TESSL_TOKEN.
The workflow passes this secret to the Action through the tessl-token input. Do not put the token in the workflow file, an environment file, a command argument, or a pull request comment.
No other provider credential is needed.
Step 2: Choose a review cadence
The caller workflow controls when Tessl Code Review runs. Choose one cadence for the repository:
Ready for review plus requested rounds
Most repositories. This is the recommended starting point.
One automatic review when the pull request becomes ready. The author asks for another round once fixes or replies are ready, so pushing commits does not spend a review on its own.
Every commit
Repositories that want every pushed head reviewed automatically, and the strongest gate coverage.
Faster feedback, at the cost of more review runs and more pull request activity.
Manual only
Trials, unusual repositories, and controlled evaluation.
Nothing runs until someone asks, by mentioning @tessl-code-review on a pull request or dispatching the workflow with a pull request number.
Start with ready for review plus requested rounds. It avoids reviewing draft work and lets the author decide when a new round is worth running.
Step 3: Add the workflow
One caller workflow per repository, whichever cadence you choose. Two workflows that both invoke the Action double every review, and giving them the same concurrency group is not a fix: it serializes the runs, so the second review still happens, just afterwards. The cadence changes the on: block, the job's if: condition, and cancel-in-progress, and nothing else.
The workflow references the Action by its major tag, @v1. That tag moves to each 1.x release, so a fix reaches your repository without anyone editing the workflow. It is the recommended reference and what the examples below use.
The trade is yours to make. A moving tag means every review round hands the repository's TESSL_TOKEN to whatever that tag currently points at. A repository that wants the revision frozen references the full commit SHA of a release instead, taken from that release's notes, and accepts that a fix then waits for a deliberate bump. Both references are supported.
Whichever you choose, it fixes the Action's own code. It does not fix the Tessl CLI, which runs the review and publishes it. The Action installs the current CLI release by default, so review behavior follows CLI releases between Action updates, even while the SHA stays the same. To fix both, set the cli-version input to an exact CLI release:
Leave cli-version unset, or set it to latest, to track the current release. Pinning it means the review stops picking up CLI fixes until you raise the pin, so treat it as something to review on the same cadence as the Action SHA. A pinned version older than the CLI's support for publishing a review is refused: the Action checks the installed CLI before the review starts and fails the job with an error naming the installed version and telling you to raise cli-version or unset it.
The Action checks out the pull request head itself, with persisted credentials disabled. Do not add a checkout step to the caller job.
Review when a pull request is ready, plus requested rounds
Create .github/workflows/tessl-code-review.yml:
The four triggers divide the work. pull_request starts the one automatic review, when the pull request becomes ready. issue_comment and pull_request_review_comment start a requested round: the review Tessl publishes closes by asking for a mention when fixes or replies are ready, so a comment on the Conversation tab and an inline comment on the diff both work. workflow_dispatch starts a review by hand: open the workflow in the Actions tab, choose Run workflow, and enter the number of an open pull request in the same repository.
@tessl-code-review is text in a comment rather than a GitHub account, and deciding whether a comment names it is the Action's job, not the workflow's. It matches the handle as a whole token, case-insensitively, and only where the comment is saying it rather than showing it, so @tessl-code-reviewer is not a request and neither is the handle inside a code span, a fenced block or a quoted line. That is what lets a comment write about the reviewer, or quote a round that mentioned it, without starting another one. A comment it admits gets a reaction straight away, which is the only signal that reaches the person at the moment they asked. A comment it does not admit ends the run with nothing published, no check run and no reaction, and reports status: not-requested. Treat that as success: declining to review a comment that asked for nothing is not a failure.
The draft == false condition means a pull request opened as a draft is not reviewed, and the transition to ready for review starts the first review. Remove the condition if you want drafts reviewed too.
A few more things about this workflow are worth understanding before you install it:
allowed-associationsis the actor check, and choosing it is yours even though the Action enforces it. A comment-driven run holds the repository write permissions and theTESSL_TOKENsecret, and anyone who can comment on a pull request can start one, so without this input an outside commenter can spend the token at will. Tighten the list to suit the repository, or leave the input out only if any commenter may request a review. Two things to know about it: an association is what the event payload claims rather than a permission lookup, and the pull request's own author is never refused, because an author already decides what the pull request contains.approver-loginsis who may ask for an approval instead of a review. A comment can instruct Tessl to approve the pull request rather than review it, which skips the review entirely. Owners, members and collaborators may do that already, by the same associationallowed-associationsreads. Nobody else can, and a GitHub App cannot at all: an App comments with associationNONEwhatever its permissions, so no association names one. Addapprover-logins: my-agent[bot]to permit a specific commenter, carrying the[bot]suffix the event payload spells; capitalization does not matter, and a bot has no unsuffixed form to fall back on. Leaving the input out names no one, and does not stop an owner, member or collaborator approving this way.A refused approval request runs no review. If the commenter may not approve, Tessl does not review the change instead. It publishes no review, concludes the check neutral, and posts one comment saying the request was refused and that commenting
@tessl-code-reviewstill gets a review. Naming a login inapprover-loginsalso admits it pastallowed-associations, for an ordinary review as well as an approval, so read the two inputs together when you tighten either.The same permission covers asking for a full review. A comment can ask for the whole change to be reviewed again rather than the narrower later round described under What appears on a pull request, and whoever may approve may ask for that. A request from anyone else is not refused: it runs the ordinary round, because asking to be reviewed more thoroughly is not something to reject.
cancel-in-progress: falsekeeps a requested review from being canceled by the next request. A newer run waits instead, and GitHub holds only one waiting run per group, so a third request arriving during a run replaces the one already waiting.The
if:condition is deliberately loose. A workflow expression cannot match a token boundary, so it tests for the handle anywhere in the body and leaves the exact rule to the Action. The state check belongs there rather than in the Action: a stray mention on a closed or merged pull request would otherwise start a run that fails without explaining itself, because the pull request number is never resolved and the failure notice has nothing to address.Comment events run the copy of the workflow on the default branch, not the copy on the pull request branch. The mention trigger does nothing until this file is merged, and later edits to the condition take effect only once they land on the default branch.
The @tessl-code-review token is part of the Action's contract, and the published review tells reviewers to use it. A workflow whose prefilter looks for anything else installs a review that teaches a token its own workflow never passes on.
Review every commit
To review every pushed head, add synchronize to the pull_request types and cancel in-flight reviews on synchronize events only:
synchronize fires on every push to the pull request branch, and the cancel condition means the next push cancels the review already running for the head it replaced instead of racing it, which also avoids paying for reviews that would end up superseded. Canceling is safe on this cadence: the head is verified immediately before publishing, publication is refused for a head that has moved, and publication is idempotent.
The condition matters. A run for any matching event enters the concurrency group when it is created, before the job's if: condition evaluates, so an unconditional true would let any comment on the pull request cancel the in-flight review and then skip its own job. With the condition, only a push to a ready pull request cancels. The draft check matters for the same timing reason: a draft's push enters the group before its job is skipped by the draft == false condition, so without it a draft push could cancel a requested review while performing none of its own. Every other event waits for the running review; GitHub keeps a single pending run per group, so the newest waiting request replaces the one already waiting.
The draft == false condition still applies, so pushes to a draft pull request are not reviewed and the first review still starts when the pull request becomes ready. Remove that condition as well if you want every commit reviewed from the moment the pull request is opened.
Review manually only
For a controlled trial, remove the pull_request trigger from the on: block and remove the pull_request clause from the job's if: condition. Nothing then runs until someone asks, either by mentioning @tessl-code-review in a comment on a pull request or by dispatching the workflow with a pull request number. Both requested paths keep allowed-associations and pass the pull request number through the Action's pr-number input, so nothing else in the workflow changes.
Permissions the job needs
Every caller grants exactly four permissions:
contents
read
Resolve and check out the exact pull request head.
checks
write
Report the review result on the reviewed head.
pull-requests
write
Publish a native pull request review.
issues
write
Publish and clear visible failure notices.
Without checks: write, the Action logs a warning naming the missing permission and completes the review as it otherwise would. No other behavior depends on the check run, but branch protection does, so gate mode needs it.
Choose the reviewing identity
The Action's github-token input decides who authors the published review. Left unset, the Action uses the workflow's own token, so every review is authored by github-actions[bot], the same identity as the repository's linters and other jobs. In the timeline and in notifications, a review is then indistinguishable from a lint job: no distinct avatar, and nothing to filter on.
Pass a token that carries its own identity to change that. Two token shapes work:
A GitHub App installation token. Mint one per run with
actions/create-github-app-tokenand pass its output asgithub-token. Reviews then arrive as that App's bot login, for exampletessl-code-review[bot], with the App's avatar. This is whattesslio/monorepo's own workflow does.A machine user's personal access token. Store a token belonging to a dedicated GitHub account as a secret and pass it as
github-token. Reviews arrive as that account. An App is preferable: its token is short-lived and minted per run, and its permissions are scoped to the installation rather than to a person's whole account.
Mint the token in a step before the Action and fail soft, so a minting problem signs the review with the wrong identity rather than stopping the review. Every pull request needs its review to reach approval, so a hard failure here would hold the repository rather than change how a review is signed. Warn on the fallback, because a review quietly signed by github-actions[bot] is a regression nobody reports:
Two facts about the App token's permissions are easy to get wrong:
contents: writebuys exactly one thing: reopening a resolved thread whose finding still requires changes. GitHub files thread resolve and unresolve under Contents, even though neither touches repository content, so a read-only token cannot reopen a thread and the reviewer republishes the finding as a new comment instead. Nothing else the Action does needs write on contents; its comment reaction, check run, and failure notice keep using the workflow token.Whether an App's approving review satisfies a required-approving-review rule is decided by the App installation's write access, not by the token's scopes. Widening or narrowing the token's
contentspermission does not change whether an approval counts. If gate mode publishes an approval that branch protection does not accept, check the installation's repository access, not the token permissions in the workflow.
Step 4: Start in advisory mode
Advisory mode is the default and the recommended way to roll out. A GitHub COMMENT review is published, and no review outcome fails the check. A technical failure to run or publish still fails the job.
Run advisory reviews on real pull requests before enabling a gate, and judge whether:
required changes are accurate and actionable;
optional suggestions are useful without adding noise;
the selected lenses cover the risks that matter in this repository;
review latency and cadence fit how the team works;
later rounds correctly account for fixes and replies.
Do not require the Tessl Code Review check in branch protection while the workflow is advisory. Advisory mode never concludes failure, so requiring the check cannot turn advisory into a gate. What a required advisory check tells you is whether the review reached a verdict, not whether the run was healthy.
Step 5: Choose profiles and lenses
standard is the supported review profile, and it supplies the default review behavior and lens selection. Most repositories should stay with it:
A lens is a focused set of review instructions, published as a skill in a plugin and referenced as workspace/plugin@version#lens-name. The standard profile runs these lenses from the tessl/code-review plugin by default:
review-correctness-and-data-integrity: whether the change does what it is meant to do, and whether the data it touches survives it intact.review-maintainability-and-code-quality: whether the next person can understand the change and modify it safely.review-scale-and-resilience: what the change costs as load, data volume, and concurrency grow, and what it does when something it depends on fails.review-security-and-privacy: what an adversary could do with the change, and what it exposes about people.
The plugin's registry page describes each lens and how to select, pin, and fork one. The lenses are meant to be forked: their sources live at code-review/skills/<lens-name>/SKILL.md in tesslio/product-plugins, so copy one into your own repository or plugin and tune it from there.
To replace the profile's lens selection, pass the complete ordered selection as a JSON array. A review supports at most eight lenses. Pin every registry reference so the review does not change when a plugin publishes a new version:
Passing lenses replaces the profile's complete default selection rather than adding to it, so anything from the profile you still want has to appear in the array. Keep each lens responsible for a distinct concern, so findings do not repeat each other. Add repository-specific lenses only when you can name the concern and show examples of what a good review should catch; the create-code-review-lens skill in the tessl/code-review plugin walks an agent through drafting a lens, validating it against changes that should and should not trip it, and packaging it as a pinned registry reference.
Route reviews with YAML
For CLI and Action reviews, a repository-owned YAML profile can route lenses to parts of the change:
Tessl does not discover this file or make it the default. It runs only when the command names its .yml or .yaml path. Start the file with schemaVersion: 1, then provide an ordered, non-empty lenses list:
Local lens paths are relative to the profile and must stay inside the repository. Globs are case-sensitive, repository-relative POSIX patterns. They are evaluated in order, must include a positive pattern, and may use ! to exclude a previous match. A lens without globs applies to the whole change. A renamed file matches on either its old or new path.
ignore excludes paths from every lens the profile selects, so generated code, lockfiles, snapshots, or vendored directories are named once instead of negated in each lens. Each pattern is positive: it excludes what it matches, so a leading ! is rejected, as is a bare ** that would leave every lens with nothing to review. A lens's own globs still narrow it further, and ignore overrides anything a lens selected. Two limits are worth knowing: because a file is selected when either rename endpoint matches, a file renamed into an ignored path is still reviewed and that path appears in the rename patch; and ignore bounds which paths a lens reviews rather than keeping their contents out of a model's context.
effort sets how hard a lens thinks. At the profile level it accepts low, medium, high, or adaptive and applies to every lens; on a single lens it accepts a fixed low, medium, or high and makes that one think harder or less hard than the rest, which is how you spend depth where it pays and keep it cheap elsewhere. adaptive uses medium for a full review and low for a re-review, and is the built-in standard profile's default; a single lens cannot take it, because the round-dependent policy is set once for the whole review. A lens without its own uses the profile's effort; with neither, the model applies its own default. --effort applies to every lens and takes precedence over both. Higher settings take longer.
reviewMode controls how much blocking strength an eligible finding needs:
strictblocks at strength zero.standardblocks at strength one.relaxedblocks at strength two.
Low, Medium, and High likelihood provide zero, one, and two strength points. Each consequence level above requestChangesAt adds one more.
Omit the key to use standard. Low-confidence fresh findings are omitted in every mode. Pre-existing findings and findings whose relationship to the change is unclear appear as optional on full reviews and never block.
requestChangesAt sets the minimum consequence severity eligible to request changes: critical, major, minor, or nit. Omit it to use major.
Because published severity also reflects likelihood, a Strict or Standard review can require a change for a finding displayed below requestChangesAt. The review's required-versus-optional classification is authoritative.
The first review and an authorised full re-review show every valid optional finding. An incremental re-review shows a fresh finding only when it blocks and continues to reconcile findings from earlier rounds.
Each lens sees only the files routed to it. Lenses with no matching files do not run or count toward the limit of eight lenses. If no lens matches, Tessl returns a skipped result without implying approval. Passing --skill replaces every lens, glob and ignore pattern in the file profile, so the lenses it supplies are not bounded by the profile's routing. A profile-level effort still applies to them.
To use the same file with the Action, pass its repository-relative path:
The Action reads this file from the pull request head it checks out, so its contents are whatever the change under review contains. In gate mode that means a contributor who can push to the pull request can also edit the profile in the same change: route every lens away from the changed files or raise requestChangesAt so nothing blocks. A repository-relative profile is therefore not a gate control the change author cannot reach. To require separate approval for review-policy changes, protect the profile with CODEOWNERS and enable required code-owner approval in the repository's branch protection or ruleset.
See the CLI command reference for the complete file profile behavior.
Step 6: Enable gate mode
Gate mode connects the review outcome to both a native GitHub review event and the Action-owned check. requestChangesAt sets the consequence baseline, reviewMode sets the strength required to block, the Action's mode decides whether the check then fails, and branch protection decides whether a failing check holds the pull request.
Changes approved attempts to publish
APPROVEand reports a successful check.Changes requested (N required, M advisory) attempts to publish
REQUEST_CHANGES, publishes the complete review, and reports a failed check.If repository settings do not allow the requested review event, the completed review is published as a comment instead, and the Action explains the configuration problem and fails the check.
If the review returns no approval verdict, the check fails. Only a boolean verdict approves a head, so a missing or malformed one fails closed rather than passing the head through.
To enable it:
In the repository's Settings > Actions > General page, enable the setting that allows GitHub Actions to create and approve pull requests. Approval does not work without it.
In Settings > Rules or the branch protection rule, check that nothing restricts who may review pull requests on the protected branch. If reviews are restricted to a named set of people or teams, GitHub refuses the Action's review event, and gate mode reports that as a configuration failure rather than a verdict.
Change the workflow input to
mode: gate.Run the workflow on a change that should be approved and on a change that should be blocked.
Add
Tessl Code Reviewas a required status check in the branch protection rule or ruleset.
Require the check named exactly Tessl Code Review. Do not require the caller workflow's job. Requiring the job enforces only on pull_request runs: a comment-driven run is associated with the default branch, and a dispatched run with whichever branch it was dispatched from, so the job status does not reliably reach the pull request and the required check may never arrive. The Action resolves the reviewed head itself, so its own check run lands on that head whatever the trigger was.
Gate mode works best when every merge candidate gets a review. On the every-commit cadence that happens automatically. On the other two cadences, a blocked pull request does not unblock itself, because pushing commits does not start a review: the author has to mention @tessl-code-review to request a round against the new head. Make that step part of the team's merge process before you turn the gate on.
Check conclusions
The Tessl Code Review check concludes differently in the two modes:
Changes approved
success
success
Findings reported
not reachable
neutral
Changes requested
failure
not reachable
Review or publication did not complete
failure
neutral
Repository settings blocked the review event
failure
not reachable
Review verdict missing
failure
not reachable
Superseded by a newer commit
neutral
neutral
No matching review lenses
neutral
neutral
Approval request refused
neutral
neutral
These conclusions assume a neutral conclusion does not block a required check. Confirm that against the branch protection rule or ruleset your repository actually uses before requiring the check. Note which conclusions a comment can reach: an approval request from a commenter who may not approve concludes neutral, so where neutral does block, that comment holds the pull request until something reviews the head.
Superseded runs
If the pull request head moves while a review is running, nothing is published for the head that was reviewed, because that head is no longer the one the pull request points at. The job fails with exit code 1, so that an unpublished review is never mistaken for a completed one. The check concludes neutral in both modes, because the reviewed head got no verdict and nothing is asserted about the head that replaced it. The workflow run carries a warning naming the reason, and the check run output repeats it.
Nothing needs fixing. The push that superseded the run is itself a new head, and a run against that head reviews it. Only if your triggers do not cover that push do you need to run the workflow again for the current head.
Inspect the result
The primary result is the native review on the pull request. From there, the check run and the pull request comment both link to the workflow run, which carries the logs, any warning or error annotations, and the result artifact.
The artifact contains the review outcome, findings, selected configuration, duration, and publication receipt. It is built from an explicit field allowlist, so it excludes credentials, source contents, prompts, and debug output, and a field the CLI adds later is dropped until it is added to the published schema.
Later steps in the same job can read the Action's outputs. Give the Action step an ID first (the example below assumes id: review on the uses: step), so an operational step can record the terminal status and reviewed head without parsing logs:
Use the outputs for reporting and workflow coordination. Do not add a second review publisher: publication, retry reconciliation, and duplicate prevention belong to the Tessl CLI the Action runs, and a second publisher gives the repository two execution paths that can disagree.
Security and data handling
The Action is built so that reviewing untrusted code does not mean executing it. Pull request code, diffs, branches, comments, titles, and repository files are all treated as untrusted input:
support code runs from the pinned Action revision, not from the reviewed checkout;
the exact pull request head is checked out separately, with persisted credentials disabled;
the Action does not run repository scripts, builds, tests, or installation hooks;
GitHub's automatic token is used for publication, and the Tessl credential is accepted only through the declared Action input;
credentials never appear in command arguments, logs, outputs, or artifacts;
the head is verified again immediately before publication, so a review is never posted against a superseded commit;
uploaded artifacts are built from an explicit field allowlist.
Two boundaries are yours rather than the Action's. Choose the Action reference deliberately: @v1 moves, so a fix arrives without an edit and so does any other change to the code your secrets run, which rests on Tessl restricting who may move that tag; a release commit SHA moves only when you move it, and cli-version fixes the CLI alongside it. And set allowed-associations, because comment-driven runs are privileged and spend the repository's Tessl credits.
Update, roll back, or remove
To update:
Read the target release notes.
On
@v1, nothing to do: the tag already points at the newest 1.x release. On a pinned SHA, take the target release's commit SHA from its notes and replace it in the workflow.Review the diff between the old and new Action revisions.
Run a manual review before relying on the new revision in gate mode.
To roll back, reference the previous release's commit SHA. That is the whole change and it takes effect on the next run. A repository on @v1 cannot roll back by editing the tag, so rolling back means naming a SHA.
Rolling the Action reference back does not roll the review behavior back if it changed with a CLI release rather than an Action revision. A repository that needs to move both deliberately sets cli-version and changes it as its own step, in either direction. The input takes effect only in Action revisions that define it. Rolling back past the revision that introduced it does not fail the run: the job logs a warning naming cli-version as an unexpected input, and that revision installs the CLI it selects instead, so a workflow that looks like it pins the CLI does not.
To remove Tessl Code Review:
Remove the
Tessl Code Reviewrequired check from branch protection or the repository ruleset.Delete the caller workflow.
Delete the
TESSL_TOKENrepository secret if no other workflow uses it.
Do that in order. Deleting only the workflow leaves gate-mode pull requests waiting for a required check that can no longer be reported.
Troubleshooting
No workflow starts when a pull request is opened
Draft pull requests are skipped by the draft == false condition. Mark the pull request ready for review, and confirm the workflow exists on the default branch.
A mention does nothing
Confirm the comment is on an open pull request rather than an issue, and that it names @tessl-code-review as a whole word: a longer handle containing it does not count. If the run started and reported not-requested, the Action declined the comment, and allowed-associations is the usual reason. The caller workflow must be merged to the default branch before mentions do anything, and editing an existing comment to add the mention does not trigger it.
The workflow cannot resolve the pull request
Confirm the number refers to an open pull request in the same repository. Cross-repository pull requests are rejected before review execution.
The review appears, but no Tessl Code Review check does
Add checks: write to the workflow permissions. Without it, the Action warns and completes without reporting the check.
Gate mode publishes a comment and fails even though the review completed
Enable the GitHub setting that allows Actions to create and approve pull requests, then check repository review restrictions. The published comment names the review event GitHub refused.
Gate mode fails with a missing review verdict
The review returned no boolean approval verdict, so the gate was not established. Gate mode fails closed rather than passing an unjudged head. Run the review again, and open a support request if it recurs.
A run reports that it was superseded, and the job fails
A newer commit replaced the reviewed head, so nothing was published for it. No action is needed if your triggers cover the newer push. If they do not, run the workflow again for the current head.
The check stays in progress after a canceled runner or timeout
Run the workflow again. A later check run of the same name replaces the abandoned one for branch protection.
A retry looks likely to publish twice
Do not add a second publisher. Tessl Code Review uses stable markers and publication receipts to reconcile retries and avoid duplicate reviews.
A run fails saying the installed CLI cannot publish a review
The cli-version you pinned predates the CLI's support for publishing. Raise it to a release that supports publishing, or unset the input to track the current release. The check happens before the review starts, so nothing was run or published.
For a technical failure, start from the workflow run linked by the pull request comment or the check run. The Action makes failures visible without including credentials or source contents.
Related capabilities
Tessl Code Review is the supported pull request review product. Other tessl change capabilities solve separate problems and are not required to use it:
tessl change riskevaluates a repository-owned policy to decide whether a pull request needs a human reviewer. It judges the change, not the code.tessl change verifychecks targeted, observable invariants and can emit GitHub Actions annotations.
Add either as its own workflow, only when its policy or verification model matches what the repository needs.
The tessl code review CLI command runs a review locally and prints the result, and its --publish flag can post that review to the pull request it reviewed. Use it to try a review on a diff you already understand. The Action remains the way to review pull requests in CI: it owns the workflow triggers, the check run, and the blocking behavior that a bare command invocation does not.
To turn recurring review feedback into skills, rules, tests, or verifiers, continue with Improving agent code quality.
Last updated

