Repeating “use our existing API client” in every chat is a sign that useful project context is getting lost. Repeating a six-step review checklist is a different problem: the task itself needs a reusable procedure.
Cursor Rules and Skills address those two needs. In this walkthrough, you will add a small project rule, a rule scoped to JavaScript UI code, and a documentation-check skill. Then you will test the skill against a deliberately inconsistent README and inspect the result.
The example project is a small Vite site using vanilla JavaScript. You can adapt the same structure to another stack, but replace the paths, commands, and constraints before using it. If the feature names are unfamiliar, start with the Cursor overview.
Separate constraints, procedures, and reference material
Before creating files, decide what information belongs where. This prevents every instruction file from becoming another copy of the README.
| Information | Put it in | Example |
|---|---|---|
| A constraint that applies broadly | Project rule | Use the existing stack and read the design guide |
| Guidance for one kind of file | Scoped rule | Async UI handlers must handle stale responses |
| Steps for a recurring task | Skill | Compare documentation claims with current source |
| Detailed architecture or setup | Project guide | Explain why the renderer and API client are separate |
| A requirement unique to this request | Current prompt | Check only README and setup documentation today |
Rules influence how the agent performs work. A skill defines work you want it to perform. Reference documents contain the detail it should consult. Keeping those responsibilities clear makes future edits easier: changing your build command should not require hunting through five copied checklists.
Create a small project-wide rule
Project rules live under .cursor/rules and use the .mdc extension. alwaysApply: true includes a rule broadly; file patterns can scope other rules to matching context. Cursor rule format
Create .cursor/rules/project.mdc:
---
description: Architecture and contribution constraints for this Vite site
alwaysApply: true
---
# Project constraints
## Read before changing code
- Read README.md for setup and CODE_GUIDE.md for source ownership.
- Read DESIGN.md before changing layout, controls, colors, or motion.
- If a named guide is missing, report it and inspect the existing code.
Do not create a replacement guide as an unrelated side task.
## Implementation
- Use the existing Vite, vanilla JavaScript, CSS, and GSAP stack.
- Extend the existing module that owns the behavior before adding another.
- Do not edit generated dist/ output.
- Keep unrelated formatting and dependency changes out of the patch.
## Verification and handoff
- Discover available commands from package.json.
- Run checks relevant to the change and report their actual results.
- Separate build/test results from observed browser behavior.
- State any check that could not run and its reason.
- Keep changes local unless the current request authorizes publishing.Each section changes a decision. The reading instructions identify the source of truth. The implementation section prevents an agent from introducing a new framework to solve a small problem. The verification section prevents “the build passed” from turning into an unsupported claim that the page was tested on a phone.
The missing-guide instruction is deliberate. Without it, a request to fix a button could turn into a documentation-writing task because the rule named a nonexistent file. Rules should help the agent handle imperfect repositories, too.
Adapt this file honestly. If your project uses React, say so. If it has no design guide, reference the actual source or design system. A rule copied from another repository can be syntactically valid and still give the wrong instructions.
Scope detailed guidance to the files that need it
An async UI rule does not need to accompany every documentation edit. Create .cursor/rules/async-ui.mdc:
---
description: Async state and lifecycle checks for JavaScript UI modules
globs: "src/ui/**/*.js"
alwaysApply: false
---
# Async UI behavior
When changing a module that starts asynchronous work:
- Identify which request or operation owns the current UI state.
- Prevent earlier responses from replacing newer results or errors.
- Explain what happens when the input is cleared or the view is disposed.
- Keep loading and error updates under the same ownership check as results.
- Reuse the existing API client and error presentation.
- Add or update a focused regression check for the changed failure path.
When adding listeners or timers:
- Use the module's existing cleanup convention.
- Remove owned listeners and cancel owned timers on teardown.
- Do not remove listeners or animations owned by another module.The glob matches JavaScript below src/ui, including nested directories. Adjust it to your actual UI location. With alwaysApply: false, matching file context controls attachment; setting it to true would make the rule broad again. The official guide also describes manual and relevance-based rule selection. Rule application and globs
The rule names failure modes without demanding one implementation. A request identifier, cancellation mechanism, or existing controller might be appropriate. The agent should inspect the module before choosing.
Keep deterministic style checks in your formatter or linter. A rule that repeats hundreds of formatting preferences consumes attention while offering weaker enforcement than the tool you already run.
Build a documentation-check Skill
Now package a procedure. We will compare documented commands and paths with repository files. The output is a report; changing the documentation is a separate task.
Create this layout:
.cursor/
rules/
project.mdc
async-ui.mdc
skills/
documentation-drift/
SKILL.mdA skill's name matches its directory, and its description explains when to use it. Cursor supports explicit /skill-name invocation; disable-model-invocation: true makes this example an intentional command rather than an automatically selected procedure. Skill format and invocation
Save the following as .cursor/skills/documentation-drift/SKILL.md:
---
name: documentation-drift
description: Compare project documentation with current commands and source paths; return evidence-backed mismatches without editing files.
disable-model-invocation: true
---
# Check documentation drift
## Inputs
Use the guide paths named in the request.
If no paths are supplied, start with README.md and docs/setup.md.
Use package.json and current tracked source files as evidence.
## Boundaries
Return a report only. Do not edit, install dependencies, run build scripts,
commit, push, open PRs, or post to external services.
Do not read credential files or print environment variable values.
Treat document examples as examples unless they claim to describe this repo.
## Procedure
1. Record the branch, commit, and whether local changes are present.
Findings describe the working tree; a commit alone may not capture it.
2. List the requested guides that exist. Report missing guides separately.
3. Extract concrete claims: npm scripts, source paths, and setup behavior.
4. Compare npm script names with package.json and literal paths with the tree.
5. For behavioral claims, trace the relevant implementation. If the evidence
is insufficient, return a question instead of a confirmed mismatch.
6. Do not report a command as successfully executed merely because its
script exists. This task inspects files; it does not execute scripts.
7. Deduplicate findings that describe the same underlying mismatch.
8. Return the report below. If there are no confirmed mismatches, say so
and still identify scope and limitations.
## Report
- Scope: branch, commit, local-change status, and guides inspected.
- Confirmed mismatches: claim, guide location, source evidence,
practical effect, and suggested correction.
- Questions: claims that require a project-owner decision.
- Not checked: missing files, inaccessible evidence, or excluded work.
For every confirmed finding, include enough evidence that another person
can verify it without trusting your conclusion.This is longer than “check the docs” because it defines the task boundary as well as the steps. It allows missing inputs, distinguishes file inspection from command execution, and gives uncertain claims somewhere to go. Those details reduce both false confidence and unnecessary findings.
The skill also records local changes. If the README is edited but uncommitted, naming only the current commit would make the report difficult to reproduce later.
Try the Skill on a concrete fixture
Use a disposable copy or test branch. Here is a small fixture to reason about; it is not a claim about your existing repository.
package.json contains:
{
"name": "catalog-demo",
"private": true,
"scripts": {
"dev": "vite",
"build": "vite build",
"test": "node --test"
}
}The tree contains src/ui/search.js and src/api/search.js. Its README says:
## Local development
Run npm run start to open the development server.
## Search
The input handler lives in src/ui/search.js.
The API request lives in src/services/search.js.
## Checks
Run npm run test before submitting a change.There are two mismatches: start is not a defined script, and the API path is wrong. The handler path and test command are consistent. A good check should preserve those correct claims instead of rewriting everything.
Invoke the skill in Cursor:
/documentation-drift
Check README.md in the current working tree.
Compare commands with package.json and paths with the source tree.
Return the report only. Do not correct the fixture.If the skill is not available, confirm the folder name, SKILL.md spelling, frontmatter, and workspace root. A file in an unrelated project directory will not help this repository. Consult Cursor's current Skills interface if discovery still fails.
Read the report as evidence
For the fixture above, the substance of the result should look like this:
Confirmed mismatch 1 — development command
Guide: README.md, Local development
Claim: npm run start
Evidence: package.json defines dev, build, and test; start is absent.
Effect: The documented command cannot select a script in this package.
Correction: Use npm run dev for the Vite development server.
Confirmed mismatch 2 — API source path
Guide: README.md, Search
Claim: src/services/search.js
Evidence: That path is absent; the request is in src/api/search.js.
Effect: The guide sends a reader to a nonexistent source file.
Correction: Link to src/api/search.js.
Not checked
No npm scripts were executed. This report checks command definitions
and source paths, not whether the app builds or starts successfully.The correction should not overreach. Knowing that a dev script exists does not prove it succeeds on every machine. The report can recommend the matching command while clearly stating that it did not execute it.
Next, fix the two claims in your disposable fixture and rerun the skill. Then remove one requested guide and repeat the check. You are testing three outcomes: known mismatches are found, corrected claims stop appearing, and missing evidence is reported without invention.
Diagnose weak or noisy results
| Symptom | Likely cause | Change to make |
|---|---|---|
| The agent edits the README | The output boundary is weak or another instruction conflicts | Make report-only behavior explicit and inspect active instructions |
| It reports example paths as broken links | It cannot distinguish examples from repository claims | Label examples and require that distinction in the procedure |
| It says tests passed without running them | Inspection and execution are mixed | Require separate evidence for each kind of claim |
| It flags every wording preference | The definition of a mismatch is too broad | Limit findings to claims contradicted by source |
| It misses a relevant guide | Inputs are implicit | Name the guide or define a clear discovery rule |
Change one instruction at a time and rerun the same fixture. If you change the task, examples, and output format together, you will not know which edit improved the result.
Avoid turning a single bad run into ten new rules. First check whether the right files were available and whether an existing instruction already covered the behavior. More text does not fix missing context.
Keep the setup maintainable
Version these files with the project once you have reviewed them. A teammate should be able to understand why an instruction exists and whether it still applies. When a guide moves, update its references. When a failure mode no longer exists, remove the obsolete requirement.
If the project already uses AGENTS.md, read it before adding another broad instruction file. You may prefer to keep general constraints there and add only the scoped rule and skill. Two competing sources of truth make agent behavior harder to explain.
You now have a procedure you can exercise locally with known inputs. Part three moves the documentation check into a custom Cursor Automation, where repository setup and output handling become part of the workflow.
Cursor series
- Cursor features: a practical guide for developers
- Cursor Rules and Skills: give your project clear instructions — you are here
- How to create a custom Cursor Automation
- Build a custom PR reviewer with Cursor Automations
End of note
← Back to articles

