From qol-project
Use when adding or refactoring symbols (functions, types, constants, use statements) that *might* be consumed by only one platform's backend, even when the symbol itself looks platform-neutral. Prevents the most common qol-tools cross-platform regression: code that compiles green on Linux but emits dead_code / unused_imports / unused_mut errors on macOS or Windows under `-D warnings`. Triggers on edits to shared modules that border `platform/` directories, on `#[allow(dead_code)]` / `#[allow(unused_mut)]` reaches, on `#[cfg(target_os)]` attributes attached to `use` statements, and any time you find yourself "quieting a lint" on one OS. For the strategy-pattern code layout that this skill builds on, see `qol-arch-code`. For CI-side enforcement that catches the failures across all three OSes, see `qol-arch-cicd`.
How this skill is triggered — by the user, by Claude, or both
Slash command
/qol-project:qol-arch-cross-platformThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> Brief always-loaded summary: `qol-tray/CLAUDE.md` ("Cross-platform: warnings are errors"). Full symbol-hygiene patterns and triggers stay here.
Brief always-loaded summary:
qol-tray/CLAUDE.md("Cross-platform: warnings are errors"). Full symbol-hygiene patterns and triggers stay here.
The qol-arch-code skill compartmentalizes platform-specific bodies into platform/{linux,macos,windows}.rs. That solves the easy half of the problem.
The hard half is symbols that look cross-platform but in practice are consumed by only one OS's backend. Those symbols compile clean on the host you're on (because the consumer compiles too), and explode under -D warnings on the OS where the consumer is cfg'd out:
dead_code — pub fn, pub const, pub struct in a shared module whose only callers live behind #[cfg(target_os = "linux")].unused_imports — use statements that pull in symbols only referenced from a cfg-gated function body.unused_mut — function parameters or local bindings that are only mutated in one platform's branch.The qol-tools commit history is full of these. The d797294 refactor moved sixteen dead_code errors out of macOS-side qol-tray builds by relocating a BindingMatcher table from the shared capture/mod.rs into the linux-only capture/platform/linux/matcher.rs. The 33df35d follow-up flipped a constants module from pub to pub(crate) to make the linter quiet on a different OS. These are not "lint nits" — they are full red CI builds that block release.
This class of bug is invisible to single-file static analysis when looking only at the symbol. You need either (a) cross-module symbol-flow analysis or (b) actually compiling on each platform. The deterministic catch lives in qol-arch-cicd's matrix build. This skill catches the patterns that produce them at edit time, before they reach CI.
#[allow(dead_code)] outside platform/If a symbol is dead on macOS or Windows, the answer is not #[allow(dead_code)]. The answer is to either:
d797294 move).#[cfg(target_os = "linux")] to the symbol so it doesn't exist on the OSes where it has no consumer. The hook permits this on mod/pub use re-export lines (the canonical pattern from qol-arch-code); for non-mod cfg gates you must restructure (see "Refactor recipe" below).#[allow(dead_code)] says "I know this is dead on some platform but I refuse to fix it." That permission slip outlives the situation that justified it and re-rots into mystery code two refactors later. The hook blocks it in non-platform/ files.
Permitted (the hook allows): #[allow(dead_code)] inside platform/<os>.rs files. Inside an OS impl, dead_code may legitimately mean "this stub method exists for trait parity but the host doesn't call it on this OS yet" — a defensible case. Outside platform/, the symbol is shared, and dead-on-some-OS is a smell.
#[allow(unused_mut)] outside platform/Same logic. unused_mut on a non-platform symbol means one OS's branch never mutates it. Two honest fixes:
#[cfg(...)] let mut x / #[cfg(...)] let x — but at that point you're back in cfg-sprawl territory; relocate instead.The hook blocks #[allow(unused_mut)] outside platform/.
#[cfg(target_os)] on use statements outside platform/// ❌ src/foo.rs
#[cfg(target_os = "linux")]
use crate::evdev::KeyState;
This pattern is almost always a refactor leftover. Either:
KeyState consumer in this file is also #[cfg(target_os = "linux")] — in which case the consumer (and its use) belong in platform/linux.rs, not here. Move both.use is genuinely only needed on Linux but other items are cross-platform — split the file.The hook blocks #[cfg(target_os = ...)] use ...; outside platform/. Inside platform/<os>.rs it's redundant (the file is already OS-gated) but harmless; the hook doesn't fire there.
If WindowOps::move_to_monitor exists in platform/mod.rs's trait, then linux.rs, macos.rs, and windows.rs must all impl WindowOps with move_to_monitor. Stub the unsupported OSes with a typed Err return — never unimplemented!(), never delete the method from the trait "because only Linux needs it". The trait is the contract. Stubs honor the contract.
The compiler enforces this for traits. The skill calls it out so you don't reach for the easy escape ("I'll just gate the trait method on Linux") which produces exactly the dead-code-on-other-OS class this skill exists to prevent.
When you discover a symbol in a shared module is causing dead_code on another platform (typical CI signal: unused: KEY_LEFTCTRL on macOS), do this:
rg "KEY_LEFTCTRL" across the crate. Note which file each consumer lives in.platform/<os>.rs or behind #[cfg(target_os = "<os>")], the symbol belongs in that platform's module. Skip to step 4.platform/<os>.rs (or a sibling platform/<os>/<feature>.rs if the symbol is large enough to warrant). Update its visibility: pub → pub(crate) or pub(super) as tight as possible.use statements in consumers.RUSTFLAGS="-D warnings" cargo clippy --all-targets --all-features --keep-going on the host you're on. Then trust CI for the other OSes (or run make ci-local if cross-compile toolchains are installed locally — see qol-arch-cicd).Concrete example (the d797294 pattern):
Before — src/hotkeys/capture/mod.rs:
pub struct BindingMatcher { ... } // <-- 16 dead_code errors on macOS
pub struct ModifierState { ... }
pub mod keycodes { pub const KEY_LEFTCTRL: u16 = 29; ... }
fn mod_to_key_codes(m: Mod) -> [u16; 2] { ... }
After:
// src/hotkeys/capture/mod.rs — only cross-platform surface
pub use binding::{Binding, parse_combo};
pub use platform::install;
// src/hotkeys/capture/platform/linux/matcher.rs — all of it lives here
pub(super) struct BindingMatcher { ... }
pub(super) struct ModifierState { ... }
pub(super) mod keycodes { pub(crate) const KEY_LEFTCTRL: u16 = 29; ... }
fn mod_to_key_codes(m: Mod) -> [u16; 2] { ... }
macOS now compiles clean — there's nothing for it to find dead.
// ❌ src/foo.rs (not under platform/)
#[allow(dead_code)]
pub fn parse_evdev_event(...) -> Event { ... }
// ❌ src/foo.rs (not under platform/)
#[allow(unused_mut)]
fn collect_diagnoses(mut diags: Vec<Diag>) -> Vec<Diag> { ... }
// ❌ src/foo.rs (not under platform/)
#[cfg(target_os = "linux")]
use crate::evdev::KeyState;
// ❌ shared trait method gated by cfg
pub trait WindowOps {
fn focus(&self, id: u64) -> Result<()>;
#[cfg(target_os = "linux")]
fn move_to_monitor(&self, id: u64, m: usize) -> Result<()>; // breaks parity
}
Inside src/<feature>/platform/<os>.rs, ANY of these are fine — the file is already OS-gated:
#[allow(dead_code)]
pub(crate) fn helper_only_used_on_some_paths() { ... } // ok inside platform/
#[allow(unused_mut)]
fn macos_stub(mut buf: Vec<u8>) { ... } // ok inside platform/
In tests/ and examples/, cfg gates are unrestricted — cross-platform tests legitimately need them.
The hook is genuinely bypassable for the rare legitimate case (e.g., a vendored generated file you cannot move):
# next 1 edit passes
touch .claude/bypass-qol-arch-cross-platform
# next N edits pass
echo 5 > .claude/bypass-qol-arch-cross-platform
If you find yourself bypassing more than once a quarter, the rule is wrong, not your edit. File an issue against the skill.
qol-arch-code — strategy-pattern code layout (platform/ subfolders, trait + impls). This skill assumes that layout exists.qol-arch-cicd — the matrix build that catches the OS-specific failures this skill tries to prevent at edit time. Belt-and-braces: this skill catches the patterns, the matrix catches the escapes.npx claudepluginhub qol-tools/qol-skills --plugin qol-projectCreates structured, bite-sized implementation plans from specs or requirements before writing code. Useful for breaking down multi-step tasks into testable steps with file structure and task boundaries.