Skip to main content

repo-roast

CI Python License: MIT OpenSSF Scorecard

A terminal CLI that reads a GitHub profile through the GitHub REST API — repos, language breakdown, stars, abandoned projects, and a sample of recent commit messages — then asks an LLM to roast the developer's coding habits.

It shows its receipts: every roast is preceded by an evidence table, and the model is instructed to only joke about facts that are actually in the data.

$ repo-roast roast torvalds --spice hot

Install

pip install -e .

Configure

cp .env.example .env

Then fill in:

Variable What it is
GITHUB_TOKEN A personal access token. public_repo scope is enough for public data; add repo to include your own private repos.
LLM_API_KEY A free Groq key (no credit card; starts with gsk_).
LLM_BASE_URL Defaults to https://api.groq.com/openai/v1.
LLM_MODEL Defaults to llama-3.3-70b-versatile.

Usage

repo-roast roast                        # roast yourself (the authenticated user)
repo-roast roast torvalds               # roast someone else
repo-roast roast torvalds --spice hot   # roast them harder
repo-roast roast torvalds --dry-run     # evidence + the exact prompt, no LLM call
repo-roast compare torvalds gvanrossum  # roast battle: two profiles, one verdict
repo-roast repo psf/requests            # roast a repository, not a person
repo-roast card torvalds -o card.svg    # a shareable SVG card, for a README
repo-roast --help                       # the commands
repo-roast roast --help                 # the flags below

Breaking change in 0.2.0. The tool now takes a sub-command: repo-roast torvalds became repo-roast roast torvalds. This made room for compare and repo below, without compare being ambiguous with a user who happens to be called compare. The old form prints the new one rather than a bare "No such command".

Flags

--spice, --model, --commits, --dry-run and --no-cache mean the same thing on all four commands; --evidence and --format apply to every command except card, whose only output is the SVG file itself. --version and --clear-cache belong to the top level (repo-roast --version, not repo-roast roast --version).

Flag Default Meaning
username (positional, roast, card) authenticated user Which GitHub user to roast.
username_a / username_b (positional, compare) — The two GitHub users to pit against each other.
full_name (positional, repo) — A repository, as owner/name.
--spice / -s medium mild, medium, or hot.
--model / -m $LLM_MODEL or llama-3.3-70b-versatile Model name to send to the provider.
--repos / -r (roast, compare, card) 5 How many recently-pushed repos to sample commit messages from.
--prs (repo) 30 Recent pull requests to sample.
--issues (repo) 30 Recent open issues to sample.
--commits / -c 8 Commits to sample (per repository, for roast/compare/card; from the target repo, for repo). 1–50.
--evidence / --no-evidence on Show the stats table.
--format / -f text text, json, or markdown.
--output / -o (card) <login>-card.svg Where to write the SVG.
--theme (card) dark dark or light.
--dry-run off Gather stats, print the evidence table and the exact prompt, then exit — no LLM call and no LLM_API_KEY required.
--no-cache off Skip the on-disk cache for this run.
--version off Print the installed version and exit (top level).
--clear-cache off Delete all cached responses, then exit (top level).

--dry-run is the quickest way to check the GitHub half on its own.

repo samples pull requests, issues, the repository's file tree, and a code search for TODO/FIXME — all bounded, the same way roast's commit sampling is. It deliberately does not compute mean-time-to-review (would need one extra API call per sampled PR) or "commits pushed at odd hours" (GitHub normalises commit timestamps to UTC server-side, so the author's real local hour isn't recoverable from the API at all — reporting a UTC hour as if it were local would be presenting a fact that isn't actually in the data).

card asks the LLM for one sentence instead of a full roast — there is only room for one on a badge — then renders it into a self-contained SVG (no external fonts, no network requests) with the same evidence table any other command would show. It is XML, and both the display name and the roast sentence can contain &, <, >, or quotes (a quoted commit message, an attacker-chosen GitHub display name); every dynamic value is escaped before it reaches the document, so none of that can break the markup. Drop the file straight into a README:

![repo-roast](card.svg)

Scripting it

--format json prints one document to stdout and nothing else:

repo-roast roast torvalds -f json | jq '.stats.total_stars'
repo-roast roast torvalds -f json --dry-run | jq -r '.prompt.user'
repo-roast compare torvalds gvanrossum -f json | jq -r '.verdict'
repo-roast repo psf/requests -f json | jq -r '.repo.oldest_open_issue_days'

Progress spinners and error messages go to stderr, so a pipe receives either a valid document or nothing at all — never half of one. Failures still exit non-zero, with the message on stderr where it belongs.

--format markdown prints the evidence table(s) and the roast or verdict as Markdown, ready to paste into an issue or a README.

Provider

The default backend is Groq: free, no credit card, and OpenAI-compatible. repo-roast talks to it with the official openai SDK pointed at a custom base URL, so any OpenAI-compatible endpoint works — switching providers is just three environment variables.

Provider LLM_BASE_URL Example LLM_MODEL
Groq (default) https://api.groq.com/openai/v1 llama-3.3-70b-versatile
Google Gemini https://generativelanguage.googleapis.com/v1beta/openai/ gemini-2.0-flash
Mistral https://api.mistral.ai/v1 mistral-small-latest
OpenRouter https://openrouter.ai/api/v1 meta-llama/llama-3.3-70b-instruct:free
Cerebras https://api.cerebras.ai/v1 llama-3.3-70b

Model strings change over time — if a call 404s, check the provider's current model list.

Running it with Docker

No local Python needed. Images are published to the GitHub Container Registry on every release, for linux/amd64 and linux/arm64:

docker run --rm -e GITHUB_TOKEN=ghp_... -e LLM_API_KEY=gsk_... \
  ghcr.io/amayyas/repo-roast roast torvalds --spice hot

Environment variables, not a mounted .env: simpler, and there is no file to accidentally bake into a container. LLM_BASE_URL and LLM_MODEL work the same way if you are pointing at a different provider.

Tags: latest tracks the newest release, vX.Y.Z pins a specific one — same versions as PyPI.

How it stays polite to the API

Repo metadata (languages, stars, descriptions, push dates) comes from the single repo listing that PyGithub already paginates. The only per-repo calls are for commit messages, and they are bounded on both axes: the --repos most recently pushed originals, up to 8 commits each.

Every run is cached on disk for 15 minutes, keyed on the target and the sampling flags — roast torvalds --repos 5 and roast torvalds --repos 10 are different cache entries, since they're genuinely different data. Re-running the same command while iterating on --spice or --format costs no API calls at all. Two exceptions: --no-cache skips the cache for one run, and roasting yourself (roast with no username) is never cached — the cache key has no way to tell two different tokens' "yourself" apart, and handing one token's profile back to another would be a real bug. The cache never stores a token, only GitHub's public responses. repo-roast --clear-cache deletes it.

Before spending any quota, repo-roast checks how much is left — checking itself costs nothing. Below a safety margin it refuses to start, with a clear message instead of burning through what little remains and failing partway through with a raw 403.

Ethical use

repo-roast generates jokes about named, real people from their public GitHub activity. That comes with rules, not just a disclaimer:

  • Roast the code and the habits — commit hygiene, abandoned repos, a suspicious TODO — never the person. No appearance, no identity, no protected characteristic. The system prompt enforces this on every call, and it's the first hard rule in roast.py.
  • Don't use the output to harass, dogpile, or target someone who didn't ask for it. A roast run against a stranger without their knowledge is not the friendly-jab use case this tool is built for. card raises the stakes here: the SVG is meant to be embedded somewhere public, so only put one in your own README, about yourself.
  • This isn't only a prompt-level promise. SECURITY.md documents the structural defense that keeps a booby-trapped repo from turning the tool into a weapon against whoever is being roasted.

repo-roast repo sidesteps the "named person" concern differently: it targets a codebase's pull requests, issues, and commits, not an individual. The data it hands to the model never includes a contributor's name, so the model has nothing to single anyone out with in the first place.

This project follows a Code of Conduct; the same spirit applies to how the tool itself gets used.

Support

Questions, bugs, or a roast that missed? See SUPPORT.md, or reach out directly at amayyas.aouadene@epitech.eu.

Found a security issue? See SECURITY.md instead of opening a public issue.

Want to contribute? See CONTRIBUTING.md. This project follows a Code of Conduct.

License

MIT © Amayyas Aouadene

Metadata

Release files for repo-roast 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for repo-roast 0.5.0
File Size Uploaded
repo_roast-0.5.0.tar.gz 50.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for repo-roast 0.5.0
File Interpreter ABI Platform
repo_roast-0.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 83.4 kB

Release files / repo_roast-0.5.0.tar.gz

Download URL repo_roast-0.5.0.tar.gz
Size 50.4 kB
Tags Source
SHA-256 checksum
How to use checksums
049967903c3d3ff0e3a1cfa605e7be6dd7475df7d7570a60f15bbb4b9c81b3c5
BLAKE2b-256 checksum
How to use checksums
17a9d3f823d7f25c852a6a358f6273b2df9c650e56d82b2b086d2f9f20af1fdc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 11, 2026.

Transparency log

Release files / repo_roast-0.5.0-py3-none-any.whl

Download URL repo_roast-0.5.0-py3-none-any.whl
Size 33.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9a57b4528bf9378e97b7cec1a8f04034c24e8fa774d7f2e8f58c80f00e05b08e
BLAKE2b-256 checksum
How to use checksums
8cd1e08be45cbf96d9a6ce0a997ca8a91fd7ea7bafeb471530ef41abc5d3bdbc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 11, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 release files

0.4.0

2 release files

0.3.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page