with one click
pre-pr-check
// Check local changes against the LMCache coding standards and fix issues before creating a PR
// Check local changes against the LMCache coding standards and fix issues before creating a PR
| name | pre-pr-check |
| description | Check local changes against the LMCache coding standards and fix issues before creating a PR |
| allowed-tools | Bash, Read, Edit, Write, Grep, Glob, Agent |
| argument-hint | [--scope uncommitted|branch|staged] [--fix|--check-only] |
Check the developer's local changes against the coding standards defined in
docs/coding_standards.md and modify the code to fix compliance issues, so the
PR is clean before it is opened.
This skill is meant to be run before /create-pr.
--scope (default: branch)
uncommitted -- check only unstaged + staged changes vs HEADstaged -- check only staged changesbranch -- check all commits on the current branch not yet in dev (the
full PR diff). This is the default since that matches what a reviewer sees.--fix (default) -- automatically fix issues that can be fixed mechanically--check-only -- only report issues, do not modify filesRead docs/coding_standards.md at the repo root. This is the authoritative reference.
Run git status --short and git branch --show-current to orient yourself.
Then, based on --scope, compute the diff:
| Scope | Command |
|---|---|
uncommitted | git diff HEAD |
staged | git diff --cached |
branch (default) | git diff dev...HEAD |
Also list changed files:
| Scope | Command |
|---|---|
uncommitted | git diff --name-only HEAD |
staged | git diff --cached --name-only |
branch | git diff --name-only dev...HEAD |
If there are no changes in the selected scope, report that and stop.
For each changed file, read the current content (not just the diff) so you can make accurate edits. Focus on:
.py files -- full coding-standard review.md, .rst -- documentation review (brief).cpp, .cu, .rs -- light review (style only; clang-format / cargo fmt handle most of it)For each changed file, also identify the changed public symbols (functions, methods, classes, fields whose signature, return type, raised exceptions, or behavior contract changed). You will use these in Step 4 to find and inspect callers.
For large changes, delegate to the Explore agent to summarize per-file responsibilities before reviewing.
For each changed Python file, check the following (from docs/coding_standards.md):
--check-only)These are straightforward to fix:
# SPDX-License-Identifier: Apache-2.0 on line 1 of new Python files.assert used for runtime validation (Section 2.2): Replace with if <not cond>: raise ValueError(<clear msg>).Optional usage (Section 2.1): Where a value is always initialized, remove the Optional wrapper and initialize directly. Where None is genuinely possible, rewrite as X | None.list, dict, tuple, set in annotations with parameterized forms (list[T], dict[K, V]).torch-before-native-C-extension ordering.logging.getLogger(__name__) (Section 7.4): Replace with init_logger(__name__) from lmcache.logging.INFO level (Section 7.4): If a log is about store/retrieve/task progress, change logger.info(...) to logger.debug(...).WARNING (Section 7.4): For log messages about benign concurrent conditions (e.g., "key not found, this should not happen" in a code path documented as not holding the global lock), downgrade to debug and fix the misleading message.TODO: confirm note where you are uncertain, and flag it in the report.These are judgment calls and should be reported, not auto-fixed:
other._private outside the defining class.None for multiple distinct meanings.self._lock; shared state accessed without synchronization.For category A and B issues (unless --check-only):
Edit to make precise, minimal changes.For category C issues: do NOT auto-fix. Report them for the developer to address.
Even when the diff itself looks clean, a change can silently break unchanged callers. Before declaring the changes ready for PR, verify the global view for each changed public symbol identified in Step 2.
Triggers -- run this step if the diff does any of:
None to accepted values, narrows a type)None means)If none of the above applies, skip this step.
How to run it:
Grep its name across the whole repo
(production code, tests/, benchmarks/, lmcache/integration/, docs/).
Do not limit to files in the diff.Grep -A 2 -B 2
for context, or delegate to the Agent (Explore) tool with a focused prompt
(e.g., "find all callers of LMCacheMPWorkerAdapter.submit_store_request
and summarize the arguments each caller passes").class \w+\(<BaseName>).For each caller, decide:
Broken and must be fixed in this PR (category A-like, fix it):
For these, update the caller in the same pass as the main change. Apply the
edit using Edit, then re-read to confirm. If the caller is in an unrelated
module and the fix is non-trivial, flag it for manual review instead.
Behaviorally risky (category C-like, flag for the developer):
Do NOT silently edit these -- the developer needs to confirm the intent. Flag
them in the output with path:line of the caller and a one-line explanation.
Safe (no action):
Track the caller-impact findings under the existing output sections:
error if the caller is clearly broken and warning otherwiseRun these checks and report the outcome. Do NOT auto-run them; print the command the developer should run (respecting the user's preference to run these themselves):
pre-commit run --all-files
pytest -xvs tests/v1/distributed/ # if distributed/ changed
pytest -xvs tests/v1/mp_observability/ # if mp_observability/ changed
<uncommitted|staged|branch><N><total> (auto-fixed: <N>, manual: <N>)Grouped by category, with file:line references. E.g.:
Typing (3 fixes)
lmcache/v1/foo.py:42 -- replaced Optional[int] with int | Nonelmcache/v1/foo.py:87 -- added type hint for limit: int and return type -> list[str]lmcache/v1/bar.py:120 -- replaced dict with dict[str, int]Runtime validation (1 fix)
lmcache/v1/config.py:548 -- replaced assert config.url is not None with if config.url is None: raise ValueError("url is required")Docstrings (2 fixes)
lmcache/v1/baz.py:15 -- added full docstring for public method submit_requestlmcache/v1/baz.py:60 -- updated docstring for lookup to reflect new cache_salt parameterGrouped by severity:
error (must fix before PR):
lmcache/v1/foo.py:230 -- new feature BatchProcessor.process_async has no tests in tests/v1/. Add unit tests that exercise the public process_async API.lmcache/v1/bar.py:15 -- BarAdapter.do_thing accesses self._cache._internal_map directly; use a public accessor or expose a method on Cache.warning (should fix):
lmcache/v1/baz.py:42 -- register(name: str, force: bool) uses a boolean parameter. Consider splitting into register(name) and register_overwrite(name), or using an enum RegisterMode.info (suggestion):
lmcache/v1/baz.py:78 -- filter parameter is named filter; consider key_eligible_filter for clarity.pre-commit run --all-files
# then run relevant test suites
| Category | Auto-fixed | Manual | Total |
|---|---|---|---|
| Typing | 3 | 0 | 3 |
| Runtime validation | 1 | 0 | 1 |
| Docstrings | 2 | 0 | 2 |
| Design | 0 | 2 | 2 |
| Tests | 0 | 1 | 1 |
| Total | 6 | 3 | 9 |
git add, git commit, or git push. The developer handles git operations themselves.pre-commit or the test suite automatically; print the command for the developer to run.branch and the branch has no upstream or is far behind dev, warn the developer but proceed.docs/coding_standards.md is missing, stop and ask the developer to check it out or pull the latest dev.