This walkthrough shows a complete hotcb session from initialization to replay. All commands run from a second terminal while training is active.
pip install "hotcb[yaml]"Initialize a run directory before starting training:
hotcb --dir runs/exp1 initThis creates:
runs/exp1/
hotcb.yaml # desired-state config (callbacks, opt, loss)
hotcb.commands.jsonl # command queue (append-only, polled by kernel)
Start your training script (see the integration examples for Lightning, HF, and bare PyTorch).
hotcb --dir runs/exp1 statusShows current freeze mode, active callbacks, and the last few applied ledger entries.
hotcb --dir runs/exp1 cb load timing \
--path hotcb.modules.cb.callbacks.timing \
--symbol TimingCallback \
--enabled \
--init every=50 window=200The kernel picks this up at the next safe point (end of next batch) and instantiates
TimingCallback(id="timing", every=50, window=200).
Load a few more:
hotcb --dir runs/exp1 cb load sys \
--path hotcb.modules.cb.callbacks.system_stats \
--symbol SystemStatsCallback \
--enabled --init every=100
hotcb --dir runs/exp1 cb load anomaly \
--path hotcb.modules.cb.callbacks.anomaly_guard \
--symbol AnomalyGuardCallback \
--enabled --init raise_on_trigger=false# Disable timing to reduce log noise
hotcb --dir runs/exp1 disable timing
# Re-enable it later
hotcb --dir runs/exp1 enable timing# Halve the timing window
hotcb --dir runs/exp1 cb set timing every=25 window=100Or use the shorthand set (auto-routes by key pattern):
hotcb --dir runs/exp1 set every=25 # won't auto-route — use cb set for callback params# /tmp/my_diag.py
class MyDiag:
def __init__(self, id, prefix="step"):
self.id = id
self.prefix = prefix
def set_params(self, **kwargs):
if "prefix" in kwargs:
self.prefix = kwargs["prefix"]
def handle(self, event, env):
if event == "train_step_end":
print(f"[{self.id}] {self.prefix}={env.get('step')}")hotcb --dir runs/exp1 cb load my_diag \
--file /tmp/my_diag.py \
--symbol MyDiag \
--enabled \
--init prefix=batchhotcb captures the source file (SHA-256, stored in hotcb.sources/) so the exact
version is available for deterministic replay later.
# Drop learning rate
hotcb --dir runs/exp1 opt set_params lr=5e-5
# Add weight decay
hotcb --dir runs/exp1 opt set_params lr=5e-5 weight_decay=0.01
# Add gradient clipping
hotcb --dir runs/exp1 opt set_params clip_norm=1.0
# Shorthand (set auto-routes lr, weight_decay, clip_norm → opt)
hotcb --dir runs/exp1 set lr=5e-5 weight_decay=0.01# Scale up the depth loss weight
hotcb --dir runs/exp1 loss set_params depth_w=2.0
# Turn off an auxiliary loss term
hotcb --dir runs/exp1 loss set_params terms.aux_heatmap=false
# Turn it back on
hotcb --dir runs/exp1 loss set_params terms.aux_heatmap=true
# Shorthand (set auto-routes *_w, *_loss keys → loss)
hotcb --dir runs/exp1 set distill_w=0.3hotcb --dir runs/exp1 cb unload my_diagThe callback is torn down cleanly at the next safe point.
Every mutation is written to hotcb.applied.jsonl with the exact step it took effect:
tail -n 20 runs/exp1/hotcb.applied.jsonlExample entries:
{"step": 150, "event": "train_step_end", "module": "cb", "op": "load", "id": "timing", ...}
{"step": 200, "event": "train_step_end", "module": "opt", "op": "set_params", "params": {"lr": 5e-5}}
{"step": 350, "event": "train_step_end", "module": "loss", "op": "set_params", "params": {"depth_w": 2.0}}At any point, export the run's mutations as a portable replay plan:
hotcb --dir runs/exp1 recipe export --out runs/exp1/hotcb.recipe.jsonlhotcb --dir runs/exp1 recipe validate --recipe runs/exp1/hotcb.recipe.jsonl# Initialize a new run directory
hotcb --dir runs/exp2 init
# Freeze in replay mode with the exported recipe
hotcb --dir runs/exp2 freeze --mode replay \
--recipe runs/exp1/hotcb.recipe.jsonlTraining in runs/exp2 will replay every cb/opt/loss change at the exact
same steps — using the captured callback source files, not your current disk versions.
Generate a patch template from the recipe to see what's adjustable:
hotcb --dir runs/exp1 recipe patch-template \
--recipe runs/exp1/hotcb.recipe.jsonl \
--output runs/exp2/hotcb.adjust.yamlEdit the YAML to add your overrides, then replay:
hotcb --dir runs/exp2 freeze --mode replay_adjusted \
--recipe runs/exp1/hotcb.recipe.jsonl \
--adjust runs/exp2/hotcb.adjust.yamlSee adjust_overlay.yaml for the full list of patch types
(replace_params, shift_step, drop, insert, transform_params).
hotcb --dir runs/prod freeze --mode prodAll incoming commands are silently ignored. The run produces the same output regardless of what anyone types in the control terminal.
Unlock when done:
hotcb --dir runs/prod freeze --mode off| File | Written by | Purpose |
|---|---|---|
hotcb.yaml |
You (init) | Desired-state config, polled by kernel |
hotcb.commands.jsonl |
CLI commands | Command queue, append-only |
hotcb.applied.jsonl |
Kernel | Authoritative mutation timeline |
hotcb.recipe.jsonl |
recipe export |
Portable replay plan |
hotcb.sources/ |
Kernel (on cb load) | Captured callback source files |
hotcb.freeze.json |
freeze command |
Current freeze mode and recipe path |