spb/forge-studio Public
The Instruments of LLM training — a native macOS cockpit for Forge. Train language models from scratch on Apple Silicon without a terminal.
Swift 95.7%
Shell 4.3%
1// Author: Simon-Pierre Boucher — contact@spboucher.ai2//3// A training run: identity, config, directories, and the state machine4// (RunSupervisor is the only mutator; every transition is persisted5// atomically by RunStore).6import Foundation78enum RunState: String, Codable, CaseIterable {9 case queued, launching, running, finishing, finished, failed, stopped1011 var isActive: Bool {12 switch self {13 case .launching, .running, .finishing: return true14 default: return false15 }16 }1718 // Legal transitions — RunSupervisor refuses anything else.19 static let transitions: [RunState: Set<RunState>] = [20 .queued: [.launching, .stopped],21 .launching: [.running, .failed, .stopped],22 .running: [.finishing, .finished, .failed, .stopped],23 .finishing: [.finished, .failed, .stopped],24 .finished: [], .failed: [], .stopped: [],25 ]26}2728struct Run: Codable, Identifiable, Equatable {29 var id: UUID = UUID()30 var name: String31 var createdAt: Date32 var state: RunState = .queued33 var config: ForgeConfig34 var datasetPath: String35 var outDirectory: String // <workspace>/runs/<name>-<timestamp>36 var resumeCheckpoint: String? // forge train --resume37 var pid: Int32? // live forge process (crash recovery)38 var lastStep: Int?39 var lastTrainLoss: Double?40 var bestValLoss: Double?41 var bestValStep: Int?42 var exitCode: Int32?43 var failureReason: String?4445 var logCSVPath: String { outDirectory + "/log.csv" }46 var runLogPath: String { outDirectory + "/run.log" }47 var configPath: String { outDirectory + "/config.json" }4849 var progress: Double {50 guard let step = lastStep, config.train.maxSteps > 0 else { return 0 }51 return min(1.0, Double(step + 1) / Double(config.train.maxSteps))52 }53}54