pre-commit — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited pre-commit (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Run all checks, fix any issues found, then present a summary table.
Run the following checks if there are changes in the tapo/, tapo-py/, or tapo-mcp/ directories. Fix all issues found. Run independent checks (cargo check, cargo clippy, cargo fmt, cargo test) in parallel. Unless otherwise specified, run checks at the workspace level (no -p flags) with --all-features to ensure cross-crate issues are caught. Link-free checks (check, clippy) take --workspace so they cover tapo-py too; cargo test must NOT — it links test binaries and examples, which fails with tapo-py's pyo3/extension-module, so it relies on default-members excluding tapo-py.
cargo check --workspace --all-featurescargo clippy --workspace --all-targets --all-features -- -D warningscargo fmt --allcargo test --all-featurescargo clean --doc && RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps --all-featuresunwrap() in non-test code without a // safe: commentunsafe in non-test code without a // SAFETY: commentuse (max one level of {} nesting)redact_session_token in tapo/src/error.rs and its tests, because reqwest prints the full URL in its errorsmodule_name.rs next to the module_name/ folder, never by module_name/mod.rsmodule_name.rs holds only its mod declarations and use/pub use re-exports (plus //! docs and attributes such as #[cfg(...)] on them). Move any types, functions, impls, constants, or tests into a submodule fileRun the following checks if there are changes in the tapo/ or tapo-py/ directories. Fix all issues found.
.pyi stubs if Python-exposed Rust types changed#[pyclass] types are imported and registered in tapo-py/src/lib.rstapo-py/examples/ are updated to match corresponding Rust examples in tapo/examples/cd tapo-py and activate the virtual environmentuv run mypy . — fix all type errorsuv run black . — fix all formatting issuesRun the following checks if there are changes in the tapo-mcp/ directory. Fix all issues found.
#[derive(JsonSchema)] types have schemars annotations — including tool input params, response types, enums, and their fields/variants. Check for descriptions and range constraints where applicable.tapo-mcp/README.md reflects any MCP API changes (tools, resources, capabilities, env vars, auth)tapo-mcp/openclaw-skill/SKILL.md — frontmatter (description, version, requires), Setup, Tools section with example npx mcporter call invocationstapo-mcp/openclaw-skill/references/setup.md — verification table (tool, description, parameters)tapo-mcp/openclaw-skill/references/tapo-mcp-setup.md — Tools table, Resources table, Configuration env vars, Authentication, Deployment (kept in sync with tapo-mcp/README.md)tapo-mcp/src/server.rs with_instructions(...) and the OpenClaw description: are checked by /verify-device-support, which the Rust and Python checks below run when a model or category changesRun these checks if a change adds a variant to a #[non_exhaustive] enum in tapo/src (DeviceType, DiscoveryResult, ChildDeviceHubResult, ChildDeviceHubIrResult, RecordingType, …). Fix all issues found.
#[non_exhaustive] lets end users of tapo skip new variants with a _ => arm. tapo-py, tapo-mcp and the examples in tapo/examples don't get that choice: they must support every variant tapo has. Their matches end in a _ => unreachable!() arm only to compile, so the compiler no longer flags a missing variant there. The grep below lists those enums and their unreachable!() sites. Other _ => arms (the capability matches in tapo-mcp) don't show up in it and are covered by the MCP capabilities check:
grep -rn -A2 '#\[non_exhaustive\]' tapo/src/api/discovery tapo/src/responses | grep 'pub enum'
grep -rn 'unreachable!()' tapo-py/src tapo-mcp/src tapo/examplesFor each new variant:
match that ends in _ => unreachable!() names the new variant. A variant without a capability is still named, in the arm that rejects it (for example, a device without on/off support in the WrongDeviceType arm of control_device)PyDiscoveryResult (tapo-py/src/api/discovery/discovery_result.rs), PyRecordingType and the hub child list macros. Add it to the .pyi stubs, including those for enums exposed directly, such as DeviceTypetapo-mcp/src/requests/get_devices.rs and check_device.rs and the tools under tapo-mcp/src/tools/ give the new variant every capability it supports, and list its children if it has anyRun the following checks if there are changes in the tapo/ or tapo-py/ directories. Fix all issues found.
/verify-device-support when a device model or category was added or removed, a handler's public method list changed, or a method's #[cfg(feature = "debug")] gating changed. It checks SUPPORTED_DEVICES.md, the "Tested with" sentences, the builders, the handler and device info docs, the Python stubs, the examples and tapo-mcp against the code. Fix every finding it reportsTROUBLESHOOTING.md still matches the library when the change touches protocols, authentication, discovery, error types or messages, or logging. Read the whole file, not only the sections the change seems to concern:tapo/src/ and tapo-py/ and fix the ones that driftedRun these checks on every change, whatever directories it touches. Fix all issues found.
The decompiled Tapo Android app is a private reverse-engineering aid that lives outside the repo, and its names are obfuscated per app release. Nothing committed may point at it.
Type.CONSTANT, Type.method()) or right after "app's": { git diff --name-only --diff-filter=d HEAD -- . ':!.claude/skills/pre-commit/SKILL.md'; git ls-files -o --exclude-standard -- . ':!.claude/skills/pre-commit/SKILL.md'; } | xargs grep -nEi '\.(java|kt|smali)\b|decompil|base\.apk|apkmirror|jadx|com[./]tplink'
{ git diff --name-only --diff-filter=d HEAD -- . ':!.claude/skills/pre-commit/SKILL.md'; git ls-files -o --exclude-standard -- . ':!.claude/skills/pre-commit/SKILL.md'; } | xargs grep -nE '`[A-Z][A-Za-z0-9]*\.([A-Z_]+|[a-z][A-Za-z0-9]*\(\))`|app(.s)?[^`]{0,30}`[A-Z][a-z]+[A-Z][A-Za-z]*`'The second pattern works one line at a time, so it misses a class name that wraps onto the line after "app". Then read every comment in the touched files that mentions the app, not only the lines the diff changed, for what the patterns miss: two/three-character package or class names (ab1, xy2, zz9/c1), app-internal class and method names (KeyMixer.d(), StreamGatewayImpl), and absolute paths into the decompiled tree.
//! The Tapo app (ab1/c.java, xy2/b.java) derives the keys from the Key-Exchange header`//! The Tapo app derives the keys from the Key-Exchange header`Run these checks if anything under tapo/tests/ was added or changed, including new untracked files. Fix all issues found.
The simulator stands in for a real device, so a test only proves something if the simulator behaves like the device and not like the library. Everything it knows comes from a fixture or from what real devices were seen to do.
#### Fixtures
Read every added or changed fixture in full.
result, a login answer keyed by sub_method, or an error response the device gave. Trimming the per-login fields the simulator computes is fine; adding a flag, setting, or hint that no device sends is notfixtures/smartcam/, everything else in fixtures/smart/. The file name follows the convention in tapo/tests/simulator/fixture.rs and names the protocol the device takes. The simulator reads both, so a wrong folder or protocol changes how it behavesdevice_id, owner, hw_id, fw_id, oem_id, dev_id, …) are obvious placeholders: hex counting patterns such as 0123456789ABCDEF… or FEDCBA98…, all zeros, or 8000…0110 ending in the model numberAA-BB-CC-DD-EE-FF or end in a short model suffix such as -35, in every spelling the device uses (AABBCCDDEEFF in the discover login answer)192.168.1.100nickname, ssid, and every other base64 string to check; camera names such as device_name are plain textlatitude and longitude are 0, or the London placeholder 515074 / -1278 with region Europe/LondonLeave values that only describe the device: model, versions, component lists, signal strength, settings, and usage or energy counters.
#### Simulator
assertions.rs, which checks what the library returned: grep -rnE '\btapo::|use tapo\b' tapo/tests/simulator/tapo/src/. A comment that justifies the simulator with what "the library" does is a sign of this; rewrite it to say what the device doesAfter fixing all issues found in the checks, review the code changes for correctness, readability, and maintainability and propose improvements. Summarize the findings according to severity.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.