@contentrain/rules 0.1.0 → 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 +3 -0
- package/ide/claude-code/rules/contentrain-accessibility-rules.md +155 -0
- package/ide/claude-code/rules/contentrain-content-conventions.md +314 -0
- package/ide/claude-code/rules/contentrain-content-quality.md +294 -0
- package/ide/claude-code/rules/contentrain-i18n-quality.md +293 -0
- package/ide/claude-code/rules/contentrain-mcp-usage.md +405 -0
- package/ide/claude-code/rules/contentrain-media-rules.md +165 -0
- package/ide/claude-code/rules/contentrain-normalize-rules.md +312 -0
- package/ide/claude-code/rules/contentrain-schema-rules.md +380 -0
- package/ide/claude-code/rules/contentrain-security-rules.md +141 -0
- package/ide/claude-code/rules/contentrain-seo-rules.md +224 -0
- package/ide/claude-code/rules/contentrain-workflow-rules.md +262 -0
- package/ide/cursor/rules/contentrain-accessibility-rules.mdc +160 -0
- package/ide/cursor/rules/contentrain-content-conventions.mdc +319 -0
- package/ide/cursor/rules/contentrain-content-quality.mdc +299 -0
- package/ide/cursor/rules/contentrain-i18n-quality.mdc +298 -0
- package/ide/cursor/rules/contentrain-mcp-usage.mdc +410 -0
- package/ide/cursor/rules/contentrain-media-rules.mdc +170 -0
- package/ide/cursor/rules/contentrain-normalize-rules.mdc +317 -0
- package/ide/cursor/rules/contentrain-schema-rules.mdc +385 -0
- package/ide/cursor/rules/contentrain-security-rules.mdc +146 -0
- package/ide/cursor/rules/contentrain-seo-rules.mdc +229 -0
- package/ide/cursor/rules/contentrain-workflow-rules.mdc +267 -0
- package/ide/windsurf/rules/contentrain-accessibility-rules.md +160 -0
- package/ide/windsurf/rules/contentrain-content-conventions.md +319 -0
- package/ide/windsurf/rules/contentrain-content-quality.md +299 -0
- package/ide/windsurf/rules/contentrain-i18n-quality.md +298 -0
- package/ide/windsurf/rules/contentrain-mcp-usage.md +410 -0
- package/ide/windsurf/rules/contentrain-media-rules.md +170 -0
- package/ide/windsurf/rules/contentrain-normalize-rules.md +317 -0
- package/ide/windsurf/rules/contentrain-schema-rules.md +385 -0
- package/ide/windsurf/rules/contentrain-security-rules.md +146 -0
- package/ide/windsurf/rules/contentrain-seo-rules.md +229 -0
- package/ide/windsurf/rules/contentrain-workflow-rules.md +267 -0
- package/package.json +4 -4
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Security Rules
|
|
2
|
+
|
|
3
|
+
These rules are MANDATORY for all AI agents creating or editing content in Contentrain projects.
|
|
4
|
+
Content that violates these rules MUST be rejected. These rules protect against XSS, data leaks, and injection attacks.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## XSS Prevention in Content
|
|
9
|
+
|
|
10
|
+
1. `richtext` and `markdown` fields MUST NOT contain any of the following:
|
|
11
|
+
- `<script>` or `</script>` tags
|
|
12
|
+
- `javascript:` protocol in any attribute value
|
|
13
|
+
- Event handler attributes: `onerror`, `onload`, `onclick`, `onmouseover`, `onfocus`, `onblur`, `onsubmit`, `onchange`, `onkeydown`, `onkeyup`, `onkeypress`, `ondblclick`, `onmousedown`, `onmouseup`, `onmousemove`, `onmouseout`, `oncontextmenu`, `ondrag`, `ondrop`, `onpaste`, `oninput`
|
|
14
|
+
- `<iframe>`, `<embed>`, `<object>`, `<applet>`, `<form>`, `<input>`, `<textarea>`, `<select>`, `<button>` tags
|
|
15
|
+
- `data:` URIs containing executable content (e.g., `data:text/html`, `data:application/javascript`)
|
|
16
|
+
- CSS expressions: `expression()`, `url(javascript:)`, `-moz-binding`
|
|
17
|
+
- `<base>` tag (can redirect all relative URLs)
|
|
18
|
+
- `<meta>` tag with `http-equiv="refresh"`
|
|
19
|
+
- `<svg>` with embedded scripts or event handlers
|
|
20
|
+
|
|
21
|
+
2. **Allowed HTML tags** in richtext fields:
|
|
22
|
+
```
|
|
23
|
+
p, strong, em, a, ul, ol, li, h2, h3, h4, h5, h6,
|
|
24
|
+
blockquote, code, pre, img, br, hr,
|
|
25
|
+
table, thead, tbody, tr, th, td,
|
|
26
|
+
del, ins, sup, sub, abbr, mark, details, summary
|
|
27
|
+
```
|
|
28
|
+
Any tag not on this list MUST be stripped or rejected.
|
|
29
|
+
|
|
30
|
+
3. **Allowed attributes on `<a>` tags**: `href`, `title`, `target`.
|
|
31
|
+
- `href` MUST use `http://`, `https://`, or `mailto:` protocol only.
|
|
32
|
+
- `target` MUST be `_blank` or `_self` only.
|
|
33
|
+
- When `target="_blank"`, the frontend should add `rel="noopener noreferrer"` — but the content itself must not rely on this.
|
|
34
|
+
|
|
35
|
+
4. **Allowed attributes on `<img>` tags**: `src`, `alt`, `width`, `height`.
|
|
36
|
+
- `src` MUST use `https://`, `http://`, or a relative path starting with `/` or `./`.
|
|
37
|
+
- No `data:` URIs for `src` in production content.
|
|
38
|
+
|
|
39
|
+
5. Strip or reject all other HTML attributes not explicitly allowed above.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Secret Detection
|
|
44
|
+
|
|
45
|
+
1. NEVER include any of the following in ANY content field:
|
|
46
|
+
- **API keys**: patterns matching `sk-`, `pk_`, `sk_live_`, `sk_test_`, `api_key=`, `apiKey:`, `x-api-key`
|
|
47
|
+
- **Access tokens**: JWT tokens (`eyJ...`), Bearer tokens, OAuth tokens, session tokens
|
|
48
|
+
- **Passwords or credentials**: any field value resembling `password=`, `passwd:`, `secret=`
|
|
49
|
+
- **Private keys**: `-----BEGIN RSA PRIVATE KEY-----`, `-----BEGIN OPENSSH PRIVATE KEY-----`, `-----BEGIN PGP PRIVATE KEY BLOCK-----`, or similar PEM blocks
|
|
50
|
+
- **Database connection strings**: `mongodb://`, `postgres://`, `mysql://`, `redis://` with credentials
|
|
51
|
+
- **Cloud credentials**: AWS (`AKIA...`), GCP (`AIza...`), Azure storage keys
|
|
52
|
+
- **Webhook URLs with tokens**: URLs containing `token=`, `secret=`, or `/hooks/` with embedded credentials
|
|
53
|
+
|
|
54
|
+
2. If a field value matches any secret pattern, **reject the value** and warn the user: `"This value appears to contain a secret or credential. Secrets must not be stored in content fields."`
|
|
55
|
+
|
|
56
|
+
3. Environment-specific values (API endpoints, service IDs) SHOULD use placeholder references (e.g., `{{API_URL}}`) or be stored in environment configuration, not hardcoded in content.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## PII Handling
|
|
61
|
+
|
|
62
|
+
1. **Flag** when email addresses appear in fields that are not typed as `email`. The agent should warn: `"Email address detected in a non-email field. Confirm this is intentional."`
|
|
63
|
+
|
|
64
|
+
2. **Flag** when phone numbers appear in fields that are not typed as `phone`.
|
|
65
|
+
|
|
66
|
+
3. **Flag** physical addresses, government ID numbers (SSN, national ID), and dates of birth when they appear in generic `string` or `richtext` fields.
|
|
67
|
+
|
|
68
|
+
4. User-generated content fields SHOULD be marked for frontend sanitization in the model metadata.
|
|
69
|
+
|
|
70
|
+
5. NEVER store authentication credentials (usernames, passwords, tokens) in content fields.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## URL Validation
|
|
75
|
+
|
|
76
|
+
1. All URLs in `url` type fields MUST use `https://` protocol.
|
|
77
|
+
- **Exception**: `http://localhost` and `http://127.0.0.1` URLs are allowed for development references.
|
|
78
|
+
|
|
79
|
+
2. Reject URLs containing path traversal sequences: `../`, `..\\`, `%2e%2e/`, `%2e%2e%5c`.
|
|
80
|
+
|
|
81
|
+
3. URLs MUST have a valid format: protocol + domain + valid TLD. Reject malformed URLs.
|
|
82
|
+
|
|
83
|
+
4. Do not use IP-based URLs in production content. Use domain names.
|
|
84
|
+
- **Exception**: private/internal documentation that explicitly references infrastructure IPs.
|
|
85
|
+
|
|
86
|
+
5. Reject `file://` protocol URLs. Content must never reference local filesystem paths as URLs.
|
|
87
|
+
|
|
88
|
+
6. Reject `ftp://` protocol URLs unless the content model explicitly documents FTP support.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## File & Media Security
|
|
93
|
+
|
|
94
|
+
1. Media paths MUST be relative to the `assets_path` defined in `config.json`. Never use absolute filesystem paths.
|
|
95
|
+
|
|
96
|
+
2. Reject any file path containing:
|
|
97
|
+
- Absolute system paths: `/etc/`, `/usr/`, `/var/`, `C:\\`, `C:/`, `/Users/`, `/home/`
|
|
98
|
+
- Path traversal: `../`, `..\\`, `%2e%2e`
|
|
99
|
+
|
|
100
|
+
3. Validate file extensions match the field type:
|
|
101
|
+
- `image` fields: `.webp`, `.png`, `.jpg`, `.jpeg`, `.gif`, `.svg`, `.avif`
|
|
102
|
+
- `video` fields: `.mp4`, `.webm`, `.ogg`
|
|
103
|
+
- `file` fields: any extension, but **flag executables** and warn the user: `.exe`, `.sh`, `.bat`, `.cmd`, `.ps1`, `.msi`, `.dmg`, `.app`, `.jar`, `.dll`, `.so`
|
|
104
|
+
|
|
105
|
+
4. File names MUST NOT contain spaces or special characters. Only alphanumeric characters, hyphens (`-`), underscores (`_`), and dots (`.`) are allowed.
|
|
106
|
+
|
|
107
|
+
5. Reject files with double extensions that disguise executables: `report.pdf.exe`, `image.jpg.sh`.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Content Injection
|
|
112
|
+
|
|
113
|
+
1. Values in `object` and `array` type fields MUST be valid JSON. Reject values with:
|
|
114
|
+
- Trailing commas
|
|
115
|
+
- JavaScript comments (`//`, `/* */`)
|
|
116
|
+
- Unquoted keys
|
|
117
|
+
- Single-quoted strings
|
|
118
|
+
- Executable code patterns (function declarations, `eval()`, `require()`, `import()`)
|
|
119
|
+
|
|
120
|
+
2. `code` type fields are displayed as code and never executed, but still apply these rules:
|
|
121
|
+
- No embedded secrets (see Secret Detection above)
|
|
122
|
+
- Content is stored as-is — no sanitization needed beyond secret detection
|
|
123
|
+
|
|
124
|
+
3. Template literals and interpolation patterns (`${...}`, `{{...}}`, `{%...%}`) in content fields MUST be intentional. Flag unexpected template syntax in plain text fields.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Markdown-Specific
|
|
129
|
+
|
|
130
|
+
1. Fenced code blocks (`` ``` ``) are rendered as code, not executed. They are safe from an execution standpoint but still subject to secret detection rules.
|
|
131
|
+
|
|
132
|
+
2. Raw HTML embedded in markdown MUST follow the same XSS rules as richtext fields. Apply the allowed-tags whitelist.
|
|
133
|
+
|
|
134
|
+
3. Link destinations in markdown (`[text](url)`) MUST use `http://`, `https://`, or `mailto:` protocol only. Reject `javascript:`, `data:`, `vbscript:`, and `file:` protocols.
|
|
135
|
+
|
|
136
|
+
4. Image sources in markdown (``) MUST use valid paths:
|
|
137
|
+
- No path traversal (`../`)
|
|
138
|
+
- Valid image extensions (`.webp`, `.png`, `.jpg`, `.jpeg`, `.gif`, `.svg`, `.avif`)
|
|
139
|
+
- `https://` for external images, relative paths for local images
|
|
140
|
+
|
|
141
|
+
5. Do not allow HTML comments (`<!-- -->`) to hide content in markdown — they may be rendered in some parsers and can be used to smuggle payloads.
|
|
@@ -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,262 @@
|
|
|
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
|
+
- Branch is created, changes are committed, branch is **automatically merged to main**.
|
|
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 Worktree-Based Transactions
|
|
71
|
+
|
|
72
|
+
Every write operation follows this flow:
|
|
73
|
+
|
|
74
|
+
1. MCP creates a **Git worktree** on a new branch.
|
|
75
|
+
2. Changes are made in the worktree (content files, model files).
|
|
76
|
+
3. Changes are committed to the branch.
|
|
77
|
+
4. **auto-merge mode:** Branch is merged to main. Worktree is cleaned up.
|
|
78
|
+
5. **review mode:** Branch is pushed to remote. Worktree is cleaned up. Studio notifies reviewers.
|
|
79
|
+
|
|
80
|
+
### 3.2 Critical Rules
|
|
81
|
+
|
|
82
|
+
- **NEVER commit directly to main.** All changes go through branches.
|
|
83
|
+
- **NEVER create branches manually.** MCP tools handle all Git operations.
|
|
84
|
+
- **NEVER force-push or rebase** Contentrain branches.
|
|
85
|
+
- Worktrees are temporary. They are created for the operation and cleaned up afterward.
|
|
86
|
+
- Each branch contains a cohesive set of changes (e.g., all entries for one model update).
|
|
87
|
+
|
|
88
|
+
### 3.3 Branch Lifecycle
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
Created (worktree) --> Committed --> Merged/Pushed --> Cleaned up
|
|
92
|
+
|
|
|
93
|
+
v
|
|
94
|
+
auto-merge: merged to main
|
|
95
|
+
review: pushed to remote, awaiting review
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Merged branches are retained for `branchRetention` days (default: 30) for audit trail, then pruned.
|
|
99
|
+
|
|
100
|
+
### 3.4 Branch Health
|
|
101
|
+
|
|
102
|
+
MCP enforces branch health limits to prevent branch accumulation:
|
|
103
|
+
|
|
104
|
+
- **50+ active branches**: Warning. Operations continue but the user is alerted.
|
|
105
|
+
- **80+ active branches**: Blocked. No new write operations until branches are merged or deleted.
|
|
106
|
+
- `contentrain_status` reports branch health automatically (total, merged, unmerged counts).
|
|
107
|
+
- Merged branches are cleaned up lazily during status checks and submit operations.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## 4. Conflict Resolution
|
|
112
|
+
|
|
113
|
+
### 4.1 How Conflicts Are Minimized
|
|
114
|
+
|
|
115
|
+
Contentrain's storage format is designed to minimize Git merge conflicts:
|
|
116
|
+
|
|
117
|
+
- **Object-map storage** for collections: each entry is a separate key-value pair. Two branches adding different entries rarely conflict.
|
|
118
|
+
- **Canonical serialization**: sorted keys and deterministic formatting prevent artificial diffs.
|
|
119
|
+
- **Review mode for normalize**: separate branches for extraction and reuse reduce concurrent editing conflicts.
|
|
120
|
+
|
|
121
|
+
### 4.2 When Conflicts Occur
|
|
122
|
+
|
|
123
|
+
| Scenario | Likelihood | Resolution |
|
|
124
|
+
|----------|-----------|------------|
|
|
125
|
+
| Different fields on the same entry | Low | Auto-merge succeeds (JSON field-level merge) |
|
|
126
|
+
| Same field changed by two branches | Medium | Studio conflict resolution UI |
|
|
127
|
+
| Two entries added with adjacent IDs | Very low | Auto-merge usually succeeds |
|
|
128
|
+
| Concurrent normalize operations | Avoided | Always review mode, sequential per model |
|
|
129
|
+
|
|
130
|
+
### 4.3 Conflict Resolution Rules
|
|
131
|
+
|
|
132
|
+
- Field-level merge for JSON: if the same entry has different fields changed in two branches, Git auto-merges.
|
|
133
|
+
- Same field changed by multiple branches creates a conflict requiring Studio resolution.
|
|
134
|
+
- When a conflict occurs, the agent should NOT attempt to resolve it. Inform the user and direct them to Studio.
|
|
135
|
+
- Collection object-map format with sorted keys means ~0.3% chance of conflict for two new entries in a 350-entry collection.
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## 5. Workflow States
|
|
140
|
+
|
|
141
|
+
Content entries move through these states:
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
draft --> in_review --> published
|
|
145
|
+
|
|
|
146
|
+
v
|
|
147
|
+
rejected (with feedback)
|
|
148
|
+
|
|
149
|
+
published --> archived
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### 5.1 State Definitions
|
|
153
|
+
|
|
154
|
+
| State | Git State | Trigger |
|
|
155
|
+
|-------|-----------|---------|
|
|
156
|
+
| `draft` | Branch exists, not yet reviewed/merged | Content created or updated |
|
|
157
|
+
| `in_review` | PR/branch open, labeled `contentrain-content` | `contentrain_submit` in review mode |
|
|
158
|
+
| `published` | Content is on main branch | Auto-merge, or PR merged after review |
|
|
159
|
+
| `rejected` | PR closed without merge | Studio reviewer rejects changes |
|
|
160
|
+
| `archived` | Metadata-only state | Manual action -- content hidden but retained |
|
|
161
|
+
|
|
162
|
+
### 5.2 State Rules
|
|
163
|
+
|
|
164
|
+
- **State is tracked in `.contentrain/meta/`, NOT in content files.** Agents never read or write state directly.
|
|
165
|
+
- **auto-merge mode:** `draft` --> `published` (no `in_review` step).
|
|
166
|
+
- **review mode:** `draft` --> `in_review` --> `published` or `rejected`.
|
|
167
|
+
- **Git is the source of truth.** States are derived from Git state (branch existence, merge status, PR status).
|
|
168
|
+
- Rejected content includes reviewer feedback. The agent can address feedback and resubmit.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## 6. Validation Rules
|
|
173
|
+
|
|
174
|
+
### 6.1 When to Validate
|
|
175
|
+
|
|
176
|
+
- ALWAYS call `contentrain_validate` before `contentrain_submit`.
|
|
177
|
+
- `contentrain_submit` will fail if validation errors exist.
|
|
178
|
+
- Run validation after completing all changes in a batch, not after every individual save.
|
|
179
|
+
|
|
180
|
+
### 6.2 What Validation Checks
|
|
181
|
+
|
|
182
|
+
| Check | Severity | Description |
|
|
183
|
+
|-------|----------|-------------|
|
|
184
|
+
| Schema compliance | Error | Field values match their type definitions |
|
|
185
|
+
| Required fields | Error | All `required: true` fields have values |
|
|
186
|
+
| Unique constraints | Error | `unique: true` fields have no duplicates within the model |
|
|
187
|
+
| Locale completeness | Error/Warning | All supported locales have corresponding files and entries |
|
|
188
|
+
| Referential integrity | Error | Relation targets (IDs/slugs) exist in the target model |
|
|
189
|
+
| Canonical format | Warning | Files follow canonical serialization rules |
|
|
190
|
+
| Vocabulary usage | Warning | Content uses vocabulary terms when available |
|
|
191
|
+
|
|
192
|
+
### 6.3 Handling Validation Results
|
|
193
|
+
|
|
194
|
+
- **Errors:** MUST be fixed before submitting. Fix the content and re-validate.
|
|
195
|
+
- **Warnings:** Acceptable but should be addressed when possible. Acknowledge them before submitting.
|
|
196
|
+
- If validation returns zero errors, proceed with `contentrain_submit`.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## 7. Submit Behavior
|
|
201
|
+
|
|
202
|
+
### 7.1 auto-merge Mode
|
|
203
|
+
|
|
204
|
+
```
|
|
205
|
+
contentrain_submit
|
|
206
|
+
--> Merge branch to main
|
|
207
|
+
--> Update context.json
|
|
208
|
+
--> Clean up worktree
|
|
209
|
+
--> Status: published
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### 7.2 review Mode
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
contentrain_submit
|
|
216
|
+
--> Push branch to remote
|
|
217
|
+
--> Update context.json
|
|
218
|
+
--> Clean up worktree
|
|
219
|
+
--> Status: in_review
|
|
220
|
+
--> Studio notifies reviewers
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### 7.3 Submit Rules
|
|
224
|
+
|
|
225
|
+
- Submit operates on the current pending branch. There must be pending changes.
|
|
226
|
+
- If no changes are pending, submit is a no-op.
|
|
227
|
+
- After submit, the agent can continue with other operations (new branch will be created for new changes).
|
|
228
|
+
- Normalize operations ALWAYS submit in review mode, regardless of project workflow setting.
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## 8. Metadata Structure
|
|
233
|
+
|
|
234
|
+
Metadata files track governance information. They are system-managed -- agents NEVER write to them.
|
|
235
|
+
|
|
236
|
+
### File Paths
|
|
237
|
+
|
|
238
|
+
| Kind | Path |
|
|
239
|
+
|------|------|
|
|
240
|
+
| Singleton / Dictionary | `.contentrain/meta/{modelId}/{locale}.json` |
|
|
241
|
+
| Collection | `.contentrain/meta/{modelId}/{locale}.json` (object-map: `{ entryId: meta }`) |
|
|
242
|
+
| Document | `.contentrain/meta/{modelId}/{slug}/{locale}.json` |
|
|
243
|
+
|
|
244
|
+
### Metadata Fields
|
|
245
|
+
|
|
246
|
+
```json
|
|
247
|
+
{
|
|
248
|
+
"status": "published",
|
|
249
|
+
"source": "agent",
|
|
250
|
+
"updated_by": "claude",
|
|
251
|
+
"approved_by": "ahmet@contentrain.io",
|
|
252
|
+
"version": "1"
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
| Field | Values | Description |
|
|
257
|
+
|-------|--------|-------------|
|
|
258
|
+
| `status` | `draft`, `in_review`, `published`, `rejected`, `archived` | Current workflow state |
|
|
259
|
+
| `source` | `agent`, `human`, `import` | How the content was created |
|
|
260
|
+
| `updated_by` | string | Agent name or user email |
|
|
261
|
+
| `approved_by` | string or null | Who approved (review mode only) |
|
|
262
|
+
| `version` | string | Content version identifier |
|