@contentrain/skills 0.1.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.
@@ -0,0 +1,91 @@
1
+ # Skill: Initialize Contentrain in a Project
2
+
3
+ > Set up Contentrain content infrastructure in an existing project.
4
+
5
+ ---
6
+
7
+ ## When to Use
8
+
9
+ The user wants to add Contentrain to their project, or says something like "set up contentrain", "initialize contentrain", "add content management".
10
+
11
+ ---
12
+
13
+ ## Steps
14
+
15
+ ### 1. Detect the Tech Stack
16
+
17
+ Read `package.json` to identify the framework:
18
+
19
+ | Dependency | Stack |
20
+ |---|---|
21
+ | `nuxt` | Nuxt 3 |
22
+ | `next` | Next.js |
23
+ | `@astrojs/astro` or `astro` | Astro |
24
+ | `@sveltejs/kit` | SvelteKit |
25
+
26
+ If none match, treat as a generic Node.js project. Report the detected stack to the user before proceeding.
27
+
28
+ ### 2. Ask for Configuration
29
+
30
+ Ask the user for:
31
+
32
+ - **Supported locales:** Which languages will the project support? Default: `["en"]`. Use ISO 639-1 codes.
33
+ - **Source locale:** Which locale is the primary/source locale? Default: `"en"`.
34
+ - **Domain names:** Suggest domains based on the project structure (e.g., `marketing`, `blog`, `app`, `docs`). Ask the user to confirm or modify.
35
+
36
+ ### 3. Initialize the Project
37
+
38
+ Call the MCP tool:
39
+
40
+ ```
41
+ contentrain_init(stack: "<detected>", locales: ["en", ...], domains: ["marketing", ...])
42
+ ```
43
+
44
+ This creates the `.contentrain/` directory structure, `config.json`, and initial `context.json`.
45
+
46
+ ### 4. Analyze Project Conventions
47
+
48
+ After initialization, review the project for conventions to inform content creation:
49
+
50
+ - **Tone:** Analyze existing copy in the project (README, landing page, UI text) to determine the appropriate tone (e.g., `professional`, `casual`, `technical`).
51
+ - **Naming conventions:** Note any patterns in file naming, component naming, or content structure.
52
+
53
+ > **Note:** Do NOT manually edit `context.json`. It is managed automatically by MCP tools and updated after every write operation.
54
+
55
+ ### 5. Suggest Initial Models
56
+
57
+ Based on the project analysis, suggest models that would be useful:
58
+
59
+ - If the project has a landing page: suggest `hero` (singleton), `features` (singleton or collection).
60
+ - If the project has a blog section: suggest `blog-post` (document), `categories` (collection), `authors` (collection).
61
+ - If the project has UI text: suggest `ui-labels` (dictionary), `error-messages` (dictionary).
62
+
63
+ Present suggestions to the user and ask which to create. For selected models, call `contentrain_model_save` for each.
64
+
65
+ ### 6. Offer Scaffold Templates
66
+
67
+ If the project matches a common pattern, offer to use a scaffold template:
68
+
69
+ ```
70
+ contentrain_scaffold(template: "blog", locales: ["en"], with_sample_content: true)
71
+ ```
72
+
73
+ Available templates: `blog`, `landing`, `docs`, `ecommerce`, `saas`, `i18n`, `mobile`.
74
+
75
+ ### 7. Set Up Agent Rules
76
+
77
+ Copy the appropriate rules file to the project:
78
+
79
+ - For Claude Code projects: append Contentrain rules to the project's `CLAUDE.md` or create a new section.
80
+ - For Cursor projects: create or update `.cursorrules` with Contentrain conventions.
81
+
82
+ Include a reference to the framework-specific guide (nuxt.md, next.md, astro.md, sveltekit.md).
83
+
84
+ ### 8. Final Summary
85
+
86
+ Report to the user:
87
+
88
+ - What was created in `.contentrain/`.
89
+ - Which models were set up.
90
+ - How to import content in their code (show the `#contentrain` import).
91
+ - Next steps: create content, run `npx contentrain generate`, start the dev server.
@@ -0,0 +1,134 @@
1
+ # Skill: Design and Save Models
2
+
3
+ > Create or evolve Contentrain model definitions safely.
4
+
5
+ ---
6
+
7
+ ## When to Use
8
+
9
+ Use this when the user wants to:
10
+
11
+ - add a new model
12
+ - change fields on an existing model
13
+ - choose between `singleton`, `collection`, `document`, and `dictionary`
14
+ - define relations, locales, or custom content paths
15
+
16
+ ---
17
+
18
+ ## Steps
19
+
20
+ ### 1. Inspect Project State
21
+
22
+ Call `contentrain_status` first:
23
+
24
+ - confirm the project is initialized
25
+ - see existing model IDs and domains
26
+ - avoid creating duplicates
27
+
28
+ If the user is extending an existing model, call `contentrain_describe(model: "<model-id>")`.
29
+
30
+ ### 2. Confirm Storage Contract
31
+
32
+ Call `contentrain_describe_format` before proposing structure changes.
33
+
34
+ Use it to confirm:
35
+
36
+ - model kinds and storage expectations
37
+ - locale behavior
38
+ - document vs JSON model tradeoffs
39
+ - how custom `content_path` and `locale_strategy` affect files
40
+
41
+ ### 3. Choose the Right Kind
42
+
43
+ - `singleton`: one object per locale, e.g. hero, navigation, footer
44
+ - `collection`: repeated entries with IDs, e.g. testimonials, faq items, authors
45
+ - `document`: long-form markdown content with frontmatter, e.g. blog posts, docs pages
46
+ - `dictionary`: flat key-value strings, e.g. UI labels, error messages
47
+
48
+ Default rules:
49
+
50
+ - use `dictionary` for UI/system strings
51
+ - use `document` for markdown-heavy long-form content
52
+ - use `collection` for repeated structured items
53
+ - use `singleton` for one page/section config per locale
54
+
55
+ ### 4. Design Fields
56
+
57
+ Follow these rules:
58
+
59
+ - model IDs must be kebab-case
60
+ - field names must be snake_case
61
+ - relation fields must define a target `model`
62
+ - prefer small, explicit schemas over large generic `object` blobs
63
+ - only mark fields as `required` when the content truly cannot function without them
64
+
65
+ Relation guidance:
66
+
67
+ - `relation`: single reference
68
+ - `relations`: multiple references
69
+ - use `slug`-driven relations for document-like linking
70
+
71
+ ### 5. Decide i18n and Path Strategy
72
+
73
+ Ask or infer:
74
+
75
+ - should this model be localized?
76
+ - should it use the default `.contentrain/content/...` path or a custom `content_path`?
77
+ - if custom path is needed, which `locale_strategy` matches the project layout?
78
+
79
+ Use custom paths only when the framework or repo structure clearly benefits from it.
80
+
81
+ ### 6. Present the Proposed Model
82
+
83
+ Before writing, show:
84
+
85
+ - model ID
86
+ - kind
87
+ - domain
88
+ - `i18n` behavior
89
+ - field list with types
90
+ - relation targets
91
+ - any custom `content_path` / `locale_strategy`
92
+
93
+ Get user confirmation before saving.
94
+
95
+ ### 7. Save the Model
96
+
97
+ Call `contentrain_model_save` with the approved definition.
98
+
99
+ Example:
100
+
101
+ ```json
102
+ {
103
+ "id": "hero",
104
+ "name": "Hero",
105
+ "kind": "singleton",
106
+ "domain": "marketing",
107
+ "i18n": true,
108
+ "fields": {
109
+ "title": { "type": "string", "required": true },
110
+ "subtitle": { "type": "text" },
111
+ "cta_label": { "type": "string" },
112
+ "featured_post": { "type": "relation", "model": "blog-post" }
113
+ }
114
+ }
115
+ ```
116
+
117
+ ### 8. Validate Downstream Impact
118
+
119
+ After changing a model:
120
+
121
+ - review whether existing content now needs updates
122
+ - call `contentrain_validate`
123
+ - if the model is consumed by the SDK, recommend `contentrain generate`
124
+
125
+ ### 9. Final Summary
126
+
127
+ Report:
128
+
129
+ - model created or updated
130
+ - kind and domain
131
+ - field count
132
+ - any relation targets
133
+ - whether content migration is needed next
134
+
@@ -0,0 +1,294 @@
1
+ # Skill: Extract Hardcoded Content Strings (Two-Phase Normalize)
2
+
3
+ > Scan the project for hardcoded user-visible strings, extract them into Contentrain models, and then patch source files to reference the extracted content.
4
+
5
+ ---
6
+
7
+ ## When to Use
8
+
9
+ The user wants to extract hardcoded strings from their codebase, or says something like "normalize my project", "extract content", "move strings to contentrain", "find hardcoded text", "internationalize", "add i18n".
10
+
11
+ This is a two-phase process:
12
+ - **Phase 1 (Extraction):** Pull hardcoded strings into `.contentrain/content/` — source files are NOT modified.
13
+ - **Phase 2 (Reuse):** Replace hardcoded strings in source files with i18n/content references.
14
+
15
+ Phase 1 is valuable on its own — extracted content can be managed in Studio, translated, and published without touching source code.
16
+
17
+ ---
18
+
19
+ ## Phase 1: Extraction
20
+
21
+ Extract content from source code into `.contentrain/` without modifying source files.
22
+
23
+ ### Step 1. Check Project State
24
+
25
+ Call `contentrain_status` to confirm:
26
+
27
+ - The project is initialized (if not, run the `contentrain-init` skill first).
28
+ - Note supported locales and configured domains.
29
+ - Check for pending changes — resolve them before starting.
30
+
31
+ ### Step 1.5. Understand Content Formats
32
+
33
+ Call `contentrain_describe_format` to review the storage format for each model kind before deciding how to structure extracted content.
34
+
35
+ Know the four formats:
36
+
37
+ - **Dictionary:** Flat key-value JSON. All values are strings. Keys are semantic dot-separated addresses (e.g., `auth.login.button`). No field schema. Path: `{model-id}/{locale}.json`
38
+ - **Collection:** Object-map JSON keyed by auto-generated 12-char hex IDs. Each entry has typed fields. Path: `{model-id}/{locale}.json`
39
+ - **Singleton:** Single JSON object per locale. One instance of typed fields. Path: `{model-id}/{locale}.json`
40
+ - **Document:** Markdown file with frontmatter per slug per locale. Path: `{model-id}/{slug}/{locale}.md`
41
+
42
+ Understanding these formats is essential for Step 4, where you choose the right model kind for each group of candidates.
43
+
44
+ ### Step 2. Build the Project Graph
45
+
46
+ Call `contentrain_scan(mode: "graph")` to build the import/component dependency graph.
47
+
48
+ Use this graph to:
49
+
50
+ - Understand which components belong to which pages or features.
51
+ - Identify shared components vs page-specific components.
52
+ - Prioritize files by their role in the project (layout, page, component).
53
+
54
+ ### Step 3. Find Candidates
55
+
56
+ Call `contentrain_scan(mode: "candidates")` iteratively to find hardcoded strings.
57
+
58
+ The scan returns candidates with file paths, line numbers, string values, and surrounding context. Review candidates by file — not all strings should be extracted.
59
+
60
+ ### Step 4. Evaluate Candidates
61
+
62
+ This is the intelligence step — you (the agent) make all the decisions:
63
+
64
+ - **Filter false positives:** Remove CSS values, technical identifiers, import paths, variable names, config values, log messages, and test strings. Refer to `normalize-rules.md` Section 5 for the full heuristics.
65
+ - **Assign domains:** Group candidates by domain (e.g., `marketing`, `blog`, `ui`, `system`).
66
+ - **Determine model types:** Decide the appropriate model kind for each group:
67
+ - **dictionary** — UI strings, button labels, error messages, validation messages. Flat key-value, all strings, no field schema. Choose this when content is short text with no structured fields.
68
+ - **singleton** — Page-specific content with structured fields (hero section, features block, pricing header). One instance per locale with typed fields.
69
+ - **collection** — Repeating items with structured fields (testimonials, FAQs, team members). Multiple entries sharing the same field schema.
70
+ - **document** — Long-form content with markdown body and typed metadata (blog posts, documentation pages, changelogs).
71
+ - **Structure fields:** Define field names and assign candidate strings to fields.
72
+
73
+ ### Step 5. Write Normalize Plan
74
+
75
+ After evaluating candidates, write the plan as `.contentrain/normalize-plan.json`:
76
+
77
+ ```json
78
+ {
79
+ "version": 1,
80
+ "status": "pending",
81
+ "created_at": "2026-03-16T12:00:00.000Z",
82
+ "agent": "claude",
83
+ "scan_stats": {
84
+ "files_scanned": 42,
85
+ "raw_strings": 320,
86
+ "candidates_sent": 85,
87
+ "extracted": 28,
88
+ "skipped": 57
89
+ },
90
+ "models": [
91
+ {
92
+ "id": "hero-section",
93
+ "kind": "singleton",
94
+ "domain": "marketing",
95
+ "i18n": true,
96
+ "fields": { "title": { "type": "string", "required": true }, "subtitle": { "type": "string" } }
97
+ }
98
+ ],
99
+ "extractions": [
100
+ { "value": "Build faster apps", "file": "src/pages/index.vue", "line": 12, "model": "hero-section", "field": "title" }
101
+ ],
102
+ "patches": [
103
+ { "file": "src/pages/index.vue", "line": 12, "old_value": "Build faster apps", "new_expression": "{{ $t('hero.title') }}" }
104
+ ]
105
+ }
106
+ ```
107
+
108
+ This file is watched by the serve UI — writing it triggers automatic detection.
109
+
110
+ ### Step 6. Open UI for Review
111
+
112
+ Start the review UI and direct the developer to visually inspect the plan:
113
+
114
+ 1. **Start serve** (if not already running):
115
+
116
+ ```bash
117
+ contentrain serve
118
+ ```
119
+
120
+ 2. **Direct the user** to the normalize page:
121
+
122
+ > "I've prepared a normalize plan with **{N} extractions** across **{M} models**.
123
+ > Review it visually at **http://localhost:3333/normalize** — you can inspect each extraction, see source traces, and preview patches.
124
+ > **Approve** or **Reject** directly from the UI."
125
+
126
+ 3. **Wait for user action.** The UI provides:
127
+ - Extraction review panel — grouped by model with field mappings
128
+ - Source trace panel — click any extraction to see its original location
129
+ - Patch preview panel — see exact source file changes
130
+ - **Approve & Apply** button — executes the extraction
131
+ - **Reject** button — deletes the plan
132
+
133
+ Do NOT proceed to apply unless the user approves (either via UI or explicit confirmation in chat).
134
+
135
+ 4. **Detect the user's decision.** After directing the user to the UI, check the plan file to determine the outcome:
136
+ - **Plan file exists** (`status: "pending"`) → user has not decided yet — wait
137
+ - **Plan file deleted + new `contentrain/normalize/extract/*` branch exists** → user approved, extraction applied
138
+ - **Plan file deleted + no new branch** → user rejected the plan
139
+
140
+ If rejected, ask the user what to change and iterate from Step 4 (re-evaluate candidates).
141
+
142
+ If approved, proceed to Step 9 (Validate and Submit).
143
+
144
+ **Alternative (no UI):** If the user prefers terminal-only workflow, present the summary inline and wait for explicit confirmation before proceeding. Skip to Step 7.
145
+
146
+ ### Step 7. Preview Extraction (if not using UI)
147
+
148
+ Call `contentrain_apply(mode: "extract", dry_run: true)` to generate a preview.
149
+
150
+ Review the dry-run output:
151
+
152
+ - Verify model definitions are correct.
153
+ - Verify content assignments are accurate.
154
+ - Check for any missed candidates or misclassifications.
155
+
156
+ Show the preview to the user.
157
+
158
+ ### Step 8. Execute Extraction
159
+
160
+ After user approval (via UI or chat), call `contentrain_apply(mode: "extract", dry_run: false)`.
161
+
162
+ Note: `dry_run` defaults to `true`, so you MUST explicitly set `dry_run: false` to execute.
163
+
164
+ This creates model definitions and content files in `.contentrain/` on a `contentrain/normalize/extract/{timestamp}` branch. Source files are NOT modified.
165
+
166
+ If approved via UI, the UI calls this automatically — no additional agent action needed.
167
+
168
+ ### Step 9. Validate and Submit
169
+
170
+ Call `contentrain_validate` to check the extracted content:
171
+
172
+ - Schema compliance for all new models and entries.
173
+ - i18n completeness — source locale has all keys.
174
+ - No duplicate entries.
175
+ - Vocabulary alignment.
176
+
177
+ Call `contentrain_submit` to push the branch for review.
178
+
179
+ Normalize operations always use `review` workflow mode — changes are never auto-merged.
180
+
181
+ Tell the user: "Phase 1 complete. Content is now in Contentrain and can be managed, translated, and published from Studio. When ready, proceed with Phase 2 to update source files."
182
+
183
+ ---
184
+
185
+ ## Phase 2: Reuse
186
+
187
+ Patch source files to replace hardcoded strings with content references. Only start after Phase 1 is reviewed and merged.
188
+
189
+ ### Step 1. Select Scope
190
+
191
+ List the extracted models and ask the user which model or domain to process first.
192
+
193
+ Process one model or domain at a time to keep diffs small and reviewable.
194
+
195
+ ### Step 2. Determine Replacement Expressions
196
+
197
+ Based on the project's tech stack, determine the correct replacement pattern:
198
+
199
+ | Stack | Pattern | Example |
200
+ |---|---|---|
201
+ | Vue/Nuxt (vue-i18n) | `{{ $t('key') }}` | `{{ $t('hero.title') }}` |
202
+ | React/Next (next-intl) | `{t('key')}` | `{t('hero.title')}` |
203
+ | React/Next (react-intl) | `{intl.formatMessage({id: 'key'})}` | `{intl.formatMessage({id: 'hero.title'})}` |
204
+ | Svelte/SvelteKit | `{$t('key')}` | `{$t('hero.title')}` |
205
+ | Astro | `{t('key')}` | `{t('key')}` |
206
+ | SDK direct import | `query('model').all()` | Direct data access via `#contentrain` |
207
+
208
+ Also determine any necessary import statements that must be added to patched files (e.g., `import { useTranslation } from 'next-intl'`).
209
+
210
+ The agent determines the replacement expression — MCP does exact string replacement only.
211
+
212
+ ### Step 3. Preview Reuse
213
+
214
+ Call `contentrain_apply(mode: "reuse", scope: { model: "<model-id>" }, patches: [...], dry_run: true)`.
215
+
216
+ The `scope` requires at least one of `model` or `domain`. The `patches` array contains the replacement instructions:
217
+
218
+ Review the dry-run output:
219
+
220
+ - Verify each string replacement is correct.
221
+ - Verify import statements will be added where needed.
222
+ - Confirm no non-content strings are being replaced.
223
+ - Check that component structure and behavior are preserved.
224
+
225
+ Show the preview to the user.
226
+
227
+ ### Step 4. Execute Reuse
228
+
229
+ After user confirmation, call `contentrain_apply(mode: "reuse", scope: { model: "<model-id>" }, patches: [...], dry_run: false)`.
230
+
231
+ Note: `dry_run` defaults to `true`, so you MUST explicitly set `dry_run: false` to execute.
232
+
233
+ This patches source files and creates a `contentrain/normalize/reuse/{model}/{timestamp}` branch.
234
+
235
+ ### Step 5. Validate and Submit
236
+
237
+ Call `contentrain_validate` to verify:
238
+
239
+ - Source files parse correctly after patching.
240
+ - Content references resolve to existing entries.
241
+ - No strings were missed or double-replaced.
242
+
243
+ Call `contentrain_submit` to push the branch for review.
244
+
245
+ ### Step 6. Repeat
246
+
247
+ Ask the user which model or domain to process next. Repeat steps 1-5 for each remaining model until all extracted content is referenced in source code.
248
+
249
+ ---
250
+
251
+ ## Phase 3: Translation (Optional)
252
+
253
+ After Phase 1 (extract) and Phase 2 (reuse) are complete:
254
+
255
+ 1. Copy source locale to target locales:
256
+ ```
257
+ contentrain_bulk({ operation: "copy_locale", model: "ui-texts", source_locale: "en", target_locale: "tr" })
258
+ ```
259
+
260
+ 2. Translate each key's value while keeping the key names identical across locales.
261
+
262
+ 3. Re-generate the SDK client:
263
+ ```bash
264
+ npx contentrain generate
265
+ ```
266
+
267
+ 4. The application now serves localized content from the dictionary.
268
+
269
+ ---
270
+
271
+ ## Content Update Workflow
272
+
273
+ When dictionary content is added or updated:
274
+
275
+ 1. Edit content via MCP (`contentrain_content_save`).
276
+ 2. Re-run `contentrain generate` to update the static data modules.
277
+ 3. Rebuild the application.
278
+
279
+ For development, use watch mode:
280
+
281
+ ```bash
282
+ npx contentrain generate --watch
283
+ ```
284
+
285
+ ---
286
+
287
+ ## Important Rules
288
+
289
+ - **ALWAYS dry-run before apply.** Both extract and reuse require a preview step.
290
+ - **Normalize branches always use `review` mode.** Never auto-merge.
291
+ - **Phase 2 requires Phase 1 to be merged.** Content must exist in `.contentrain/` before patching source.
292
+ - **Process reuse one model at a time.** Keep diffs small and reviewable.
293
+ - **MCP is framework-agnostic.** You (the agent) provide all stack-specific replacement expressions.
294
+ - **Do not change component structure.** Only replace string literals with content references.
@@ -0,0 +1,162 @@
1
+ # Skill: Review Pending Content Changes
2
+
3
+ > Review content changes on Contentrain branches, apply quality checks, and recommend approval or rejection.
4
+
5
+ ---
6
+
7
+ ## When to Use
8
+
9
+ The user wants to review content quality, audit existing entries, check pending changes, or run a pre-publish checklist. Triggers: "review content", "check pending changes", "review the contentrain branch", "content QA", "audit content", "pre-publish check".
10
+
11
+ ---
12
+
13
+ ## Steps
14
+
15
+ ### 1. Check Project State
16
+
17
+ Call `contentrain_status` to understand the current project:
18
+
19
+ - All models, their kinds, domains, and entry counts.
20
+ - Configured locales and source locale.
21
+ - Pending branches or unsubmitted changes.
22
+ - Workflow mode (auto-merge or review).
23
+
24
+ ### 2. List Content for Review
25
+
26
+ For each model (or the user-specified scope), call `contentrain_content_list(model: "<modelId>", locale: "<locale>")`:
27
+
28
+ - Retrieve entries for the source locale first.
29
+ - For i18n models, also retrieve entries for each target locale.
30
+ - Note entry counts per locale to identify i18n coverage gaps.
31
+
32
+ If reviewing a specific branch, list the `contentrain/*` branches and show:
33
+
34
+ - Branch name (indicates operation type: extract, reuse, content-save, model-save).
35
+ - Number of changed files.
36
+ - Last commit date.
37
+
38
+ ### 3. Run Automated Validation
39
+
40
+ Call `contentrain_validate` to get the automated validation report:
41
+
42
+ - Schema compliance errors (missing required fields, type mismatches).
43
+ - Referential integrity issues (broken relation references).
44
+ - i18n completeness gaps (missing locale entries).
45
+ - Content policy violations.
46
+
47
+ ### 4. Apply Quality Checklist
48
+
49
+ Go through each category and report findings:
50
+
51
+ #### 4.1 Content Quality (from content-quality.md)
52
+
53
+ - [ ] All required fields are populated with real, non-placeholder values.
54
+ - [ ] Text fields respect `min`/`max` constraints.
55
+ - [ ] No placeholder text (lorem ipsum, TODO, TBD, [insert here]).
56
+ - [ ] Tone is consistent with `context.json` → `conventions.tone`.
57
+ - [ ] Vocabulary terms from `vocabulary.json` are used consistently.
58
+ - [ ] Collection entries have no duplicate `unique` field values.
59
+ - [ ] Content follows the correct content type pattern (blog post, landing page, docs, etc.).
60
+ - [ ] No duplicate content across entries.
61
+
62
+ #### 4.2 SEO (from seo-rules.md)
63
+
64
+ - [ ] Page titles: 50-60 characters (max 70), primary keyword in first 30 characters.
65
+ - [ ] Meta descriptions: 120-160 characters, complete sentences.
66
+ - [ ] Slugs: kebab-case, descriptive, 3-5 words, no stop words.
67
+ - [ ] Heading hierarchy in markdown/richtext: h1 → h2 → h3 (no skips).
68
+ - [ ] Image alt text is present and descriptive (under 125 characters).
69
+ - [ ] No orphan pages (content exists but is not linked/referenced).
70
+
71
+ #### 4.3 Accessibility (from accessibility-rules.md)
72
+
73
+ - [ ] Image fields have corresponding alt text fields (or the alt is embedded).
74
+ - [ ] Color contrast: text color values meet WCAG AA ratio if paired colors are in the model.
75
+ - [ ] Link text is descriptive (no raw URLs, "click here", or "read more" without context).
76
+ - [ ] Media content has text alternatives where applicable.
77
+ - [ ] Heading hierarchy is sequential (no skipped levels).
78
+ - [ ] Color is not used as the sole means of conveying information.
79
+
80
+ #### 4.4 Security (from security-rules.md)
81
+
82
+ - [ ] No hardcoded secrets, API keys, or credentials in content fields.
83
+ - [ ] No internal URLs or staging domains in production content.
84
+ - [ ] User-generated or external URLs use HTTPS.
85
+ - [ ] No inline JavaScript or script injection vectors in richtext/markdown fields.
86
+ - [ ] No user-supplied HTML that could enable XSS.
87
+ - [ ] Email fields contain valid, non-internal addresses (unless intended).
88
+
89
+ #### 4.5 i18n Completeness (from i18n-quality.md)
90
+
91
+ - [ ] All models with `i18n: true` have entries for every supported locale.
92
+ - [ ] Entry counts match across locales (no missing translations).
93
+ - [ ] Required fields are populated in every locale.
94
+ - [ ] Dictionary keys are identical across all locale files.
95
+ - [ ] Vocabulary terms are translated in all locales.
96
+ - [ ] Translations are idiomatic (not word-for-word).
97
+ - [ ] Translated text fits within field `max` constraints.
98
+ - [ ] No source-locale text left untranslated in target locales.
99
+
100
+ #### 4.6 Referential Integrity
101
+
102
+ - [ ] All `relation` fields point to existing entries.
103
+ - [ ] All `relations` arrays contain valid references.
104
+ - [ ] No circular relations that could cause infinite loops.
105
+ - [ ] Referenced entries are in a publishable state.
106
+
107
+ ### 5. Generate Review Report
108
+
109
+ Present a structured report:
110
+
111
+ ```
112
+ ## Content Review Report
113
+
114
+ ### Summary
115
+ - Models reviewed: X
116
+ - Total entries: X
117
+ - Locales checked: X
118
+
119
+ ### Issues Found
120
+
121
+ #### Critical (must fix before publish)
122
+ - [list of blocking issues with field references]
123
+
124
+ #### Warning (should fix)
125
+ - [list of non-blocking issues]
126
+
127
+ #### Info (suggestions)
128
+ - [list of improvements]
129
+
130
+ ### Per-Model Breakdown
131
+ | Model | Kind | Entries | Issues | Status |
132
+ |---|---|---|---|---|
133
+
134
+ ### i18n Coverage
135
+ | Locale | Coverage | Missing Entries |
136
+ |---|---|---|
137
+ ```
138
+
139
+ ### 6. Make a Recommendation
140
+
141
+ Based on the findings:
142
+
143
+ - **Approve:** No errors, few or no warnings. Changes are ready to merge.
144
+ - **Request changes:** Errors or significant warnings found. List the specific changes needed.
145
+ - **Reject:** Fundamental issues (wrong model structure, placeholder-only content, security violations). Explain why and suggest starting over.
146
+
147
+ ### 7. Offer Fixes
148
+
149
+ For each fixable issue, offer to resolve it:
150
+
151
+ - Missing translations: offer to run `/contentrain-translate`.
152
+ - Schema violations: offer to update entries with `contentrain_content_save`.
153
+ - Missing required fields: draft content for empty fields.
154
+ - SEO issues: suggest improved titles, descriptions, slugs.
155
+
156
+ Only make changes after user approval.
157
+
158
+ ### 8. Re-validate
159
+
160
+ If fixes were applied, call `contentrain_validate` again to confirm all issues are resolved.
161
+
162
+ Report the final status: "All checks passed" or list remaining issues that require manual attention.