@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.
Files changed (45) hide show
  1. package/README.md +65 -60
  2. package/dist/index.cjs +65 -1
  3. package/dist/index.d.cts +50 -2
  4. package/dist/index.d.cts.map +1 -1
  5. package/dist/index.d.mts +50 -2
  6. package/dist/index.d.mts.map +1 -1
  7. package/dist/index.mjs +65 -2
  8. package/dist/index.mjs.map +1 -1
  9. package/frameworks/nuxt.md +26 -1
  10. package/package.json +3 -1
  11. package/skills/contentrain/SKILL.md +149 -0
  12. package/skills/contentrain/references/architecture.md +212 -0
  13. package/skills/contentrain/references/content-formats.md +279 -0
  14. package/skills/contentrain/references/i18n.md +298 -0
  15. package/skills/contentrain/references/mcp-pipelines.md +192 -0
  16. package/skills/contentrain/references/mcp-tools.md +308 -0
  17. package/skills/contentrain/references/model-kinds.md +330 -0
  18. package/skills/contentrain/references/schema-types.md +177 -0
  19. package/skills/contentrain/references/security.md +146 -0
  20. package/skills/contentrain/references/workflow.md +267 -0
  21. package/skills/contentrain-bulk/SKILL.md +99 -0
  22. package/skills/contentrain-content/SKILL.md +162 -0
  23. package/skills/contentrain-diff/SKILL.md +62 -0
  24. package/skills/contentrain-doctor/SKILL.md +62 -0
  25. package/skills/contentrain-generate/SKILL.md +183 -0
  26. package/skills/contentrain-generate/references/generated-client.md +198 -0
  27. package/skills/contentrain-init/SKILL.md +99 -0
  28. package/skills/contentrain-model/SKILL.md +141 -0
  29. package/skills/contentrain-normalize/SKILL.md +185 -0
  30. package/skills/contentrain-normalize/references/extraction.md +164 -0
  31. package/skills/contentrain-normalize/references/reuse.md +146 -0
  32. package/skills/contentrain-normalize/references/what-is-content.md +115 -0
  33. package/skills/contentrain-quality/SKILL.md +180 -0
  34. package/skills/contentrain-quality/references/accessibility.md +160 -0
  35. package/skills/contentrain-quality/references/content-quality.md +299 -0
  36. package/skills/contentrain-quality/references/media.md +170 -0
  37. package/skills/contentrain-quality/references/seo.md +229 -0
  38. package/skills/contentrain-review/SKILL.md +170 -0
  39. package/skills/contentrain-sdk/SKILL.md +145 -0
  40. package/skills/contentrain-sdk/references/bundler-config.md +135 -0
  41. package/skills/contentrain-serve/SKILL.md +96 -0
  42. package/skills/contentrain-translate/SKILL.md +180 -0
  43. package/skills/contentrain-validate-fix/SKILL.md +92 -0
  44. package/workflows/contentrain-content.md +1 -1
  45. package/workflows/contentrain-generate.md +5 -5
@@ -0,0 +1,162 @@
1
+ ---
2
+ name: contentrain-content
3
+ description: "Create and manage content entries for existing Contentrain models. Use when adding entries to collections, populating singletons, writing documents, or managing dictionary keys."
4
+ metadata:
5
+ author: Contentrain
6
+ version: "1.0.0"
7
+ ---
8
+
9
+ # Skill: Create Content for Existing Models
10
+
11
+ > Generate and save content entries for models already defined in the project.
12
+
13
+ ---
14
+
15
+ ## When to Use
16
+
17
+ The user wants to create new content, add entries to a collection, populate a singleton, or says something like "add a blog post", "create content", "fill in the hero section".
18
+
19
+ ---
20
+
21
+ ## Steps
22
+
23
+ ### 1. Check Project State
24
+
25
+ Call `contentrain_status` to get the full project context:
26
+
27
+ - Confirm the project is initialized.
28
+ - List available models, their kinds, domains, and field counts.
29
+ - Note supported locales and the source locale.
30
+ - Check for any pending changes or validation errors.
31
+
32
+ If `.contentrain/` does not exist, stop and suggest running `/contentrain-init` first.
33
+
34
+ ### 2. Identify the Target Model
35
+
36
+ If the user specified a model, use it. Otherwise:
37
+
38
+ - Present the list of available models from status.
39
+ - Ask the user which model to create content for.
40
+ - If the user describes content without naming a model (e.g., "write a blog post about X"), infer the model from context.
41
+
42
+ ### 3. Read the Model Definition
43
+
44
+ Call `contentrain_describe(model: "<model-id>", include_sample: true)` to get:
45
+
46
+ - All field definitions (name, type, required, constraints).
47
+ - A sample entry if one exists (use it as a structural reference).
48
+ - Relation fields and their target models.
49
+
50
+ If the user's request does not match an existing model, offer to create one first with `contentrain_model_save`.
51
+
52
+ ### 4. Read Vocabulary and Context
53
+
54
+ - Check `.contentrain/vocabulary.json` for canonical terms. All content must use these terms consistently across locales. Do not use alternative spellings or synonyms for vocabulary-defined terms.
55
+ - Check `.contentrain/context.json` for tone conventions (professional, casual, technical).
56
+
57
+ ### 5. Generate Content
58
+
59
+ Create content following the rules in `content-quality.md`:
60
+
61
+ - **Required fields:** Every required field must have a real, non-placeholder value.
62
+ - **Field constraints:** Respect `min`, `max`, `pattern`, and `options` constraints.
63
+ - **Unique fields:** Verify `unique` field values do not collide with existing entries.
64
+ - **Tone:** Match the tone defined in `.contentrain/context.json` → `conventions.tone`.
65
+ - **Vocabulary:** Use terms from `.contentrain/vocabulary.json` if it exists.
66
+ - **Content patterns:** Follow the appropriate content type pattern (blog post, landing page, documentation, etc.) from `content-quality.md` Section 3.
67
+ - **Consistency:** If existing entries exist, read 2-3 via `contentrain_content_list` to match the established style and structure.
68
+
69
+ **Relation integrity:** For `relation` and `relations` fields, verify referenced entries exist by calling `contentrain_content_list` on the target model.
70
+
71
+ ### 6. Apply SEO Rules
72
+
73
+ For fields that affect SEO (from `seo-rules.md`):
74
+
75
+ - **Title:** 50-60 characters optimal, max 70. Primary keyword in the first 30 characters.
76
+ - **Slug:** Lowercase, hyphen-separated, 3-5 words, no stop words.
77
+ - **Description/excerpt:** 120-160 characters, complete sentence, summarizes value.
78
+ - **Alt text:** Descriptive, includes context, under 125 characters.
79
+ - **Heading hierarchy:** In markdown/richtext content: h1 → h2 → h3 (no skips).
80
+
81
+ ### 7. Present Draft for Approval
82
+
83
+ Show the user the content draft before writing. Include:
84
+
85
+ - The model name and kind.
86
+ - The content for each locale (if i18n).
87
+ - Any relations being set.
88
+ - A summary of which quality rules were applied.
89
+
90
+ Wait for user confirmation before proceeding.
91
+
92
+ ### 8. Save Content
93
+
94
+ Call `contentrain_content_save` with the approved content. The tool takes `model` and an `entries` array:
95
+
96
+ ```json
97
+ contentrain_content_save({
98
+ "model": "<model-id>",
99
+ "entries": [
100
+ { "locale": "en", "data": { "field": "value" } }
101
+ ]
102
+ })
103
+ ```
104
+
105
+ **Kind-specific entry format:**
106
+
107
+ - **singleton:** `{ "locale": "en", "data": { "title": "My Site", "cta": "Get Started" } }` -- no `id` or `slug`.
108
+ - **collection:** `{ "id": "optional-id", "locale": "en", "data": { "name": "John", "role": "CEO" } }` -- omit `id` to auto-generate, provide `id` to update.
109
+ - **document:** `{ "slug": "getting-started", "locale": "en", "data": { "title": "Getting Started", "body": "# Welcome\n..." } }` -- `slug` is required, use `"body"` key for markdown content.
110
+ - **dictionary:** `{ "locale": "en", "data": { "auth.login": "Log In", "auth.logout": "Log Out" } }` -- flat key-value pairs, no `id` or `slug`.
111
+
112
+ **Critical rules:**
113
+ - NEVER include system fields (`status`, `source`, `updated_by`, `approved_by`) in `data`. These are managed in meta files, not content. Temporal data (created/updated timestamps) comes from git history.
114
+ - Prefer batch mode -- send multiple entries in a single call when possible.
115
+ - Locale defaults to the project's default locale if omitted, but explicit locale is recommended.
116
+
117
+ ### 9. Handle i18n Completeness
118
+
119
+ If the project has multiple supported locales and the model has `i18n: true`:
120
+
121
+ - Ask the user if they want translations created now.
122
+ - If yes, generate translations following `i18n-quality.md` rules:
123
+ - Translate meaning, not words.
124
+ - Respect string expansion ratios.
125
+ - Preserve tone across locales.
126
+ - Check `vocabulary.json` for approved term translations.
127
+ - Call `contentrain_content_save` for each target locale.
128
+
129
+ If the user defers translations, note incomplete locales in the final summary.
130
+
131
+ ### 10. Validate
132
+
133
+ Call `contentrain_validate` to check all changes:
134
+
135
+ - Schema compliance (all required fields, correct types).
136
+ - Referential integrity (relations point to existing entries).
137
+ - i18n completeness (all locales have matching keys).
138
+ - Content policy compliance.
139
+
140
+ Fix any errors reported. Acknowledge any warnings.
141
+
142
+ ### 11. Submit
143
+
144
+ Call `contentrain_submit` to push branches to remote:
145
+
146
+ - Write operations already create branches and commit changes automatically.
147
+ - `contentrain_submit` pushes unmerged `contentrain/*` branches to the remote.
148
+ - In `auto-merge` mode, branches are already merged to the base branch during the write operation.
149
+ - In `review` mode, branches are pushed for team review.
150
+
151
+ Report the Studio URL if provided in the tool response -- the user can review and approve content there.
152
+
153
+ ### 12. Final Summary
154
+
155
+ Report to the user:
156
+
157
+ - How many entries were created/updated.
158
+ - Which locales were covered.
159
+ - The validation result.
160
+ - The submission status (auto-merged or pending review).
161
+ - Studio link for visual review (if available).
162
+ - Next steps: run `/contentrain-generate` to update SDK types if models changed.
@@ -0,0 +1,62 @@
1
+ ---
2
+ name: contentrain-diff
3
+ description: "View content diffs between Contentrain branches. Use when comparing changes, reviewing branch differences, or checking what changed."
4
+ metadata:
5
+ author: Contentrain
6
+ version: "1.0.0"
7
+ ---
8
+
9
+ # Skill: Review Pending Branches with `contentrain diff`
10
+
11
+ > Inspect pending Contentrain branches and decide whether to merge, reject, or defer them.
12
+
13
+ ---
14
+
15
+ ## When to Use
16
+
17
+ Use this when:
18
+
19
+ - the project has pending `contentrain/*` branches
20
+ - the user asks to review or merge changes
21
+ - branch pressure is growing and cleanup is needed
22
+
23
+ ---
24
+
25
+ ## Steps
26
+
27
+ ### 1. Check Branch Pressure
28
+
29
+ Start with `contentrain status`.
30
+
31
+ If many `contentrain/*` branches are active, move into review immediately.
32
+
33
+ ### 2. Run `contentrain diff`
34
+
35
+ Use the CLI to:
36
+
37
+ - list pending branches
38
+ - inspect the diff summary
39
+ - review full patch output
40
+
41
+ ### 3. Evaluate the Change
42
+
43
+ Check:
44
+
45
+ - which model/content files changed
46
+ - whether the change matches the intended operation
47
+ - whether validation/normalize work was completed properly
48
+
49
+ ### 4. Choose an Outcome
50
+
51
+ - merge when the diff is correct and complete
52
+ - delete when the change is wrong or should be rejected
53
+ - defer only when more human input is required
54
+
55
+ ### 5. Report the Decision
56
+
57
+ Summarize:
58
+
59
+ - branch reviewed
60
+ - action taken
61
+ - base branch affected
62
+ - any follow-up branch still pending
@@ -0,0 +1,62 @@
1
+ ---
2
+ name: contentrain-doctor
3
+ description: "Diagnose Contentrain project health issues. Use when troubleshooting setup problems, checking configuration, or verifying project integrity."
4
+ metadata:
5
+ author: Contentrain
6
+ version: "1.0.0"
7
+ ---
8
+
9
+ # Skill: Diagnose Project Health with `contentrain doctor`
10
+
11
+ > Run health checks and turn failures into actionable fixes.
12
+
13
+ ---
14
+
15
+ ## When to Use
16
+
17
+ Use this when:
18
+
19
+ - setup seems broken
20
+ - generated client may be stale
21
+ - Git/content structure may be inconsistent
22
+ - the user asks "what is wrong with this project?"
23
+
24
+ ---
25
+
26
+ ## Steps
27
+
28
+ ### 1. Run `contentrain doctor`
29
+
30
+ Use the CLI health check as the first diagnostic pass.
31
+
32
+ ### 2. Group Findings
33
+
34
+ Interpret failures by category:
35
+
36
+ - Git problems
37
+ - missing `.contentrain/` structure
38
+ - bad config/model parsing
39
+ - orphan content
40
+ - too many pending branches
41
+ - stale SDK client
42
+
43
+ ### 3. Fix in Priority Order
44
+
45
+ Recommended order:
46
+
47
+ 1. Git / initialization blockers
48
+ 2. config/model parse failures
49
+ 3. orphan content or missing paths
50
+ 4. branch pressure
51
+ 5. stale generated client
52
+
53
+ ### 4. Apply the Correct Follow-up
54
+
55
+ - not initialized → `contentrain init`
56
+ - stale client → `contentrain generate`
57
+ - branch pressure → `contentrain diff`
58
+ - invalid content/model state → `contentrain validate`
59
+
60
+ ### 5. Re-run Doctor
61
+
62
+ After changes, run `contentrain doctor` again to confirm the project is healthy.
@@ -0,0 +1,183 @@
1
+ ---
2
+ name: contentrain-generate
3
+ description: "Generate the typed @contentrain/query SDK client from models. Use when running contentrain generate, setting up SDK, configuring bundler aliases, or integrating #contentrain imports."
4
+ metadata:
5
+ author: Contentrain
6
+ version: "1.0.0"
7
+ ---
8
+
9
+ # Skill: Generate SDK Client
10
+
11
+ > Generate the typed Contentrain query client from model definitions using the Prisma-pattern codegen.
12
+
13
+ ---
14
+
15
+ ## When to Use
16
+
17
+ The user wants to generate or regenerate the SDK client, or says something like "generate client", "regenerate types", "set up contentrain imports", "run contentrain generate", "update SDK types".
18
+
19
+ ---
20
+
21
+ ## Steps
22
+
23
+ ### 1. Check Project State
24
+
25
+ Call `contentrain_status` to verify:
26
+
27
+ - `.contentrain/` directory exists with `config.json`.
28
+ - At least one model exists in `.contentrain/models/`.
29
+ - Content files exist for the configured locales.
30
+
31
+ If the project is not initialized, stop and suggest running `/contentrain-init` first. If no models exist, suggest `/contentrain-content` to create content first.
32
+
33
+ ### 2. Verify Prerequisites
34
+
35
+ Check that the required packages are available:
36
+
37
+ - `@contentrain/query` must be installed in the project's `package.json` (as a dependency).
38
+ - The `contentrain` CLI must be available (via `npx contentrain` or globally installed).
39
+
40
+ If `@contentrain/query` is not installed, install it using the project's package manager:
41
+
42
+ ```bash
43
+ # Use whichever package manager the project uses
44
+ pnpm add @contentrain/query
45
+ # or: npm install @contentrain/query
46
+ # or: yarn add @contentrain/query
47
+ ```
48
+
49
+ ### 3. Run the Generator
50
+
51
+ Execute the generation command:
52
+
53
+ ```bash
54
+ npx contentrain generate
55
+ ```
56
+
57
+ If the project uses a non-standard root directory, specify it:
58
+
59
+ ```bash
60
+ npx contentrain generate --root .
61
+ ```
62
+
63
+ This reads `.contentrain/models/` and `.contentrain/content/` to produce:
64
+
65
+ ```
66
+ .contentrain/client/
67
+ index.mjs — ESM entry (query runtime + re-exports)
68
+ index.cjs — CJS entry (NestJS, Express, legacy tooling)
69
+ index.d.ts — Generated types (from model schemas)
70
+ data/
71
+ {model}.{locale}.mjs — Static data modules per model/locale
72
+ ```
73
+
74
+ ### 4. Verify package.json Imports
75
+
76
+ The generator should have added `#contentrain` subpath imports to `package.json`. Verify the full import map:
77
+
78
+ ```json
79
+ {
80
+ "imports": {
81
+ "#contentrain": {
82
+ "types": "./.contentrain/client/index.d.ts",
83
+ "import": "./.contentrain/client/index.mjs",
84
+ "require": "./.contentrain/client/index.cjs",
85
+ "default": "./.contentrain/client/index.mjs"
86
+ },
87
+ "#contentrain/*": {
88
+ "types": "./.contentrain/client/*.d.ts",
89
+ "import": "./.contentrain/client/*.mjs",
90
+ "require": "./.contentrain/client/*.cjs",
91
+ "default": "./.contentrain/client/*.mjs"
92
+ }
93
+ }
94
+ }
95
+ ```
96
+
97
+ If the imports entry is missing or incomplete, update `package.json` manually to match the full structure above.
98
+
99
+ ### 5. Verify TypeScript Configuration
100
+
101
+ Ensure `tsconfig.json` does not block the generated client:
102
+
103
+ - `paths` should not conflict with `#contentrain`.
104
+ - `rootDir` or `include` should not exclude `.contentrain/client/`.
105
+ - If using `moduleResolution: "bundler"` or `"node16"`, subpath imports resolve natively.
106
+
107
+ ### 6. Configure Bundler Alias
108
+
109
+ The `#contentrain` subpath import works natively in Node.js 22+ but **does NOT resolve in browser bundlers**. If the project uses a bundler, configure an alias so `#contentrain` resolves to the generated client.
110
+
111
+ See `references/generated-client.md` for framework-specific bundler configuration patterns (Vite, Next.js, Nuxt 3, SvelteKit, Expo/React Native, Pure Node.js).
112
+
113
+ ### 7. Verify Imports Work
114
+
115
+ Run a quick verification that the imports resolve correctly.
116
+
117
+ **Node.js / SSR-only projects:**
118
+
119
+ ```bash
120
+ node -e "import('#contentrain').then(m => console.log('OK:', Object.keys(m)))"
121
+ ```
122
+
123
+ **Browser / bundler projects:** run the framework's build command instead, since the Node.js check does not exercise the bundler alias:
124
+
125
+ ```bash
126
+ # Vite-based (Vue, React, Svelte, Astro)
127
+ npx vite build
128
+
129
+ # Next.js
130
+ npx next build
131
+
132
+ # Nuxt 3
133
+ npx nuxi build
134
+
135
+ # Expo
136
+ npx expo export
137
+ ```
138
+
139
+ A successful build confirms the `#contentrain` alias resolves correctly through the bundler pipeline.
140
+
141
+ If verification fails, check:
142
+ - Node.js version >= 22 (required for native subpath imports).
143
+ - `package.json` has `"type": "module"` (for ESM projects).
144
+ - The `.contentrain/client/` directory was generated successfully.
145
+ - The bundler alias is configured (see Step 6) for browser projects.
146
+
147
+ ### 8. Show Usage Examples
148
+
149
+ Based on the detected stack and available models, show relevant examples using actual model IDs and field names from the project — not generic placeholders.
150
+
151
+ See `references/generated-client.md` for the complete SDK API reference, relation patterns, and framework-specific usage patterns.
152
+
153
+ ### 9. Offer Watch Mode
154
+
155
+ Suggest setting up watch mode for development:
156
+
157
+ ```bash
158
+ npx contentrain generate --watch
159
+ ```
160
+
161
+ This re-generates the client automatically whenever models or content change under `.contentrain/`. Recommend running it alongside the framework's dev server.
162
+
163
+ For convenience, suggest adding a script to `package.json`:
164
+
165
+ ```json
166
+ {
167
+ "scripts": {
168
+ "contentrain:watch": "contentrain generate --watch"
169
+ }
170
+ }
171
+ ```
172
+
173
+ ### 10. Final Summary
174
+
175
+ Report to the user:
176
+
177
+ - Models processed: list each model and its kind.
178
+ - Generated files: list the `.contentrain/client/` contents.
179
+ - Locales included: list data files per locale.
180
+ - Import path: `#contentrain` is ready to use.
181
+ - TypeScript types: available via `index.d.ts`.
182
+ - Next steps: import `query` from `#contentrain` and start querying content.
183
+ - Reminder: re-run `contentrain generate` after model or content changes.
@@ -0,0 +1,198 @@
1
+ ---
2
+ name: generated-client
3
+ description: "Generated client structure, framework bundler configs, and API patterns"
4
+ ---
5
+
6
+ # Generated Client Reference
7
+
8
+ ## Bundler Alias Configuration
9
+
10
+ The `#contentrain` subpath import works natively in Node.js 22+ but **does NOT resolve in browser bundlers**. Configure an alias for your framework.
11
+
12
+ ### Vite (Vue, React, Svelte, Astro)
13
+
14
+ ```ts
15
+ // vite.config.ts
16
+ import { resolve } from 'node:path'
17
+ export default defineConfig({
18
+ resolve: {
19
+ alias: {
20
+ '#contentrain': resolve(__dirname, '.contentrain/client/index.mjs'),
21
+ },
22
+ },
23
+ })
24
+ ```
25
+
26
+ Also add a `paths` entry to `tsconfig.json` so the TypeScript language server resolves the alias:
27
+
28
+ ```json
29
+ {
30
+ "compilerOptions": {
31
+ "paths": {
32
+ "#contentrain": ["./.contentrain/client/index.d.ts"]
33
+ }
34
+ }
35
+ }
36
+ ```
37
+
38
+ ### Next.js (webpack)
39
+
40
+ ```js
41
+ // next.config.js
42
+ const path = require('path')
43
+ module.exports = {
44
+ webpack: (config) => {
45
+ config.resolve.alias['#contentrain'] = path.resolve(__dirname, '.contentrain/client/index.mjs')
46
+ return config
47
+ },
48
+ }
49
+ ```
50
+
51
+ Add the same `tsconfig.json` paths entry:
52
+
53
+ ```json
54
+ {
55
+ "compilerOptions": {
56
+ "paths": {
57
+ "#contentrain": ["./.contentrain/client/index.d.ts"]
58
+ }
59
+ }
60
+ }
61
+ ```
62
+
63
+ ### Nuxt 3
64
+
65
+ Nuxt provides a top-level `alias` option — no Vite config needed:
66
+
67
+ ```ts
68
+ // nuxt.config.ts
69
+ export default defineNuxtConfig({
70
+ alias: {
71
+ '#contentrain': './.contentrain/client/index.mjs',
72
+ },
73
+ })
74
+ ```
75
+
76
+ Add the `tsconfig.json` paths entry as above. Nuxt auto-extends `tsconfig.json` via `.nuxt/tsconfig.json`, so ensure the paths entry is in the project root `tsconfig.json`.
77
+
78
+ ### SvelteKit
79
+
80
+ SvelteKit uses Vite internally. Add the alias in `vite.config.ts` as shown in the Vite section above.
81
+
82
+ ### Expo / React Native (Metro)
83
+
84
+ ```js
85
+ // metro.config.js
86
+ const path = require('path')
87
+ module.exports = {
88
+ resolver: {
89
+ extraNodeModules: {
90
+ '#contentrain': path.resolve(__dirname, '.contentrain/client/index.mjs'),
91
+ },
92
+ },
93
+ }
94
+ ```
95
+
96
+ ### Pure Node.js / SSR-only
97
+
98
+ No alias needed. Node.js 22+ resolves `#contentrain` from `package.json` imports natively.
99
+
100
+ ---
101
+
102
+ ## Complete SDK API Reference
103
+
104
+ ```ts
105
+ import { query, singleton, dictionary, document } from '#contentrain'
106
+ ```
107
+
108
+ ### QueryBuilder (for collection models) -- SYNC, no await needed
109
+
110
+ ```ts
111
+ const posts = query('blog-post')
112
+ .locale('en') // set locale
113
+ .where('status', 'published') // exact match filter
114
+ .sort('date', 'desc') // sort by field
115
+ .limit(10) // limit results
116
+ .offset(5) // skip results
117
+ .include('author', 'tags') // resolve relation fields (1 level deep)
118
+ .all() // --> T[] (returns array)
119
+ .first() // --> T | undefined (first match)
120
+ ```
121
+
122
+ ### SingletonAccessor (for singleton models)
123
+
124
+ ```ts
125
+ const hero = singleton('hero')
126
+ .locale('en')
127
+ .include('featured_post') // resolve relations on singletons too
128
+ .get() // --> T (single object)
129
+ ```
130
+
131
+ ### DictionaryAccessor (for dictionary models)
132
+
133
+ ```ts
134
+ const allLabels = dictionary('ui-labels').locale('en').get() // --> Record<string, string>
135
+ const oneLabel = dictionary('ui-labels').locale('en').get('key') // --> string | undefined
136
+ const withParams = dictionary('ui-labels').locale('en').get('add-entry', { model: 'blog' }) // --> "Add a new entry to blog"
137
+ ```
138
+
139
+ Parameterized templates use `{placeholder}` syntax in dictionary values. The `get(key, params)` overload replaces `{name}` with the provided value. Unmatched placeholders are left as-is.
140
+
141
+ ### DocumentQuery (for document models -- markdown + frontmatter)
142
+
143
+ ```ts
144
+ const article = document('blog-article')
145
+ .locale('en')
146
+ .where('category', 'tech')
147
+ .include('author') // resolve relations in frontmatter
148
+ .bySlug('getting-started') // --> T | undefined (find by slug)
149
+
150
+ const docs = document('doc-page').locale('en').all() // --> T[]
151
+ const first = document('doc-page').locale('en').first() // --> T | undefined
152
+ ```
153
+
154
+ ### DOES NOT EXIST -- never use these
155
+
156
+ - `.filter()` -- use `.where(field, value)` instead
157
+ - `.byId()` -- use `.where('id', value).first()` instead
158
+ - `.count()` -- use `.all().length` instead
159
+ - `dictionary().all()` -- use `.get()` instead
160
+ - Queries are SYNC -- do not use `await` with `query()`, `singleton()`, `dictionary()`, or `document()`
161
+ - `.where('field', 'eq', value)` -- just `.where('field', value)`
162
+ - `.get()` on QueryBuilder -- use `.all()` or `.first()`
163
+
164
+ ---
165
+
166
+ ## With Relations
167
+
168
+ ```ts
169
+ // Relations are resolved 1 level deep via .include()
170
+ const posts = query('blog-post')
171
+ .locale('en')
172
+ .include('author', 'tags')
173
+ .all()
174
+ // posts[0].author --> { id: '...', name: 'John', ... } (resolved object)
175
+
176
+ // Without include:
177
+ const raw = query('blog-post').locale('en').all()
178
+ // raw[0].author --> 'author-id-123' (raw string ID, NOT resolved)
179
+
180
+ // Singletons support include too:
181
+ const hero = singleton('hero').locale('en').include('featured_post').get()
182
+
183
+ // Documents support include too:
184
+ const article = document('blog-article').locale('en').include('author').bySlug('my-post')
185
+ ```
186
+
187
+ ---
188
+
189
+ ## Framework-Specific Patterns
190
+
191
+ | Stack | Usage Pattern | Alias Setup |
192
+ |---|---|---|
193
+ | Nuxt 3 | `useAsyncData(() => singleton('hero').locale(locale).get())` | `nuxt.config.ts` alias |
194
+ | Next.js | In RSC: `const data = singleton('hero').locale('en').get()` | `next.config.js` webpack alias |
195
+ | Astro | In frontmatter: `const posts = query('blog-post').locale('en').all()` | `vite.config.ts` alias |
196
+ | SvelteKit | In `+page.server.ts`: `export const load = () => ({ hero: singleton('hero').locale('en').get() })` | `vite.config.ts` alias |
197
+ | Expo / RN | `const hero = singleton('hero').locale('en').get()` | `metro.config.js` resolver |
198
+ | Node.js / SSR | Direct import — no alias needed | Native subpath imports |