@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.
- package/README.md +65 -60
- package/dist/index.cjs +65 -1
- package/dist/index.d.cts +50 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +50 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +65 -2
- package/dist/index.mjs.map +1 -1
- package/frameworks/nuxt.md +26 -1
- package/package.json +3 -1
- package/skills/contentrain/SKILL.md +149 -0
- package/skills/contentrain/references/architecture.md +212 -0
- package/skills/contentrain/references/content-formats.md +279 -0
- package/skills/contentrain/references/i18n.md +298 -0
- package/skills/contentrain/references/mcp-pipelines.md +192 -0
- package/skills/contentrain/references/mcp-tools.md +308 -0
- package/skills/contentrain/references/model-kinds.md +330 -0
- package/skills/contentrain/references/schema-types.md +177 -0
- package/skills/contentrain/references/security.md +146 -0
- package/skills/contentrain/references/workflow.md +267 -0
- package/skills/contentrain-bulk/SKILL.md +99 -0
- package/skills/contentrain-content/SKILL.md +162 -0
- package/skills/contentrain-diff/SKILL.md +62 -0
- package/skills/contentrain-doctor/SKILL.md +62 -0
- package/skills/contentrain-generate/SKILL.md +183 -0
- package/skills/contentrain-generate/references/generated-client.md +198 -0
- package/skills/contentrain-init/SKILL.md +99 -0
- package/skills/contentrain-model/SKILL.md +141 -0
- package/skills/contentrain-normalize/SKILL.md +185 -0
- package/skills/contentrain-normalize/references/extraction.md +164 -0
- package/skills/contentrain-normalize/references/reuse.md +146 -0
- package/skills/contentrain-normalize/references/what-is-content.md +115 -0
- package/skills/contentrain-quality/SKILL.md +180 -0
- package/skills/contentrain-quality/references/accessibility.md +160 -0
- package/skills/contentrain-quality/references/content-quality.md +299 -0
- package/skills/contentrain-quality/references/media.md +170 -0
- package/skills/contentrain-quality/references/seo.md +229 -0
- package/skills/contentrain-review/SKILL.md +170 -0
- package/skills/contentrain-sdk/SKILL.md +145 -0
- package/skills/contentrain-sdk/references/bundler-config.md +135 -0
- package/skills/contentrain-serve/SKILL.md +96 -0
- package/skills/contentrain-translate/SKILL.md +180 -0
- package/skills/contentrain-validate-fix/SKILL.md +92 -0
- package/workflows/contentrain-content.md +1 -1
- 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.
|