Roast analysis tool for the Hottop KN-8828B-2K+ connected to Artisan. Analyzes .alog roast logs, looks up bean profiles, and gives you actionable recommendations for the next roast — reasoning from roasting theory and how the bean cupped, not from fixed target curves.
Artisan logs auto-sync from the roaster to roast-logs/ via inotifywait + rsync (see log-sync/ for the watcher scripts and systemd service). Then run:
run_roast-analyzer analyze.py fullThis scans for new log files, shows a summary of the latest roast, prints recommendations with a priority legend, and ends with a Next Roast box telling you exactly what to change.
Tip: Enter the post-roast weight (weight-out) in Artisan before saving. When it's present, the report adds roast-loss analysis — see Understanding Your Output.
Requires Python 3.10+ and uv:
uv syncAll commands run through the wrapper script (it injects secrets):
run_roast-analyzer analyze.py <command>Integrations (configured via env vars in the wrapper script):
| Env var | Purpose |
|---|---|
ANTHROPIC_API_KEY |
Required for recommendations — the next-roast advice is generated by Claude reading your full log |
FIND_COFFEE_URL |
find-coffee API URL for bean profile lookup |
FIND_COFFEE_WRAPPER |
Path to run_find-coffee script (auto-starts the server if needed) |
SENTINEL_CAPTURES_DIRS |
Colon-separated paths to r1-eye/GoPro capture directories for visual scoring |
Without ANTHROPIC_API_KEY, scans still record the roast metrics, but skip recommendations (the scan prints why). The find-coffee and sentinel vars are optional — those features are silently skipped when unset.
Every command is run as run_roast-analyzer analyze.py <command>. Most accept an optional roast ID (see Picking a Roast by ID); without one they use the latest roast.
Daily workflow
| Command | What it does |
|---|---|
full [id] |
Scan + full report (summary, bean profile, recommendations, next roast, trend) |
full [id] -v |
Same, with full professional cupping notes |
show [id] |
Roast summary only (temps, times, phases, RoR, weight) |
Re-analyze & inspect
| Command | What it does |
|---|---|
scan / scan --force |
Ingest new .alog files (or re-analyze everything from scratch) |
recommend [id] [-v] |
Recommendations + next-roast actions |
compare [id1 id2] |
Side-by-side comparison of two roasts |
list |
All analyzed roasts with batch number, date, bean, metrics |
Notes & lookup
| Command | What it does |
|---|---|
cupping <id> -n "notes" |
Attach tasting notes to a roast |
cupping <id> |
View existing cupping notes |
bean <name> |
Look up a bean in find-coffee |
Re-scanning with --force preserves any cupping notes you've added.
Most commands accept an optional roast identifier:
- Batch number —
3(simplest, fromlist) - Partial name —
ethiopia(case-insensitive match, most recent wins) - Full roast ID —
3_Ethiopia Gerba Hechere_2026-02-21
If you don't specify an ID, the command uses the latest roast.
Recommendations are generated by Claude reading your full log — including the move-by-move heater/fan timeline — so the advice points at specific dial moves and moments ("ease the heater to ~80% by 250F", "make one cut around 340F and hold it through first crack") rather than generic targets. They're prioritized:
[!!!]— fix this first[ ! ]— worth improving[ ]— info
Phase Breakdown in the summary shows each phase's raw time and RoR next to the percentage — e.g. Drying: 61.6% (8:30 @ 26.8 F/min) — so you can tell whether a high drying % is coming from a long phase or a short total time.
Weight loss: if you entered the post-roast weight in Artisan, the summary shows roast loss (226g -> 192g (15.0% loss)). It's a readout of development — an outcome of time after first crack — not a lever you steer directly.
RoR smoothness: the summary rates the rate-of-rise curve (smooth / moderate / oscillating) with heat context. If the RoR climbs through Maillard instead of falling — a violation of Rao's rule that the bean temp should always decelerate — a line flags it (! RoR rising in Maillard (+X F/min) - should decelerate) and the recommendations typically steer you to get more heat in earlier so the curve peaks just after the turning point and declines into first crack.
CHARGE warning: if charge_bt wasn't recorded (missed/late CHARGE press), a warning line appears in the summary so you know to mark CHARGE manually next roast.
Next Roast box gives 2-4 concrete action items for your next roast, distilled from the analysis as specific changes to make at the machine.
Trend table shows key metrics across all roasts so you can see progress.
There are no fixed numeric targets — no "your drying should be 50%" bands. Until you've roasted a bean you genuinely like, any target curve would be an unvalidated guess. Instead the analysis reasons from two things:
- Flavor — what the bean is supposed to taste like (from the bean profile) versus how it actually cupped (your tasting notes). Add your notes with
cupping <id> -n "..."so the next analysis can use them. - Roasting theory — things that hold regardless of the bean: a smoothly declining rate of rise, an ever-decelerating bean temp, no crash or flick into first crack, and a sensible balance of drying / Maillard / development. Drop temp and weight loss are treated as outcomes of development time, not goals to hit.
The raw numbers (phase times, temperatures, RoR) are still shown as facts in the summary — they're just not graded against a band. The one fixed reference is the 408°F safety eject (the Hottop manual's 395°F figure is wrong).
Down the road, once you have a roast you love, the plan is to make that roast's curve the reference — "match the one that tasted great" — instead of theory guesses.
If the r1-eye or GoPro sentinel was running during the roast, visual development data (color scoring, uniformity) is automatically included in the analysis. No extra steps — just run full --force after sentinel captures have synced.
Sentinel sessions are linked to .alog files by UUID when Artisan's OFF button is configured to send send({"event": "OFF"}) via WebSocket. This triggers the sentinel to read the .alog that Artisan just saved and embed the roastUUID for deterministic matching. Without OFF configured, matching falls back to date/time.
- Hottop manuals: download from Hottop USA and place in
reference/ - Roast logs: auto-synced from roaster to
roast-logs/(gitignored); seelog-sync/for setup - Technical details for working on the code: CLAUDE.md