Low-level fan control for Apple Silicon macOS (14+), implemented in Swift.
- Menu bar app (
ThermalForgeApp) - CLI (
thermalforge) - Privileged launchd daemon (
com.thermalforge.daemon)
Original creator: ProducerGuy. This repository is an actively maintained fork.
Current fork release: v0.2.1
- Release page: https://github.com/d37atm/ThermalForge/releases/tag/v0.2.1
- Artifacts:
ThermalForge-v0.2.1-macos-arm64-app.zipThermalForge-v0.2.1-macos-arm64-cli.tar.gzchecksums.txt
v0.2.1 adds:
- fix for menu bar freeze path caused by high-frequency repeated rule command dispatch
- daemon client socket timeout hardening + non-blocking app-side daemon call path
- runtime performance optimization: deduped rule-trigger events and reduced UI update cadence
v0.2.0 added:
- typed daemon protocol (
DaemonRequest/DaemonResponse) with legacy command fallback - rule engine (IF/THEN with priority + latch/until)
- extracted control state machine + service
- unified built-in profiles (Smart included)
- structured event logging + expanded tests
- hardened app bundle/release pipeline
ThermalForgeCore is split into explicit layers:
- Hardware
- SMC adapter (
FanControl) - test seams:
FanController,SensorProvider
- Control
ThermalMonitorruntime loopControlService,ControlStateMachineRuleEngine,RulePersistence
- Transport
- daemon socket:
/var/run/thermalforge.sock - protocol:
DaemonRequest,DaemonResponse,DaemonCodec
- Observability
- rotating text logs (
~/Library/Logs/ThermalForge) - structured events (
thermalforge-events-YYYY-MM-DD.jsonl) - research logger (
thermalforge log)
Execution precedence:
- hard safety override (
>=95°C-> max fan) - rule engine decisions
- profile curve logic
Daemon boundary:
- launchd system daemon (
root) - local Unix socket with restrictive permissions
- peer UID authorization (root or active console user)
- heartbeat watchdog resets fans if client disappears
Built-in:
silentbalancedperformancemaxsmart
Control loop:
- thermal cadence: 100ms
- monitor cadence: 2s
- UI cadence: 1s
Rules are persisted at:
~/Library/Application Support/ThermalForge/rules.json
CLI:
thermalforge rules list
thermalforge rules add --trigger 55 --until 65 --max
thermalforge rules enable <rule-id>
thermalforge rules disable <rule-id>
thermalforge rules remove <rule-id>
thermalforge rules test --cpu 70 --gpu 62 --profile balancedbrew install ProducerGuy/tap/thermalforge
sudo thermalforge installgit clone https://github.com/d37atm/ThermalForge.git
cd ThermalForge
./setup.shOpen app:
open /Applications/ThermalForge.appswift build
swift test
./Scripts/ci-smoke.shRelease build scripts:
Scripts/version.shScripts/build-app-bundle.shScripts/ci-smoke.sh
CI workflows:
.github/workflows/ci.yml(build + test + package smoke).github/workflows/release.yml(tag-based artifact release)
thermalforge status
thermalforge max
thermalforge auto
thermalforge set 4000
thermalforge watch --profile smart
thermalforge discover
thermalforge log --rate 10 --duration 1h --no-expireIf macOS blocks the app after download:
xattr -dr com.apple.quarantine /Applications/ThermalForge.app
codesign --force --deep --sign - /Applications/ThermalForge.app
open /Applications/ThermalForge.appReset fans immediately:
thermalforge autoMIT