@contentrain/rules 0.3.2 → 0.3.3
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 +3 -1
- package/shared/accessibility-rules.md +155 -0
- package/shared/content-conventions.md +314 -0
- package/shared/content-quality.md +294 -0
- package/shared/i18n-quality.md +293 -0
- package/shared/mcp-usage.md +408 -0
- package/shared/media-rules.md +165 -0
- package/shared/normalize-rules.md +335 -0
- package/shared/schema-rules.md +380 -0
- package/shared/security-rules.md +141 -0
- package/shared/seo-rules.md +224 -0
- package/shared/workflow-rules.md +317 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# SEO Rules
|
|
2
|
+
|
|
3
|
+
These rules govern search engine optimization for all content managed through Contentrain.
|
|
4
|
+
Apply these rules to every content entry that produces a public-facing page.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 1. Page Titles
|
|
9
|
+
|
|
10
|
+
### 1.1 Length and Format
|
|
11
|
+
|
|
12
|
+
- Length: 50-60 characters including spaces. Google truncates titles beyond ~60 characters.
|
|
13
|
+
- Measure character count before saving. Truncated titles harm click-through rates.
|
|
14
|
+
- No ALL CAPS titles. Use sentence case or title case per project convention.
|
|
15
|
+
- No excessive punctuation: no `!!!`, no `???`, no `...` in titles.
|
|
16
|
+
- No emoji in titles unless explicitly configured in `context.json`.
|
|
17
|
+
|
|
18
|
+
### 1.2 Keyword Placement
|
|
19
|
+
|
|
20
|
+
- Place the primary keyword within the first 30 characters.
|
|
21
|
+
- Structure: `Primary Keyword Phrase | Brand Name` or `Primary Keyword Phrase — Brand Name`.
|
|
22
|
+
- Acceptable separators: ` | `, ` — `, ` - `. Pick one and use it consistently across all entries.
|
|
23
|
+
- The keyword must read naturally — no keyword stuffing.
|
|
24
|
+
- GOOD: "Deploy Node.js to Production | Acme Docs"
|
|
25
|
+
- BAD: "Node.js Deploy Node Production Deployment | Acme"
|
|
26
|
+
|
|
27
|
+
### 1.3 Uniqueness
|
|
28
|
+
|
|
29
|
+
- Every entry in a collection MUST have a unique title.
|
|
30
|
+
- Before saving, query existing entries and confirm no title collision.
|
|
31
|
+
- Titles across collections should also be unique when they produce public pages.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 2. Meta Descriptions
|
|
36
|
+
|
|
37
|
+
### 2.1 Length and Format
|
|
38
|
+
|
|
39
|
+
- Length: 120-155 characters including spaces.
|
|
40
|
+
- Must be a complete sentence or two short sentences.
|
|
41
|
+
- End with a period.
|
|
42
|
+
- No keyword stuffing — write for humans, not crawlers.
|
|
43
|
+
|
|
44
|
+
### 2.2 Content Requirements
|
|
45
|
+
|
|
46
|
+
- Include a clear value proposition or call-to-action.
|
|
47
|
+
- GOOD: "Learn how to set up CI/CD for your Node.js project in 10 minutes. Step-by-step guide with examples."
|
|
48
|
+
- BAD: "CI/CD Node.js setup guide tutorial deployment continuous integration."
|
|
49
|
+
- Must differ from the page title — do not repeat the title as the description.
|
|
50
|
+
- Must be unique per entry. No two entries may share the same meta description.
|
|
51
|
+
|
|
52
|
+
### 2.3 What to Avoid
|
|
53
|
+
|
|
54
|
+
- No quotes or special characters that break HTML meta tags: avoid `"`, `<`, `>`.
|
|
55
|
+
- No "Click here to learn more" — search engines ignore generic CTAs.
|
|
56
|
+
- No date references that will become stale (prefer "latest" over "2024").
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 3. Slugs
|
|
61
|
+
|
|
62
|
+
### 3.1 Format
|
|
63
|
+
|
|
64
|
+
- Lowercase only. No uppercase characters.
|
|
65
|
+
- Words separated by hyphens (`-`). No underscores, no spaces, no dots.
|
|
66
|
+
- No special characters: only `a-z`, `0-9`, and `-`.
|
|
67
|
+
- No consecutive hyphens (`--`). No leading or trailing hyphens.
|
|
68
|
+
|
|
69
|
+
### 3.2 Length and Content
|
|
70
|
+
|
|
71
|
+
- Optimal: 3-5 words.
|
|
72
|
+
- Maximum: 60 characters.
|
|
73
|
+
- Remove stop words (`the`, `a`, `an`, `is`, `of`, `and`, `or`, `in`, `to`) unless removing them changes meaning.
|
|
74
|
+
- "how-to-deploy-node" → "deploy-node" is acceptable.
|
|
75
|
+
- "state-of-the-art" → keep as-is because meaning changes if shortened.
|
|
76
|
+
|
|
77
|
+
### 3.3 Stability
|
|
78
|
+
|
|
79
|
+
- NEVER change a slug on a published entry. Changing slugs breaks existing links, bookmarks, and search engine indexing.
|
|
80
|
+
- If a slug must change, the human must set up a redirect. The agent must not change published slugs without explicit human instruction.
|
|
81
|
+
- Draft entries may have their slugs changed freely before first publication.
|
|
82
|
+
|
|
83
|
+
### 3.4 Locale Consistency
|
|
84
|
+
|
|
85
|
+
- Use the same slug value across all locales for the same entry.
|
|
86
|
+
- Do NOT translate slugs. Slugs are identifiers, not content.
|
|
87
|
+
- Example: the slug `deploy-node` remains `deploy-node` in `en`, `tr`, `de`, and all other locales.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## 4. Heading Structure
|
|
92
|
+
|
|
93
|
+
### 4.1 H1 Rule
|
|
94
|
+
|
|
95
|
+
- Exactly one H1 per page. The H1 is the entry title or the primary heading.
|
|
96
|
+
- The H1 should contain the primary keyword naturally.
|
|
97
|
+
- Do not duplicate the H1 text elsewhere on the page.
|
|
98
|
+
|
|
99
|
+
### 4.2 Subheading Keywords
|
|
100
|
+
|
|
101
|
+
- Include relevant keywords in H2 and H3 headings where natural.
|
|
102
|
+
- Do not force keywords into every heading. Clarity takes priority over keyword density.
|
|
103
|
+
- Use question-format headings for FAQ-style content: "How do I reset my password?"
|
|
104
|
+
|
|
105
|
+
### 4.3 Hierarchy Reflects Content
|
|
106
|
+
|
|
107
|
+
- Heading levels must reflect the logical structure of the content.
|
|
108
|
+
- Do not use H3 because it renders smaller — use CSS for styling, headings for structure.
|
|
109
|
+
- Every heading must have content beneath it. No empty sections.
|
|
110
|
+
- Do not place two headings consecutively without content between them.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## 5. Images and Alt Text
|
|
115
|
+
|
|
116
|
+
### 5.1 Alt Text Requirements
|
|
117
|
+
|
|
118
|
+
- Every `image` field that displays on a public page MUST have corresponding alt text.
|
|
119
|
+
- Describe the image content and its context: "Dashboard showing monthly revenue chart with 15% growth indicator."
|
|
120
|
+
- Maximum length: 125 characters.
|
|
121
|
+
- Do not start with "Image of", "Photo of", "Picture of" — describe directly.
|
|
122
|
+
|
|
123
|
+
### 5.2 Decorative Images
|
|
124
|
+
|
|
125
|
+
- If an image is purely decorative (visual separator, background pattern), set alt text to an empty string (`""`).
|
|
126
|
+
- Do not omit the alt field entirely — explicitly set it to empty.
|
|
127
|
+
|
|
128
|
+
### 5.3 Keywords in Alt Text
|
|
129
|
+
|
|
130
|
+
- Include relevant keywords naturally when they describe the image.
|
|
131
|
+
- Do not stuff keywords: "Node.js Node deployment Node server Node production" is forbidden.
|
|
132
|
+
- The alt text must accurately describe what is in the image.
|
|
133
|
+
|
|
134
|
+
### 5.4 Image File Names
|
|
135
|
+
|
|
136
|
+
- When the agent controls the image file name, use descriptive, hyphenated names.
|
|
137
|
+
- GOOD: `revenue-dashboard-chart.png`
|
|
138
|
+
- BAD: `IMG_2847.png`, `screenshot.png`, `image1.png`
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## 6. Open Graph and Social Media
|
|
143
|
+
|
|
144
|
+
### 6.1 Open Graph Tags
|
|
145
|
+
|
|
146
|
+
When OG fields exist in the model, populate them:
|
|
147
|
+
|
|
148
|
+
| Field | Max Length | Requirement |
|
|
149
|
+
|---|---|---|
|
|
150
|
+
| `og:title` | 60 characters | Concise version of the page title |
|
|
151
|
+
| `og:description` | 200 characters | Slightly longer than meta description, conversational |
|
|
152
|
+
| `og:image` | — | 1200x630 pixels recommended, must be absolute URL |
|
|
153
|
+
| `og:type` | — | `article` for blog/docs, `website` for landing pages |
|
|
154
|
+
|
|
155
|
+
### 6.2 Twitter Card
|
|
156
|
+
|
|
157
|
+
- Use `summary_large_image` for content with strong visual elements.
|
|
158
|
+
- Use `summary` for text-focused content.
|
|
159
|
+
- Twitter title and description may differ from OG — optimize for each platform.
|
|
160
|
+
|
|
161
|
+
### 6.3 Fallback
|
|
162
|
+
|
|
163
|
+
- If OG-specific fields are absent, the system uses the standard title and description.
|
|
164
|
+
- Ensure the standard title and description are suitable for social sharing.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## 7. Internal Linking
|
|
169
|
+
|
|
170
|
+
### 7.1 Relation Fields
|
|
171
|
+
|
|
172
|
+
- Use Contentrain `relation` and `relations` model fields for cross-references between entries.
|
|
173
|
+
- Prefer structured relations over hardcoded links in body content.
|
|
174
|
+
- Structured relations are maintainable — if a slug changes, relations still resolve.
|
|
175
|
+
|
|
176
|
+
### 7.2 Bidirectional Relations
|
|
177
|
+
|
|
178
|
+
- When Entry A references Entry B, check if Entry B should reference Entry A.
|
|
179
|
+
- Example: if a blog post links to a product, the product's "related articles" should include that blog post.
|
|
180
|
+
- The agent should suggest bidirectional relations but not create them without confirmation.
|
|
181
|
+
|
|
182
|
+
### 7.3 Manual Links in Body Content
|
|
183
|
+
|
|
184
|
+
- If the model does not have relation fields and links must be in body text, use relative paths.
|
|
185
|
+
- Verify that linked entries exist before saving.
|
|
186
|
+
- Do not link to draft or archived entries from published content.
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## 8. URL and Canonical Rules
|
|
191
|
+
|
|
192
|
+
### 8.1 Slug Patterns
|
|
193
|
+
|
|
194
|
+
- All entries in a collection must follow the same slug pattern.
|
|
195
|
+
- If existing entries use `verb-noun` format (e.g., `deploy-app`, `configure-server`), new entries must follow the same pattern.
|
|
196
|
+
- Check existing entries before generating a slug for a new entry.
|
|
197
|
+
|
|
198
|
+
### 8.2 Multi-Locale URLs
|
|
199
|
+
|
|
200
|
+
- Same slug across all locales (see Section 3.4).
|
|
201
|
+
- Locale prefix is handled by the frontend routing, not by the content slug.
|
|
202
|
+
- Example: `/en/deploy-node` and `/tr/deploy-node` share the slug `deploy-node`.
|
|
203
|
+
|
|
204
|
+
### 8.3 Trailing Slashes
|
|
205
|
+
|
|
206
|
+
- The agent does not control trailing slash behavior — this is a frontend routing concern.
|
|
207
|
+
- Ensure slug values do not include leading or trailing slashes.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Validation Checklist
|
|
212
|
+
|
|
213
|
+
Before committing any content with SEO impact, verify:
|
|
214
|
+
|
|
215
|
+
- [ ] Title is 50-60 characters, primary keyword near start, unique
|
|
216
|
+
- [ ] Meta description is 120-155 characters, complete sentence, unique
|
|
217
|
+
- [ ] Slug is lowercase, hyphenated, 3-5 words, no special characters
|
|
218
|
+
- [ ] Published slugs have not been changed
|
|
219
|
+
- [ ] Slugs are identical across all locales for the same entry
|
|
220
|
+
- [ ] One H1 per page, sequential heading hierarchy
|
|
221
|
+
- [ ] All images have descriptive alt text (max 125 chars) or empty string for decorative
|
|
222
|
+
- [ ] OG fields populated if model supports them
|
|
223
|
+
- [ ] Relation fields used for internal cross-references
|
|
224
|
+
- [ ] No keyword stuffing in titles, descriptions, headings, or alt text
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
# Contentrain Workflow Rules
|
|
2
|
+
|
|
3
|
+
> These rules govern how content changes flow through the Git-based workflow, including branching, validation, review, and status management.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Two Workflow Modes
|
|
8
|
+
|
|
9
|
+
Contentrain supports two workflow modes, configured in `.contentrain/config.json` under the `workflow` field.
|
|
10
|
+
|
|
11
|
+
### 1.1 auto-merge
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{ "workflow": "auto-merge" }
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
- Feature branch is created from the `contentrain` branch, changes are committed, feature branch is **merged into `contentrain`**, then baseBranch is advanced via **update-ref** (fast-forward), and `.contentrain/` files are **selectively synced** to the developer's working tree.
|
|
18
|
+
- No review step -- changes go live immediately.
|
|
19
|
+
- Best for: solo developers, rapid iteration, prototyping, vibe coding.
|
|
20
|
+
- Status flow: `draft` --> `published` (skips `in_review`).
|
|
21
|
+
|
|
22
|
+
### 1.2 review
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{ "workflow": "review" }
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
- Branch is created, changes are committed, branch is **pushed to remote**.
|
|
29
|
+
- Studio or team reviews the changes before merging.
|
|
30
|
+
- Best for: teams, content governance, production environments.
|
|
31
|
+
- Status flow: `draft` --> `in_review` --> `published` | `rejected`.
|
|
32
|
+
|
|
33
|
+
### 1.3 Mode Selection Rules
|
|
34
|
+
|
|
35
|
+
- Default is `auto-merge` -- minimal friction for getting started.
|
|
36
|
+
- Switch to `review` as the project or team grows and governance becomes important.
|
|
37
|
+
- **Normalize operations ALWAYS use `review` mode** regardless of the config setting. Normalize changes are never auto-merged.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 2. Branch Naming Convention
|
|
42
|
+
|
|
43
|
+
All Contentrain branches follow a strict naming pattern:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
contentrain/{operation}/{model}/{locale}/{timestamp}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Examples
|
|
50
|
+
|
|
51
|
+
| Scenario | Branch Name |
|
|
52
|
+
|----------|-------------|
|
|
53
|
+
| Content update | `contentrain/content/blog-post/en/1710300000` |
|
|
54
|
+
| Model creation | `contentrain/model/team-member/1710300000` |
|
|
55
|
+
| Normalize extraction | `contentrain/normalize/extract/blog/1710300000` |
|
|
56
|
+
| Normalize reuse | `contentrain/normalize/reuse/marketing-hero/en/1710300000` |
|
|
57
|
+
| Scaffold | `contentrain/new/scaffold-landing/en/1710300000` |
|
|
58
|
+
|
|
59
|
+
### Rules
|
|
60
|
+
|
|
61
|
+
- Branches are created automatically by MCP tools. Do NOT create them manually.
|
|
62
|
+
- The `{timestamp}` component ensures uniqueness.
|
|
63
|
+
- `{locale}` is included when the operation is locale-specific.
|
|
64
|
+
- `{model}` is included when the operation targets a specific model.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## 3. Git Workflow
|
|
69
|
+
|
|
70
|
+
### 3.1 Dedicated `contentrain` Branch
|
|
71
|
+
|
|
72
|
+
The `contentrain` branch is the **single source of truth** for content state:
|
|
73
|
+
|
|
74
|
+
- Created automatically at `contentrain_init`.
|
|
75
|
+
- All content writes happen on feature branches forked from `contentrain`.
|
|
76
|
+
- The `contentrain` branch is **protected from deletion**.
|
|
77
|
+
- context.json is committed together with content changes, not as a separate commit.
|
|
78
|
+
|
|
79
|
+
### 3.2 Worktree-Based Transactions
|
|
80
|
+
|
|
81
|
+
Every write operation follows this flow:
|
|
82
|
+
|
|
83
|
+
1. MCP creates a **temporary Git worktree** on a new feature branch forked from `contentrain`.
|
|
84
|
+
2. Changes are made in the worktree (content files, model files, context.json).
|
|
85
|
+
3. Changes are committed to the feature branch.
|
|
86
|
+
4. **auto-merge mode:** Feature branch is merged into `contentrain`, then baseBranch is advanced via **update-ref** (fast-forward), then `.contentrain/` files are **selectively synced** to the developer's working tree. Dirty files are skipped with a warning. Worktree is cleaned up.
|
|
87
|
+
5. **review mode:** Feature branch is pushed to remote for team review. Worktree is cleaned up. Studio notifies reviewers.
|
|
88
|
+
|
|
89
|
+
Developer's working tree is **never mutated** during MCP git operations. There is no stash, no checkout, and no merge on the developer's tree.
|
|
90
|
+
|
|
91
|
+
### 3.3 Developer Manual Editing
|
|
92
|
+
|
|
93
|
+
If the developer manually edits `.contentrain/` files in their working tree, MCP selective sync skips those dirty files and issues a warning. The developer must commit or discard their local changes before MCP can sync those files.
|
|
94
|
+
|
|
95
|
+
### 3.4 Critical Rules
|
|
96
|
+
|
|
97
|
+
- **NEVER commit directly to main or the `contentrain` branch.** All changes go through feature branches.
|
|
98
|
+
- **NEVER create branches manually.** MCP tools handle all Git operations.
|
|
99
|
+
- **NEVER force-push or rebase** Contentrain branches.
|
|
100
|
+
- **NEVER delete the `contentrain` branch.** It is the content state SSOT.
|
|
101
|
+
- Worktrees are temporary. They are created for the operation and cleaned up afterward.
|
|
102
|
+
- Each branch contains a cohesive set of changes (e.g., all entries for one model update).
|
|
103
|
+
|
|
104
|
+
### 3.5 Branch Lifecycle
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
Feature branch created (worktree on contentrain)
|
|
108
|
+
--> Changes committed
|
|
109
|
+
--> auto-merge: feature merged into contentrain
|
|
110
|
+
--> update-ref advances baseBranch
|
|
111
|
+
--> selective sync .contentrain/ to developer's tree
|
|
112
|
+
--> review: feature pushed to remote, awaiting review
|
|
113
|
+
--> Worktree cleaned up
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The `contentrain` branch is permanent and protected. Feature branches are retained for `branchRetention` days (default: 30) for audit trail, then pruned.
|
|
117
|
+
|
|
118
|
+
### 3.6 Branch Health
|
|
119
|
+
|
|
120
|
+
MCP enforces branch health limits to prevent branch accumulation:
|
|
121
|
+
|
|
122
|
+
- **50+ active branches**: Warning. Operations continue but the user is alerted.
|
|
123
|
+
- **80+ active branches**: Blocked. No new write operations until branches are merged or deleted.
|
|
124
|
+
- `contentrain_status` reports branch health automatically (total, merged, unmerged counts).
|
|
125
|
+
- Merged branches are cleaned up lazily during status checks and submit operations.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## 4. Conflict Resolution
|
|
130
|
+
|
|
131
|
+
### 4.1 How Conflicts Are Minimized
|
|
132
|
+
|
|
133
|
+
Contentrain's storage format is designed to minimize Git merge conflicts:
|
|
134
|
+
|
|
135
|
+
- **Object-map storage** for collections: each entry is a separate key-value pair. Two branches adding different entries rarely conflict.
|
|
136
|
+
- **Canonical serialization**: sorted keys and deterministic formatting prevent artificial diffs.
|
|
137
|
+
- **Review mode for normalize**: separate branches for extraction and reuse reduce concurrent editing conflicts.
|
|
138
|
+
|
|
139
|
+
### 4.2 When Conflicts Occur
|
|
140
|
+
|
|
141
|
+
| Scenario | Likelihood | Resolution |
|
|
142
|
+
|----------|-----------|------------|
|
|
143
|
+
| Different fields on the same entry | Low | Auto-merge succeeds (JSON field-level merge) |
|
|
144
|
+
| Same field changed by two branches | Medium | Studio conflict resolution UI |
|
|
145
|
+
| Two entries added with adjacent IDs | Very low | Auto-merge usually succeeds |
|
|
146
|
+
| Concurrent normalize operations | Avoided | Always review mode, sequential per model |
|
|
147
|
+
|
|
148
|
+
### 4.3 Conflict Resolution Rules
|
|
149
|
+
|
|
150
|
+
- Field-level merge for JSON: if the same entry has different fields changed in two branches, Git auto-merges.
|
|
151
|
+
- Same field changed by multiple branches creates a conflict requiring Studio resolution.
|
|
152
|
+
- When a conflict occurs, the agent should NOT attempt to resolve it. Inform the user and direct them to Studio.
|
|
153
|
+
- Collection object-map format with sorted keys means ~0.3% chance of conflict for two new entries in a 350-entry collection.
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## 5. Workflow States
|
|
158
|
+
|
|
159
|
+
Content entries move through these states:
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
draft --> in_review --> published
|
|
163
|
+
|
|
|
164
|
+
v
|
|
165
|
+
rejected (with feedback)
|
|
166
|
+
|
|
167
|
+
published --> archived
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### 5.1 State Definitions
|
|
171
|
+
|
|
172
|
+
| State | Git State | Trigger |
|
|
173
|
+
|-------|-----------|---------|
|
|
174
|
+
| `draft` | Branch exists, not yet reviewed/merged | Content created or updated |
|
|
175
|
+
| `in_review` | PR/branch open, labeled `contentrain-content` | `contentrain_submit` in review mode |
|
|
176
|
+
| `published` | Content is on `contentrain` branch and synced to baseBranch | Auto-merge, or PR merged after review |
|
|
177
|
+
| `rejected` | PR closed without merge | Studio reviewer rejects changes |
|
|
178
|
+
| `archived` | Metadata-only state | Manual action -- content hidden but retained |
|
|
179
|
+
|
|
180
|
+
### 5.2 State Rules
|
|
181
|
+
|
|
182
|
+
- **State is tracked in `.contentrain/meta/`, NOT in content files.** Agents never read or write state directly.
|
|
183
|
+
- **auto-merge mode:** `draft` --> `published` (no `in_review` step).
|
|
184
|
+
- **review mode:** `draft` --> `in_review` --> `published` or `rejected`.
|
|
185
|
+
- **Git is the source of truth.** States are derived from Git state (branch existence, merge status, PR status).
|
|
186
|
+
- Rejected content includes reviewer feedback. The agent can address feedback and resubmit.
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## 6. Validation Rules
|
|
191
|
+
|
|
192
|
+
### 6.1 When to Validate
|
|
193
|
+
|
|
194
|
+
- ALWAYS call `contentrain_validate` before `contentrain_submit`.
|
|
195
|
+
- `contentrain_submit` will fail if validation errors exist.
|
|
196
|
+
- Run validation after completing all changes in a batch, not after every individual save.
|
|
197
|
+
|
|
198
|
+
### 6.2 What Validation Checks
|
|
199
|
+
|
|
200
|
+
| Check | Severity | Description |
|
|
201
|
+
|-------|----------|-------------|
|
|
202
|
+
| Schema compliance | Error | Field values match their type definitions |
|
|
203
|
+
| Required fields | Error | All `required: true` fields have values |
|
|
204
|
+
| Unique constraints | Error | `unique: true` fields have no duplicates within the model |
|
|
205
|
+
| Locale completeness | Error/Warning | All supported locales have corresponding files and entries |
|
|
206
|
+
| Referential integrity | Error | Relation targets (IDs/slugs) exist in the target model |
|
|
207
|
+
| Canonical format | Warning | Files follow canonical serialization rules |
|
|
208
|
+
| Vocabulary usage | Warning | Content uses vocabulary terms when available |
|
|
209
|
+
|
|
210
|
+
### 6.3 Handling Validation Results
|
|
211
|
+
|
|
212
|
+
- **Errors:** MUST be fixed before submitting. Fix the content and re-validate.
|
|
213
|
+
- **Warnings:** Acceptable but should be addressed when possible. Acknowledge them before submitting.
|
|
214
|
+
- If validation returns zero errors, proceed with `contentrain_submit`.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## 7. Submit Behavior
|
|
219
|
+
|
|
220
|
+
### 7.1 auto-merge Mode
|
|
221
|
+
|
|
222
|
+
```
|
|
223
|
+
contentrain_submit
|
|
224
|
+
--> Merge feature branch into contentrain
|
|
225
|
+
--> Advance baseBranch via update-ref (fast-forward)
|
|
226
|
+
--> Selectively sync .contentrain/ files to developer's working tree
|
|
227
|
+
--> Clean up worktree
|
|
228
|
+
--> Status: published
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### 7.2 review Mode
|
|
232
|
+
|
|
233
|
+
```
|
|
234
|
+
contentrain_submit
|
|
235
|
+
--> Push feature branch to remote
|
|
236
|
+
--> Clean up worktree
|
|
237
|
+
--> Status: in_review
|
|
238
|
+
--> Studio notifies reviewers
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### 7.3 Submit Rules
|
|
242
|
+
|
|
243
|
+
- Submit operates on the current pending branch. There must be pending changes.
|
|
244
|
+
- If no changes are pending, submit is a no-op.
|
|
245
|
+
- After submit, the agent can continue with other operations (new branch will be created for new changes).
|
|
246
|
+
- Normalize operations ALWAYS submit in review mode, regardless of project workflow setting.
|
|
247
|
+
|
|
248
|
+
### 7.4 Branch Merge Mechanisms
|
|
249
|
+
|
|
250
|
+
Review-mode branches can be merged three ways:
|
|
251
|
+
|
|
252
|
+
**1. CLI Serve UI (Browser — recommended for normalize)**
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
contentrain serve
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Navigate to http://localhost:3333/branches → select branch → click Merge.
|
|
259
|
+
|
|
260
|
+
**2. MCP Tool (Programmatic — for agent-driven workflows)**
|
|
261
|
+
|
|
262
|
+
```
|
|
263
|
+
contentrain_merge(branch: "cr/normalize/extract/...", confirm: true)
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Local git merge: feature → contentrain → update-ref → selective sync.
|
|
267
|
+
No external platform required. Agent can continue immediately.
|
|
268
|
+
|
|
269
|
+
**3. Git Platform (GitHub/GitLab — for team governance)**
|
|
270
|
+
|
|
271
|
+
```
|
|
272
|
+
contentrain_submit # pushes to remote
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Then create PR on platform → review → merge.
|
|
276
|
+
|
|
277
|
+
**Agent Decision Guide:**
|
|
278
|
+
|
|
279
|
+
| Workflow | Recommended Merge Method |
|
|
280
|
+
|----------|--------------------------|
|
|
281
|
+
| Normalize (extract/reuse) | CLI serve UI (visual review of content) |
|
|
282
|
+
| Content CRUD | `contentrain_merge` (programmatic, fast) |
|
|
283
|
+
| Team with code review | Git platform PR |
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## 8. Metadata Structure
|
|
288
|
+
|
|
289
|
+
Metadata files track governance information. They are system-managed -- agents NEVER write to them.
|
|
290
|
+
|
|
291
|
+
### File Paths
|
|
292
|
+
|
|
293
|
+
| Kind | Path |
|
|
294
|
+
|------|------|
|
|
295
|
+
| Singleton / Dictionary | `.contentrain/meta/{modelId}/{locale}.json` |
|
|
296
|
+
| Collection | `.contentrain/meta/{modelId}/{locale}.json` (object-map: `{ entryId: meta }`) |
|
|
297
|
+
| Document | `.contentrain/meta/{modelId}/{slug}/{locale}.json` |
|
|
298
|
+
|
|
299
|
+
### Metadata Fields
|
|
300
|
+
|
|
301
|
+
```json
|
|
302
|
+
{
|
|
303
|
+
"status": "published",
|
|
304
|
+
"source": "agent",
|
|
305
|
+
"updated_by": "claude",
|
|
306
|
+
"approved_by": "ahmet@contentrain.io",
|
|
307
|
+
"version": "1"
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
| Field | Values | Description |
|
|
312
|
+
|-------|--------|-------------|
|
|
313
|
+
| `status` | `draft`, `in_review`, `published`, `rejected`, `archived` | Current workflow state |
|
|
314
|
+
| `source` | `agent`, `human`, `import` | How the content was created |
|
|
315
|
+
| `updated_by` | string | Agent name or user email |
|
|
316
|
+
| `approved_by` | string or null | Who approved (review mode only) |
|
|
317
|
+
| `version` | string | Content version identifier |
|