VS Code extension ignores `.cline/rules/`, which the SDK resolver supports
Cline Surface
VSCode Extension
Cline Version
4.1.18
Beta version
- I am using a beta version of Cline
What happened?
This issue was spotted meanwhile working with Cline with human supervision, I supported myself with the agent to write the issue detailed as possible
Summary
Project rules placed in .cline/rules/ are loaded by the SDK/CLI but silently ignored by the VS Code extension. The extension's rule loader is hardcoded to .clinerules and never consults the SDK's resolveRulesConfigSearchPaths(), which searches both locations.
Because .cline/skills/ is supported by the extension, a project that adopts the .cline/ layout ends up in a state where its skills load and its rules do not — with no warning, no log line, and no entry in the Rules panel. The rules read as binding to anyone reviewing the repo, but never reach the model.
Why this looks like a bug rather than "just use .clinerules/"
Three things make the current behavior surprising rather than merely undocumented:
- The SDK explicitly supports
<workspace>/.cline/rules. It is not an accident or a leftover — it is a named constant combination in the shared resolver. - The SDK labels
.clinerulesasDEPRECATED_CONFIG_DIR. The location the extension exclusively supports is the one the SDK calls deprecated, so the two halves of the product point in opposite directions. - The extension already depends on
@cline/sharedand@cline/core(workspace:*inapps/vscode/package.json, v4.1.18) and already imports from@cline/shared/storageelsewhere — just not for rules.
Evidence
SDK — sdk/packages/shared/src/storage/paths.ts supports both locations:
const DEPRECATED_CONFIG_DIR = ".clinerules";
const CLINE_CONFIG_DIR = ".cline";
export const RULES_CONFIG_DIRECTORY_NAME = "rules";
export function resolveRulesConfigSearchPaths(workspacePath?: string): string[] {
const wsPaths = workspacePath
? [
join(workspacePath, DEPRECATED_CONFIG_DIR), // .clinerules
join(workspacePath, CLINE_CONFIG_DIR, RULES_CONFIG_DIRECTORY_NAME), // .cline/rules
]
: [];
// ...
}
VS Code extension — apps/vscode/src/core/storage/disk.ts supports only one:
export const GlobalFileNames = {
clineRules: ".clinerules",
workflows: ".clinerules/workflows",
hooksDir: ".clinerules/hooks",
clineruleSkillsDir: ".clinerules/skills",
// ...
}
The extension's rule loader (apps/vscode/src/core/context/instructions/user-instructions/cline-rules.ts) resolves that constant and nothing else:
const localClineRulesFilePath = path.resolve(workingDirectory, GlobalFileNames.clineRules)
apps/vscode/src/core/context/instructions/user-instructions/rule-helpers.ts repeats the same hardcoded literals.
By contrast, skills are handled correctly — apps/vscode/src/core/storage/skill-directories.ts scans several roots including .cline/skills:
const SKILL_DIRECTORY_NAMES = {
clineruleSkillsDir: ".clinerules/skills",
clineSkillsDir: ".cline/skills",
claudeSkillsDir: ".claude/skills",
agentsSkillsDir: ".agents/skills",
}
…and getSkillsDirectoriesForScan() in the same file walks all of them:
{ path: path.join(cwd, SKILL_DIRECTORY_NAMES.clineruleSkillsDir), source: "project" },
{ path: path.join(cwd, SKILL_DIRECTORY_NAMES.clineSkillsDir), source: "project" },
This is the inconsistency: for skills the extension deliberately scans multiple roots including .cline/, while for rules it resolves a single hardcoded constant.
The extension already consumes SDK storage helpers, e.g. apps/vscode/src/sdk/sdk-task-history.ts:
import { resolveSessionDataDir } from "@cline/shared/storage"
So wiring resolveRulesConfigSearchPaths in would follow an existing pattern rather than introduce a new dependency.
Support matrix (as of apps/vscode v4.1.18)
| Path | VS Code extension | SDK / CLI |
|---|---|---|
.clinerules/ |
✅ supported | ✅ supported (DEPRECATED_CONFIG_DIR) |
.cline/rules/ |
❌ ignored | ✅ supported |
.cline/skills/ |
✅ supported | ✅ supported |
Steps to reproduce
In any workspace, create
.cline/rules/test-rule.mdwith no frontmatter (so it should always be active):# Test rule Always begin your reply with the exact token RULE-LOADED.Also create
.cline/skills/test-skill/SKILL.md, so a working.cline/artifact can be compared against a non-working one in the same workspace.Make sure there is no
.clinerules/directory in the workspace.Open the workspace in the VS Code extension and start a new task.
For the comparison, run a task over the same workspace through the CLI.
Expected: the rule is active (the reply starts with RULE-LOADED) and is listed in the Rules panel, matching the SDK/CLI behavior.
Actual:
- VS Code extension — the rule is absent from the Rules panel and has no effect on the reply. The skill in
.cline/skills/is picked up normally in the same session. - CLI — the same rule is applied.
Moving the file to .clinerules/test-rule.md makes it work in the extension, confirming the content and frontmatter are not at fault.
Impact
The failure mode is silent, which is what makes it costly. A team that standardizes on .cline/ gets:
- Rules that are ignored for every developer on the extension, while working for anyone on the CLI — so behavior differs per teammate with no visible cause.
- No diagnostic anywhere: the directory exists, the files are valid, nothing warns.
- False confidence in review: rules describing guardrails are read as enforced when they are inert.
This is easy to hit in practice. A repository with its rule set in .cline/rules/ will have those rules apply in a CLI-based session and be entirely absent in an extension-based one — so two people reviewing the same code get different agent behavior, with nothing in either UI to indicate why. Reading the extension and SDK sources is currently the only way to explain the discrepancy.
Possible resolutions
Any one of these would resolve the confusion; listed in order of preference:
- Make the extension use the SDK resolver — have the rule loader call
resolveRulesConfigSearchPaths()from@cline/shared/storage, as it already does for other storage paths. This aligns both clients on one implementation and removes the duplicated literals indisk.ts/rule-helpers.ts. - Add
.cline/rulesto the extension's lookup — mirroring howskill-directories.tsalready scans multiple roots. Smaller change, but keeps two resolvers that can drift again. - Documentation-only — if
.cline/rules/is intentionally SDK/CLI-only, say so explicitly in the Rules docs, which currently list.clinerules/without mentioning that.cline/rules/exists and works elsewhere. This is the least satisfying option given the SDK marks.clinerulesdeprecated.
Happy to open a PR for option 1 or 2 if you can confirm which direction you'd prefer — in particular whether .clinerules being DEPRECATED_CONFIG_DIR reflects a planned migration to .cline/ across all clients.
Environment
apps/vscodeversion inspected: 4.1.18 (apps/vscode/package.json)- Sources read from
mainas of 2026-09-16.
Files referenced above:
| File | Relevance |
|---|---|
apps/vscode/src/core/storage/disk.ts |
GlobalFileNames.clineRules, hardcoded to .clinerules |
.../user-instructions/cline-rules.ts |
the rule loader that resolves only that constant |
.../user-instructions/rule-helpers.ts |
repeats the same literals |
apps/vscode/src/core/storage/skill-directories.ts |
multi-root scan that does include .cline/skills |
sdk/packages/shared/src/storage/paths.ts |
resolveRulesConfigSearchPaths(), searches both roots |
sdk/packages/core/.../user-instruction-config-loader.ts |
SDK consumer of that resolver |
apps/vscode/src/sdk/sdk-task-history.ts |
existing example of the extension importing @cline/shared/storage |
Steps to reproduce
Provider/Model
No response
Diagnostics
No response
System Information
No response
Source: cline/cline