@contentrain/skills 0.1.1 → 0.2.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.
Files changed (45) hide show
  1. package/README.md +65 -60
  2. package/dist/index.cjs +65 -1
  3. package/dist/index.d.cts +50 -2
  4. package/dist/index.d.cts.map +1 -1
  5. package/dist/index.d.mts +50 -2
  6. package/dist/index.d.mts.map +1 -1
  7. package/dist/index.mjs +65 -2
  8. package/dist/index.mjs.map +1 -1
  9. package/frameworks/nuxt.md +26 -1
  10. package/package.json +3 -1
  11. package/skills/contentrain/SKILL.md +149 -0
  12. package/skills/contentrain/references/architecture.md +212 -0
  13. package/skills/contentrain/references/content-formats.md +279 -0
  14. package/skills/contentrain/references/i18n.md +298 -0
  15. package/skills/contentrain/references/mcp-pipelines.md +192 -0
  16. package/skills/contentrain/references/mcp-tools.md +308 -0
  17. package/skills/contentrain/references/model-kinds.md +330 -0
  18. package/skills/contentrain/references/schema-types.md +177 -0
  19. package/skills/contentrain/references/security.md +146 -0
  20. package/skills/contentrain/references/workflow.md +267 -0
  21. package/skills/contentrain-bulk/SKILL.md +99 -0
  22. package/skills/contentrain-content/SKILL.md +162 -0
  23. package/skills/contentrain-diff/SKILL.md +62 -0
  24. package/skills/contentrain-doctor/SKILL.md +62 -0
  25. package/skills/contentrain-generate/SKILL.md +183 -0
  26. package/skills/contentrain-generate/references/generated-client.md +198 -0
  27. package/skills/contentrain-init/SKILL.md +99 -0
  28. package/skills/contentrain-model/SKILL.md +141 -0
  29. package/skills/contentrain-normalize/SKILL.md +185 -0
  30. package/skills/contentrain-normalize/references/extraction.md +164 -0
  31. package/skills/contentrain-normalize/references/reuse.md +146 -0
  32. package/skills/contentrain-normalize/references/what-is-content.md +115 -0
  33. package/skills/contentrain-quality/SKILL.md +180 -0
  34. package/skills/contentrain-quality/references/accessibility.md +160 -0
  35. package/skills/contentrain-quality/references/content-quality.md +299 -0
  36. package/skills/contentrain-quality/references/media.md +170 -0
  37. package/skills/contentrain-quality/references/seo.md +229 -0
  38. package/skills/contentrain-review/SKILL.md +170 -0
  39. package/skills/contentrain-sdk/SKILL.md +145 -0
  40. package/skills/contentrain-sdk/references/bundler-config.md +135 -0
  41. package/skills/contentrain-serve/SKILL.md +96 -0
  42. package/skills/contentrain-translate/SKILL.md +180 -0
  43. package/skills/contentrain-validate-fix/SKILL.md +92 -0
  44. package/workflows/contentrain-content.md +1 -1
  45. package/workflows/contentrain-generate.md +5 -5
@@ -0,0 +1,99 @@
1
+ ---
2
+ name: contentrain-init
3
+ description: "Initialize a new Contentrain project. Use when setting up .contentrain/ directory, configuring stack and locales, or scaffolding templates."
4
+ metadata:
5
+ author: Contentrain
6
+ version: "1.0.0"
7
+ ---
8
+
9
+ # Skill: Initialize Contentrain in a Project
10
+
11
+ > Set up Contentrain content infrastructure in an existing project.
12
+
13
+ ---
14
+
15
+ ## When to Use
16
+
17
+ The user wants to add Contentrain to their project, or says something like "set up contentrain", "initialize contentrain", "add content management".
18
+
19
+ ---
20
+
21
+ ## Steps
22
+
23
+ ### 1. Detect the Tech Stack
24
+
25
+ Read `package.json` to identify the framework:
26
+
27
+ | Dependency | Stack |
28
+ |---|---|
29
+ | `nuxt` | Nuxt 3 |
30
+ | `next` | Next.js |
31
+ | `@astrojs/astro` or `astro` | Astro |
32
+ | `@sveltejs/kit` | SvelteKit |
33
+
34
+ If none match, treat as a generic Node.js project. Report the detected stack to the user before proceeding.
35
+
36
+ ### 2. Ask for Configuration
37
+
38
+ Ask the user for:
39
+
40
+ - **Supported locales:** Which languages will the project support? Default: `["en"]`. Use ISO 639-1 codes.
41
+ - **Source locale:** Which locale is the primary/source locale? Default: `"en"`.
42
+ - **Domain names:** Suggest domains based on the project structure (e.g., `marketing`, `blog`, `app`, `docs`). Ask the user to confirm or modify.
43
+
44
+ ### 3. Initialize the Project
45
+
46
+ Call the MCP tool:
47
+
48
+ ```
49
+ contentrain_init(stack: "<detected>", locales: ["en", ...], domains: ["marketing", ...])
50
+ ```
51
+
52
+ This creates the `.contentrain/` directory structure, `config.json`, and initial `context.json`.
53
+
54
+ ### 4. Analyze Project Conventions
55
+
56
+ After initialization, review the project for conventions to inform content creation:
57
+
58
+ - **Tone:** Analyze existing copy in the project (README, landing page, UI text) to determine the appropriate tone (e.g., `professional`, `casual`, `technical`).
59
+ - **Naming conventions:** Note any patterns in file naming, component naming, or content structure.
60
+
61
+ > **Note:** Do NOT manually edit `context.json`. It is managed automatically by MCP tools and updated after every write operation.
62
+
63
+ ### 5. Suggest Initial Models
64
+
65
+ Based on the project analysis, suggest models that would be useful:
66
+
67
+ - If the project has a landing page: suggest `hero` (singleton), `features` (singleton or collection).
68
+ - If the project has a blog section: suggest `blog-post` (document), `categories` (collection), `authors` (collection).
69
+ - If the project has UI text: suggest `ui-labels` (dictionary), `error-messages` (dictionary).
70
+
71
+ Present suggestions to the user and ask which to create. For selected models, call `contentrain_model_save` for each.
72
+
73
+ ### 6. Offer Scaffold Templates
74
+
75
+ If the project matches a common pattern, offer to use a scaffold template:
76
+
77
+ ```
78
+ contentrain_scaffold(template: "blog", locales: ["en"], with_sample_content: true)
79
+ ```
80
+
81
+ Available templates: `blog`, `landing`, `docs`, `ecommerce`, `saas`, `i18n`, `mobile`.
82
+
83
+ ### 7. Set Up Agent Rules
84
+
85
+ Copy the appropriate rules file to the project:
86
+
87
+ - For Claude Code projects: append Contentrain rules to the project's `CLAUDE.md` or create a new section.
88
+ - For Cursor projects: create or update `.cursorrules` with Contentrain conventions.
89
+
90
+ Include a reference to the framework-specific guide (nuxt.md, next.md, astro.md, sveltekit.md).
91
+
92
+ ### 8. Final Summary
93
+
94
+ Report to the user:
95
+
96
+ - What was created in `.contentrain/`.
97
+ - Which models were set up.
98
+ - How to import content in their code (show the `#contentrain` import).
99
+ - Next steps: create content, run `npx contentrain generate`, start the dev server.
@@ -0,0 +1,141 @@
1
+ ---
2
+ name: contentrain-model
3
+ description: "Design and save Contentrain model definitions. Use when creating models, updating schemas, adding fields, or changing model structure."
4
+ metadata:
5
+ author: Contentrain
6
+ version: "1.0.0"
7
+ ---
8
+
9
+ # Skill: Design and Save Models
10
+
11
+ > Create or evolve Contentrain model definitions safely.
12
+
13
+ ---
14
+
15
+ ## When to Use
16
+
17
+ Use this when the user wants to:
18
+
19
+ - add a new model
20
+ - change fields on an existing model
21
+ - choose between `singleton`, `collection`, `document`, and `dictionary`
22
+ - define relations, locales, or custom content paths
23
+
24
+ ---
25
+
26
+ ## Steps
27
+
28
+ ### 1. Inspect Project State
29
+
30
+ Call `contentrain_status` first:
31
+
32
+ - confirm the project is initialized
33
+ - see existing model IDs and domains
34
+ - avoid creating duplicates
35
+
36
+ If the user is extending an existing model, call `contentrain_describe(model: "<model-id>")`.
37
+
38
+ ### 2. Confirm Storage Contract
39
+
40
+ Call `contentrain_describe_format` before proposing structure changes.
41
+
42
+ Use it to confirm:
43
+
44
+ - model kinds and storage expectations
45
+ - locale behavior
46
+ - document vs JSON model tradeoffs
47
+ - how custom `content_path` and `locale_strategy` affect files
48
+
49
+ ### 3. Choose the Right Kind
50
+
51
+ - `singleton`: one object per locale, e.g. hero, navigation, footer
52
+ - `collection`: repeated entries with IDs, e.g. testimonials, faq items, authors
53
+ - `document`: long-form markdown content with frontmatter, e.g. blog posts, docs pages
54
+ - `dictionary`: flat key-value strings, e.g. UI labels, error messages
55
+
56
+ Default rules:
57
+
58
+ - use `dictionary` for UI/system strings
59
+ - use `document` for markdown-heavy long-form content
60
+ - use `collection` for repeated structured items
61
+ - use `singleton` for one page/section config per locale
62
+
63
+ ### 4. Design Fields
64
+
65
+ Follow these rules:
66
+
67
+ - model IDs must be kebab-case
68
+ - field names must be snake_case
69
+ - relation fields must define a target `model`
70
+ - prefer small, explicit schemas over large generic `object` blobs
71
+ - only mark fields as `required` when the content truly cannot function without them
72
+
73
+ Relation guidance:
74
+
75
+ - `relation`: single reference
76
+ - `relations`: multiple references
77
+ - use `slug`-driven relations for document-like linking
78
+
79
+ ### 5. Decide i18n and Path Strategy
80
+
81
+ Ask or infer:
82
+
83
+ - should this model be localized?
84
+ - should it use the default `.contentrain/content/...` path or a custom `content_path`?
85
+ - if custom path is needed, which `locale_strategy` matches the project layout?
86
+
87
+ Use custom paths only when the framework or repo structure clearly benefits from it.
88
+
89
+ ### 6. Present the Proposed Model
90
+
91
+ Before writing, show:
92
+
93
+ - model ID
94
+ - kind
95
+ - domain
96
+ - `i18n` behavior
97
+ - field list with types
98
+ - relation targets
99
+ - any custom `content_path` / `locale_strategy`
100
+
101
+ Get user confirmation before saving.
102
+
103
+ ### 7. Save the Model
104
+
105
+ Call `contentrain_model_save` with the approved definition.
106
+
107
+ Example:
108
+
109
+ ```json
110
+ {
111
+ "id": "hero",
112
+ "name": "Hero",
113
+ "kind": "singleton",
114
+ "domain": "marketing",
115
+ "i18n": true,
116
+ "fields": {
117
+ "title": { "type": "string", "required": true },
118
+ "subtitle": { "type": "text" },
119
+ "cta_label": { "type": "string" },
120
+ "featured_post": { "type": "relation", "model": "blog-post" }
121
+ }
122
+ }
123
+ ```
124
+
125
+ ### 8. Validate Downstream Impact
126
+
127
+ After changing a model:
128
+
129
+ - review whether existing content now needs updates
130
+ - call `contentrain_validate`
131
+ - if the model is consumed by the SDK, recommend `contentrain generate`
132
+
133
+ ### 9. Final Summary
134
+
135
+ Report:
136
+
137
+ - model created or updated
138
+ - kind and domain
139
+ - field count
140
+ - any relation targets
141
+ - whether content migration is needed next
@@ -0,0 +1,185 @@
1
+ ---
2
+ name: contentrain-normalize
3
+ description: "Two-phase normalize flow: extract hardcoded strings from source code into .contentrain/ (Phase 1) and patch source files with content references (Phase 2). Use when normalizing, extracting content, or replacing hardcoded strings."
4
+ metadata:
5
+ author: Contentrain
6
+ version: "1.0.0"
7
+ ---
8
+
9
+ # Contentrain Normalize
10
+
11
+ Normalize converts a codebase with hardcoded strings into a Contentrain-managed content architecture. It runs in two independent phases, each producing a separate branch for review.
12
+
13
+ - **Phase 1 (Extraction):** Pull content from source code into `.contentrain/` structure. Source files are NOT modified.
14
+ - **Phase 2 (Reuse):** Patch source files to replace hardcoded strings with content references. Requires completed extraction.
15
+
16
+ Phase 1 alone is valuable: content becomes manageable in Studio, translatable, and publishable without touching source code.
17
+
18
+ ---
19
+
20
+ ## Two-Phase Architecture
21
+
22
+ | Aspect | Phase 1: Extraction | Phase 2: Reuse |
23
+ |--------|-------------------|----------------|
24
+ | Purpose | Pull content from source to `.contentrain/` | Patch source files with content references |
25
+ | Scope | Full project scan | Per model or per domain |
26
+ | Source files modified | No | Yes |
27
+ | Branch pattern | `contentrain/normalize/extract/{domain}/{timestamp}` | `contentrain/normalize/reuse/{model}/{locale}/{timestamp}` |
28
+ | Prerequisite | Initialized `.contentrain/` | Completed extraction (content exists in `.contentrain/`) |
29
+ | Workflow mode | Always `review` | Always `review` |
30
+ | Standalone value | Yes -- content is manageable in Studio immediately | Depends on Phase 1 |
31
+
32
+ ---
33
+
34
+ ## Agent vs MCP Responsibilities
35
+
36
+ ### Agent (Intelligence Layer)
37
+
38
+ - **Decide what is content vs code.** Semantic judgment requiring context understanding.
39
+ - **Assign domain grouping.** Determine which domain each piece of content belongs to.
40
+ - **Determine model structure.** Group related content into models, choose the right kind.
41
+ - **Create replacement expressions.** Stack-specific, requires framework knowledge (Vue/Nuxt, React/Next, Svelte, Astro, SDK).
42
+ - **Filter false positives** from scan candidates.
43
+ - **Evaluate and group** candidates into logical models.
44
+
45
+ ### MCP (Deterministic Infrastructure)
46
+
47
+ - **Scan the file system** (build graph, find candidates).
48
+ - **Read and write files** in `.contentrain/`.
49
+ - **Patch source files** with exact string replacement (agent provides the replacement expression).
50
+ - **Create branches, commit, validate** all changes.
51
+ - **Enforce guardrails** (file limits, type restrictions, dry-run requirement).
52
+
53
+ MCP is framework-agnostic. It does NOT know how `{t('key')}` differs from `{{ $t('key') }}`. The agent provides all stack-specific logic.
54
+
55
+ ---
56
+
57
+ ## Guardrails
58
+
59
+ | Guardrail | Limit | Rationale |
60
+ |-----------|-------|-----------|
61
+ | Allowed source file types | `.vue`, `.tsx`, `.jsx`, `.ts`, `.js`, `.mjs`, `.astro`, `.svelte` | Only scan files that can contain UI content |
62
+ | Max files per scan | 500 | Prevent scanning entire monorepos |
63
+ | Max files per apply | 100 | Keep diffs reviewable |
64
+ | Dry-run before apply | **MANDATORY** | Preview all changes before executing |
65
+ | Workflow mode | Always `review` | Normalize changes are never auto-merged |
66
+ | Reuse scope | Per model or per domain | No whole-project reuse in one operation |
67
+ | Reuse prerequisite | Extraction must be complete | Content must exist in `.contentrain/` before patching source |
68
+
69
+ Attempting to apply without a prior dry-run will be rejected. Exceeding file limits will truncate results with a warning.
70
+
71
+ ---
72
+
73
+ ## Phase 1: Extraction (Step-by-Step)
74
+
75
+ ### 1. Check Project State
76
+
77
+ Call `contentrain_status` to confirm the project is initialized and note supported locales. Call `contentrain_describe_format` to understand the four storage formats (dictionary, collection, singleton, document) before deciding model structure.
78
+
79
+ ### 2. Build the Project Graph
80
+
81
+ Call `contentrain_scan(mode: "graph")` to build the import/component dependency graph. Use this to understand which components belong to which pages, identify shared vs page-specific components, and prioritize files.
82
+
83
+ ### 3. Find Candidates
84
+
85
+ Call `contentrain_scan(mode: "candidates")` to find hardcoded strings. The scan returns candidates with file paths, line numbers, string values, and surrounding context.
86
+
87
+ ### 4. Evaluate Candidates (Agent Intelligence)
88
+
89
+ - **Filter false positives:** Remove CSS values, technical identifiers, import paths, variable names, config values, log messages, test strings. See [What Is Content](references/what-is-content.md) for full heuristics.
90
+ - **Assign domains:** Group candidates by domain (e.g., `marketing`, `blog`, `ui`, `system`).
91
+ - **Determine model types:** Choose dictionary, singleton, collection, or document kind for each group.
92
+ - **Structure fields:** Define field names and assign candidate strings to fields.
93
+
94
+ ### 5. Preview Extraction
95
+
96
+ Call `contentrain_apply(mode: "extract", dry_run: true)` to generate a preview. Review the dry-run output: verify model definitions, content assignments, and check for missed or misclassified candidates. Show the preview to the user.
97
+
98
+ ### 6. Execute Extraction
99
+
100
+ After user approval, call `contentrain_apply(mode: "extract", dry_run: false)`. This creates model definitions and content files in `.contentrain/` on a `contentrain/normalize/extract/{timestamp}` branch. Source files are NOT modified.
101
+
102
+ ### 7. Validate and Submit
103
+
104
+ Call `contentrain_validate` to check schema compliance, i18n completeness, and duplicate entries. Call `contentrain_submit` to push the branch for review. Normalize operations always use `review` workflow mode.
105
+
106
+ 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."
107
+
108
+ ---
109
+
110
+ ## Phase 2: Reuse (Step-by-Step)
111
+
112
+ Only start after Phase 1 is reviewed and merged.
113
+
114
+ ### 1. Select Scope
115
+
116
+ List the extracted models and ask the user which model or domain to process first. Process one model or domain at a time to keep diffs small and reviewable.
117
+
118
+ ### 2. Determine Replacement Expressions (Agent Intelligence)
119
+
120
+ Based on the project's tech stack, determine the correct replacement pattern. See [Reuse Details](references/reuse.md) for the full replacement expressions table by stack. Also determine any necessary import statements for patched files.
121
+
122
+ ### 3. Preview Reuse
123
+
124
+ Call `contentrain_apply(mode: "reuse", scope: { model: "<model-id>" }, patches: [...], dry_run: true)`. Review: verify each replacement is correct, import statements will be added, no non-content strings are being replaced, component structure is preserved.
125
+
126
+ ### 4. Execute Reuse
127
+
128
+ After user confirmation, call `contentrain_apply(mode: "reuse", scope: { model: "<model-id>" }, patches: [...], dry_run: false)`. This patches source files and creates a `contentrain/normalize/reuse/{model}/{timestamp}` branch.
129
+
130
+ ### 5. Validate and Submit
131
+
132
+ Call `contentrain_validate` to verify source files parse correctly, content references resolve, and no strings were missed or double-replaced. Call `contentrain_submit` to push the branch for review.
133
+
134
+ ### 6. Repeat
135
+
136
+ 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.
137
+
138
+ ---
139
+
140
+ ## Domain and Model Grouping Guidelines
141
+
142
+ ### Domain Assignment
143
+
144
+ | Content Location | Suggested Domain |
145
+ |------------------|-----------------|
146
+ | Landing page, marketing sections | `marketing` |
147
+ | Blog, articles, posts | `blog` |
148
+ | Navigation, footer, header | `ui` |
149
+ | Error messages, validation | `system` |
150
+ | Product pages, e-commerce | `product` |
151
+ | Documentation, help | `docs` |
152
+ | User-facing app strings | `app` |
153
+
154
+ ### Model Kind Selection
155
+
156
+ | Content Pattern | Kind | Rationale |
157
+ |----------------|------|-----------|
158
+ | One set of fields per page section | `singleton` | Hero, features, pricing header |
159
+ | Multiple items of same type | `collection` | Team members, FAQs, testimonials |
160
+ | Long-form with metadata | `document` | Blog posts, documentation pages |
161
+ | Key-value UI strings | `dictionary` | Error messages, button labels, form labels |
162
+
163
+ ---
164
+
165
+ ## Common Mistakes
166
+
167
+ | Mistake | Correct Approach |
168
+ |---------|-----------------|
169
+ | Extracting CSS values as content | Only extract user-visible text |
170
+ | Creating one model per component | Group related content into shared models |
171
+ | Skipping dry-run | ALWAYS preview before apply |
172
+ | Auto-merging normalize changes | Normalize ALWAYS uses review mode |
173
+ | Reusing before extraction is merged | Wait for extraction review and merge first |
174
+ | Processing all models in one reuse | Scope reuse to one model/domain at a time |
175
+ | Ignoring project graph | Use graph output to understand component relationships |
176
+ | Hardcoding replacement patterns | Detect the project's i18n stack and use its conventions |
177
+ | Extracting strings with runtime variables | Split parameterized strings: extract the static part, leave interpolation in code |
178
+
179
+ ---
180
+
181
+ ## References
182
+
183
+ - [Extraction Details](references/extraction.md) -- Phase 1 extraction rules, parameters, and examples
184
+ - [Reuse Details](references/reuse.md) -- Phase 2 replacement expressions by stack and patching rules
185
+ - [What Is Content](references/what-is-content.md) -- Heuristics for identifying content vs code strings
@@ -0,0 +1,164 @@
1
+ ---
2
+ name: extraction
3
+ description: "Phase 1 extraction details, rules, and examples"
4
+ ---
5
+
6
+ # Phase 1: Extraction Details
7
+
8
+ Extraction pulls hardcoded content from source code into `.contentrain/` without modifying source files. Each extraction produces a single branch with all extracted content for review.
9
+
10
+ ---
11
+
12
+ ## Extraction Flow
13
+
14
+ ### 1. Build Project Graph
15
+
16
+ ```
17
+ contentrain_scan(mode: "graph")
18
+ ```
19
+
20
+ Returns the import/component dependency graph. Use this to:
21
+
22
+ - Understand which components belong to which pages or features.
23
+ - Identify shared components vs page-specific components.
24
+ - Prioritize files by their role in the project (layout, page, component).
25
+
26
+ ### 2. Find Candidates
27
+
28
+ ```
29
+ contentrain_scan(mode: "candidates")
30
+ ```
31
+
32
+ Returns hardcoded string candidates with file paths, line numbers, and surrounding context. Review candidates by file -- not all strings should be extracted. See [What Is Content](what-is-content.md) for filtering heuristics.
33
+
34
+ ### 3. Agent Evaluation
35
+
36
+ This is the intelligence step -- the agent makes all decisions:
37
+
38
+ - **Filter false positives:** Remove CSS values, technical identifiers, import paths, variable names, config values, log messages, and test strings.
39
+ - **Assign domains:** Group candidates by domain (e.g., `marketing`, `blog`, `ui`, `system`).
40
+ - **Determine model types:** Choose the appropriate model kind for each group:
41
+ - **dictionary** -- UI strings, button labels, error messages. Flat key-value, all strings, no field schema.
42
+ - **singleton** -- Page-specific content with structured fields (hero section, features block).
43
+ - **collection** -- Repeating items with structured fields (testimonials, FAQs, team members).
44
+ - **document** -- Long-form content with markdown body and typed metadata (blog posts, docs).
45
+ - **Structure fields:** Define field names and assign candidate strings to fields.
46
+
47
+ ### 4. Write Normalize Plan
48
+
49
+ After evaluation, write the plan as `.contentrain/normalize-plan.json`:
50
+
51
+ ```json
52
+ {
53
+ "version": 1,
54
+ "status": "pending",
55
+ "created_at": "2026-03-16T12:00:00.000Z",
56
+ "agent": "claude",
57
+ "scan_stats": {
58
+ "files_scanned": 42,
59
+ "raw_strings": 320,
60
+ "candidates_sent": 85,
61
+ "extracted": 28,
62
+ "skipped": 57
63
+ },
64
+ "models": [
65
+ {
66
+ "id": "hero-section",
67
+ "kind": "singleton",
68
+ "domain": "marketing",
69
+ "i18n": true,
70
+ "fields": {
71
+ "title": { "type": "string", "required": true },
72
+ "subtitle": { "type": "string" }
73
+ }
74
+ }
75
+ ],
76
+ "extractions": [
77
+ {
78
+ "value": "Build faster apps",
79
+ "file": "src/pages/index.vue",
80
+ "line": 12,
81
+ "model": "hero-section",
82
+ "field": "title"
83
+ }
84
+ ],
85
+ "patches": [
86
+ {
87
+ "file": "src/pages/index.vue",
88
+ "line": 12,
89
+ "old_value": "Build faster apps",
90
+ "new_expression": "{{ $t('hero.title') }}"
91
+ }
92
+ ]
93
+ }
94
+ ```
95
+
96
+ This file is watched by the serve UI -- writing it triggers automatic detection.
97
+
98
+ ### 5. Preview Extraction
99
+
100
+ ```
101
+ contentrain_apply(mode: "extract", dry_run: true)
102
+ ```
103
+
104
+ Returns a preview of what will be created in `.contentrain/` without making changes. Review the output:
105
+
106
+ - Verify models are structured correctly.
107
+ - Verify content assignments are accurate.
108
+ - Check for missing or misclassified candidates.
109
+
110
+ ### 6. Execute Extraction
111
+
112
+ ```
113
+ contentrain_apply(mode: "extract", dry_run: false)
114
+ ```
115
+
116
+ Creates model definitions and content files in `.contentrain/` on a `contentrain/normalize/extract/{timestamp}` branch. `dry_run` defaults to `true`, so you MUST explicitly set `dry_run: false` to execute.
117
+
118
+ ### 7. Validate and Submit
119
+
120
+ ```
121
+ contentrain_validate
122
+ contentrain_submit
123
+ ```
124
+
125
+ Submit always uses `review` mode for normalize operations.
126
+
127
+ ---
128
+
129
+ ## Extraction Rules
130
+
131
+ - Extraction creates content in `.contentrain/` but does NOT modify source files.
132
+ - Each extraction produces a single branch with all extracted content.
133
+ - Group related content into the fewest models that make semantic sense.
134
+ - Prefer **dictionary** kind for UI labels and error messages.
135
+ - Prefer **singleton** kind for page-specific content (hero, features).
136
+ - Prefer **collection** kind for repeating items (team members, FAQs, testimonials).
137
+ - Prefer **document** kind for long-form content with markdown body.
138
+
139
+ ---
140
+
141
+ ## Group Related Content Guidelines
142
+
143
+ When grouping candidates into models:
144
+
145
+ - Content from the same page section should go into the same model.
146
+ - Shared UI strings (navigation, footer, error messages) should be grouped into a single dictionary per domain.
147
+ - Do not create one model per component -- group related content into shared models.
148
+ - Use the project graph to understand component relationships and group accordingly.
149
+ - If multiple components share the same type of content (e.g., all cards have a title and description), consider a single collection model.
150
+
151
+ ---
152
+
153
+ ## Content Format Reference
154
+
155
+ Understand these formats before choosing model kinds:
156
+
157
+ | Kind | Format | Keys | Example Path |
158
+ |------|--------|------|-------------|
159
+ | Dictionary | Flat key-value JSON, all strings | Semantic dot-separated addresses | `{model-id}/{locale}.json` |
160
+ | Collection | Object-map JSON by 12-char hex ID | Auto-generated entry IDs | `{model-id}/{locale}.json` |
161
+ | Singleton | Single JSON object per locale | Typed field names | `{model-id}/{locale}.json` |
162
+ | Document | Markdown with frontmatter per slug | Slug-based file names | `{model-id}/{slug}/{locale}.md` |
163
+
164
+ Call `contentrain_describe_format` before deciding model structure to see the exact format for each kind.