|
| 1 | +# Conditional Rules Schema |
| 2 | + |
| 3 | +Epic 9 Task 9.1 defines the schema and precedence contract for conditional rule injection. |
| 4 | + |
| 5 | +## Rule sources and discovery |
| 6 | + |
| 7 | +Rules are discovered from layered scopes in deterministic order: |
| 8 | + |
| 9 | +1. user scope: `~/.config/opencode/rules/**/*.md` |
| 10 | +2. project scope: `.opencode/rules/**/*.md` |
| 11 | + |
| 12 | +Project scope has higher precedence when two rules have equivalent priority and target overlap. |
| 13 | + |
| 14 | +## Rule file format |
| 15 | + |
| 16 | +Each rule file is markdown with YAML frontmatter. |
| 17 | + |
| 18 | +Required frontmatter fields: |
| 19 | + |
| 20 | +- `description`: short purpose summary |
| 21 | +- `priority`: integer from `0` to `100` (higher applies first) |
| 22 | + |
| 23 | +Optional frontmatter fields: |
| 24 | + |
| 25 | +- `globs`: list of file globs where rule applies |
| 26 | +- `alwaysApply`: boolean forcing rule application regardless of file path |
| 27 | +- `id`: stable rule identifier (fallback: normalized file stem) |
| 28 | +- `tags`: list of category tags for diagnostics/reporting |
| 29 | + |
| 30 | +Rule body (markdown after frontmatter) is the instruction payload injected at runtime. |
| 31 | + |
| 32 | +## Matching semantics |
| 33 | + |
| 34 | +- If `alwaysApply` is `true`, the rule always applies. |
| 35 | +- Else if `globs` is present, any glob match applies the rule. |
| 36 | +- Else the rule is considered inactive by default. |
| 37 | + |
| 38 | +Glob matching uses workspace-relative POSIX-style paths. |
| 39 | + |
| 40 | +## Conflict resolution |
| 41 | + |
| 42 | +Sort and merge rules by deterministic key: |
| 43 | + |
| 44 | +1. descending `priority` |
| 45 | +2. scope precedence (`project` before `user`) |
| 46 | +3. lexical `id` |
| 47 | + |
| 48 | +Conflicts are resolved by first-writer-wins over normalized rule ids after sorting. |
| 49 | + |
| 50 | +Diagnostics must surface: |
| 51 | + |
| 52 | +- winning rule id and source |
| 53 | +- overridden/conflicting rule ids |
| 54 | +- effective ordered rule stack for any target path |
| 55 | + |
| 56 | +## Config controls (for Task 9.3) |
| 57 | + |
| 58 | +Planned config controls: |
| 59 | + |
| 60 | +- `rules.enabled` (default `true`) |
| 61 | +- `rules.disabled_ids` (list) |
| 62 | +- `rules.extra_paths` (additional discovery roots) |
| 63 | + |
| 64 | +## Validation requirements |
| 65 | + |
| 66 | +Reject and report rules when: |
| 67 | + |
| 68 | +- required frontmatter keys are missing |
| 69 | +- `priority` is out of range or non-numeric |
| 70 | +- `globs` is not a list of strings |
| 71 | +- `alwaysApply` is non-boolean |
| 72 | + |
| 73 | +Validation errors should include rule path and actionable remediation. |
0 commit comments