ozturkkl/framework-control

A local lightweight Linux/Windows service with a Svelte web UI for Framework devices (Laptop 12, 13, 16, and Desktop). It exposes a loopback HTTP API to monitor telemetry and tweak fans, power, and charging, including auto, manual, and curve fan control with hysteresis, rate limiting, a live RPM overlay, and calibration.

Svelte

292

322 commits

updated Oct 18, 2026

See the code

README

Framework Control

A local lightweight Linux/Windows service with a Svelte web UI for Framework devices (Laptop 12, 13, 16, and Desktop). It exposes a loopback HTTP API to monitor telemetry and tweak fans, power, and charging, including auto, manual, and curve fan control with hysteresis, rate limiting, a live RPM overlay, and calibration.

How To Use

⚠️ Warning (Framework 16) At minimum BIOS 3.07 is required for proper EC/fan control behavior. Install the latest BIOS before using this tool or it won't work.

image

https://github.com/user-attachments/assets/5d7c07c2-83cc-4b82-b685-df5f86318597

  1. Open the web app: https://ozturkkl.github.io/framework-control/
  2. Install the background service that allows the web app to talk to the low level CLI (download link provided in the web app)
  3. Launch via Start Menu/Desktop shortcuts or visit the local service URL in your browser (check installer output or service logs for the configured port)

Linux install options (see LINUX_INSTALL.MD for full details):

  • Install script (any distro): curl -fsSL https://raw.githubusercontent.com/ozturkkl/framework-control/main/install-linux.sh | sudo bash
  • Arch Linux (AUR): yay -S framework-control (stable · beta)
  • NixOS: services.framework-control.enable = true; in your NixOS configuration

Uninstall

  • Windows: Uninstall "Framework Laptop Control Service" from Settings → Apps (or Add/Remove Programs). This removes the service, install folder, and the Start Menu/Desktop shortcuts.
  • Linux (install script): Run the uninstall script (see LINUX_INSTALL.MD):
    curl -fsSL https://raw.githubusercontent.com/ozturkkl/framework-control/main/uninstall-linux.sh | sudo bash
    
  • Linux (AUR): sudo pacman -R framework-control (or framework-control-beta)
  • NixOS: Set services.framework-control.enable = false; and run sudo nixos-rebuild switch

Disclaimer

This software is provided "as is," without warranty of any kind, express or implied. By using it, you acknowledge that you are responsible for any configuration changes you make to your system and accept all risks associated with its use. The authors and contributors are not liable for any damage, data loss, hardware wear, unintended behavior, or other harm that may result from use or misuse of this application.

Star History

Star History Chart

Current Features

  • Fan Controls: Auto, Manual duty, and Curve editor with hysteresis and rate-limit
    • Per-fan overrides on multi-fan devices (optional custom manual duty or curve per fan)
    • Live RPM overlay with crosshair showing current temperature and estimated duty% on the curve editor
    • One-time calibration wizard for accurate RPM-to-duty mapping
  • Telemetry & Sensors: Live temperature and fan RPM graphs with history
    • Background telemetry sampling with configurable poll interval and history window
    • Per-sensor series with selection and legend, sourced from the local service
  • Persistent Settings: Configurations saved locally with sensible defaults
  • Clean Architecture: Minimal always-on local service with REST API on loopback
  • User-Friendly: No terminal required - MSI installer for Windows with automatic service registration
  • Native App Experience: Start Menu/Desktop shortcuts open Chrome/Edge in app mode on Windows; Linux gets an application menu desktop entry (created on first run)
  • Battery Controls: View battery health/SoC, live charge/discharge power and estimated time remaining/ to target, with configurable max charge limit and optional charge-rate (C) limit + SoC threshold, plus a charge/power history graph.
  • Power Controls:
    • Windows (RyzenAdj): TDP and thermal limit control for AMD Ryzen systems
    • Linux (Native): Uses kernel interfaces (AMD P-State EPP, cpufreq governor)
    • Set energy preferences (AMD P-State) or governors/frequency limits (cpufreq)
    • Separate AC/Battery profiles with background reapply and live power readout
  • Updates & Shortcuts: In-app update checks and optional auto-install, Start Menu/Desktop shortcut management, and framework_tool version selection from the Settings modal
  • Themes: DaisyUI theme picker persisted in config and applied across clients
  • Linux Support:
    • systemd unit with udev rules for input modules
    • Native power management via kernel interfaces (no external dependencies)
    • Install script, AUR package, and nixpkgs / NixOS module

Upcoming Goals

  • LED Matrix Support (Framework 16 input module):
    • Live canvas editor (draw/erase/brightness/sleep) inspired by https://ledmatrix.frame.work/
    • One/two-module layouts (9×34 and 9×68), dithering and content scheduling
    • Optional integrations for animations/GIF/pixel art
  • Additional EC Controls: Keyboard backlight, fingerprint LED levels, input deck modes
  • Import/Export: Settings backup and sharing
  • App Signing for Windows: Support for Windows Store app signing and distribution

Architecture

  • Backend Service: Rust (Tokio + Poem + poem-openapi)
    • Exposes HTTP API with OpenAPI generation
    • Executes Framework CLI (framework_tool) for all EC interactions
    • Power management: RyzenAdj on Windows, native kernel interfaces (AMD P-State EPP, cpufreq) on Linux
    • Applies persisted fan-control and power config at boot
  • Frontend UI: Svelte + TypeScript + Vite + Tailwind + DaisyUI
    • Responsive panel layout adapting to active fan mode
    • Real-time telemetry updates
  • Packaging: WiX MSI installer for Windows; Linux install script, AUR package, and nixpkgs / NixOS module

Why CLI-only for EC?

Early iterations used the Rust framework_lib directly. On Windows that required build-time git metadata and custom driver bindings, which added fragility to packaging and dev setup. Pivoting to the official CLI (framework_tool) gives a stable, tested interface with consistent elevation semantics on Windows. It also maps cleanly to Linux.

Contributing

Pull requests are welcome only when they originate from an issue labeled pr-welcome. Please open an issue first, wait for the label, then link it in your PR (e.g. Fixes #123). PRs without a linked pr-welcome issue will be closed. See CONTRIBUTING.md for details.

Developer Setup

Prerequisites:

  • Rust stable toolchain
  • Node.js for the web UI

Dev Commands:

# Backend (dev)
cd framework-control/service
cargo run

# Frontend (dev)
cd framework-control/web
npm i
npm run dev

Frontend API Usage Policy (Important)

  • Always use the generated client in web/src/api (DefaultService, OpenAPI) for all calls to the local service.
  • Do NOT use fetch directly for service endpoints anywhere in the UI.
  • After changing backend routes or models, regenerate the client:
    1. Build the service to refresh web/openapi.json
    2. From framework-control/web, run: npm run gen:api

Backend Environment Variables Policy (Important)

⚠️ Compile-Time Configuration Baking

All FRAMEWORK_CONTROL_* environment variables read in the service code must support both runtime and compile-time fallback using option_env!(). This allows the Linux build process to bake configuration into the binary.

Pattern to follow:

std::env::var("FRAMEWORK_CONTROL_PORT")
    .ok()
    .or_else(|| option_env!("FRAMEWORK_CONTROL_PORT").map(String::from))
    .expect("FRAMEWORK_CONTROL_PORT must be set")

Environment Variables:

Service .env file (framework-control/service/.env):

# Allow your dev UI origin(s)
FRAMEWORK_CONTROL_ALLOWED_ORIGINS=http://127.0.0.1:5174,http://localhost:5174

# Required: port for the service
FRAMEWORK_CONTROL_PORT=8090

# Optional: GitHub repo used by the update endpoints (owner/name or full URL-ish form)
FRAMEWORK_CONTROL_UPDATE_REPO=ozturkkl/framework-control

Web UI .env.local file (framework-control/web/.env.local):

# Local service URL (optional; auto-detects from current origin if omitted)
# Set this to match your FRAMEWORK_CONTROL_PORT in the service
VITE_API_BASE=http://127.0.0.1:8090

Updates & Caching

  • UI is served by the service; static assets are built with Vite and cached by the browser
  • After installing or applying a service update, refresh the browser once to pick up new UI assets

API & Configuration

The service provides a REST API for health and telemetry (/api/health, /api/thermal, /api/thermal/history, /api/battery/history, /api/power, /api/versions), system info (/api/system), update and helper management (/api/update/*, /api/ryzenadj/*), shortcut management (/api/shortcuts/*), and config management (/api/config).

  • /api/power: combined battery telemetry (SoC, capacity, voltages/currents, charger wattage) plus charge-limit info and power_control object with platform capabilities and current_state.
  • /api/thermal/history: recent temperature/RPM samples collected by the background telemetry task.
  • /api/battery/history: charge % and signed pack watts from the history task. Optional since (unix ms) returns only newer samples.

Configuration is stored (by default) in C:\ProgramData\FrameworkControl\config.json on Windows (overridable via FRAMEWORK_CONTROL_CONFIG) and /etc/framework-control/config.json on Linux. It includes fan mode settings, curve points, calibration data, hysteresis, and rate limiting parameters, power AC/Battery profiles, battery charge-limit/rate settings and SoC threshold, telemetry poll/retention, update preferences, and UI theme.

UI Features

Sensors & Telemetry

  • Live per-sensor temperature graph with history window
  • Configurable poll interval and history duration (via Telemetry settings)
  • Sensor selection with color-coded legend and hover readouts

Fan Curve Editor

  • Visual curve editing with drag-and-drop points
  • Live RPM overlay with real-time crosshair showing current temperature and fan duty
  • Guided calibration wizard for accurate RPM-to-duty% mapping
  • Hysteresis and rate limiting controls (including optional separate spin-down rate) to prevent oscillation
  • Per-fan curve tabs and RPM overlays when overrides are configured
  • Sensor selection (APU/CPU)

Fan Modes

  • Auto: Platform-managed fan control
  • Manual: Fixed duty percentage slider
  • Curve: Custom temperature-to-duty curve with advanced controls

Security Notes

  • API binds to loopback only (127.0.0.1) - no remote exposure
  • CORS restricts browser-based cross-origin requests
  • Service logs diagnostics via the Windows service wrapper (rolling logs in the install directory) or journalctl on Linux
daisyui
fan-control
framework13
framework16
framework-computer
framework-desktop
framework-laptop
nixos
openapi
rust
ryzenadj
svelte
systemd
tokio
typescript

ozturkkl/framework-control

A local lightweight Linux/Windows service with a Svelte web UI for Framework devices (Laptop 12, 13, 16, and Desktop). It exposes a loopback HTTP API to monitor telemetry and tweak fans, power, and charging, including auto, manual, and curve fan control with hysteresis, rate limiting, a live RPM overlay, and calibration.

Svelte

292

322 commits

updated Oct 18, 2026

See the code

README

Framework Control

A local lightweight Linux/Windows service with a Svelte web UI for Framework devices (Laptop 12, 13, 16, and Desktop). It exposes a loopback HTTP API to monitor telemetry and tweak fans, power, and charging, including auto, manual, and curve fan control with hysteresis, rate limiting, a live RPM overlay, and calibration.

How To Use

⚠️ Warning (Framework 16) At minimum BIOS 3.07 is required for proper EC/fan control behavior. Install the latest BIOS before using this tool or it won't work.

image

https://github.com/user-attachments/assets/5d7c07c2-83cc-4b82-b685-df5f86318597

  1. Open the web app: https://ozturkkl.github.io/framework-control/
  2. Install the background service that allows the web app to talk to the low level CLI (download link provided in the web app)
  3. Launch via Start Menu/Desktop shortcuts or visit the local service URL in your browser (check installer output or service logs for the configured port)

Linux install options (see LINUX_INSTALL.MD for full details):

  • Install script (any distro): curl -fsSL https://raw.githubusercontent.com/ozturkkl/framework-control/main/install-linux.sh | sudo bash
  • Arch Linux (AUR): yay -S framework-control (stable · beta)
  • NixOS: services.framework-control.enable = true; in your NixOS configuration

Uninstall

  • Windows: Uninstall "Framework Laptop Control Service" from Settings → Apps (or Add/Remove Programs). This removes the service, install folder, and the Start Menu/Desktop shortcuts.
  • Linux (install script): Run the uninstall script (see LINUX_INSTALL.MD):
    curl -fsSL https://raw.githubusercontent.com/ozturkkl/framework-control/main/uninstall-linux.sh | sudo bash
    
  • Linux (AUR): sudo pacman -R framework-control (or framework-control-beta)
  • NixOS: Set services.framework-control.enable = false; and run sudo nixos-rebuild switch

Disclaimer

This software is provided "as is," without warranty of any kind, express or implied. By using it, you acknowledge that you are responsible for any configuration changes you make to your system and accept all risks associated with its use. The authors and contributors are not liable for any damage, data loss, hardware wear, unintended behavior, or other harm that may result from use or misuse of this application.

Star History

Star History Chart

Current Features

  • Fan Controls: Auto, Manual duty, and Curve editor with hysteresis and rate-limit
    • Per-fan overrides on multi-fan devices (optional custom manual duty or curve per fan)
    • Live RPM overlay with crosshair showing current temperature and estimated duty% on the curve editor
    • One-time calibration wizard for accurate RPM-to-duty mapping
  • Telemetry & Sensors: Live temperature and fan RPM graphs with history
    • Background telemetry sampling with configurable poll interval and history window
    • Per-sensor series with selection and legend, sourced from the local service
  • Persistent Settings: Configurations saved locally with sensible defaults
  • Clean Architecture: Minimal always-on local service with REST API on loopback
  • User-Friendly: No terminal required - MSI installer for Windows with automatic service registration
  • Native App Experience: Start Menu/Desktop shortcuts open Chrome/Edge in app mode on Windows; Linux gets an application menu desktop entry (created on first run)
  • Battery Controls: View battery health/SoC, live charge/discharge power and estimated time remaining/ to target, with configurable max charge limit and optional charge-rate (C) limit + SoC threshold, plus a charge/power history graph.
  • Power Controls:
    • Windows (RyzenAdj): TDP and thermal limit control for AMD Ryzen systems
    • Linux (Native): Uses kernel interfaces (AMD P-State EPP, cpufreq governor)
    • Set energy preferences (AMD P-State) or governors/frequency limits (cpufreq)
    • Separate AC/Battery profiles with background reapply and live power readout
  • Updates & Shortcuts: In-app update checks and optional auto-install, Start Menu/Desktop shortcut management, and framework_tool version selection from the Settings modal
  • Themes: DaisyUI theme picker persisted in config and applied across clients
  • Linux Support:
    • systemd unit with udev rules for input modules
    • Native power management via kernel interfaces (no external dependencies)
    • Install script, AUR package, and nixpkgs / NixOS module

Upcoming Goals

  • LED Matrix Support (Framework 16 input module):
    • Live canvas editor (draw/erase/brightness/sleep) inspired by https://ledmatrix.frame.work/
    • One/two-module layouts (9×34 and 9×68), dithering and content scheduling
    • Optional integrations for animations/GIF/pixel art
  • Additional EC Controls: Keyboard backlight, fingerprint LED levels, input deck modes
  • Import/Export: Settings backup and sharing
  • App Signing for Windows: Support for Windows Store app signing and distribution

Architecture

  • Backend Service: Rust (Tokio + Poem + poem-openapi)
    • Exposes HTTP API with OpenAPI generation
    • Executes Framework CLI (framework_tool) for all EC interactions
    • Power management: RyzenAdj on Windows, native kernel interfaces (AMD P-State EPP, cpufreq) on Linux
    • Applies persisted fan-control and power config at boot
  • Frontend UI: Svelte + TypeScript + Vite + Tailwind + DaisyUI
    • Responsive panel layout adapting to active fan mode
    • Real-time telemetry updates
  • Packaging: WiX MSI installer for Windows; Linux install script, AUR package, and nixpkgs / NixOS module

Why CLI-only for EC?

Early iterations used the Rust framework_lib directly. On Windows that required build-time git metadata and custom driver bindings, which added fragility to packaging and dev setup. Pivoting to the official CLI (framework_tool) gives a stable, tested interface with consistent elevation semantics on Windows. It also maps cleanly to Linux.

Contributing

Pull requests are welcome only when they originate from an issue labeled pr-welcome. Please open an issue first, wait for the label, then link it in your PR (e.g. Fixes #123). PRs without a linked pr-welcome issue will be closed. See CONTRIBUTING.md for details.

Developer Setup

Prerequisites:

  • Rust stable toolchain
  • Node.js for the web UI

Dev Commands:

# Backend (dev)
cd framework-control/service
cargo run

# Frontend (dev)
cd framework-control/web
npm i
npm run dev

Frontend API Usage Policy (Important)

  • Always use the generated client in web/src/api (DefaultService, OpenAPI) for all calls to the local service.
  • Do NOT use fetch directly for service endpoints anywhere in the UI.
  • After changing backend routes or models, regenerate the client:
    1. Build the service to refresh web/openapi.json
    2. From framework-control/web, run: npm run gen:api

Backend Environment Variables Policy (Important)

⚠️ Compile-Time Configuration Baking

All FRAMEWORK_CONTROL_* environment variables read in the service code must support both runtime and compile-time fallback using option_env!(). This allows the Linux build process to bake configuration into the binary.

Pattern to follow:

std::env::var("FRAMEWORK_CONTROL_PORT")
    .ok()
    .or_else(|| option_env!("FRAMEWORK_CONTROL_PORT").map(String::from))
    .expect("FRAMEWORK_CONTROL_PORT must be set")

Environment Variables:

Service .env file (framework-control/service/.env):

# Allow your dev UI origin(s)
FRAMEWORK_CONTROL_ALLOWED_ORIGINS=http://127.0.0.1:5174,http://localhost:5174

# Required: port for the service
FRAMEWORK_CONTROL_PORT=8090

# Optional: GitHub repo used by the update endpoints (owner/name or full URL-ish form)
FRAMEWORK_CONTROL_UPDATE_REPO=ozturkkl/framework-control

Web UI .env.local file (framework-control/web/.env.local):

# Local service URL (optional; auto-detects from current origin if omitted)
# Set this to match your FRAMEWORK_CONTROL_PORT in the service
VITE_API_BASE=http://127.0.0.1:8090

Updates & Caching

  • UI is served by the service; static assets are built with Vite and cached by the browser
  • After installing or applying a service update, refresh the browser once to pick up new UI assets

API & Configuration

The service provides a REST API for health and telemetry (/api/health, /api/thermal, /api/thermal/history, /api/battery/history, /api/power, /api/versions), system info (/api/system), update and helper management (/api/update/*, /api/ryzenadj/*), shortcut management (/api/shortcuts/*), and config management (/api/config).

  • /api/power: combined battery telemetry (SoC, capacity, voltages/currents, charger wattage) plus charge-limit info and power_control object with platform capabilities and current_state.
  • /api/thermal/history: recent temperature/RPM samples collected by the background telemetry task.
  • /api/battery/history: charge % and signed pack watts from the history task. Optional since (unix ms) returns only newer samples.

Configuration is stored (by default) in C:\ProgramData\FrameworkControl\config.json on Windows (overridable via FRAMEWORK_CONTROL_CONFIG) and /etc/framework-control/config.json on Linux. It includes fan mode settings, curve points, calibration data, hysteresis, and rate limiting parameters, power AC/Battery profiles, battery charge-limit/rate settings and SoC threshold, telemetry poll/retention, update preferences, and UI theme.

UI Features

Sensors & Telemetry

  • Live per-sensor temperature graph with history window
  • Configurable poll interval and history duration (via Telemetry settings)
  • Sensor selection with color-coded legend and hover readouts

Fan Curve Editor

  • Visual curve editing with drag-and-drop points
  • Live RPM overlay with real-time crosshair showing current temperature and fan duty
  • Guided calibration wizard for accurate RPM-to-duty% mapping
  • Hysteresis and rate limiting controls (including optional separate spin-down rate) to prevent oscillation
  • Per-fan curve tabs and RPM overlays when overrides are configured
  • Sensor selection (APU/CPU)

Fan Modes

  • Auto: Platform-managed fan control
  • Manual: Fixed duty percentage slider
  • Curve: Custom temperature-to-duty curve with advanced controls

Security Notes

  • API binds to loopback only (127.0.0.1) - no remote exposure
  • CORS restricts browser-based cross-origin requests
  • Service logs diagnostics via the Windows service wrapper (rolling logs in the install directory) or journalctl on Linux
daisyui
fan-control
framework13
framework16
framework-computer
framework-desktop
framework-laptop
nixos
openapi
rust
ryzenadj
svelte
systemd
tokio
typescript

Significant stargazers

Daniel Martí

2,567 followers · starred Oct 2026

Burak Yigit Kaya

1,695 followers · starred Jan 2026

Andrey Petrov

1,260 followers · starred May 2026

Daniel Schaefer

210 followers · starred Jan 2026