Thanks for considering contributing! Vifty is a native macOS utility for Apple Silicon fan control, thermal monitoring, and charger/battery power tracking — with a safety-bounded agent CLI for AI coding workloads.
- macOS 15+ on Apple Silicon
- Xcode 16+ with Swift 6
- Command Line Tools (
xcode-select --install)
# Clone
git clone https://github.com/Reedtrullz/Vifty.git
cd Vifty
# Run the fast local trust gate
make verify
# Run the full test suite locally when needed
make verify-full
# Build release app bundle
make app CONFIGURATION=release
# Install locally
make installSee README.md for the full layout. Key areas:
| Area | What it does |
|---|---|
Sources/ViftyCore/ |
Shared models, fan coordinator, SMC client, power telemetry, agent control |
Sources/Vifty/ |
SwiftUI menu bar app + AppModel |
Sources/ViftyDaemon/ |
Privileged XPC daemon (runs as root) |
Sources/ViftyCtl/ |
Agent CLI with bounded workload leases |
Sources/ViftyPrivateIOKit/ |
C IOKit bridge for HID sensors |
Tests/ViftyCoreTests/ |
XCTest suite |
- Curve resolution happens in
FanControlCoordinator— the daemon only receives resolvedfixedRPMcommands. Never passtemperatureCurveacross XPC. - RPM clamping —
FanCurve.clamp()is the single source. All callers must clamp before writing. - Daemon-first, fail-closed writes — the app tries the daemon first for fan writes. Unprivileged direct SMC writes are refused.
- Protocol abstraction — tests use
FakeHardwareconforming toHardwareService. Fan logic lives in the coordinator, not the hardware layer. - Agent control is lease-based — agents request bounded workload cooling. Never expose raw SMC writes or arbitrary fixed RPM to agent tools.
- User Auto-restore wins — user selecting Auto overrides any active agent lease.
For full conventions, see AGENTS.md.
- Open an issue first for significant changes — discuss the approach before writing code.
- Fill out the PR safety impact section — call out fan/SMC writes, daemon/helper/XPC changes, agent leases, release trust, hardware validation, UI ownership/restore state, and local persistence changes explicitly.
- Run
make verify— it is the standard fast local trust gate. GitHub Actions runsmake verify-full, including the slow evidence/release script suites. Runmake verify-fulllocally for release-facing or safety-sensitive changes when practical; otherwise, explain any skipped full gate and let CI carry it. - Add tests for new functionality or bug fixes.
- Keep changes focused — one concern per PR.
- Update documentation if you change public APIs, CLI flags, architecture rules, JSON contracts, release behavior, compatibility claims, or safety policy.
- Sign your commits — we prefer signed commits.
Public release mode must be explicit. Source-first tags may publish source plus clearly marked unsigned-dev tester artifacts when Developer ID credentials are unavailable, without claiming Developer ID signing, notarization, Homebrew trust, or official trusted binary status. Trusted binary releases follow docs/release.md and require Developer ID signing, notarization, stapling, release verification, and Homebrew updates only after the canonical artifact passes those checks.
Use docs/support-triage.md to sort reports into release trust, hardware validation, unsupported hardware, helper install, SMC telemetry, agent-cooling, or UI buckets. Ask for read-only evidence first and do not suggest manual fan-write tests when readiness is blocked. For machines outside the Apple Silicon MacBook Pro scope, follow docs/unsupported-hardware.md. For GitHub Release asset, Homebrew cask checksum, Gatekeeper, notarization, TeamID, release-readiness, verifier, or reviewer failures, use the Release Trust Report issue template. For viftyctl run, prepare, restore-auto, guarded wrapper, expired-lease, rate-limit, or restore-failure reports, use the Agent Cooling Report issue template.
Repository topics and triage labels are part of the contributor surface. When changing issue templates or triage buckets, update .github/repo-metadata.json and run scripts/check-github-metadata.sh --repo Reedtrullz/Vifty --json when you have GitHub access.
@MainActorfor UI state, actors for mutable shared state- XPC callbacks are one-shot (guarded by
CallbackStatelock) - SMC key names are 4-char strings (e.g.
F0Ac,Tp09) - Fan IDs are 0-indexed Ints matching SMC key suffixes
- Bundle identifier:
tech.reidar.vifty(app),tech.reidar.vifty.daemon(Mach service)
Start with SUPPORT.md. Open a GitHub Discussion for questions, or open an issue for bugs and feature requests.