Lesson 5 — Continuous review in CI
25 minTwo ways through this lesson: read it on this page, or run it hands-on in your coding agent. To do it in your agent:
npx tessl install tessl-academy/tuning-your-agent
Run this once, in a fresh project directory (for example a new tuning folder — Tessl won't initialize in your home directory). It installs the skills your agent uses to guide you through the lessons interactively.
“guide me through continuous review in CI”
Open your coding agent (Claude Code, Cursor, Codex, or Tessl Agent) in that directory and ask it the prompt above. The installed skill picks it up and walks you through this lesson step by step. Prefer a command? Launch it directly with tessl launch skill --agent claude-code -i 05-continuous-review-in-ci (swap claude-code for cursor, codex, or tessl-agent).
In Lesson 1 you sketched a CI gate, a one-liner with --threshold to show the idea. This lesson makes it real. You'll stand up a production workflow, point it at a repo whose skill fails the bar, and watch the pull request go red. Then you'll close the loop: run the optimizer, push the fix, and watch the same gate go green.
That fail → fix → pass cycle is what "continuous review" actually means. A gate that only ever passes teaches you nothing; a gate that catches a weak skill, blocks it, and clears once you fix it is the quality bar doing its job on every change, without anyone arguing about it in a meeting.
What you'll build
By the end you'll have:
- A GitHub Actions workflow that runs a review eval on every pull request touching your skills.
- A first-hand look at the gate failing a real PR, and the report that tells you why.
- The full loop of optimize the skill, re-review, and watch the gate clear, run against a repo you can keep.
Start with a skill that fails
To see continuous review earn its keep, you need a skill that fails it. Start from a repo holding a deliberately thin commit-conventions skill (vague description, no examples, no rules) of the kind a review eval should flag:
ci-review-lab/
├── .git/
└── skills/
└── commit-conventions/
└── SKILL.md
The SKILL.md is intentionally underbuilt:
---
name: commit-conventions
description: Helps with commits.
---
# Commit conventions
Write a commit message for the staged changes.
The description says nothing about when to use the skill or what it produces, there are no examples, and the body is a single line: exactly the weaknesses tessl review run scores down. Confirm the starting state before you wire up CI:
tessl review run ./skills/commit-conventions
tessl review view --last
You'll see a low overall score with suggestions clustered on the description and missing examples. That low score is the point: it gives the CI gate something to block and the optimizer something to fix.
Why a bad skill on purpose. A fixture that already passes teaches nothing about review. Starting below the bar lets you watch the gate fail a PR, run
tessl review fix, and watch it pass: the whole loop in one repo.
Gate every pull request
tessl review run accepts a --threshold flag and exits non-zero if the score falls below it. Review runs are async, but passing --threshold makes the command wait for the score and set the exit code, so that's all you need to block a PR:
tessl review run --threshold 85 ./skills/commit-conventions
# exits non-zero if below 85, perfect for blocking a PR
To run that on every pull request, set the CLI up in CI with the official tesslio/setup-tessl action. A review eval calls a real model and costs credits, so CI has to authenticate: the action reads a TESSL_TOKEN secret you add once under your repo's Settings → Secrets and variables → Actions (mint the key at https://tessl.io/account/api-keys).
Wire it into .github/workflows/skills-gate.yml to run on every PR that touches skills/ or plugins/:
name: Skills eval gate
on:
pull_request:
paths:
- 'skills/**'
- 'plugins/**'
jobs:
eval-gate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # need history to diff against the base branch
- name: Set up Tessl
uses: tesslio/setup-tessl@v2
with:
token: ${{ secrets.TESSL_TOKEN }}
- name: Review changed skills
run: |
git diff --name-only origin/${{ github.base_ref }}...HEAD \
| grep -E '^(skills|plugins/.*/skills)/' \
| xargs -I{} dirname {} | sort -u \
| xargs -I{} tessl review run --threshold 85 {}
Why authenticate in CI. A review eval spends credits, so an unauthenticated runner can't score anything. The
tesslio/setup-tesslaction installs the CLI and signs it in from theTESSL_TOKENsecret, the same key you'd use to publish from CI.
Open a pull request that touches skills/commit-conventions/SKILL.md and the gate runs. With the thin skill from the fixture, it scores below 85 and the step exits non-zero, so the check goes red and the PR is blocked. That red X is the system working: a weak skill stopped at the door instead of landing in your registry.
Close the loop with the optimizer
A blocked PR is only half the loop. Now fix the skill the same way you did in Lesson 3: let the optimizer raise the structural score. tessl review fix runs the review eval in a loop, applying improvements each round until it converges or hits the iteration cap:
tessl review fix --max-iterations 5 ./skills/commit-conventions
It'll show you each round of changes before applying them. Accept them, reject them, or use --yes to auto-apply. When it finishes, run a plain review to confirm the new score clears your bar:
tessl review run ./skills/commit-conventions
tessl review view --last
# Overall score: 94 / 100
Push that fix to the same pull request. The gate re-runs, the score is now above 85, the step exits zero, so the check flips to green and the PR is mergeable. You've watched one change travel the entire loop: failed the gate, got fixed, cleared the gate.
What the optimizer can't fix. It only touches what review evals can see: structure, frontmatter clarity, body shape. It won't fix a skill that scores 100/100 on review but still produces wrong output; that's a task-eval problem, the signal you wired up in Lesson 2.
Raise the bar over time
Tune the threshold to the bar your policy sets. Once the gate is green for a few weeks, raise it by 5 and see what breaks; that's how the quality bar moves up over time without anyone having to argue about it in a meeting. The fixture's job was to give you one failing PR to learn on; in a real repo, the same workflow quietly holds the line on every change your team pushes.
What you keep
You walk away with a GitHub Actions workflow that reviews every pull request, a repo where you watched the gate block a weak skill and clear once it was fixed, and the muscle memory of the full loop: review, gate, optimize, re-review. That's the review→optimize cycle from the last three lessons turned into something continuous, running on every change, not just when you remember to ask. Combine it with the task evals from Lesson 2 and you have both halves of skill quality enforced automatically, all the way from your editor to your team's registry.