feat: implement agent-os standards system and feature planning tools

- 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>
This commit is contained in:
2026-05-16 12:59:49 -07:00
parent 2fa8295ad0
commit dd0ef45645
26 changed files with 1757 additions and 1 deletions

View File

@@ -0,0 +1,89 @@
---
name: platform-parity
description: All agent features must ship on Windows, Linux, and macOS; silent no-ops on one platform are bugs
applies-to: 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 `Components` returns empty on most Linux systems (requires kernel hwmon driver exposure).
- Correct approach: read `/sys/class/thermal/thermal_zone*/temp` directly (always available on Linux).
- Pattern:
```rust
#[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/interrupts` delta (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-failure` in the unit file is the correct equivalent — no in-process watchdog needed.
- macOS: launchd `KeepAlive` key 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) and `windows-service` under `cfg(windows)`.
- Keep `nix` under `cfg(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-darwin` on Linux (requires `osxcross` toolchain — 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.