🔥 Forge Studio
The Instruments of LLM training — a native macOS cockpit for Forge
Train language models from scratch on Apple Silicon without ever opening a terminal. Pick a dataset, shape an architecture, hit Start — and watch the loss fall on a silky live dashboard.
Swift + SwiftUI + Swift Charts · macOS 14+ · Apple Silicon · zero third-party dependencies
✨ What it is
Forge is a from-scratch C++20 + Metal LLM
training framework: its own tensors, autograd, flash attention, Muon optimizer,
MoE, QAT, and the .forge zero-copy weight format. Forge Studio is its native
GUI companion — the whole train-a-model workflow, end to end, as a first-party-feeling
Mac app:
- Prepare data — TinyStories or streamed Hugging Face mixtures (FineWeb-Edu, DCLM, Cosmopedia, research presets), with a live console
- Design a model — every Forge config field, from
n_layersto DeepSeek-style MoE routing, with live validation - Train — launch, monitor, stop; runs survive app crashes without lying
- Understand — a loss dashboard built to the TensorBoard/W&B standard, native
- Compare — multi-run overlays on the tokens axis, the honest one
- Use the model — generate and evaluate from any checkpoint, in-app
Forge Studio never reimplements training. It drives the real forge binary and
reads its structured metrics — what you see is exactly what the framework did.
📊 The dashboard
The centerpiece. Built on Swift Charts, fed by an actor-isolated metrics store:
- Raw + smoothed loss — low-opacity raw train line under a bias-corrected EMA (TensorBoard semantics, 0→0.99 slider), val loss as connected points
- Hover crosshair with a full callout: step, train, EMA, perplexity, val
- Pinch-zoom & pan on X, double-click to reset, and a "follow live ⏵" pill that re-pins the window to incoming data after you've panned away mid-run
- Best-val marker — dashed rule +
best val 2.146 @ step 999annotation - Log/linear Y, secondary charts for LR schedule (watch warmup + cosine/WSD
actually happen), tokens/sec, grad norm with the
grad_clipthreshold drawn - Scale discipline: raw data is never discarded; the UI reads LTTB-downsampled snapshots (~2× pixel width). Measured: 200,000 CSV rows ingest in ~1.1 s and snapshot to chart width in <250 ms — hover stays hitch-free on 100k-step runs
🛡️ Runs that can't lie
- Single-writer state machine (
queued → launching → running → … → finished | failed | stopped) with an explicit legal-transition table — illegal transitions are unrepresentable - Atomic persistence (temp-file-then-rename) for the registry:
kill -9the app whenever you like - Crash recovery: runs persisted as active at launch are truthfully resolved —
including the case where the forge process is still alive — with an honest
explanation and the recovery path (
ckpt_latest.bin) - Watchdog: a "possibly stalled" badge when metrics stop flowing for 30 s
- Stop is SIGTERM and the UI tells you exactly what that means (Forge doesn't
checkpoint on signals; you lose at most
checkpoint_everysteps) - Local notifications with the final loss when a run finishes or fails
🧪 Ground truth, tested
RESEARCH.md documents the full Forge contract (config schema, CLI, log.csv
grammar, checkpoint/resume, signal behavior) extracted from the source. The test
suite enforces it:
ForgeConfiground-trips the realconfigs/*.jsonfrom the forge repo, byte-compatible field names- The Swift param-count formula matches
forge infofor every shipped config - CSV/stdout parsers are exercised against real and mutated lines (legacy 6-column headers, garbage, truncation)
- LTTB invariants (endpoints exact, monotonic X), EMA bias correction,
state-machine table, LR-preview math vs
scheduler.h, 200k-point stress test
🚀 Quick start
# 1. Build Forge (once)
git clone https://github.com/spboucher-ai/forge && cd forge
cmake -B build && cmake --build build -j
# 2. Run Forge Studio
# — from the DMG on the Releases page, or from source:
git clone https://github.com/spboucher-ai/forge-studio && cd forge-studio
./scripts/package-app.sh release && open dist/ForgeStudio.appIn Settings: point to forge/build/forge (validated live via forge info) and
pick a workspace. Then Datasets → New dataset (TinyStories at vocab 4096 takes
a few minutes), + New run, pick the gpt-10m preset, Start — first loss point
lands within seconds.
🏗️ Architecture
| Layer | What lives there |
|---|---|
Models/ |
ForgeConfig (Codable mirror of every Forge field + validation + derived math), Run (state machine), MetricPoint, Dataset (bin-header readers) |
Services/ |
ProcessRunner (actor, incremental line streaming), LogParser (header-driven CSV + stdout events), MetricsStore (actor, incremental tail, LTTB snapshots), RunStore (atomic registry), RunSupervisor, ForgeBinaryLocator, SystemInfo |
Charts/ |
TrainingChartView (the interactive dashboard), Downsampler (LTTB), Smoothing (bias-corrected EMA) |
Views/ |
Navigation shell, run dashboard, New Run editor (presets, derived panel, LR preview), Compare, Datasets, Checkpoints/Generate/Eval, Settings |
scripts/ |
package-app.sh (SwiftPM → .app), generate-icon.sh, notarize.sh (Developer ID + hardened runtime + DMG + notarytool + stapler) |
Swift Concurrency throughout: the process I/O and metrics paths never touch the main thread; the UI observes debounced snapshots. No third-party packages.
🗺️ Roadmap
- Linked axes across secondary charts + synchronized crosshair
- Clickable checkpoint annotations on the loss chart
- Exhaustive form for every architecture-variant knob (today: JSON import covers them)
- PNG/CSV chart export, run queue for sequential trainings
.forgerepo browser (weight history as commits — the format already does git-style deltas)
👤 Author
Simon-Pierre Boucher — contact@spboucher.ai
Built alongside Forge. If Forge is the engine, Studio is the cockpit.