- Split CODING_GUIDELINES.md into 19 indexed standards files under .claude/standards/ - 9 from CODING_GUIDELINES (conventions, powershell, security, api, git, gururmm) - 10 from session log tribal knowledge (syncro, ssh, gitea, python, client, gururmm) - Add .claude/standards/index.yml for cheap relevance-based lookup - Add /inject-standards command: load targeted standards per task instead of full guidelines - Add /shape-spec command: pre-implementation spec for GuruRMM features (plan.md, shape.md, references.md, standards.md) with mandatory out-of-scope gate - Add docs/tech-stack.md and docs/mission.md for ClaudeTools API - Add projects/msp-tools/guru-rmm/docs/tech-stack.md and mission.md for GuruRMM - Update CLAUDE.md commands table with /inject-standards and /shape-spec Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5.5 KiB
name, description, applies-to
| name | description | applies-to |
|---|---|---|
| platform-parity | All agent features must ship on Windows, Linux, and macOS; silent no-ops on one platform are bugs | gururmm |
GuruRMM Agent — Platform Parity
All agent features that are not inherently platform-specific must ship on Windows, Linux, and macOS. A feature that silently no-ops on one platform is a gap, not a cross-platform implementation.
The rule
"Add feature X to the agent" means Windows + Linux + macOS. All three, in the same change. No exceptions for convenience. If a real implementation is not feasible on a given platform, add a working stub and a
// TODO(platform): <os> — <reason>comment in the same commit. A feature that silently no-ops on one platform without a stub and TODO is a bug, not a gap.
cfg gating — choose the right target
| Condition | Attribute | When to use |
|---|---|---|
| Windows only | #[cfg(windows)] |
Windows API (Win32, WMI, SCM, OpenSSH registry) |
| Linux + macOS | #[cfg(unix)] |
POSIX: nix crate, signals, /proc, /sys, sockets |
| Linux only | #[cfg(target_os = "linux")] |
/sys/class/thermal, systemd, procfs, D-Bus |
| macOS only | #[cfg(target_os = "macos")] |
CoreFoundation, IOKit, launchd, NSStatusBar |
| Build flag | #[cfg(feature = "native-service")] |
Service harness (Windows only in Cargo.toml) |
Never use #[cfg(not(windows))] as a proxy for "Linux + macOS works the same" without verifying the macOS codepath. Linux and macOS diverge on /sys, D-Bus, and GUI IPC.
Current parity matrix (as of 2026-05-15)
| Feature | Windows | Linux | macOS |
|---|---|---|---|
| CPU / memory / disk / network metrics | [OK] | [OK] | [OK] |
| Temperature via sysinfo | [OK] fallback | [WARN] empty if no hwmon | [WARN] empty if no sensors |
| Temperature via LibreHardwareMonitor | [OK] primary | N/A | N/A |
| Temperature via /sys/class/thermal | N/A | [GAP] not implemented | N/A |
| User detection (logged-in user) | [OK] | [OK] nix crate | [OK] nix crate |
| User idle time | [OK] GetLastInputInfo | [GAP] returns None | [GAP] returns None |
| IPC / tray | [OK] named pipe + WinTray | [GAP] stub no-op | [GAP] stub no-op |
| Watchdog (process monitor) | [OK] native-service | [GAP] stub no-op | [GAP] stub no-op |
| Script execution | [OK] cmd / PowerShell | [OK] bash / sh | [OK] bash / sh |
| Hardware inventory | [OK] WMI | [OK] /proc + lshw | [OK] system_profiler |
| Auto-updater | [OK] full | [OK] simpler | [OK] simpler |
| Checks (AV, updates, firewall) | [OK] full | [WARN] partial stub | [WARN] partial stub |
| Network discovery | [OK] | [OK] | [OK] |
Known gaps — priority order
1. Linux temperature collection (agent/src/metrics/mod.rs)
- sysinfo
Componentsreturns empty on most Linux systems (requires kernel hwmon driver exposure). - Correct approach: read
/sys/class/thermal/thermal_zone*/tempdirectly (always available on Linux). - Pattern:
#[cfg(target_os = "linux")] fn collect_temps_linux() -> (Option<f32>, Option<f32>, Vec<TemperatureReading>) { // read /sys/class/thermal/thermal_zone*/temp // parse millidegrees, classify by type label in /sys/class/thermal/thermal_zone*/type }
2. Linux / macOS user idle time (agent/src/metrics/mod.rs — get_user_idle_time())
- Linux: use X11
XScreenSaverQueryInfo(display sessions) or parse/proc/interruptsdelta (headless). - macOS: use
CGEventSourceSecondsSinceLastEventType(IOKit, always available). - Stub is acceptable short-term; mark with
// TODO(platform): linux/macos idle time.
3. Watchdog on Linux / macOS (agent/src/watchdog/)
- Windows: Windows Service Control Manager restarts the agent.
- Linux: systemd
Restart=on-failurein the unit file is the correct equivalent — no in-process watchdog needed. - macOS: launchd
KeepAlivekey in the plist. - Document the OS-native mechanism in
build-agents.sh/ installer rather than porting the Rust watchdog.
4. Checks on Linux / macOS (agent/src/checks.rs)
- Windows-specific checks (Windows Update pending, Windows Defender status, Windows Firewall) have no direct equivalents; that is expected.
- Cross-platform checks (disk SMART, certificate expiry, open ports) should run on all platforms.
- Add
// TODO(platform): linux/macos — <check name>for each unimplemented cross-platform check.
Cargo.toml dependency discipline
- Platform-specific crates go in
[target.'cfg(...)'.dependencies], never in[dependencies]. - Keep
lhm(LibreHardwareMonitor) andwindows-serviceundercfg(windows). - Keep
nixundercfg(unix). - When adding a new crate, verify it compiles on all three targets before merging. Use the build server for Windows; CI covers Linux. macOS cross-compile via
--target aarch64-apple-darwinon Linux (requiresosxcrosstoolchain — see build-agents.sh TODO-MACOS).
Additional notes from past sessions
service.rs must mirror main.rs AppState: On Windows, the agent runs as a Windows Service via a separate entry point in service.rs that constructs AppState independently. Any field added to AppState in main.rs must also be added to the AppState struct literal in service.rs. This has caused Windows-only build failures in the past (missing agent_id field). There is no shared constructor — both sites must be updated manually.
sc.exe over Get-Service: Get-Service silently fails to enumerate GuruRMMAgent even with the exact service name in some session contexts. sc.exe queryex "GuruRMMAgent" is reliable. All PS1-based service checks in agent code use sc.exe query equivalents.