@contentrain/rules 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,15 +10,16 @@ Shared AI-agent rules for Contentrain.
10
10
  Start here:
11
11
 
12
12
  - [2-minute product demo](https://ai.contentrain.io/demo)
13
- - [Rules & skills docs](https://ai.contentrain.io/packages/rules)
13
+ - [Rules & skills docs](https://ai.contentrain.io/packages/rules)
14
14
 
15
- This package is the policy layer of the Contentrain ecosystem. It defines how agents should behave when they work with:
15
+ This package is the **policy layer** of the Contentrain ecosystem. It defines how agents should behave when they work with:
16
16
 
17
- - Contentrain MCP tools
17
+ - Contentrain MCP tools (17 operations)
18
18
  - schema and model design
19
- - content quality
20
- - normalize workflows
19
+ - content quality (SEO, accessibility, media, i18n)
20
+ - normalize workflows (extraction + reuse)
21
21
  - git-backed review flows
22
+ - security guardrails
22
23
 
23
24
  If `@contentrain/mcp` is the deterministic execution layer, `@contentrain/rules` is the behavioral contract.
24
25
 
@@ -32,71 +33,100 @@ pnpm add @contentrain/rules
32
33
 
33
34
  ### Essential guardrails
34
35
 
35
- Published under `essential/*`:
36
+ Published under `essential/`:
36
37
 
37
- - `contentrain-essentials.md` — compact, always-loaded rules (~86 lines) covering architecture, model kinds, MCP tools, mandatory protocols, and security basics
38
+ - `contentrain-essentials.md` — compact, always-loaded rules covering architecture, model kinds, MCP tools, mandatory protocols, git workflow, and security basics.
39
+
40
+ ### Shared quality rules
41
+
42
+ Published under `shared/` — detailed standards per domain:
43
+
44
+ - `content-quality.md` — structure, required fields, content completeness
45
+ - `seo-rules.md` — meta optimization, keywords, canonical URLs
46
+ - `accessibility-rules.md` — alt text, ARIA labels, color contrast
47
+ - `media-rules.md` — image optimization, responsive sizing, asset naming
48
+ - `schema-rules.md` — model design, field types, relations, inheritance
49
+ - `i18n-quality.md` — translation completeness, locale parity
50
+ - `security-rules.md` — sensitive data patterns, secret detection, XSS prevention
51
+ - `mcp-usage.md` — tool invocation patterns, git workflows, trust levels
52
+ - `normalize-rules.md` — extraction and reuse constraints, scope safety
53
+ - `workflow-rules.md` — review mode, approval flows, branch lifecycle
54
+ - `content-conventions.md` — naming, slug generation, status conventions
38
55
 
39
56
  ### Prompt layers
40
57
 
41
- Published under `prompts/*`:
58
+ Published under `prompts/` — mode-specific context the agent loads per task:
42
59
 
43
- - `common.md`
44
- - `generate-mode.md`
45
- - `normalize-mode.md`
46
- - `review-mode.md`
60
+ - `common.md` — shared preamble for all agent modes
61
+ - `generate-mode.md` — content creation constraints
62
+ - `normalize-mode.md` — string extraction and patching workflows
63
+ - `review-mode.md` — content validation and change review
47
64
 
48
65
  ### Context bridge
49
66
 
50
- Published under `context/*`:
67
+ Published under `context/`:
51
68
 
52
- - `context-bridge.md`
69
+ - `context-bridge.md` — how to integrate rules into agent context systems
70
+ - `templates/` — framework-specific context JSON for `nuxt`, `next`, `astro`, `sveltekit`
53
71
 
54
72
  ## Public Exports
55
73
 
56
- The package root exports constants that can be used by tooling:
74
+ The package root exports constants for tooling:
57
75
 
58
76
  - `FIELD_TYPES` — 27 flat field types
59
- - `MODEL_KINDS` — singleton, collection, document, dictionary
60
- - `MCP_TOOLS` — 15 MCP tool names
77
+ - `MODEL_KINDS` — `singleton`, `collection`, `document`, `dictionary`
78
+ - `MCP_TOOLS` — 17 MCP tool names (includes `contentrain_merge` and `contentrain_doctor`)
61
79
  - `ESSENTIAL_RULES_FILE` — path to essential guardrails markdown
62
80
  - `STACKS` — supported framework stacks
63
81
 
64
- ## Example
82
+ ## Quick Example
65
83
 
66
84
  ```ts
67
85
  import { MCP_TOOLS, ESSENTIAL_RULES_FILE, FIELD_TYPES } from '@contentrain/rules'
68
86
 
69
- console.log(MCP_TOOLS.includes('contentrain_validate'))
70
- console.log(ESSENTIAL_RULES_FILE) // 'essential/contentrain-essentials.md'
71
- console.log(FIELD_TYPES.length) // 27
87
+ console.log(MCP_TOOLS.length) // 17
88
+ console.log(MCP_TOOLS.includes('contentrain_merge')) // true
89
+ console.log(MCP_TOOLS.includes('contentrain_doctor')) // true
90
+ console.log(ESSENTIAL_RULES_FILE) // 'essential/contentrain-essentials.md'
91
+ console.log(FIELD_TYPES.length) // 27
72
92
  ```
73
93
 
74
94
  ## Design Role
75
95
 
76
96
  `@contentrain/rules` exists to keep agent behavior aligned across tools and environments.
77
97
 
78
- It should answer questions like:
98
+ Typical questions it answers:
99
+
100
+ - What is acceptable content quality? (shared quality rules)
101
+ - How should an agent use MCP tools safely? (mcp-usage + tool reference)
102
+ - What is the normalize contract? (normalize-rules)
103
+ - What workflow and review constraints exist? (workflow-rules)
104
+
105
+ Detailed procedures and step-by-step guides live in `@contentrain/skills` (Agent Skills standard format).
106
+
107
+ ## Parity with `@contentrain/mcp`
108
+
109
+ `@contentrain/rules` is kept in lockstep with the MCP tool registry via cross-package parity tests. When a new MCP tool is registered in `@contentrain/mcp`:
79
110
 
80
- - What is acceptable content quality?
81
- - How should an agent use MCP tools?
82
- - What is the normalize contract?
83
- - What workflow and review constraints exist?
111
+ - `MCP_TOOLS` must include it (otherwise `tests/mcp-parity.test.ts` fails)
112
+ - the essentials document must mention it
113
+ - the skills reference must have a `### <tool>` section
84
114
 
85
- Detailed reference material and step-by-step procedures live in `@contentrain/skills` (Agent Skills standard format).
115
+ When MCP's branch-naming convention changes (e.g. `contentrain/*` → `cr/*`), the rules prose must follow — the parity test scans the rules for the legacy prefix and fails if it reappears.
86
116
 
87
117
  ## Relationship To Other Packages
88
118
 
89
119
  - `@contentrain/mcp` enforces file, validation, and git behavior
90
120
  - `@contentrain/skills` provides Agent Skills with progressive disclosure (SKILL.md + references/)
91
- - `contentrain` exposes CLI and serve UX
121
+ - `contentrain` (CLI) installs rules + skills into the IDE during `contentrain init`
92
122
  - `@contentrain/query` is the generated runtime consumption layer
93
123
 
94
124
  Rule of thumb:
95
125
 
96
- - `rules` = essential guardrails (always loaded, ~86 lines)
97
- - `skills` = detailed procedures and reference docs (on-demand)
126
+ - `rules` = policy layer (quality standards, constraints, essentials)
127
+ - `skills` = procedural layer (workflows, detailed reference docs)
98
128
 
99
- See [`AGENTS.md`](../../AGENTS.md) at the repo root for agent-level project guidance.
129
+ See [`AGENTS.md`](../../AGENTS.md) at the repo root for project-level agent guidance.
100
130
 
101
131
  ## Build
102
132
 
package/dist/index.cjs CHANGED
@@ -55,7 +55,9 @@ const MCP_TOOLS = [
55
55
  "contentrain_apply",
56
56
  "contentrain_validate",
57
57
  "contentrain_submit",
58
- "contentrain_bulk"
58
+ "contentrain_merge",
59
+ "contentrain_bulk",
60
+ "contentrain_doctor"
59
61
  ];
60
62
  const ESSENTIAL_RULES_FILE = "essential/contentrain-essentials.md";
61
63
  const STACKS = [
package/dist/index.d.cts CHANGED
@@ -8,7 +8,7 @@ declare const FIELD_TYPES: readonly ["string", "text", "email", "url", "slug", "
8
8
  type FieldType = (typeof FIELD_TYPES)[number];
9
9
  declare const MODEL_KINDS: readonly ["singleton", "collection", "document", "dictionary"];
10
10
  type ModelKind = (typeof MODEL_KINDS)[number];
11
- declare const MCP_TOOLS: readonly ["contentrain_status", "contentrain_describe", "contentrain_describe_format", "contentrain_init", "contentrain_scaffold", "contentrain_model_save", "contentrain_model_delete", "contentrain_content_save", "contentrain_content_delete", "contentrain_content_list", "contentrain_scan", "contentrain_apply", "contentrain_validate", "contentrain_submit", "contentrain_bulk"];
11
+ declare const MCP_TOOLS: readonly ["contentrain_status", "contentrain_describe", "contentrain_describe_format", "contentrain_init", "contentrain_scaffold", "contentrain_model_save", "contentrain_model_delete", "contentrain_content_save", "contentrain_content_delete", "contentrain_content_list", "contentrain_scan", "contentrain_apply", "contentrain_validate", "contentrain_submit", "contentrain_merge", "contentrain_bulk", "contentrain_doctor"];
12
12
  type McpTool = (typeof MCP_TOOLS)[number];
13
13
  declare const ESSENTIAL_RULES_FILE: "essential/contentrain-essentials.md";
14
14
  declare const STACKS: readonly ["nuxt", "next", "astro", "sveltekit", "react", "node"];
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":";;AAQA;;;;cAAa,WAAA;AAAA,KAUD,SAAA,WAAoB,WAAA;AAAA,cAInB,WAAA;AAAA,KACD,SAAA,WAAoB,WAAA;AAAA,cAInB,SAAA;AAAA,KAUD,OAAA,WAAkB,SAAA;AAAA,cAIjB,oBAAA;AAAA,cAIA,MAAA;AAAA,KACD,KAAA,WAAgB,MAAA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":";;AAQA;;;;cAAa,WAAA;AAAA,KAUD,SAAA,WAAoB,WAAA;AAAA,cAInB,WAAA;AAAA,KACD,SAAA,WAAoB,WAAA;AAAA,cAInB,SAAA;AAAA,KAYD,OAAA,WAAkB,SAAA;AAAA,cAIjB,oBAAA;AAAA,cAIA,MAAA;AAAA,KACD,KAAA,WAAgB,MAAA"}
package/dist/index.d.mts CHANGED
@@ -8,7 +8,7 @@ declare const FIELD_TYPES: readonly ["string", "text", "email", "url", "slug", "
8
8
  type FieldType = (typeof FIELD_TYPES)[number];
9
9
  declare const MODEL_KINDS: readonly ["singleton", "collection", "document", "dictionary"];
10
10
  type ModelKind = (typeof MODEL_KINDS)[number];
11
- declare const MCP_TOOLS: readonly ["contentrain_status", "contentrain_describe", "contentrain_describe_format", "contentrain_init", "contentrain_scaffold", "contentrain_model_save", "contentrain_model_delete", "contentrain_content_save", "contentrain_content_delete", "contentrain_content_list", "contentrain_scan", "contentrain_apply", "contentrain_validate", "contentrain_submit", "contentrain_bulk"];
11
+ declare const MCP_TOOLS: readonly ["contentrain_status", "contentrain_describe", "contentrain_describe_format", "contentrain_init", "contentrain_scaffold", "contentrain_model_save", "contentrain_model_delete", "contentrain_content_save", "contentrain_content_delete", "contentrain_content_list", "contentrain_scan", "contentrain_apply", "contentrain_validate", "contentrain_submit", "contentrain_merge", "contentrain_bulk", "contentrain_doctor"];
12
12
  type McpTool = (typeof MCP_TOOLS)[number];
13
13
  declare const ESSENTIAL_RULES_FILE: "essential/contentrain-essentials.md";
14
14
  declare const STACKS: readonly ["nuxt", "next", "astro", "sveltekit", "react", "node"];
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;AAQA;;;;cAAa,WAAA;AAAA,KAUD,SAAA,WAAoB,WAAA;AAAA,cAInB,WAAA;AAAA,KACD,SAAA,WAAoB,WAAA;AAAA,cAInB,SAAA;AAAA,KAUD,OAAA,WAAkB,SAAA;AAAA,cAIjB,oBAAA;AAAA,cAIA,MAAA;AAAA,KACD,KAAA,WAAgB,MAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;AAQA;;;;cAAa,WAAA;AAAA,KAUD,SAAA,WAAoB,WAAA;AAAA,cAInB,WAAA;AAAA,KACD,SAAA,WAAoB,WAAA;AAAA,cAInB,SAAA;AAAA,KAYD,OAAA,WAAkB,SAAA;AAAA,cAIjB,oBAAA;AAAA,cAIA,MAAA;AAAA,KACD,KAAA,WAAgB,MAAA"}
package/dist/index.mjs CHANGED
@@ -54,7 +54,9 @@ const MCP_TOOLS = [
54
54
  "contentrain_apply",
55
55
  "contentrain_validate",
56
56
  "contentrain_submit",
57
- "contentrain_bulk"
57
+ "contentrain_merge",
58
+ "contentrain_bulk",
59
+ "contentrain_doctor"
58
60
  ];
59
61
  const ESSENTIAL_RULES_FILE = "essential/contentrain-essentials.md";
60
62
  const STACKS = [
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @contentrain/rules — AI agent rules for Contentrain\n *\n * Quality standards, architecture conventions, and IDE integration.\n */\n\n// ─── Field Types (27 flat types) ───\n\nexport const FIELD_TYPES = [\n 'string', 'text', 'email', 'url', 'slug', 'color', 'phone', 'code', 'icon',\n 'markdown', 'richtext',\n 'number', 'integer', 'decimal', 'percent', 'rating',\n 'boolean', 'date', 'datetime',\n 'image', 'video', 'file',\n 'relation', 'relations',\n 'select', 'array', 'object',\n] as const\n\nexport type FieldType = (typeof FIELD_TYPES)[number]\n\n// ─── Model Kinds ───\n\nexport const MODEL_KINDS = ['singleton', 'collection', 'document', 'dictionary'] as const\nexport type ModelKind = (typeof MODEL_KINDS)[number]\n\n// ─── MCP Tools (15 tools) ───\n\nexport const MCP_TOOLS = [\n 'contentrain_status', 'contentrain_describe', 'contentrain_describe_format',\n 'contentrain_init', 'contentrain_scaffold',\n 'contentrain_model_save', 'contentrain_model_delete',\n 'contentrain_content_save', 'contentrain_content_delete', 'contentrain_content_list',\n 'contentrain_scan', 'contentrain_apply',\n 'contentrain_validate', 'contentrain_submit',\n 'contentrain_bulk',\n] as const\n\nexport type McpTool = (typeof MCP_TOOLS)[number]\n\n// ─── Essential Rules ───\n\nexport const ESSENTIAL_RULES_FILE = 'essential/contentrain-essentials.md' as const\n\n// ─── Stacks ───\n\nexport const STACKS = ['nuxt', 'next', 'astro', 'sveltekit', 'react', 'node'] as const\nexport type Stack = (typeof STACKS)[number]\n"],"mappings":";;;;;;AAQA,MAAa,cAAc;CACzB;CAAU;CAAQ;CAAS;CAAO;CAAQ;CAAS;CAAS;CAAQ;CACpE;CAAY;CACZ;CAAU;CAAW;CAAW;CAAW;CAC3C;CAAW;CAAQ;CACnB;CAAS;CAAS;CAClB;CAAY;CACZ;CAAU;CAAS;CACpB;AAMD,MAAa,cAAc;CAAC;CAAa;CAAc;CAAY;CAAa;AAKhF,MAAa,YAAY;CACvB;CAAsB;CAAwB;CAC9C;CAAoB;CACpB;CAA0B;CAC1B;CAA4B;CAA8B;CAC1D;CAAoB;CACpB;CAAwB;CACxB;CACD;AAMD,MAAa,uBAAuB;AAIpC,MAAa,SAAS;CAAC;CAAQ;CAAQ;CAAS;CAAa;CAAS;CAAO"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @contentrain/rules — AI agent rules for Contentrain\n *\n * Quality standards, architecture conventions, and IDE integration.\n */\n\n// ─── Field Types (27 flat types) ───\n\nexport const FIELD_TYPES = [\n 'string', 'text', 'email', 'url', 'slug', 'color', 'phone', 'code', 'icon',\n 'markdown', 'richtext',\n 'number', 'integer', 'decimal', 'percent', 'rating',\n 'boolean', 'date', 'datetime',\n 'image', 'video', 'file',\n 'relation', 'relations',\n 'select', 'array', 'object',\n] as const\n\nexport type FieldType = (typeof FIELD_TYPES)[number]\n\n// ─── Model Kinds ───\n\nexport const MODEL_KINDS = ['singleton', 'collection', 'document', 'dictionary'] as const\nexport type ModelKind = (typeof MODEL_KINDS)[number]\n\n// ─── MCP Tools (17 tools) ───\n\nexport const MCP_TOOLS = [\n 'contentrain_status', 'contentrain_describe', 'contentrain_describe_format',\n 'contentrain_init', 'contentrain_scaffold',\n 'contentrain_model_save', 'contentrain_model_delete',\n 'contentrain_content_save', 'contentrain_content_delete', 'contentrain_content_list',\n 'contentrain_scan', 'contentrain_apply',\n 'contentrain_validate', 'contentrain_submit',\n 'contentrain_merge',\n 'contentrain_bulk',\n 'contentrain_doctor',\n] as const\n\nexport type McpTool = (typeof MCP_TOOLS)[number]\n\n// ─── Essential Rules ───\n\nexport const ESSENTIAL_RULES_FILE = 'essential/contentrain-essentials.md' as const\n\n// ─── Stacks ───\n\nexport const STACKS = ['nuxt', 'next', 'astro', 'sveltekit', 'react', 'node'] as const\nexport type Stack = (typeof STACKS)[number]\n"],"mappings":";;;;;;AAQA,MAAa,cAAc;CACzB;CAAU;CAAQ;CAAS;CAAO;CAAQ;CAAS;CAAS;CAAQ;CACpE;CAAY;CACZ;CAAU;CAAW;CAAW;CAAW;CAC3C;CAAW;CAAQ;CACnB;CAAS;CAAS;CAClB;CAAY;CACZ;CAAU;CAAS;CACpB;AAMD,MAAa,cAAc;CAAC;CAAa;CAAc;CAAY;CAAa;AAKhF,MAAa,YAAY;CACvB;CAAsB;CAAwB;CAC9C;CAAoB;CACpB;CAA0B;CAC1B;CAA4B;CAA8B;CAC1D;CAAoB;CACpB;CAAwB;CACxB;CACA;CACA;CACD;AAMD,MAAa,uBAAuB;AAIpC,MAAa,SAAS;CAAC;CAAQ;CAAQ;CAAS;CAAa;CAAS;CAAO"}
@@ -54,6 +54,7 @@ MCP is **deterministic infrastructure**. The agent (you) is the **intelligence l
54
54
  | `contentrain_submit` | Push branches to remote |
55
55
  | `contentrain_merge` | Merge a review-mode branch into contentrain locally |
56
56
  | `contentrain_bulk` | Batch operations (copy_locale/update_status/delete_entries) |
57
+ | `contentrain_doctor` | Project health report (env + structure + orphan content + branch pressure + SDK freshness) |
57
58
 
58
59
  ## Mandatory Protocols
59
60
 
@@ -68,7 +69,7 @@ MCP is **deterministic infrastructure**. The agent (you) is the **intelligence l
68
69
 
69
70
  - A dedicated `contentrain` branch is the single source of truth for content state, created at init
70
71
  - Every write operation creates a temporary worktree on the `contentrain` branch automatically
71
- - Feature branches (`contentrain/{operation}/{model}/{locale}/{timestamp}`) are created from `contentrain` for each operation
72
+ - Feature branches (`cr/{operation}/{model}/{locale}/{timestamp}`) are created from `contentrain` for each operation
72
73
  - **auto-merge** mode: feature branch merges into `contentrain`, then `contentrain` advances baseBranch via update-ref (fast-forward), then `.contentrain/` files are selectively synced to the developer's working tree
73
74
  - **review** mode: feature branch pushed to remote for team review
74
75
  - Developer's working tree is never mutated during MCP git operations (no stash, no checkout, no merge on the developer's tree)
@@ -76,7 +77,7 @@ MCP is **deterministic infrastructure**. The agent (you) is the **intelligence l
76
77
  - The `contentrain` branch is protected from deletion
77
78
  - context.json is committed together with content changes, not as a separate commit
78
79
  - Never create branches manually, never commit directly to main or the `contentrain` branch
79
- - 50+ active branches = warning, 80+ = blocked
80
+ - 50+ active `cr/*` branches = warning, 80+ = blocked
80
81
 
81
82
  ## CLI Serve — Review & Approval
82
83
 
@@ -111,6 +112,13 @@ This regenerates `.contentrain/client/` — required for `#contentrain` imports
111
112
  - Collection entry IDs and dictionary keys must match across all locales
112
113
  - IDs and slugs are locale-agnostic — same reference works everywhere
113
114
 
115
+ ## Content Governance
116
+
117
+ - **No duplicate values** — before creating a dictionary key, check if the value already exists under another key (MCP warns automatically via advisories)
118
+ - **Vocabulary first** — check `.contentrain/vocabulary.json` for canonical terms before creating content. Use approved terms exactly, do not invent synonyms
119
+ - **Run validation** — after bulk content operations, call `contentrain_validate` to catch duplicate values, missing translations, and schema issues
120
+ - **Periodic health check** — run `contentrain doctor --usage` to detect unused keys, duplicate values, and locale coverage gaps
121
+
114
122
  ## Security
115
123
 
116
124
  - No `<script>`, `javascript:`, or event handlers in richtext/markdown
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentrain/rules",
3
- "version": "0.3.2",
3
+ "version": "0.4.0",
4
4
  "license": "MIT",
5
5
  "description": "AI agent rules for Contentrain — quality standards, architecture conventions, IDE integration",
6
6
  "type": "module",
@@ -39,12 +39,14 @@
39
39
  "default": "./dist/index.mjs"
40
40
  },
41
41
  "./essential/*": "./essential/*",
42
+ "./shared/*": "./shared/*",
42
43
  "./prompts/*": "./prompts/*",
43
44
  "./context/*": "./context/*"
44
45
  },
45
46
  "files": [
46
47
  "dist",
47
48
  "essential",
49
+ "shared",
48
50
  "prompts",
49
51
  "context"
50
52
  ],
@@ -52,7 +54,8 @@
52
54
  "@types/node": "^22.0.0",
53
55
  "tsdown": "^0.21.0",
54
56
  "typescript": "^5.7.0",
55
- "vitest": "^3.0.0"
57
+ "vitest": "^3.0.0",
58
+ "@contentrain/mcp": "1.3.0"
56
59
  },
57
60
  "scripts": {
58
61
  "build": "tsdown src/index.ts --format esm,cjs --dts",
@@ -12,7 +12,7 @@ This mode converts a codebase with hardcoded strings into a Contentrain-managed
12
12
  |--------|---------------------|----------------|
13
13
  | Purpose | Pull content from source code into `.contentrain/` | Patch source files to reference extracted content |
14
14
  | Source files modified | No | Yes |
15
- | Branch pattern | `contentrain/normalize/extract/{domain}/{timestamp}` | `contentrain/normalize/reuse/{model}/{locale}/{timestamp}` |
15
+ | Branch pattern | `cr/normalize/extract/{domain}/{timestamp}` | `cr/normalize/reuse/{model}/{locale}/{timestamp}` |
16
16
  | Prerequisite | Initialized `.contentrain/` | Completed extraction (content exists) |
17
17
  | Workflow mode | Always `review` | Always `review` |
18
18
  | Standalone value | Yes — content is manageable in Studio immediately | Depends on Phase 1 |
@@ -2,14 +2,14 @@
2
2
 
3
3
  > **Prerequisites:** Read `prompts/common.md` first. All shared rules apply.
4
4
 
5
- This mode is for reviewing content changes on pending `contentrain/*` branches before they are merged. You act as a content quality reviewer, applying all Contentrain rules systematically.
5
+ This mode is for reviewing content changes on pending `cr/*` branches before they are merged. You act as a content quality reviewer, applying all Contentrain rules systematically.
6
6
 
7
7
  ---
8
8
 
9
9
  ## Pipeline
10
10
 
11
11
  ```
12
- Step 1: List open contentrain/* branches
12
+ Step 1: List open cr/* branches
13
13
  Step 2: Show diffs for selected branch
14
14
  Step 3: Apply review checklist
15
15
  Step 4: Recommend action
@@ -19,19 +19,19 @@ Step 4: Recommend action
19
19
 
20
20
  ## Step 1: List Pending Branches
21
21
 
22
- Call `contentrain_status` to see pending changes and open branches. Identify branches with the `contentrain/` prefix that are awaiting review.
22
+ Call `contentrain_status` to see pending changes and open branches. Identify branches with the `cr/` prefix that are awaiting review.
23
23
 
24
24
  Branch naming convention:
25
25
  ```
26
- contentrain/{operation}/{model}/{locale}/{timestamp}
26
+ cr/{operation}/{model}/{locale}/{timestamp}
27
27
  ```
28
28
 
29
29
  Common branch types:
30
- - `contentrain/content/...` — content updates
31
- - `contentrain/model/...` — model changes
32
- - `contentrain/normalize/extract/...` — normalize extraction
33
- - `contentrain/normalize/reuse/...` — normalize reuse (source patching)
34
- - `contentrain/new/scaffold-...` — scaffold operations
30
+ - `cr/content/...` — content updates
31
+ - `cr/model/...` — model changes
32
+ - `cr/normalize/extract/...` — normalize extraction
33
+ - `cr/normalize/reuse/...` — normalize reuse (source patching)
34
+ - `cr/new/scaffold-...` — scaffold operations
35
35
 
36
36
  ---
37
37
 
@@ -0,0 +1,155 @@
1
+ # Accessibility Rules
2
+
3
+ These rules are MANDATORY for all AI agents creating or editing content in Contentrain projects.
4
+ Violations will be flagged during validation. No exceptions unless explicitly overridden by `context.json` configuration.
5
+
6
+ ---
7
+
8
+ ## Image Accessibility
9
+
10
+ 1. Every `image` type field MUST have a corresponding alt text value. If the model defines an `image_alt` field, populate it. If not, include alt text guidance in the image field's `description` metadata.
11
+
12
+ 2. Alt text MUST describe the image's **content and function**, not its appearance.
13
+ - GOOD: `"CEO Jane Doe speaking at the 2024 product launch"`
14
+ - BAD: `"A photo with blue tones and a person on stage"`
15
+
16
+ 3. Decorative images (visual separators, background textures) MUST have alt text set to an empty string `""`. Never leave alt text undefined or null — explicitly set it to `""`.
17
+
18
+ 4. Complex images (charts, infographics, diagrams) MUST have a short alt text summarizing the conclusion, plus a detailed description in an adjacent text field or in the body content.
19
+ - Example alt: `"Bar chart showing Q3 revenue grew 22% year-over-year"`
20
+ - Example adjacent text: full data table or written summary
21
+
22
+ 5. Alt text MUST NOT exceed **125 characters**. Screen readers may truncate longer text.
23
+
24
+ 6. Icon images used as interactive elements MUST have alt text describing the **action**, not the icon.
25
+ - GOOD: `"Search"`, `"Close menu"`, `"Open settings"`
26
+ - BAD: `"Magnifying glass icon"`, `"X icon"`
27
+
28
+ 7. Do not begin alt text with "Image of" or "Photo of" — the screen reader already announces it as an image.
29
+
30
+ ---
31
+
32
+ ## Language & Readability
33
+
34
+ 1. Target a **grade 8-10 reading level** (Flesch-Kincaid) for general content.
35
+
36
+ 2. Target **grade 6-8** for public-facing critical content: legal notices, safety information, error messages, onboarding flows.
37
+
38
+ 3. Use plain language. Prefer common words over formal synonyms:
39
+ - "use" not "utilize"
40
+ - "start" not "commence"
41
+ - "help" not "facilitate"
42
+ - "buy" not "purchase"
43
+ - "end" not "terminate"
44
+
45
+ 4. Define every acronym and abbreviation on first use: `"Content Management System (CMS)"`. After the first definition, use the acronym freely.
46
+
47
+ 5. Do not use jargon unless the content targets a technical audience. Check `context.json > tone` to determine the audience. When `tone` is `"technical"`, domain-specific terms are acceptable without definitions.
48
+
49
+ 6. Keep sentences short: **15-20 words average**. Break long sentences at natural clause boundaries.
50
+
51
+ 7. Keep paragraphs short: **3-5 sentences maximum**. Use line breaks between paragraphs.
52
+
53
+ 8. Use active voice. Passive voice is acceptable only when the actor is unknown or irrelevant.
54
+ - GOOD: `"The system saves your changes automatically."`
55
+ - BAD: `"Your changes are saved automatically by the system."`
56
+
57
+ ---
58
+
59
+ ## Link Text
60
+
61
+ 1. Link text MUST be descriptive and self-explanatory. It must make sense **out of context** because screen readers present links in an isolated list.
62
+ - GOOD: `"Download the 2024 Annual Report"`
63
+ - BAD: `"Click here"`
64
+
65
+ 2. NEVER use these as standalone link text: `"click here"`, `"read more"`, `"learn more"`, `"here"`, `"link"`, `"this"`.
66
+
67
+ 3. For file downloads, include the file type and size in the link text:
68
+ - `"Download the Q3 Budget (PDF, 2.4 MB)"`
69
+
70
+ 4. Do not use the raw URL as link text unless the content is specifically listing URLs.
71
+
72
+ 5. Keep link text concise — describe the destination or action in 2-8 words.
73
+
74
+ ---
75
+
76
+ ## Heading Semantics
77
+
78
+ 1. Headings MUST describe the content of their section. Never use headings purely for visual styling (font size, bold).
79
+
80
+ 2. Heading levels MUST reflect **document hierarchy**:
81
+ - `h2` for top-level sections within the page
82
+ - `h3` for subsections of an `h2`
83
+ - `h4` for subsections of an `h3`
84
+ - Never skip levels (e.g., `h2` directly to `h4`)
85
+
86
+ 3. Every distinct content section SHOULD have a heading.
87
+
88
+ 4. Headings MUST NOT be empty or contain only whitespace.
89
+
90
+ 5. Do not duplicate heading text within the same page unless sections are genuinely distinct (e.g., "Overview" under two different parent headings is acceptable).
91
+
92
+ ---
93
+
94
+ ## Content Structure
95
+
96
+ 1. Use **semantic markup** appropriate to the content type:
97
+ - Unordered lists (`ul`) for items without sequence
98
+ - Ordered lists (`ol`) for steps or ranked items
99
+ - Headings for section titles
100
+ - Paragraphs for body text
101
+ - Blockquotes for quoted material
102
+
103
+ 2. Tables MUST include a header row or header column. Keep table structure simple — avoid merged cells and nested tables.
104
+
105
+ 3. Provide a text alternative for every piece of non-text content (images, charts, embedded media).
106
+
107
+ 4. Sequential content (steps, instructions, timelines) MUST follow logical reading order. Do not rely on CSS or layout to reorder content.
108
+
109
+ 5. Lists MUST have at least two items. A single-item list should be rewritten as a paragraph or inline text.
110
+
111
+ ---
112
+
113
+ ## Color & Visual References
114
+
115
+ 1. NEVER use color alone to convey meaning.
116
+ - BAD: `"Required fields are highlighted in red."`
117
+ - GOOD: `"Required fields are marked with an asterisk (*)."`
118
+
119
+ 2. Do not reference visual position in content text.
120
+ - BAD: `"Click the button on the right."`
121
+ - GOOD: `"Click the Submit button."`
122
+
123
+ 3. Ensure all text content is meaningful without any visual context. Content must be understandable when read aloud or rendered in plain text.
124
+
125
+ ---
126
+
127
+ ## Error Messages & Forms
128
+
129
+ 1. Error messages MUST identify **which field** has the error.
130
+
131
+ 2. Error messages MUST describe **what the error is** and how to fix it.
132
+ - GOOD: `"Enter a valid email address (e.g., name@example.com)."`
133
+ - BAD: `"Invalid input."`
134
+
135
+ 3. Use **positive framing** — tell the user what to do, not what they did wrong.
136
+ - GOOD: `"Enter a date in YYYY-MM-DD format."`
137
+ - BAD: `"Wrong date format."`
138
+
139
+ 4. Group related form fields with descriptive labels. Every input field MUST have a label.
140
+
141
+ 5. Do not use placeholder text as a substitute for labels.
142
+
143
+ ---
144
+
145
+ ## Multimedia
146
+
147
+ 1. Video content MUST reference a transcript — either as inline content, a URL, or a relation to a document entry.
148
+
149
+ 2. Audio content MUST have a text transcript available.
150
+
151
+ 3. If content auto-plays, note this in metadata so the frontend can provide pause/stop controls. Auto-playing media with audio is strongly discouraged.
152
+
153
+ 4. Time-based media (video, audio, animations) MUST include duration information when the model supports it.
154
+
155
+ 5. Animated content (GIFs, auto-playing videos) should be flagged if longer than 5 seconds — provide a mechanism to pause.