Tinker AI
Read reviews
intermediate 5 min read

`.clinerules`: project-specific guidance Cline actually reads

Published 2026-05-11 by Owner

.clinerules is a plain markdown file that lives at the root of a project. Cline reads it on every task, before any user message. That single sentence explains both its power and its constraint: whatever guidance is in that file runs unconditionally, every time, so it has to be short enough to matter and focused enough not to get summarized into nothing.

This is not the same as a README or a CONTRIBUTING guide. Those are for humans reading the repository. .clinerules is instructions to a model executing tasks. The audience is different, the format is different, and the content should reflect that. A .clinerules file that looks like a style guide is probably doing the job of a style guide rather than the job of a rules file.

Where the file lives and how it works

Drop .clinerules directly in the repo root — the same level as package.json or pyproject.toml. No subdirectory. No special extension. Cline picks it up automatically.

my-project/
├── .clinerules          ← lives here
├── package.json
├── src/
└── ...

The format is Markdown. No YAML frontmatter, no special syntax. Bullet lists, code fences, and short prose all work. Cline interprets the file as guidance about how to behave on this project.

Rule precedence. Cline has two layers of guidance: global rules set in Cline’s VS Code settings under “Custom Instructions,” and project rules in .clinerules. Project rules win when there is a conflict. If global instructions say “prefer async/await” but .clinerules says “use callbacks (legacy codebase),” Cline follows the project rule. This makes .clinerules the right place for anything project-specific, and global instructions the right place for preferences that apply to all projects.

The practical effect: a new developer clones the repo, opens Cline, and the project context is already there. No per-machine setup required.

One important note on scope: .clinerules is read every time Cline picks up a task, not just the first task of a session. Cline does not maintain memory across sessions by default, so the rules file is the only persistent, guaranteed-to-be-read context Cline has about your project. That is why rules need to be stable, opinionated, and short — they are loaded on every invocation.

Rules that actually change behavior

The highest-value rules fall into three buckets:

Coding style rules that differ from defaults. Cline will write code that looks like the center of its training distribution unless told otherwise. If a codebase uses explicit return types everywhere, or tabs instead of spaces, or a specific import order enforced by a linter, that belongs in .clinerules. Not as a reminder — Cline does not remember previous sessions — but as standing instruction that runs on every task. The question to ask when writing one of these rules: “If someone who had never seen this codebase wrote a function here, what would they get wrong?” Whatever comes to mind first is probably what .clinerules should say.

Explicit “do not do this” rules. These consistently outperform positive rules. Rules that say “do not” are also easier to verify. After a Cline session, you can scan the diff and ask: did it do the forbidden thing? If yes, the rule failed or was too vague. If no, the rule worked. This makes negative rules self-auditing in a way positive style rules are not. Telling Cline what not to suggest is often more effective than describing what to do, because the model has a strong prior toward common patterns. A rule that says “do not use any in TypeScript” is more reliable than one that says “prefer typed code.” Specific prohibitions are easier to follow than stylistic aspirations.

File location rules. Where files go is one of the most common places Cline makes a wrong assumption. If the project puts utilities in src/lib/, tests in tests/, and types in src/types/, saying so explicitly prevents Cline from creating a utils/ directory three levels deep that then has to be moved. File location rules also serve as lightweight documentation for human contributors who forget the project’s directory layout — a side benefit that costs nothing.

Here is an example .clinerules for a TypeScript monorepo:

# Project conventions

## TypeScript
- Strict mode is on. Never use `any`. Use `unknown` and narrow if the type is genuinely uncertain.
- All exported functions need explicit return types.
- Imports: `node:*` built-ins first, then third-party, then `@repo/*`, then relative. Blank line between groups.

## File locations
- Utilities go in `packages/shared/src/lib/`. Do not create a `utils/` folder.
- Tests sit next to source files: `foo.ts``foo.test.ts` in the same directory.
- Generated files go in `dist/`. Do not commit them.

## Do not suggest
- Class components. This is a hooks-only React codebase.
- `Object.assign()` for merges. Use spread syntax.
- Adding a library when a function from an existing import covers the use case.
- Inline styles on React components. Tailwind classes only.

That is about 130 words. Short enough to be read in full; specific enough to change output.

Notice what the example does not include: descriptions of the framework, explanations of why Tailwind is used, or aspirational statements about code quality. Every line is an instruction Cline can act on or not act on.

Wasted bytes

Several common .clinerules patterns consume tokens without changing anything:

Restating what package.json already says. “This project uses React 18, TypeScript 5, and Tailwind CSS 3.” Cline reads the file tree. It sees package.json. Telling it the stack in .clinerules is redundant. The space is better used for conventions that are not visible from the package manifest.

Marketing language and rationale. “We believe in clean, readable code that is easy to maintain and understand.” Cline cannot operationalize this. It has no signal for what “clean” means in this specific codebase. A rule without a testable criterion is not a rule.

Vague encouragement. “Always write comments for complex code.” What counts as complex? When in doubt, Cline will over-comment simple code and under-comment the parts that actually need explanation. “Add a comment when a function has a non-obvious side effect” is enforceable. “Always comment complex code” is not.

Anything longer than 60 lines. This is the hard ceiling that most people find out the wrong way. Cline’s context budget is finite, and the rules file competes with the conversation, the file tree, and the open file for attention. A long .clinerules gets summarized internally, and the specific guidance in the long tail — the rules you most needed to write down — is the first to go. Keep the file under 60 lines. If there are more conventions than that, keep the most commonly violated ones and skip the rest.

The underlying reason for all of these failures is the same: they treat .clinerules as documentation rather than as a behavior modifier. Documentation is for humans reading the repo. .clinerules is for Cline executing a task. The audience is different, and the content should be written accordingly — operational, testable, and brief.

The one rule that materially changed the output

The single most impactful rule in a production .clinerules file is one that blocked a specific bad pattern: “Do not wrap every function in a try/catch block. Error handling should only be added where there is a specific recovery strategy.”

Before this rule: Cline was adding try/catch wrappers to nearly every async function it touched. The catches logged the error and returned null or undefined. The function’s callers then had to handle the possible null, which led to null-checks scattered through the codebase, which masked errors instead of surfacing them.

After the rule: Cline stopped adding defensive try/catch wrappers. Errors propagated to the boundary that actually knew what to do with them. The codebase had sharper failure points instead of silent degradation, and the code Cline produced fit the existing error-handling style.

The before state was not malicious — wrapping async functions in try/catch is common in tutorials and training data. It is defensive and often well-intentioned. But it was wrong for this codebase, and Cline had no way to know that without being told. The rule told it.

The lesson generalizes: the most valuable rules are not about style preferences. They are about patterns where Cline’s training-data defaults conflict with the project’s existing conventions. The style preferences can often be enforced by a linter. The conflicting patterns cannot — only .clinerules can redirect them.

What belongs in global rules vs .clinerules

A rule belongs in .clinerules when it is specific to this project and should not follow Cline to other projects. A rule belongs in global Cline settings when it should apply everywhere.

Example split:

# Global Cline settings (applies to all projects)
- Prefer explicit over implicit.
- When asking a clarifying question, ask one question, not a list.

# .clinerules (applies to this repo only)
- Use the logger from `src/lib/logger.ts`. Never use console.log directly.
- API routes live in `src/pages/api/`. Do not create a server/ directory.

The test: would this rule make sense in every project? If yes, global. If it references a specific file path, library choice, or naming convention unique to this repo, it belongs in .clinerules.

Check .clinerules into version control. The file is part of the project. When conventions change, the rule changes, and the next pull updates everyone’s Cline behavior automatically.

Iterating on the rules

A .clinerules file is not a one-time setup. The useful workflow is to start with three to five rules on day one, observe what Cline gets wrong in the first week, and add targeted rules for the recurring misses.

The fastest signal that a rule is needed: noticing the same manual correction two or three times. If every Cline output has to have its import order fixed, a rule should replace that correction. If Cline keeps reaching for lodash when the codebase only uses native methods, a “do not import lodash” rule will save that correction on every task going forward.

The fastest signal that a rule is dead weight: it covers something Cline never actually does wrong. Rules are not documentation. They do not need to describe every true thing about the project. If a rule has not prevented a mistake in a month, remove it and reclaim the context budget for rules that are earning their space.

A practical ceiling: if .clinerules is growing past 40-50 lines, it is time to prioritize. List all the rules, rank them by how often they have prevented a concrete correction, and drop the bottom third. The file should stay lean enough that every rule in it is there because of a real, recurring pattern — not because it seemed like good documentation at the time.

The rules that survive this pruning process end up being a surprisingly accurate list of where Cline’s defaults diverge from the project’s conventions. Reading that list is a useful exercise independent of the tooling — it shows exactly where the codebase has made non-obvious choices that are not visible from the code structure alone.