Browse docs

← All docs

docs / conventions-in-use.md

Conventions in use

Three surfaces read the same rules at three different moments. This page is what each one does, what it will not do, and how to switch them off.

The check before you create

Your assistant asks about a path it is about to create, naming the kind: "is src/ui/UserCard.vue a valid components file?" It gets back a verdict, and when the answer is no, the corrected path.

Two details make this the most useful of the three:

  • The kind comes from the caller. cix doesn't guess whether a file is a component or a helper — the assistant that's about to write it already knows, and says so. That's what lets the check compare a proposed path against the folder rule instead of assuming the current location is correct.
  • It runs before the file exists. Nothing has been written, so nothing has to be moved.

Available in every supported client, on demand. Ask for it directly when you want it: "check the conventions before you create that."

The gate at write time

In Claude Code and Cursor, a guardrails install (cix install --guardrails) registers a hook that inspects a write before it lands and refuses it if:

  • the new file's name breaks the naming rule for its kind, or
  • the new file, or a new top-level symbol inside an existing file, collides with a symbol name that already exists elsewhere in the project.

A refusal names the rule, the offending filename, and the corrected name. Everything else is allowed through.

What the gate does not check

Folder placement is never checked before a write — on any client, at any setting. This is a decision, not an omission. A pre-write hook is handed a path and nothing else, so to check placement it would first have to decide which kind the file is, and the only thing a path can tell it is which declared folder the file already sits in. A placement check built on that premise can never fire: it would be asking whether a file is in the folder it's in.

Placement is checked where the question can be answered honestly — the on-demand check above, where the caller supplies the kind.

Note — one more thing this hook does is unrelated to conventions: it stops a line-based edit from cutting into a symbol cix has indexed, and points at the structural edit tools instead. That guard runs in every cix-indexed project whether or not you use conventions.

Notices alongside allowed writes

When cix can't produce a verdict but the reason is worth knowing — a document it couldn't parse, or a repository whose rules were never uploaded — it reports that next to the write it allowed, rather than blocking or staying silent.

These are deduplicated, so a given notice appears once rather than on every write. Guidance that fires on every single write trains you to stop reading it, which costs more than the notice was worth.

The repository-wide audit

The audit sweeps the whole repository rather than one path: misplaced files, naming violations, and orphan symbols — functions and classes whose names imply a live role but whose code looks dead. This is the report that tells you whether a rule you just wrote describes your project or argues with it. Part of the Max plan.

What each client gets

ClientCheck on demandPre-write gate
Claude CodeYesWith --guardrails
CursorYesWith --guardrails
CodexYesNo
Gemini CLIYesNo

Claude Code and Cursor expose a before-the-write event cix can hook — the gate arrives with the guardrails profile, and Cursor honours it only in directories you have trusted. Everywhere else, conventions are advice your assistant asks for — which is why the project instructions cix writes tell it to ask before creating a file.

Turning it off

Per project, in .cix/config.json:

json
{
  "conventions": { "enabled": false }
}

Or for specific languages only, keeping the rest:

json
{
  "conventions": { "disabled_languages": ["python", "markdown"] }
}

Both settings switch off the pre-write gate for the files they cover. The on-demand check keeps working either way — turning off enforcement isn't the same as refusing to answer the question, and your assistant can still ask.

Language names are the ones cix indexes by: python, javascript, typescript, vue, php, go, java, csharp, cpp, c, ruby, swift, kotlin, rust, scala, sql, html, css, scss, markdown. Anything cix doesn't recognise stays enabled rather than being silently suppressed.

This setting is local and is never uploaded — cix's servers can't see it, and so never infer an opt-out from an empty rulebook.

When a rule doesn't fire

Work down this list; it's ordered by how often each one is the answer.

  1. The kind isn't declared. Rules only exist for kinds in your folders or naming maps. No scripts rule means scripts are unconstrained.
  2. It's a placement question at write time. Placement is checked on demand, not before a write — see above.
  3. The naming value isn't one cix evaluates. Only PascalCase, camelCase, and snake_case produce verdicts; everything else is reported as not assessed.
  4. The document declares nothing. {"folders": {}, "naming": {}} is an empty rulebook — valid, and unable to refuse anything.
  5. The stored copy is out of date. The on-demand check reads cix's mirrored copy, refreshed on startup and by cix init. Re-run cix init after editing the document if you want it live immediately.
  6. Conventions are off for this project or this language. Check .cix/config.json.
  7. A nested document is governing the file. The nearest conventions.json above the file wins, and the answer says which one it used.

Next: Everyday use.