@contentrain/skills 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,71 @@
1
+ # Contentrain + React + Vite
2
+
3
+ > Framework guide for consuming the generated Contentrain client in a React SPA.
4
+
5
+ ---
6
+
7
+ ## 1. Setup
8
+
9
+ ```bash
10
+ pnpm add @contentrain/query
11
+ npx contentrain generate
12
+ ```
13
+
14
+ Restart Vite after the first generation so `#contentrain` imports resolve.
15
+
16
+ ---
17
+
18
+ ## 2. Component Usage
19
+
20
+ In a React SPA, import directly from `#contentrain`:
21
+
22
+ ```tsx
23
+ import { query, singleton, dictionary } from '#contentrain'
24
+
25
+ export function HomePage() {
26
+ const hero = singleton('hero').locale('en').get()
27
+ const labels = dictionary('ui-labels').locale('en').get()
28
+ const posts = query('blog-post').locale('en').all()
29
+
30
+ return (
31
+ <main>
32
+ <h1>{hero.title}</h1>
33
+ <button>{labels.cta_primary}</button>
34
+ <ul>
35
+ {posts.map(post => (
36
+ <li key={post.id}>{post.title}</li>
37
+ ))}
38
+ </ul>
39
+ </main>
40
+ )
41
+ }
42
+ ```
43
+
44
+ Rules:
45
+
46
+ - queries are synchronous
47
+ - no `await query(...)`
48
+ - regenerated client data ships with the app bundle
49
+
50
+ ### Relations
51
+
52
+ ```tsx
53
+ const posts = query('blog-post').locale('en').include('author').all()
54
+ ```
55
+
56
+ ### Documents
57
+
58
+ ```tsx
59
+ import { document } from '#contentrain'
60
+
61
+ const doc = document('doc-page').locale('en').bySlug('introduction')
62
+ ```
63
+
64
+ ---
65
+
66
+ ## 3. Best Fit
67
+
68
+ Use this guide for client-rendered React apps.
69
+
70
+ For Next.js App Router projects, use the dedicated Next guide instead.
71
+
@@ -0,0 +1,324 @@
1
+ # Contentrain + SvelteKit
2
+
3
+ > Framework guide for consuming Contentrain-managed content in SvelteKit applications.
4
+
5
+ ---
6
+
7
+ ## 1. Setup
8
+
9
+ ### 1.1 SDK Installation
10
+
11
+ ```bash
12
+ pnpm add @contentrain/query # or npm/yarn
13
+ npx contentrain generate
14
+ ```
15
+
16
+ The generator reads `.contentrain/models/` and produces a typed client in `.contentrain/client/`. Your `package.json` must include the subpath import:
17
+
18
+ ```json
19
+ {
20
+ "imports": {
21
+ "#contentrain": {
22
+ "types": "./.contentrain/client/index.d.ts",
23
+ "import": "./.contentrain/client/index.mjs",
24
+ "require": "./.contentrain/client/index.cjs",
25
+ "default": "./.contentrain/client/index.mjs"
26
+ }
27
+ }
28
+ }
29
+ ```
30
+
31
+ The generator adds this automatically. Restart the SvelteKit dev server after initial generation.
32
+
33
+ ### 1.2 Watch Mode
34
+
35
+ Run the generator alongside SvelteKit dev:
36
+
37
+ ```bash
38
+ npx contentrain generate --watch &
39
+ npx vite dev
40
+ ```
41
+
42
+ ---
43
+
44
+ ## 2. Imports
45
+
46
+ All SDK functions are imported from the `#contentrain` subpath:
47
+
48
+ ```ts
49
+ import { query, singleton, dictionary, document } from '#contentrain'
50
+ ```
51
+
52
+ This import works in server load functions (`+page.server.ts`, `+layout.server.ts`), API routes (`+server.ts`), and any server-side module. The SDK reads JSON files from the file system — no runtime API calls.
53
+
54
+ ---
55
+
56
+ ## 3. Querying Content
57
+
58
+ ### 3.1 Collections
59
+
60
+ ```ts
61
+ const posts = query('blog-post').locale('en').all()
62
+ const featured = query('blog-post').locale('en').where('featured', true).all()
63
+ const sorted = query('blog-post').locale('en').sort('publishedAt', 'desc').all()
64
+ const post = query('blog-post').locale('en').where('id', 'abc-123').first()
65
+ ```
66
+
67
+ ### 3.2 Singletons
68
+
69
+ ```ts
70
+ const hero = singleton('hero').locale('en').get()
71
+ ```
72
+
73
+ ### 3.3 Dictionaries
74
+
75
+ ```ts
76
+ const label = dictionary('ui-labels').locale('en').get('submit_button')
77
+ const allLabels = dictionary('ui-labels').locale('en').get()
78
+ ```
79
+
80
+ ### 3.4 Documents
81
+
82
+ ```ts
83
+ const article = document('blog-article').locale('en').bySlug('getting-started')
84
+ ```
85
+
86
+ ### 3.5 Relations
87
+
88
+ ```ts
89
+ const posts = query('blog-post').locale('en').include('author', 'tags').all()
90
+ // post.author → full author object
91
+ // post.tags → array of full tag objects
92
+ ```
93
+
94
+ ---
95
+
96
+ ## 4. SvelteKit Integration Patterns
97
+
98
+ ### 4.1 Server Load Functions
99
+
100
+ Content loading belongs in `+page.server.ts` or `+layout.server.ts`:
101
+
102
+ ```ts
103
+ // src/routes/blog/+page.server.ts
104
+ import { query } from '#contentrain'
105
+ import type { PageServerLoad } from './$types'
106
+
107
+ export const load: PageServerLoad = () => {
108
+ const posts = query('blog-post').locale('en').sort('publishedAt', 'desc').all()
109
+ return { posts }
110
+ }
111
+ ```
112
+
113
+ The corresponding page component receives the data:
114
+
115
+ ```svelte
116
+ <!-- src/routes/blog/+page.svelte -->
117
+ <script lang="ts">
118
+ import type { PageData } from './$types'
119
+ export let data: PageData
120
+ </script>
121
+
122
+ <ul>
123
+ {#each data.posts as post}
124
+ <li><a href="/blog/{post.slug}">{post.title}</a></li>
125
+ {/each}
126
+ </ul>
127
+ ```
128
+
129
+ ### 4.2 Dynamic Routes
130
+
131
+ For `src/routes/blog/[slug]/+page.server.ts`:
132
+
133
+ ```ts
134
+ import { document } from '#contentrain'
135
+ import { error } from '@sveltejs/kit'
136
+ import type { PageServerLoad } from './$types'
137
+
138
+ export const load: PageServerLoad = ({ params }) => {
139
+ const post = document('blog-article').locale('en').bySlug(params.slug)
140
+ if (!post) throw error(404, 'Post not found')
141
+ return { post }
142
+ }
143
+ ```
144
+
145
+ ### 4.3 Layout Data
146
+
147
+ Provide global content (navigation, footer) from a layout load function:
148
+
149
+ ```ts
150
+ // src/routes/+layout.server.ts
151
+ import { singleton, dictionary } from '#contentrain'
152
+ import type { LayoutServerLoad } from './$types'
153
+
154
+ export const load: LayoutServerLoad = () => {
155
+ const nav = singleton('navigation').locale('en').get()
156
+ const footerLabels = dictionary('footer-labels').locale('en').get()
157
+ return { nav, footerLabels }
158
+ }
159
+ ```
160
+
161
+ ### 4.4 API Routes
162
+
163
+ SDK works in SvelteKit API routes:
164
+
165
+ ```ts
166
+ // src/routes/api/posts/+server.ts
167
+ import { query } from '#contentrain'
168
+ import { json } from '@sveltejs/kit'
169
+
170
+ export function GET() {
171
+ const posts = query('blog-post').locale('en').all()
172
+ return json(posts)
173
+ }
174
+ ```
175
+
176
+ ---
177
+
178
+ ## 5. i18n Integration
179
+
180
+ ### 5.1 Locale from Route Parameters
181
+
182
+ For `src/routes/[locale]/blog/+page.server.ts`:
183
+
184
+ ```ts
185
+ import { query } from '#contentrain'
186
+ import type { PageServerLoad } from './$types'
187
+
188
+ export const load: PageServerLoad = ({ params }) => {
189
+ const posts = query('blog-post').locale(params.locale).sort('publishedAt', 'desc').all()
190
+ return { posts, locale: params.locale }
191
+ }
192
+ ```
193
+
194
+ ### 5.2 Locale from locals
195
+
196
+ Set locale in a hook and access it via `locals`:
197
+
198
+ ```ts
199
+ // src/hooks.server.ts
200
+ import type { Handle } from '@sveltejs/kit'
201
+
202
+ export const handle: Handle = ({ event, resolve }) => {
203
+ const locale = event.params.locale ?? 'en'
204
+ event.locals.locale = locale
205
+ return resolve(event)
206
+ }
207
+ ```
208
+
209
+ Then in load functions:
210
+
211
+ ```ts
212
+ export const load: PageServerLoad = ({ locals }) => {
213
+ const posts = query('blog-post').locale(locals.locale).all()
214
+ return { posts }
215
+ }
216
+ ```
217
+
218
+ ### 5.3 With sveltekit-i18n or Paraglide
219
+
220
+ Contentrain dictionaries can supplement i18n libraries. Use `dictionary()` for content-driven strings and the i18n library for app-level translations, or use Contentrain as the single source for all strings.
221
+
222
+ ### 5.4 Dictionary Strings in Components
223
+
224
+ ```svelte
225
+ <script lang="ts">
226
+ import type { PageData } from './$types'
227
+ export let data: PageData
228
+ </script>
229
+
230
+ <button>{data.labels.submit_button}</button>
231
+ <p>{data.labels.welcome_message}</p>
232
+ ```
233
+
234
+ ---
235
+
236
+ ## 6. Markdown and Document Content
237
+
238
+ ### 6.1 Rendering Markdown
239
+
240
+ For document-kind entries with markdown bodies, use `mdsvex` or a markdown renderer:
241
+
242
+ ```svelte
243
+ <script lang="ts">
244
+ import type { PageData } from './$types'
245
+ export let data: PageData
246
+ </script>
247
+
248
+ <article>
249
+ <h1>{data.post.title}</h1>
250
+ {@html data.post.bodyHtml}
251
+ </article>
252
+ ```
253
+
254
+ ### 6.2 mdsvex Integration
255
+
256
+ If using `mdsvex` for `.svelte.md` files, you can point it at Contentrain markdown content or use the SDK to load document metadata and render bodies separately.
257
+
258
+ ---
259
+
260
+ ## 7. Prerendering and Deployment
261
+
262
+ ### 7.1 Static Pages
263
+
264
+ Mark pages for prerendering:
265
+
266
+ ```ts
267
+ // src/routes/blog/+page.server.ts
268
+ export const prerender = true
269
+ ```
270
+
271
+ Or prerender the entire site:
272
+
273
+ ```ts
274
+ // src/routes/+layout.server.ts
275
+ export const prerender = true
276
+ ```
277
+
278
+ ### 7.2 Entry Generator
279
+
280
+ For dynamic routes, provide all possible parameter values:
281
+
282
+ ```ts
283
+ // src/routes/blog/[slug]/+page.server.ts
284
+ import { query } from '#contentrain'
285
+
286
+ export const prerender = true
287
+
288
+ export function entries() {
289
+ const posts = query('blog-post').locale('en').all()
290
+ return posts.map(post => ({ slug: post.slug }))
291
+ }
292
+ ```
293
+
294
+ ### 7.3 Build and Deploy
295
+
296
+ ```bash
297
+ npx vite build
298
+ ```
299
+
300
+ Use the appropriate SvelteKit adapter for your platform (`adapter-static`, `adapter-vercel`, `adapter-netlify`, `adapter-cloudflare`).
301
+
302
+ ### 7.4 Deployment Flow
303
+
304
+ 1. Content changes are committed to Git via MCP tools.
305
+ 2. Push triggers platform rebuild.
306
+ 3. `vite build` runs, SDK reads `.contentrain/` content.
307
+ 4. Static or server output is produced with embedded content.
308
+
309
+ ---
310
+
311
+ ## 8. Type Safety
312
+
313
+ The generated client provides full TypeScript types:
314
+
315
+ ```ts
316
+ import { query } from '#contentrain'
317
+
318
+ // Fully typed — autocomplete for all fields
319
+ const posts = query('blog-post').locale('en').all()
320
+ posts[0].title // string
321
+ posts[0].author // Author type when using .include('author')
322
+ ```
323
+
324
+ Keep the generator running in watch mode during development to stay in sync with model changes.
@@ -0,0 +1,76 @@
1
+ # Contentrain + Vue 3 + Vite
2
+
3
+ > Framework guide for consuming the generated Contentrain client in a Vue SPA.
4
+
5
+ ---
6
+
7
+ ## 1. Setup
8
+
9
+ ```bash
10
+ pnpm add @contentrain/query
11
+ npx contentrain generate
12
+ ```
13
+
14
+ Restart the Vite dev server after the first generate.
15
+
16
+ The generated `#contentrain` import resolves to the ESM client under `.contentrain/client/index.mjs`.
17
+
18
+ ---
19
+
20
+ ## 2. SFC Usage
21
+
22
+ In a Vue SPA, direct SFC imports are valid:
23
+
24
+ ```vue
25
+ <script setup lang="ts">
26
+ import { query, singleton, dictionary } from '#contentrain'
27
+
28
+ const hero = singleton('hero').locale('en').get()
29
+ const labels = dictionary('ui-labels').locale('en').get()
30
+ const posts = query('blog-post').locale('en').sort('publishedAt', 'desc').all()
31
+ </script>
32
+
33
+ <template>
34
+ <main>
35
+ <h1>{{ hero.title }}</h1>
36
+ <button>{{ labels.cta_primary }}</button>
37
+
38
+ <ul>
39
+ <li v-for="post in posts" :key="post.id">{{ post.title }}</li>
40
+ </ul>
41
+ </main>
42
+ </template>
43
+ ```
44
+
45
+ Rules:
46
+
47
+ - queries are synchronous
48
+ - content is bundled as static generated modules
49
+ - re-run `contentrain generate` after model/content changes
50
+
51
+ ### Relations
52
+
53
+ ```ts
54
+ const posts = query('blog-post').locale('en').include('author', 'tags').all()
55
+ ```
56
+
57
+ ### Documents
58
+
59
+ ```ts
60
+ import { document } from '#contentrain'
61
+
62
+ const article = document('blog-article').locale('en').bySlug('getting-started')
63
+ ```
64
+
65
+ ---
66
+
67
+ ## 3. Best Fit
68
+
69
+ Use this pattern for:
70
+
71
+ - marketing SPAs
72
+ - dashboard/admin SPAs
73
+ - static Vite sites
74
+
75
+ For Nuxt SSR/hybrid projects, use the dedicated Nuxt guide instead.
76
+
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@contentrain/skills",
3
+ "version": "0.1.0",
4
+ "license": "MIT",
5
+ "description": "AI agent skills for Contentrain — workflow procedures, framework integration guides",
6
+ "type": "module",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/contentrain/contentrain-ai.git",
10
+ "directory": "packages/skills"
11
+ },
12
+ "homepage": "https://github.com/contentrain/contentrain-ai/tree/main/packages/skills",
13
+ "bugs": {
14
+ "url": "https://github.com/contentrain/contentrain-ai/issues"
15
+ },
16
+ "keywords": [
17
+ "contentrain",
18
+ "ai",
19
+ "skills",
20
+ "mcp",
21
+ "workflow",
22
+ "vue",
23
+ "react",
24
+ "nuxt",
25
+ "nextjs",
26
+ "astro",
27
+ "sveltekit",
28
+ "expo",
29
+ "react-native",
30
+ "nodejs"
31
+ ],
32
+ "sideEffects": false,
33
+ "publishConfig": {
34
+ "access": "public"
35
+ },
36
+ "exports": {
37
+ ".": {
38
+ "types": "./dist/index.d.ts",
39
+ "import": "./dist/index.mjs",
40
+ "require": "./dist/index.cjs",
41
+ "default": "./dist/index.mjs"
42
+ },
43
+ "./workflows/*": "./workflows/*",
44
+ "./frameworks/*": "./frameworks/*"
45
+ },
46
+ "files": [
47
+ "dist",
48
+ "workflows",
49
+ "frameworks"
50
+ ],
51
+ "devDependencies": {
52
+ "@types/node": "^22.0.0",
53
+ "tsdown": "^0.21.0",
54
+ "typescript": "^5.7.0",
55
+ "vitest": "^3.0.0"
56
+ },
57
+ "scripts": {
58
+ "build": "tsdown src/index.ts --format esm,cjs --dts",
59
+ "test": "vitest run",
60
+ "typecheck": "tsc --noEmit"
61
+ }
62
+ }
@@ -0,0 +1,92 @@
1
+ # Skill: Run Bulk Content Operations
2
+
3
+ > Apply safe batch operations to existing content entries.
4
+
5
+ ---
6
+
7
+ ## When to Use
8
+
9
+ Use this when the user wants to:
10
+
11
+ - copy one locale to another
12
+ - update status on many entries
13
+ - delete multiple collection entries
14
+
15
+ This skill is for existing content, not for schema design.
16
+
17
+ ---
18
+
19
+ ## Steps
20
+
21
+ ### 1. Inspect the Model
22
+
23
+ Call `contentrain_status` and `contentrain_describe(model: "<model-id>")` first.
24
+
25
+ Confirm:
26
+
27
+ - model kind
28
+ - whether `i18n` is enabled
29
+ - which locales are supported
30
+
31
+ ### 2. Pick the Correct Bulk Operation
32
+
33
+ - `copy_locale`: clone one locale to another for i18n-enabled `collection`, `singleton`, or `dictionary` models
34
+ - `update_status`: update metadata state for many collection entries
35
+ - `delete_entries`: remove many collection entries at once
36
+
37
+ ### 3. Apply Safety Rules
38
+
39
+ - never use `copy_locale` on non-i18n models
40
+ - `update_status` and `delete_entries` are collection-only
41
+ - confirm entry IDs before delete operations
42
+ - batch only related entries together
43
+
44
+ ### 4. Execute with `contentrain_bulk`
45
+
46
+ Examples:
47
+
48
+ ```json
49
+ {
50
+ "operation": "copy_locale",
51
+ "model": "ui-labels",
52
+ "source_locale": "en",
53
+ "target_locale": "tr"
54
+ }
55
+ ```
56
+
57
+ ```json
58
+ {
59
+ "operation": "update_status",
60
+ "model": "blog-post",
61
+ "entry_ids": ["post_001", "post_002"],
62
+ "status": "in_review"
63
+ }
64
+ ```
65
+
66
+ ```json
67
+ {
68
+ "operation": "delete_entries",
69
+ "model": "faq-items",
70
+ "entry_ids": ["faq_01", "faq_02"],
71
+ "confirm": true
72
+ }
73
+ ```
74
+
75
+ ### 5. Validate When Needed
76
+
77
+ After `copy_locale` or status-heavy cleanup, call `contentrain_validate` if content correctness may have changed.
78
+
79
+ ### 6. Submit
80
+
81
+ Bulk operations still create branches/commits. Call `contentrain_submit` if the project is in review flow.
82
+
83
+ ### 7. Final Summary
84
+
85
+ Report:
86
+
87
+ - operation performed
88
+ - model affected
89
+ - locale or entry count affected
90
+ - validation outcome if run
91
+ - submit status
92
+