GitHub Actions
Quell ships a composite GitHub Action that scans every pull request for untested guard clauses and posts results as inline diff annotations and a PR comment. No API key. No LLM. No code leaves your runner.
Quickest setup
Run this once inside your repo:
quell install --pr
That writes .github/workflows/quell.yml and you're done. Every future PR
triggers the scanner automatically.
Manual setup
Create .github/workflows/quell.yml:
name: Quell — Guard Clause Scan
on:
pull_request:
types: [opened, synchronize, reopened]
paths:
- "**.py"
permissions:
contents: read
pull-requests: write
jobs:
quell:
name: Guard clause scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Scan for untested guard clauses
uses: shashank7109/quelltest_lib@main
with:
target: '.'
post-comment: 'true'
fail-on-gaps: 'false'
pull-requests: write is required for the PR comment step. Without it the
scan still runs and annotations appear, but no comment is posted.
What you see in the PR
Inline diff annotations — each untested guard clause appears as a warning directly on the line where it is written:
⚠ Untested guard [boundary] in process_payment()
if amount <= 0:
PR comment — a summary table is posted on open and updated (never re-posted) on each push:
🟡 Quell — Guard Clause Scan
3 untested guard clauses found — 60% covered (3/5)
| File | Function | Guard | Type |
|-----------------|-----------------|--------------------------|----------|
| payments.py:32 | process_payment | if amount <= 0: | boundary |
| sessions.py:18 | create_session | if not user: | not_null |
| auth.py:44 | require_auth | if not is_authenticated: | auth |
Fix locally: quell scan . --fix
Action inputs
| Input | Default | Description |
|---|---|---|
target | . | File or directory to scan, relative to repo root. Use src/ if your sources live there. |
python-version | 3.11 | Python version used on the runner. |
post-comment | true | Post/update a PR comment. Requires pull-requests: write. |
fail-on-gaps | false | Exit 1 if any untested guard clauses are found. Set to true to block merges. |
github-token | ${{ github.token }} | Token for comments. Default works for same-repo PRs. |
Action outputs
- name: Scan
id: quell
uses: shashank7109/quelltest_lib@main
- name: Use the result
run: echo "Found ${{ steps.quell.outputs.gaps-found }} gaps out of ${{ steps.quell.outputs.total-guards }} guards"
| Output | Description |
|---|---|
gaps-found | Untested guard clauses found in changed files |
total-guards | Total guard clauses detected |
report-path | Always quell-report.json |
Recipes
Block merges when gaps exist:
- uses: shashank7109/quelltest_lib@main
with:
fail-on-gaps: 'true'
Scan only src/ and lib/:
- uses: shashank7109/quelltest_lib@main
with:
target: 'src/'
Upload the JSON report as a CI artifact:
- uses: shashank7109/quelltest_lib@main
id: quell
- uses: actions/upload-artifact@v4
if: always()
with:
name: quell-report
path: quell-report.json
Run Quell only when Python files change:
on:
pull_request:
paths:
- "src/**/*.py"
- "lib/**/*.py"
How it works
The action runs quell scan <target> --format github on the GitHub Actions
runner. That command:
- Walks every
.pyfile in the target directory - Parses each file with the Python AST — no LLM, no network call
- Detects
if/raise,try/except/raise,assert, and standaloneraisepatterns - Checks which ones already have a corresponding test
- Emits
::warning file=...,line=...,title=...::guard textannotations (visible inline in the diff) - Writes
quell-report.json
The PR comment step reads that JSON and posts a formatted markdown table.
Want Quell installed on every repo in your org automatically, with no YAML to add? See the GitHub App guide — one install covers everything.