---
name: chous-config
source: https://app.decimal.ai/s/chous-config@1/SKILL.md
source_sha256: 5d96435bf691
---

# chous config (.chous DSL)

## Contract

A `.chous` file is written in chous's own keyword DSL, **not** YAML and **not** JSON. Apply this
whenever you author, generate, or edit a `.chous` file (including a `chous init` baseline). Every rule
is a line of DSL keywords; there are no `key: value` maps, no quoted-glob objects, and no braces.

## Rules (the complete DSL)

1. **Comments** start with `#`. Blank lines are ignored.
2. **Existence** — require entries to be present:
   `must have [name1, name2, ...]`
   One `must have` keyword, then a single square-bracketed, comma-separated list. Never `required:`,
   `mustExist:`, `files:`, or a YAML sequence.
3. **Global naming** — enforce a filename case for a glob:
   `use <case> for files <glob>`
   The keyword `use`, then the case, then the literal words `for files`, then the glob. The glob comes
   **after** `for files`. The four case keywords are spelled EXACTLY:
   `kebab-case`  `PascalCase`  `camelCase`  `snake_case`
   Never a mapping like `naming: kebab-case` or `"**/*.ts": kebab-case`.
4. **Directory scope** — group rules that apply only inside a directory:
   `in <dir>:`  then the rules indented beneath it. Blocks nest (`in app:` then, indented, `in components:`).
   Never a JSON/YAML object like `"app": { ... }` or a bare `app:` key.
5. **Whitelist** — the entries permitted inside a block:
   `allow [name1, name2, ...]`  — keyword `allow` then a bracketed list. Never `allowed:`, `whitelist:`,
   `only:`, or `include:`.
6. **Strict** — forbid everything not whitelisted in the block:
   the bare keyword `strict` on its own line. Never `strict: true`, `forbidUnknown: true`, or
   `additionalProperties: false`.
7. **Move** — suggest relocating files:
   `move <glob> to <dest>`  — keyword `move`, the glob, the keyword `to`, the destination. Never a
   `move: { from, to }` object or a `relocate:` key.
8. **Conditional naming** — vary the case by parent directory:
   append `if-parent-matches <case>` to a naming rule, e.g.
   `use kebab-case for files **/*.vue if-parent-matches PascalCase`.
   Never `when`, `if parent`, `parent:`, or a nested condition object.

Globs are standard: `**/*.ts`, `*.{css,scss}`, `utils/**/*.ts`. Indentation (2 spaces) marks block
membership.

## Worked examples (BEFORE = the generic YAML default → AFTER = chous DSL)

**Existence**
```
# BEFORE (wrong — YAML)
required:
  - package.json
  - tsconfig.json
# AFTER (chous)
must have [package.json, tsconfig.json]
```

**Global naming**
```
# BEFORE (wrong — quoted-glob map)
"**/*.ts": kebab-case
# AFTER (chous)
use kebab-case for files **/*.ts
```

**Directory scope + whitelist + strict**
```
# BEFORE (wrong — JSON object)
"app": { "allowed": ["pages","components"], "strict": true }
# AFTER (chous)
in app:
  allow [pages, components]
  strict
```

**Move**
```
# BEFORE (wrong — object)
move: { from: "*.css", to: "styles" }
# AFTER (chous)
move *.css to styles
```

**Conditional naming**
```
# BEFORE (wrong — condition object)
- glob: "**/*.vue"
  case: kebab-case
  when: { parent: PascalCase }
# AFTER (chous)
use kebab-case for files **/*.vue if-parent-matches PascalCase
```

## Edge cases & exceptions

- **Nesting:** an inner `in <dir>:` header is indented under its outer block; its rules indent one level
  further. `strict` applies only to the block it sits in, not to parent or sibling blocks.
- **Multiple naming rules:** write one `use <case> for files <glob>` line per glob; they stack.
- **Presets:** `chous init` seeds a baseline from a preset (`basic`, `js`, `ts`, `nextjs`, `nuxt4`,
  `go`, `python`). Extend it by adding DSL lines — never rewrite it as JSON.
- **Brace globs:** group extensions with `{a,b}`, e.g. `move *.{png,jpg,svg} to images`.
- **`must have` vs `allow`:** `must have` asserts entries EXIST; `allow` + `strict` asserts NOTHING ELSE
  exists. They are different rules; use both when a directory is fixed.

## Do / Don't

- Do `use PascalCase for files **/*.vue`  — Don't `"**/*.vue": PascalCase`
- Do `must have [package.json]`  — Don't `required: [package.json]`
- Do bare `strict`  — Don't `strict: true`
- Do `allow [pages, components]`  — Don't `allowed: [pages, components]`
- Do `move *.css to styles`  — Don't `move: {from: "*.css", to: "styles"}`
- Do `in src:` (with a colon)  — Don't `src: {}` or `"src": {}`
- Do `... if-parent-matches PascalCase`  — Don't `... when parent is PascalCase`

## Common mistakes

- Emitting YAML or JSON because most linters use it — chous does not; it is a keyword DSL.
- Inventing keys (`rules:`, `patterns:`, `conventions:`, `naming:`) — none exist in chous.
- `strict: true` instead of the bare keyword `strict`.
- Putting the glob before the case (`use **/*.ts kebab-case`) — the glob follows `for files`.
- Misspelling case keywords (`kebab`, `Pascal`, `snake-case`) — they are exactly `kebab-case`,
  `PascalCase`, `camelCase`, `snake_case`.
- Using `when`/`if` for the parent condition instead of `if-parent-matches`.

## Quick checklist

- [ ] Existence via `must have [ ... ]`
- [ ] Naming via `use <case> for files <glob>`, glob after `for files`
- [ ] Case keyword is exactly `kebab-case` / `PascalCase` / `camelCase` / `snake_case`
- [ ] Directory scope via `in <dir>:` blocks, rules indented
- [ ] Whitelist via `allow [ ... ]`; forbid-others via bare `strict`
- [ ] Relocation via `move <glob> to <dest>`
- [ ] Parent condition via `if-parent-matches <case>`
- [ ] No YAML/JSON syntax anywhere
