Skip to content

frogmoses/coffee-roasting

Repository files navigation

Coffee Roasting with Hottop KN-8828B-2K+

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.

After a Roast

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 full

This 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.

Setup

Requires Python 3.10+ and uv:

uv sync

All 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.

Commands

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.

Picking a Roast by ID

Most commands accept an optional roast identifier:

  • Batch number3 (simplest, from list)
  • Partial nameethiopia (case-insensitive match, most recent wins)
  • Full roast ID3_Ethiopia Gerba Hechere_2026-02-21

If you don't specify an ID, the command uses the latest roast.

Understanding Your Output

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.

How It Judges a Roast

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:

  1. 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.
  2. 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.

Visual Data

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.

Reference

  • Hottop manuals: download from Hottop USA and place in reference/
  • Roast logs: auto-synced from roaster to roast-logs/ (gitignored); see log-sync/ for setup
  • Technical details for working on the code: CLAUDE.md

About

Automated coffee roasting analysis pipeline

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors