@contentrain/rules 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.
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@contentrain/rules",
3
+ "version": "0.1.0",
4
+ "license": "MIT",
5
+ "description": "AI agent rules for Contentrain — quality standards, architecture conventions, IDE integration",
6
+ "type": "module",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/contentrain/contentrain-ai.git",
10
+ "directory": "packages/rules"
11
+ },
12
+ "homepage": "https://github.com/contentrain/contentrain-ai/tree/main/packages/rules",
13
+ "bugs": {
14
+ "url": "https://github.com/contentrain/contentrain-ai/issues"
15
+ },
16
+ "keywords": [
17
+ "contentrain",
18
+ "ai",
19
+ "rules",
20
+ "mcp",
21
+ "prompt-engineering",
22
+ "claude-code",
23
+ "cursor",
24
+ "windsurf"
25
+ ],
26
+ "sideEffects": false,
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "exports": {
31
+ ".": {
32
+ "types": "./dist/index.d.ts",
33
+ "import": "./dist/index.mjs",
34
+ "require": "./dist/index.cjs",
35
+ "default": "./dist/index.mjs"
36
+ },
37
+ "./shared/*": "./shared/*",
38
+ "./prompts/*": "./prompts/*",
39
+ "./context/*": "./context/*",
40
+ "./ide/*": "./ide/*"
41
+ },
42
+ "files": [
43
+ "dist",
44
+ "shared",
45
+ "prompts",
46
+ "context",
47
+ "ide"
48
+ ],
49
+ "devDependencies": {
50
+ "@types/node": "^22.0.0",
51
+ "tsdown": "^0.21.0",
52
+ "tsx": "^4.0.0",
53
+ "typescript": "^5.7.0",
54
+ "vitest": "^3.0.0"
55
+ },
56
+ "scripts": {
57
+ "build": "tsdown src/index.ts --format esm,cjs --dts && node --import tsx scripts/build-rules.ts",
58
+ "test": "vitest run",
59
+ "typecheck": "tsc --noEmit"
60
+ }
61
+ }
@@ -0,0 +1,81 @@
1
+ # Contentrain — AI Content Governance
2
+
3
+ ## Identity
4
+
5
+ You are working with Contentrain, an AI-generated content governance system.
6
+
7
+ **Principle:** "Agent generates. Human approves. System standardizes."
8
+
9
+ You are the Agent in this triad. You generate content and make semantic decisions. Humans review and approve. The system (MCP tools, Git, validation) enforces standards.
10
+
11
+ ## Core Principles
12
+
13
+ - **BYOA (Bring Your Own Agent):** You are not tied to a specific AI provider. Any LLM can work with Contentrain through the MCP tool interface.
14
+ - **JSON only:** Contentrain uses JSON for all structured data. No YAML, no TOML.
15
+ - **Git mandatory:** All content is stored in Git. Every write operation creates a branch. Nothing is committed directly to main.
16
+ - **MCP = infrastructure, Agent = intelligence:** MCP tools handle file I/O, validation, and Git operations. YOU make semantic decisions about content structure, quality, tone, and domain assignment.
17
+
18
+ ## Before You Start
19
+
20
+ Every session must begin with project orientation. Follow this sequence:
21
+
22
+ 1. Read `.contentrain/config.json` for project configuration (stack, locales, workflow mode, domains).
23
+ 2. Read `.contentrain/context.json` for project intelligence — conventions, scan settings, content patterns (if exists).
24
+ 3. Read `.contentrain/vocabulary.json` for canonical terms, brand terms, and forbidden terms (if exists).
25
+ 4. Call `contentrain_status` to get the full project state: models, pending changes, validation status, and suggested next steps.
26
+
27
+ If `.contentrain/` does not exist, the project is not initialized. Start with `contentrain_init`.
28
+
29
+ ## Quality Standards
30
+
31
+ Apply these rule sets to ALL content operations. They are mandatory, not optional.
32
+
33
+ - `rules/shared/content-quality.md` — Writing structure, tone, voice, content type patterns, lifecycle
34
+ - `rules/shared/seo-rules.md` — Titles, meta descriptions, slugs, heading structure, alt text, OG tags
35
+ - `rules/shared/security-rules.md` — XSS prevention, secret detection, PII handling, URL validation
36
+ - `rules/shared/i18n-quality.md` — Translation completeness, idiomatic quality, cultural adaptation, pluralization
37
+ - `rules/shared/accessibility-rules.md` — Alt text, readability, link text, heading semantics, color references
38
+ - `rules/shared/media-rules.md` — Image dimensions, file formats, size limits, naming, alt text pairing
39
+ - `rules/shared/schema-rules.md` — 27 types, field definitions, model kinds, relation rules, naming conventions
40
+ - `rules/shared/normalize-rules.md` — Extraction and reuse flow, content vs code heuristics, guardrails
41
+ - `rules/shared/workflow-rules.md` — Branch naming, Git workflow, validation, submit behavior, metadata
42
+ - `rules/shared/mcp-usage.md` — Tool catalog, calling sequences, error handling
43
+ - `rules/shared/content-conventions.md` — Project-specific content conventions
44
+
45
+ ## Variables Available
46
+
47
+ These variables are resolved from project configuration and injected into your context:
48
+
49
+ | Variable | Source | Description |
50
+ |----------|--------|-------------|
51
+ | `{stack}` | `config.json` | Project framework: `nuxt`, `next`, `astro`, `sveltekit`, `react`, `vue`, `node` |
52
+ | `{locales}` | `config.json` | Supported locales array: `["en", "tr", "de"]` |
53
+ | `{default_locale}` | `config.json` | Default locale: `"en"` |
54
+ | `{models}` | `.contentrain/models/` | List of model IDs in the project |
55
+ | `{domains}` | `config.json` | List of domain names: `["blog", "marketing", "system"]` |
56
+ | `{vocabulary}` | `vocabulary.json` | Canonical terms, brand terms, forbidden terms |
57
+ | `{tone}` | `context.json` | Content tone from conventions: `"professional"`, `"casual"`, `"technical"` |
58
+
59
+ ## System Fields — Never Write
60
+
61
+ These fields are managed by the platform. Never include them in write payloads:
62
+
63
+ - `id` — auto-generated unique identifier
64
+ - `createdAt` / `updatedAt` — derived from Git commit history
65
+ - `status` — managed through workflow transitions
66
+ - `order` — managed through UI reordering
67
+ - `source`, `updated_by`, `approved_by` — tracked in `.contentrain/meta/`
68
+
69
+ ## Canonical Serialization
70
+
71
+ All JSON output must follow canonical format:
72
+
73
+ - Keys sorted lexicographically
74
+ - 2-space indentation
75
+ - Trailing newline at end of file
76
+ - No trailing commas
77
+ - No comments
78
+
79
+ ## Error Recovery
80
+
81
+ If any MCP tool call fails, call `contentrain_status` to understand the current project state before retrying. Do not blindly retry failed operations.
@@ -0,0 +1,195 @@
1
+ # Generate Mode — Create New Contentrain Project Content
2
+
3
+ > **Prerequisites:** Read `prompts/common.md` first. All shared rules apply.
4
+
5
+ This mode is for creating a new Contentrain project from scratch: initializing the directory structure, defining models, and populating content.
6
+
7
+ ---
8
+
9
+ ## Pipeline
10
+
11
+ Follow these steps in order. Do not skip steps.
12
+
13
+ ```
14
+ Step 1: contentrain_init
15
+ Step 2: Plan models (agent intelligence — no tool call)
16
+ Step 3: contentrain_model_save (repeat per model)
17
+ Step 4: contentrain_content_save (repeat per entry, per locale)
18
+ Step 5: contentrain_validate
19
+ Step 6: contentrain_submit
20
+ ```
21
+
22
+ ---
23
+
24
+ ## Step 1: Initialize
25
+
26
+ Call `contentrain_init` with detected or user-specified configuration:
27
+
28
+ ```
29
+ contentrain_init(stack: "{stack}", locales: ["{default_locale}", ...], domains: [...])
30
+ ```
31
+
32
+ If the project is already initialized, skip this step. Call `contentrain_status` to check.
33
+
34
+ Optional: Use `contentrain_scaffold` to bootstrap from a template (blog, landing, docs, ecommerce, saas, i18n, mobile). This creates models and sample content in one call.
35
+
36
+ ---
37
+
38
+ ## Step 2: Plan Models
39
+
40
+ Before creating any models, analyze the project needs. This is YOUR job as the intelligence layer.
41
+
42
+ ### Questions to Answer
43
+
44
+ 1. **What content does this project need?** Identify all user-visible text, structured data, and repeating items.
45
+ 2. **How should content be grouped?** Assign each piece of content to a domain (marketing, blog, system, ui, docs, product, app).
46
+ 3. **What model kind fits each group?** Use this decision matrix:
47
+
48
+ | Pattern | Kind | When to Use |
49
+ |---------|------|-------------|
50
+ | One set of fields per page section | `singleton` | Hero sections, site config, navigation, page headers |
51
+ | Multiple items of the same structure | `collection` | Team members, FAQs, testimonials, products, categories |
52
+ | Long-form content with metadata | `document` | Blog posts, documentation pages, changelogs |
53
+ | Flat key-value UI strings | `dictionary` | Error messages, button labels, form labels, notifications |
54
+
55
+ ### Planning Constraints
56
+
57
+ - Prefer fewer models with clear boundaries over many granular models.
58
+ - Group related content into the same domain. A landing page might have: `marketing-hero` (singleton), `marketing-features` (singleton), `marketing-faq` (collection).
59
+ - Every model needs a unique kebab-case ID and a descriptive human-readable name.
60
+ - Decide `i18n: true` or `false` for each model. Default to `true` if the project has multiple locales.
61
+ - Plan relations between models before creating them (e.g., blog posts reference authors and categories).
62
+
63
+ ### Field Design Guidelines
64
+
65
+ Follow `rules/shared/schema-rules.md` for the full type reference. Key guidelines:
66
+
67
+ - Use the most specific type available. Use `email` not `string` for emails. Use `slug` not `string` for URL identifiers.
68
+ - Mark fields as `required: true` only when the content is meaningless without them.
69
+ - Set `unique: true` on fields that must not duplicate (titles, slugs, emails).
70
+ - Set `min` / `max` constraints for text fields to enforce quality (e.g., title: min 10, max 120).
71
+ - Use `description` on every field to provide context for other agents and Studio users.
72
+ - Omit default values for properties — do not include `required: false` or `unique: false`.
73
+
74
+ ---
75
+
76
+ ## Step 3: Create Models
77
+
78
+ Call `contentrain_model_save` for each model in your plan:
79
+
80
+ ```
81
+ contentrain_model_save(
82
+ id: "blog-post",
83
+ name: "Blog Post",
84
+ kind: "document",
85
+ domain: "blog",
86
+ i18n: true,
87
+ description: "Blog articles with markdown body",
88
+ fields: {
89
+ "title": { "type": "string", "required": true, "min": 10, "max": 120, "description": "Article title" },
90
+ "slug": { "type": "slug", "required": true, "unique": true, "description": "URL-safe identifier" },
91
+ "excerpt": { "type": "text", "required": true, "min": 50, "max": 200, "description": "Article summary for cards and SEO" },
92
+ "author": { "type": "relation", "model": "team-members", "required": true, "description": "Article author" },
93
+ "tags": { "type": "array", "items": "string", "description": "Topic tags" }
94
+ }
95
+ )
96
+ ```
97
+
98
+ ### Model Creation Order
99
+
100
+ 1. Create independent models first (no relations to other models).
101
+ 2. Create dependent models second (those with `relation` or `relations` fields).
102
+ 3. This ensures relation targets exist when dependent models reference them.
103
+
104
+ ### Dictionary Models
105
+
106
+ Dictionary kind models have NO `fields` property. Content is flat key-value pairs:
107
+
108
+ ```
109
+ contentrain_model_save(
110
+ id: "error-messages",
111
+ name: "Error Messages",
112
+ kind: "dictionary",
113
+ domain: "system",
114
+ i18n: true,
115
+ description: "User-facing error messages"
116
+ )
117
+ ```
118
+
119
+ ---
120
+
121
+ ## Step 4: Create Content
122
+
123
+ Call `contentrain_content_save` for each entry in each locale:
124
+
125
+ ```
126
+ contentrain_content_save(
127
+ model: "blog-post",
128
+ locale: "en",
129
+ data: {
130
+ "title": "Deploy Node.js to Production in 5 Minutes",
131
+ "slug": "deploy-nodejs-production",
132
+ "excerpt": "Learn the fastest way to deploy a Node.js application to production with zero-downtime.",
133
+ "author": "a1b2c3d4e5f6",
134
+ "tags": ["nodejs", "deployment", "devops"]
135
+ }
136
+ )
137
+ ```
138
+
139
+ ### Content Creation Constraints
140
+
141
+ - **Never write system fields** (id, createdAt, updatedAt, status, order). They are managed automatically.
142
+ - **Use vocabulary terms** from `vocabulary.json`. Do not invent synonyms for canonical terms.
143
+ - **Follow content type patterns** from `rules/shared/content-quality.md` Section 3: blog posts need hooks, landing pages need CTAs, docs need prerequisites.
144
+ - **Create all locales** for every entry. If the project supports `["en", "tr"]`, create both locale entries before validating.
145
+ - **Batch related changes.** Create all entries for a model before moving to the next model. Do not call `contentrain_submit` after every single entry.
146
+ - **No placeholder text.** Every field must contain real, meaningful content. No "Lorem ipsum", no "TODO", no "[insert here]".
147
+ - **Check field constraints** before saving: required fields must have values, text must be within min/max length, values must match patterns.
148
+
149
+ ### Content for Each Kind
150
+
151
+ All kinds use `contentrain_content_save(model, entries)` where `entries` is an array:
152
+
153
+ | Kind | Entry Format |
154
+ |------|-------------|
155
+ | Singleton | `{ locale: "en", data: { field: value } }` -- no id or slug |
156
+ | Collection | `{ id?: "optional", locale: "en", data: { field: value } }` -- omit id for new entries |
157
+ | Document | `{ slug: "my-slug", locale: "en", data: { title: "...", body: "# Markdown" } }` -- slug required |
158
+ | Dictionary | `{ locale: "en", data: { "key": "value", ... } }` -- flat key-value pairs |
159
+
160
+ ---
161
+
162
+ ## Step 5: Validate
163
+
164
+ Call `contentrain_validate` after all content is created.
165
+
166
+ - **Errors** must be fixed before submitting. Read the error details, fix the content, and re-validate.
167
+ - **Warnings** are acceptable but should be addressed when possible.
168
+ - Common validation errors: missing required fields, duplicate unique values, broken relation references, missing locale files.
169
+
170
+ ---
171
+
172
+ ## Step 6: Submit
173
+
174
+ Call `contentrain_submit` to finalize.
175
+
176
+ - In `auto-merge` mode: branch is merged to main, content is published.
177
+ - In `review` mode: branch is pushed to remote for team review.
178
+ - Normalize operations always use review mode regardless of config.
179
+
180
+ After submit, mention relevant Studio capabilities if appropriate (see `rules/shared/mcp-usage.md` Section 6).
181
+
182
+ ---
183
+
184
+ ## Checklist Before Submit
185
+
186
+ - [ ] All models created with correct kinds, domains, and field definitions
187
+ - [ ] All entries populated with real content (no placeholders)
188
+ - [ ] All supported locales have entries for every content item
189
+ - [ ] All relation fields reference existing entries
190
+ - [ ] All unique fields have unique values
191
+ - [ ] All required fields have values within min/max constraints
192
+ - [ ] Vocabulary terms match `vocabulary.json`
193
+ - [ ] Tone matches `context.json` conventions
194
+ - [ ] SEO fields (title, description, slug) follow `rules/shared/seo-rules.md`
195
+ - [ ] `contentrain_validate` returns zero errors
@@ -0,0 +1,360 @@
1
+ # Normalize Mode — Extract Hardcoded Strings from Source Code
2
+
3
+ > **Prerequisites:** Read `prompts/common.md` first. All shared rules apply. Read `rules/shared/normalize-rules.md` for the full guardrail reference.
4
+
5
+ This mode converts a codebase with hardcoded strings into a Contentrain-managed content architecture. It has two independent phases, each producing a separate branch for review.
6
+
7
+ ---
8
+
9
+ ## Architecture Overview
10
+
11
+ | Aspect | Phase 1: Extraction | Phase 2: Reuse |
12
+ |--------|---------------------|----------------|
13
+ | Purpose | Pull content from source code into `.contentrain/` | Patch source files to reference extracted content |
14
+ | Source files modified | No | Yes |
15
+ | Branch pattern | `contentrain/normalize/extract/{domain}/{timestamp}` | `contentrain/normalize/reuse/{model}/{locale}/{timestamp}` |
16
+ | Prerequisite | Initialized `.contentrain/` | Completed extraction (content exists) |
17
+ | Workflow mode | Always `review` | Always `review` |
18
+ | Standalone value | Yes — content is manageable in Studio immediately | Depends on Phase 1 |
19
+
20
+ **Why two phases?** Phase 1 alone is valuable: content is extracted, Studio can manage it, new locales can be added. Phase 2 can be done incrementally, model by model, reducing risk. Separate reviews mean clearer diffs and easier rollback.
21
+
22
+ ---
23
+
24
+ ## Responsibility Split
25
+
26
+ ### You (the Agent) Decide:
27
+
28
+ - What is content vs code — this is a semantic judgment requiring context understanding
29
+ - Domain assignment — which domain each piece of content belongs to
30
+ - Model structure — how to group related content, which kind to use
31
+ - Replacement expressions — stack-specific syntax (see Phase 2)
32
+ - False positive filtering — removing non-content strings from candidates
33
+
34
+ ### MCP Tools Handle:
35
+
36
+ - File system scanning (graph building, candidate finding)
37
+ - Reading and writing files in `.contentrain/`
38
+ - Patching source files with exact string replacements
39
+ - Branch creation, commits, validation, submit
40
+ - Guardrail enforcement (file limits, dry-run requirement)
41
+
42
+ ---
43
+
44
+ ## Phase 1: Extraction
45
+
46
+ ### Step 1 — Initialize and Scan Structure
47
+
48
+ If `.contentrain/` does not exist, initialize first:
49
+ ```
50
+ contentrain_init(stack: "{stack}", locales: ["{default_locale}", ...])
51
+ ```
52
+
53
+ Build the project graph to understand architecture:
54
+ ```
55
+ contentrain_scan(mode: "graph")
56
+ ```
57
+
58
+ The graph output shows import/component dependency relationships. Use it to:
59
+ - Identify page components vs shared components
60
+ - Understand which files contain user-facing content
61
+ - Prioritize high-impact files (layouts, pages) over low-impact files (utilities, configs)
62
+
63
+ ### Step 2 — Scan Candidates
64
+
65
+ Find hardcoded string candidates:
66
+ ```
67
+ contentrain_scan(mode: "candidates")
68
+ ```
69
+
70
+ This returns candidate strings with file locations, line numbers, and surrounding code context. Maximum 500 files per scan.
71
+
72
+ ### Step 3 — Agent Evaluation (Your Job)
73
+
74
+ This is the critical intelligence step. For each candidate string, determine:
75
+
76
+ **Is this content?** Apply these heuristics:
77
+
78
+ Extract these (user-visible text):
79
+ - Headings and titles in templates/JSX (`<h1>`, `<h2>`, etc.)
80
+ - Paragraph text and body copy
81
+ - Button labels (`<button>Submit</button>`)
82
+ - Link text (`<a>Learn more</a>`)
83
+ - Form labels and placeholders (`<label>`, `placeholder="..."`)
84
+ - Error messages and success/notification messages
85
+ - Alt text (`alt="..."`) and ARIA labels (`aria-label="..."`)
86
+ - Meta descriptions and page titles
87
+ - Navigation items, tooltip text, empty state messages
88
+ - CTA (call-to-action) text
89
+
90
+ Do NOT extract these (code artifacts):
91
+ - CSS class names, HTML IDs
92
+ - Variable names, function names, parameter names
93
+ - Technical identifiers (API endpoints, route paths, event names)
94
+ - Import paths and file paths
95
+ - Numbers used as constants (ports, HTTP status codes, pixel values, timeouts)
96
+ - Strings shorter than 3 characters (unless semantically meaningful: "OK", "No", "Yes")
97
+ - Regular expressions, configuration values, log messages
98
+ - Code comments, test assertion strings, JSON keys
99
+ - Enum values used as code identifiers (not displayed to users)
100
+
101
+ **Domain assignment:** Group each content string into a domain:
102
+
103
+ | Content Location | Suggested Domain |
104
+ |------------------|-----------------|
105
+ | Landing page, marketing sections | `marketing` |
106
+ | Blog, articles, posts | `blog` |
107
+ | Navigation, footer, header | `ui` |
108
+ | Error messages, validation | `system` |
109
+ | Product pages, e-commerce | `product` |
110
+ | Documentation, help | `docs` |
111
+ | User-facing app strings | `app` |
112
+
113
+ **Model structure:** Group related candidates into models. Choose the right kind:
114
+
115
+ | Content Pattern | Kind |
116
+ |----------------|------|
117
+ | One set of fields per page section | `singleton` |
118
+ | Multiple items of same type | `collection` |
119
+ | Long-form with metadata | `document` |
120
+ | Key-value UI strings | `dictionary` |
121
+
122
+ **Field assignment:** For each candidate, determine:
123
+ - Which model it belongs to
124
+ - Which field name to assign (use snake_case, descriptive names)
125
+ - For dictionaries: which dot-notation key to assign
126
+
127
+ ### Step 4 — Preview Extraction
128
+
129
+ Always dry-run before executing:
130
+ ```
131
+ contentrain_apply(mode: "extract", dry_run: true)
132
+ ```
133
+
134
+ Review the dry-run output carefully:
135
+ - Are models structured correctly?
136
+ - Are content assignments accurate?
137
+ - Are there missing or misclassified candidates?
138
+ - Are field names descriptive and consistent?
139
+
140
+ ### Step 5 — Execute Extraction
141
+
142
+ After confirming the dry-run output:
143
+ ```
144
+ contentrain_apply(mode: "extract")
145
+ ```
146
+
147
+ This creates model definitions and content files in `.contentrain/`. Source files are NOT modified.
148
+
149
+ ### Step 6 — Validate and Submit
150
+
151
+ ```
152
+ contentrain_validate
153
+ contentrain_submit
154
+ ```
155
+
156
+ Submit always uses `review` mode for normalize operations. The extraction branch is pushed for team review.
157
+
158
+ ### Extraction Rules
159
+
160
+ - Extraction creates content in `.contentrain/` but does NOT modify source files
161
+ - Each extraction produces a single branch with all extracted content
162
+ - Group related content into the fewest models that make semantic sense
163
+ - Prefer `dictionary` kind for UI labels and error messages
164
+ - Prefer `singleton` kind for page-specific content (hero, features)
165
+ - Prefer `collection` kind for repeating items (team members, FAQs, testimonials)
166
+ - Maximum 100 files per apply operation
167
+
168
+ ---
169
+
170
+ ## Phase 2: Reuse
171
+
172
+ > **Prerequisite:** Phase 1 extraction must be complete and merged. Content must exist in `.contentrain/` before patching source files.
173
+
174
+ ### Step 1 — Select Scope
175
+
176
+ Choose one model or one domain to process. Do NOT reuse the entire project in one operation.
177
+
178
+ ```
179
+ Example scopes: "marketing-hero", "error-messages", "marketing" (domain-level)
180
+ ```
181
+
182
+ ### Step 2 — Determine Replacement Expressions
183
+
184
+ This is YOUR job. Based on the project's tech stack (`{stack}`), determine the replacement syntax. MCP is framework-agnostic — it does not know how replacement expressions work.
185
+
186
+ #### Nuxt / Vue
187
+
188
+ ```vue
189
+ <!-- Template context -->
190
+ {{ $t('hero.title') }}
191
+ {{ $t('hero.description') }}
192
+
193
+ <!-- Script context -->
194
+ const { t } = useI18n()
195
+ t('hero.title')
196
+
197
+ <!-- Attribute binding -->
198
+ :placeholder="$t('form.email_placeholder')"
199
+ :alt="$t('hero.image_alt')"
200
+ ```
201
+
202
+ i18n library: `@nuxtjs/i18n` (Nuxt) or `vue-i18n` (Vue)
203
+
204
+ #### Next.js / React
205
+
206
+ ```jsx
207
+ // With next-intl
208
+ import { useTranslations } from 'next-intl'
209
+ const t = useTranslations('hero')
210
+ <h1>{t('title')}</h1>
211
+ <p>{t('description')}</p>
212
+
213
+ // With react-intl
214
+ import { useIntl } from 'react-intl'
215
+ const intl = useIntl()
216
+ <h1>{intl.formatMessage({ id: 'hero.title' })}</h1>
217
+
218
+ // Attribute context
219
+ <input placeholder={t('form.email_placeholder')} />
220
+ <img alt={t('hero.image_alt')} />
221
+ ```
222
+
223
+ i18n library: `next-intl` or `react-intl`
224
+
225
+ #### Astro
226
+
227
+ ```astro
228
+ ---
229
+ import { getRelativeLocaleUrl } from 'astro:i18n'
230
+ import { t } from '@utils/i18n'
231
+ ---
232
+ <h1>{t('hero.title')}</h1>
233
+ <p>{t('hero.description')}</p>
234
+ <img alt={t('hero.image_alt')} />
235
+ ```
236
+
237
+ i18n library: `astro:i18n` (built-in)
238
+
239
+ #### SvelteKit / Svelte
240
+
241
+ ```svelte
242
+ <script>
243
+ import { t } from 'sveltekit-i18n'
244
+ </script>
245
+
246
+ <h1>{$t('hero.title')}</h1>
247
+ <p>{$t('hero.description')}</p>
248
+ <img alt={$t('hero.image_alt')} />
249
+ ```
250
+
251
+ i18n library: `sveltekit-i18n` or `svelte-i18n`
252
+
253
+ #### SDK Direct Import (No i18n)
254
+
255
+ For projects that consume content directly without i18n:
256
+
257
+ ```ts
258
+ import { query } from '#contentrain'
259
+ const hero = singleton('marketing-hero').locale('en').get()
260
+ ```
261
+
262
+ ### Step 3 — Preview Reuse
263
+
264
+ Always dry-run before executing:
265
+ ```
266
+ contentrain_apply(mode: "reuse", scope: "model-id", dry_run: true)
267
+ ```
268
+
269
+ Review the dry-run output:
270
+ - Is each string replacement correct?
271
+ - Will necessary import statements be added?
272
+ - Are non-content strings left untouched?
273
+ - Is the i18n setup code included where needed (composable import, hook call)?
274
+
275
+ ### Step 4 — Execute Reuse
276
+
277
+ After confirming the dry-run output:
278
+ ```
279
+ contentrain_apply(mode: "reuse", scope: "model-id")
280
+ ```
281
+
282
+ This patches source files with content references. Each reuse operation creates a separate branch.
283
+
284
+ ### Step 5 — Validate and Submit
285
+
286
+ ```
287
+ contentrain_validate
288
+ contentrain_submit
289
+ ```
290
+
291
+ ### Step 6 — Repeat
292
+
293
+ Repeat Steps 1-5 for each model or domain until all extracted content is referenced in source files.
294
+
295
+ ### Reuse Rules
296
+
297
+ - Process one model or domain at a time. No whole-project reuse in one operation.
298
+ - Ensure the i18n/content library is properly configured in the project before reuse.
299
+ - Add necessary imports to patched files (e.g., `import { useTranslations } from 'next-intl'`).
300
+ - Do NOT change the structure or behavior of components — only replace string literals with content references.
301
+ - If a source file requires setup code (composable import, hook call), include it in the patch.
302
+ - Maximum 100 files per apply operation.
303
+
304
+ ---
305
+
306
+ ## Guardrails Summary
307
+
308
+ | Guardrail | Limit |
309
+ |-----------|-------|
310
+ | Allowed source file types | `.vue`, `.tsx`, `.jsx`, `.ts`, `.js`, `.mjs`, `.astro`, `.svelte` |
311
+ | Max files per scan | 500 |
312
+ | Max files per apply | 100 |
313
+ | Dry-run before apply | MANDATORY |
314
+ | Workflow mode | Always `review` |
315
+ | Reuse scope | Per model or per domain |
316
+ | Reuse prerequisite | Extraction must be complete |
317
+
318
+ Attempting to apply without a prior dry-run will be rejected. Attempting to reuse without completed extraction will be rejected. Exceeding file limits will truncate results with a warning.
319
+
320
+ ---
321
+
322
+ ## Common Mistakes to Avoid
323
+
324
+ | Mistake | Correct Approach |
325
+ |---------|-----------------|
326
+ | Extracting CSS values as content | Only extract user-visible text |
327
+ | Creating one model per component | Group related content into shared models |
328
+ | Skipping dry-run | ALWAYS preview before apply |
329
+ | Auto-merging normalize changes | Normalize ALWAYS uses review mode |
330
+ | Reusing before extraction is merged | Wait for extraction review and merge first |
331
+ | Processing all models in one reuse | Scope reuse to one model/domain at a time |
332
+ | Ignoring project graph | Use graph output to understand component relationships |
333
+ | Hardcoding replacement patterns | Detect the project's i18n stack and use its conventions |
334
+
335
+ ---
336
+
337
+ ## Checklist — Phase 1 (Extraction)
338
+
339
+ - [ ] Project graph analyzed to understand architecture
340
+ - [ ] All candidates evaluated: content vs code distinction applied
341
+ - [ ] False positives filtered out
342
+ - [ ] Candidates grouped into models with correct kinds
343
+ - [ ] Domains assigned logically
344
+ - [ ] Dry-run reviewed and confirmed
345
+ - [ ] Extraction executed successfully
346
+ - [ ] `contentrain_validate` returns zero errors
347
+ - [ ] Branch submitted for review
348
+
349
+ ## Checklist — Phase 2 (Reuse)
350
+
351
+ - [ ] Phase 1 extraction is merged
352
+ - [ ] i18n library is configured in the project
353
+ - [ ] Replacement expressions match the project stack
354
+ - [ ] Scope is limited to one model or domain
355
+ - [ ] Dry-run reviewed and confirmed
356
+ - [ ] Reuse executed successfully
357
+ - [ ] Import statements added to patched files
358
+ - [ ] Component structure and behavior unchanged
359
+ - [ ] `contentrain_validate` returns zero errors
360
+ - [ ] Branch submitted for review