@funkai/prompts 0.3.0 → 0.4.1

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 (40) hide show
  1. package/.turbo/turbo-build.log +13 -13
  2. package/CHANGELOG.md +28 -0
  3. package/README.md +3 -3
  4. package/dist/lib/cli.d.mts +2 -2
  5. package/dist/lib/cli.mjs +1 -1
  6. package/dist/lib/{engine-CQfJbVz6.d.mts → engine-BAYeiay3.d.mts} +2 -2
  7. package/dist/lib/{engine-CQfJbVz6.d.mts.map → engine-BAYeiay3.d.mts.map} +1 -1
  8. package/dist/lib/{engine-CPKs9QbX.mjs → engine-Bhv5Zxdu.mjs} +3 -1
  9. package/dist/lib/{engine-CPKs9QbX.mjs.map → engine-Bhv5Zxdu.mjs.map} +1 -1
  10. package/dist/lib/index.d.mts +59 -2
  11. package/dist/lib/index.d.mts.map +1 -1
  12. package/dist/lib/index.mjs +84 -4
  13. package/dist/lib/index.mjs.map +1 -1
  14. package/dist/lib/runtime.d.mts +1 -1
  15. package/dist/lib/runtime.mjs +1 -1
  16. package/dist/lib/{types-2PI_9h-M.d.mts → types-DmnHC99v.d.mts} +25 -3
  17. package/dist/lib/types-DmnHC99v.d.mts.map +1 -0
  18. package/docs/cli/commands.md +8 -8
  19. package/docs/cli/overview.md +1 -1
  20. package/docs/cli.md +132 -0
  21. package/docs/codegen.md +142 -0
  22. package/docs/file-format/overview.md +1 -1
  23. package/docs/file-format.md +306 -0
  24. package/docs/guides/author-prompt.md +2 -2
  25. package/docs/guides/setup-project.md +1 -1
  26. package/docs/overview.md +9 -36
  27. package/docs/setup.md +76 -0
  28. package/docs/troubleshooting.md +1 -1
  29. package/package.json +2 -2
  30. package/src/engine.ts +2 -0
  31. package/src/group.test.ts +89 -0
  32. package/src/group.ts +36 -0
  33. package/src/index.ts +3 -1
  34. package/src/prompt.test.ts +90 -0
  35. package/src/prompt.ts +60 -0
  36. package/src/registry.test.ts +10 -20
  37. package/src/registry.ts +11 -11
  38. package/src/types.ts +24 -1
  39. package/tsconfig.json +12 -5
  40. package/dist/lib/types-2PI_9h-M.d.mts.map +0 -1
@@ -0,0 +1,142 @@
1
+ # Code Generation & Library
2
+
3
+ The CLI transforms `.prompt` source files into typed TypeScript modules. This doc covers the pipeline stages, generated output shape, and the runtime library API.
4
+
5
+ ## Pipeline
6
+
7
+ ```mermaid
8
+ %%{init: {
9
+ 'theme': 'base',
10
+ 'themeVariables': {
11
+ 'primaryColor': '#313244',
12
+ 'primaryTextColor': '#cdd6f4',
13
+ 'primaryBorderColor': '#6c7086',
14
+ 'lineColor': '#89b4fa',
15
+ 'secondaryColor': '#45475a',
16
+ 'tertiaryColor': '#1e1e2e',
17
+ 'background': '#1e1e2e',
18
+ 'mainBkg': '#313244',
19
+ 'clusterBkg': '#1e1e2e',
20
+ 'clusterBorder': '#45475a'
21
+ },
22
+ 'flowchart': { 'curve': 'basis', 'padding': 15 }
23
+ }}%%
24
+ flowchart TD
25
+ classDef core fill:#313244,stroke:#89b4fa,stroke-width:2px,color:#cdd6f4
26
+ classDef agent fill:#313244,stroke:#a6e3a1,stroke-width:2px,color:#cdd6f4
27
+
28
+ subgraph Per Prompt
29
+ A[discoverPrompts]:::core --> B[parseFrontmatter]:::core
30
+ B --> C[clean]:::core
31
+ C --> D[flattenPartials]:::core
32
+ D --> E[extractVariables]:::core
33
+ E --> F[lintPrompt]:::core
34
+ end
35
+
36
+ subgraph Output
37
+ F --> G[generatePromptModule]:::agent
38
+ F --> H[generateRegistry]:::agent
39
+ end
40
+ ```
41
+
42
+ ## Pipeline Stages
43
+
44
+ | Stage | Input | Output | Description |
45
+ | ----------------- | ---------------------------- | ---------------------------------- | ------------------------------------------------------- |
46
+ | Discover | Root directories | `DiscoveredPrompt[]` | Scans for `.prompt` files (max depth 5) |
47
+ | Parse Frontmatter | Raw file content | `{ name, group, version, schema }` | Extracts and validates YAML metadata |
48
+ | Clean | Raw content | Template string | Strips frontmatter delimiters |
49
+ | Flatten Partials | Template with `{% render %}` | Resolved template | Inlines partial content with bound params |
50
+ | Extract Variables | Template string | `string[]` | Finds `{{ var }}`, `{% if var %}`, `{% for x in var %}` |
51
+ | Lint | Schema + variables | Diagnostics | Checks schema/template variable alignment |
52
+
53
+ ## Generated Output
54
+
55
+ ### Per-Prompt Module (`<name>.ts`)
56
+
57
+ Each module exports a default object conforming to `PromptModule`:
58
+
59
+ | Member | Type | Description |
60
+ | --------------------- | ------------------------ | ------------------------------------------------ |
61
+ | `name` | `string` (const) | Prompt name from frontmatter |
62
+ | `group` | `string \| undefined` | Optional grouping key |
63
+ | `schema` | `ZodObject` | Zod schema built from frontmatter `schema` block |
64
+ | `render(variables)` | `(Variables) => string` | Validates input then renders via LiquidJS |
65
+ | `validate(variables)` | `(unknown) => Variables` | Zod parse only |
66
+
67
+ ### Registry (`index.ts`)
68
+
69
+ Aggregates all per-prompt modules into a single entry point:
70
+
71
+ | Export | Type | Description |
72
+ | --------- | --------------------- | ------------------------------------------------------------------------------------------------------ |
73
+ | `prompts` | `PromptRegistry<...>` | Deep-frozen const object with dot-access, nested by group. Use `typeof prompts` for type-level access. |
74
+
75
+ ## Output Directory
76
+
77
+ Generated files go to the `--out` directory (conventionally `.prompts/client/`). This subdirectory should be gitignored. The parent `.prompts/` directory also holds `partials/` for custom partials (committed to git). Import generated code via the `~prompts` tsconfig alias.
78
+
79
+ ## Runtime Library API
80
+
81
+ The library surface provides the runtime engine and registry used by generated code and consuming packages.
82
+
83
+ ### Exports
84
+
85
+ | Export | Type | Description |
86
+ | ---------------------- | ----------------------------------- | -------------------------------------------------------------------------- |
87
+ | `engine` | `Liquid` | Shared LiquidJS instance (no filesystem, strict filters) |
88
+ | `createEngine` | `(partialsDir, options?) => Liquid` | Factory for filesystem-backed engines (used by CLI for partial resolution) |
89
+ | `clean` | `(content: string) => string` | Strips frontmatter, returns render-ready template |
90
+ | `createPromptRegistry` | `(modules) => PromptRegistry` | Creates typed registry from prompt module map |
91
+
92
+ ### Engine
93
+
94
+ The shared `engine` instance is configured with `ownPropertyOnly: true` and `strictFilters: true` for security. No filesystem access -- templates are rendered from strings via `parseAndRenderSync`.
95
+
96
+ `createEngine` accepts a `partialsDir` and optional overrides. It enables filesystem-backed partial resolution (`.prompt` extension, caching enabled) for use during codegen flattening.
97
+
98
+ ### Registry
99
+
100
+ `createPromptRegistry` accepts a (possibly nested) record of `PromptModule` objects and namespace nodes. It returns a deep-frozen `PromptRegistry` with direct property access:
101
+
102
+ ```ts
103
+ const prompts = createPromptRegistry({
104
+ agents: { coverageAssessor },
105
+ greeting,
106
+ });
107
+ prompts.agents.coverageAssessor.render({ scope: "full" });
108
+ prompts.greeting.render();
109
+ ```
110
+
111
+ Nesting is driven by the `group` field in frontmatter. Each `/`-separated segment becomes a nesting level, with all names converted to camelCase. The registry is frozen at creation time to prevent mutation.
112
+
113
+ ## Consumer Import Pattern
114
+
115
+ The generated `index.ts` calls `createPromptRegistry` with all prompt modules organized by group and exports a `prompts` const object. Consumers import via the `~prompts` tsconfig alias:
116
+
117
+ ```ts
118
+ import { prompts } from "~prompts";
119
+
120
+ // Flat (no group)
121
+ const text = prompts.greeting.render();
122
+
123
+ // Nested (group: agents)
124
+ const text = prompts.agents.coverageAssessor.render({ scope: "full" });
125
+ ```
126
+
127
+ Types are inferred from the object structure, giving full type safety on `render` and `validate` arguments at every nesting level.
128
+
129
+ ## Types Reference
130
+
131
+ | Type | Description |
132
+ | --------------------- | ------------------------------------------------------------------------------------------------------------------------- |
133
+ | `PromptModule` | Interface: `name`, `group`, `schema` (ZodType), `render(vars)`, `validate(vars)` |
134
+ | `PromptNamespace` | A nested namespace node -- values are `PromptModule` leaves or further nested namespaces |
135
+ | `PromptRegistry` | Deep-readonly mapped type over a `PromptNamespace` tree |
136
+ | `CreateEngineOptions` | Options for `createEngine`: `root`, `partials`, `extname`, `cache`, `strictFilters`, `strictVariables`, `ownPropertyOnly` |
137
+ | `Liquid` | Re-exported LiquidJS engine type |
138
+
139
+ ## References
140
+
141
+ - [File Format](file-format.md)
142
+ - [CLI](cli.md)
@@ -44,7 +44,7 @@ Names must match `^[a-z0-9-]+$` (lowercase, digits, hyphens). The `name` field i
44
44
 
45
45
  ## Discovery
46
46
 
47
- The CLI scans `--roots` directories recursively (max depth 5). Files must have the `.prompt` extension. Symbolic links are skipped. Duplicate names across roots cause an error with paths listed.
47
+ The CLI scans `--includes` glob patterns recursively (max depth 5). Files must have the `.prompt` extension. Symbolic links are skipped. Duplicate names across roots cause an error with paths listed.
48
48
 
49
49
  Results are sorted alphabetically by name.
50
50
 
@@ -0,0 +1,306 @@
1
+ # .prompt File Format
2
+
3
+ A `.prompt` file is a LiquidJS template with YAML frontmatter. It is a declarative prompt authoring format compiled to typed TypeScript at build time.
4
+
5
+ ## File Anatomy
6
+
7
+ Every `.prompt` file has two sections: a YAML frontmatter block delimited by `---` fences, and a LiquidJS template body.
8
+
9
+ ```text
10
+ ---
11
+ name: coverage-assessor
12
+ group: agents/coverage-assessor
13
+ schema:
14
+ scope:
15
+ type: string
16
+ description: Assessment scope
17
+ target:
18
+ type: string
19
+ required: false
20
+ ---
21
+
22
+ You are a coverage assessor for {{ scope }}.
23
+ {% if target %}Targeting {{ target }} docs.{% endif %}
24
+ ```
25
+
26
+ | Section | Description |
27
+ | ------------------- | ------------------------------------------------------------- |
28
+ | Frontmatter (`---`) | YAML metadata block defining name, group, and variable schema |
29
+ | Body | LiquidJS template rendered at runtime with typed variables |
30
+
31
+ ## Template Syntax
32
+
33
+ | Syntax | Purpose |
34
+ | --------------------------------------- | ----------------------------------- |
35
+ | `{{ var }}` | Variable output |
36
+ | `{{ var \| filter }}` | Filtered output |
37
+ | `{% if var %}...{% endif %}` | Conditional |
38
+ | `{% for item in list %}...{% endfor %}` | Iteration |
39
+ | `{% render 'name', key: 'value' %}` | Partial inclusion (build-time only) |
40
+
41
+ Strict filters are enabled -- unknown filters throw an error. Variable access is restricted to own properties only.
42
+
43
+ ## Frontmatter Reference
44
+
45
+ The YAML frontmatter block defines metadata and the variable schema.
46
+
47
+ ### Fields
48
+
49
+ | Field | Required | Type | Description |
50
+ | --------- | -------- | -------- | ------------------------------------------------ |
51
+ | `name` | Yes | `string` | Unique kebab-case identifier (`^[a-z0-9-]+$`) |
52
+ | `group` | No | `string` | Namespace path (e.g. `agents/coverage-assessor`) |
53
+ | `version` | No | `string` | Version identifier |
54
+ | `schema` | No | `object` | Variable declarations map |
55
+
56
+ ### Validation Rules
57
+
58
+ - `name` is required and must match `^[a-z0-9-]+$`
59
+ - Frontmatter must be valid YAML between `---` delimiters
60
+ - `schema` must be an object (not an array)
61
+ - Missing or empty `name` throws a parse error with the file path
62
+ - Non-object frontmatter (e.g. a bare string) is rejected
63
+
64
+ ## Schema Variables
65
+
66
+ Each key under `schema` declares a template variable. Two syntaxes are supported.
67
+
68
+ **Shorthand** -- type string only, defaults to required:
69
+
70
+ ```yaml
71
+ schema:
72
+ scope: string
73
+ ```
74
+
75
+ **Full object** -- explicit control over all fields:
76
+
77
+ ```yaml
78
+ schema:
79
+ scope:
80
+ type: string
81
+ required: true
82
+ description: Assessment scope
83
+ ```
84
+
85
+ Shorthand `scope: string` expands to `{ type: 'string', required: true }`.
86
+
87
+ ### Variable Fields
88
+
89
+ | Field | Default | Description |
90
+ | ------------- | -------- | ---------------------------------------------------- |
91
+ | `type` | `string` | Variable type (only `string` supported) |
92
+ | `required` | `true` | Whether the variable must be provided at render time |
93
+ | `description` | -- | Human-readable description (used in generated JSDoc) |
94
+
95
+ ## Naming and Discovery
96
+
97
+ Names must match `^[a-z0-9-]+$` (lowercase, digits, hyphens). The `name` field in frontmatter is required and takes precedence. A file named `prompt.prompt` derives its name from the parent directory (e.g. `agents/gap-detector/prompt.prompt` becomes `gap-detector`).
98
+
99
+ The CLI scans `--includes` glob patterns recursively (max depth 5). Files must have the `.prompt` extension. Symbolic links are skipped. Duplicate names across roots cause an error with paths listed. Results are sorted alphabetically by name.
100
+
101
+ ### Recommended File Structure
102
+
103
+ ```text
104
+ src/
105
+ agents/
106
+ coverage-assessor/
107
+ prompt.prompt
108
+ prompts/
109
+ identity.prompt
110
+ constraints.prompt
111
+ ```
112
+
113
+ ## Partials
114
+
115
+ Partials are reusable template fragments included with `{% render %}` tags. They are resolved and flattened at build time -- the generated output contains no render tags.
116
+
117
+ ### Syntax
118
+
119
+ ```liquid
120
+ {% render 'identity', role: 'Coverage Assessor', desc: 'an expert at assessing documentation coverage' %}
121
+ ```
122
+
123
+ Only literal string parameters are supported. Variable references (e.g. `key: myVar`) are not allowed and throw an error at codegen time. Whitespace trim variants `{%-` and `-%}` are supported.
124
+
125
+ ### Resolution Order
126
+
127
+ Partials are resolved from two locations, searched in order (first match wins):
128
+
129
+ | Priority | Location | Description |
130
+ | -------- | -------------------- | ------------------------------------------------ |
131
+ | 1 | `.prompts/partials/` | Custom project partials (committed to git) |
132
+ | 2 | SDK `src/prompts/` | Built-in partials shipped with `@funkai/prompts` |
133
+
134
+ Custom partials take precedence -- a custom partial with the same name as a built-in overrides it.
135
+
136
+ ### Built-in Partials
137
+
138
+ | Partial | Parameters | Purpose |
139
+ | ------------- | -------------------------------------------------- | --------------------------------------------------- |
140
+ | `identity` | `role`, `desc`, `context` (optional) | Agent identity block (`<identity>` wrapper) |
141
+ | `constraints` | `in_scope`, `out_of_scope`, `rules` (all optional) | Scoping constraints block (`<constraints>` wrapper) |
142
+ | `tools` | `tools` (optional) | Tool listing block (`<tools>` wrapper) |
143
+
144
+ **identity** source:
145
+
146
+ ```liquid
147
+ <identity>
148
+ You are {{ role }}, {{ desc }}.
149
+ {% if context %}
150
+ {{ context }}
151
+ {% endif %}
152
+ </identity>
153
+ ```
154
+
155
+ **constraints** source:
156
+
157
+ ```liquid
158
+ <constraints>
159
+ {% if in_scope %}
160
+ ## In Scope
161
+ {% for item in in_scope %}
162
+ - {{ item }}
163
+ {% endfor %}
164
+ {% endif %}
165
+ {% if out_of_scope %}
166
+ ## Out of Scope
167
+ {% for item in out_of_scope %}
168
+ - {{ item }}
169
+ {% endfor %}
170
+ {% endif %}
171
+ {% if rules %}
172
+ ## Rules
173
+ {% for rule in rules %}
174
+ - {{ rule }}
175
+ {% endfor %}
176
+ {% endif %}
177
+ </constraints>
178
+ ```
179
+
180
+ ### Custom Partials
181
+
182
+ Place custom `.prompt` files in `.prompts/partials/`:
183
+
184
+ ```text
185
+ .prompts/
186
+ client/ # Generated (gitignored)
187
+ partials/ # Custom partials (committed)
188
+ summary.prompt
189
+ ```
190
+
191
+ The CLI auto-discovers this directory:
192
+
193
+ - `prompts generate` derives it from `--out` (sibling `partials/` dir)
194
+ - `prompts lint` defaults to `.prompts/partials` (configurable via `--partials`)
195
+
196
+ **Creating a custom partial:**
197
+
198
+ ```bash
199
+ prompts create summary --partial
200
+ ```
201
+
202
+ Or create `.prompts/partials/<name>.prompt` by hand:
203
+
204
+ ```liquid
205
+ <summary>
206
+ {{ content }}
207
+ {% if notes %}
208
+ Notes: {{ notes }}
209
+ {% endif %}
210
+ </summary>
211
+ ```
212
+
213
+ Use it in a `.prompt` file:
214
+
215
+ ```liquid
216
+ {% render 'summary', content: 'Analysis complete' %}
217
+ ```
218
+
219
+ Run `prompts generate` -- the partial is flattened into the generated output. No `{% render %}` tags remain.
220
+
221
+ **Overriding built-ins:** Create a file with the same name in `.prompts/partials/` (e.g. `.prompts/partials/identity.prompt`). Custom partials take precedence over SDK built-ins.
222
+
223
+ **Adding a built-in partial (SDK contributors):**
224
+
225
+ 1. Create `packages/prompts/src/prompts/<name>.prompt`
226
+ 2. Write the partial template using XML-style wrapper tags and Liquid variables
227
+ 3. Test with a consumer `.prompt` file and run `prompts generate`
228
+
229
+ ## Authoring Walkthrough
230
+
231
+ ### Prerequisites
232
+
233
+ - `@funkai/prompts` installed
234
+ - Project configured ([Setup guide](setup.md))
235
+
236
+ ### Steps
237
+
238
+ 1. **Scaffold** with the CLI:
239
+
240
+ ```bash
241
+ prompts create my-agent --out src/agents/my-agent
242
+ ```
243
+
244
+ 2. **Edit** the frontmatter -- set `name`, `group`, and `schema` variables.
245
+
246
+ 3. **Write** the template body using `{{ var }}` syntax and conditionals.
247
+
248
+ 4. **Add partials** if needed:
249
+
250
+ ```liquid
251
+ {% render 'identity', role: 'Analyzer', desc: 'a code analyzer' %}
252
+ ```
253
+
254
+ 5. **Lint:**
255
+
256
+ ```bash
257
+ prompts lint --includes "src/agents/**"
258
+ ```
259
+
260
+ 6. **Generate:**
261
+
262
+ ```bash
263
+ prompts generate --out .prompts/client --includes "src/agents/**"
264
+ ```
265
+
266
+ 7. **Import and use:**
267
+
268
+ ```ts
269
+ import { prompts } from "~prompts";
270
+
271
+ const text = prompts.myAgent.render({ scope: "full" });
272
+ ```
273
+
274
+ ### Verification
275
+
276
+ - `prompts lint` reports no errors
277
+ - Generated file exists at `.prompts/client/my-agent.ts`
278
+ - TypeScript compiles without errors
279
+
280
+ ### Troubleshooting
281
+
282
+ #### Undefined variable error
283
+
284
+ **Fix:** Add the variable to the frontmatter `schema` block.
285
+
286
+ #### Duplicate prompt name
287
+
288
+ **Fix:** Two `.prompt` files share the same `name` -- rename one to a unique kebab-case identifier.
289
+
290
+ #### TypeScript can't find `~prompts`
291
+
292
+ **Fix:** Run `prompts setup` or add the path alias to `tsconfig.json`. See [setup.md](setup.md).
293
+
294
+ #### Variable reference not supported in partial
295
+
296
+ **Fix:** Only literal string params are allowed in `{% render %}` tags. Replace variable references with string literals.
297
+
298
+ #### Partial not found
299
+
300
+ **Fix:** Verify the file is in `.prompts/partials/` (custom) or `src/prompts/` (built-in) with `.prompt` extension.
301
+
302
+ ## References
303
+
304
+ - [Code Generation & Library](codegen.md)
305
+ - [CLI](cli.md)
306
+ - [Setup](setup.md)
@@ -26,13 +26,13 @@ prompts create my-agent --out src/agents/my-agent
26
26
  5. Lint:
27
27
 
28
28
  ```bash
29
- prompts lint --roots src/agents
29
+ prompts lint --includes "src/agents/**"
30
30
  ```
31
31
 
32
32
  6. Generate:
33
33
 
34
34
  ```bash
35
- prompts generate --out .prompts/client --roots src/agents
35
+ prompts generate --out .prompts/client --includes "src/agents/**"
36
36
  ```
37
37
 
38
38
  7. Import and use:
@@ -50,7 +50,7 @@ Or configure manually (steps 3-6).
50
50
  ```json
51
51
  {
52
52
  "scripts": {
53
- "prompts:generate": "prompts generate --out .prompts/client --roots prompts src/agents"
53
+ "prompts:generate": "prompts generate --out .prompts/client --includes \"prompts/**\" \"src/agents/**\""
54
54
  }
55
55
  }
56
56
  ```
package/docs/overview.md CHANGED
@@ -1,4 +1,4 @@
1
- # Prompts SDK Overview
1
+ # Prompts SDK
2
2
 
3
3
  Prompt authoring SDK with two surfaces: a **CLI** for build-time code generation from `.prompt` files, and a **library** for runtime template rendering with full type safety.
4
4
 
@@ -51,28 +51,6 @@ flowchart LR
51
51
  classDef gateway fill:#313244,stroke:#fab387,stroke-width:2px,color:#cdd6f4
52
52
  ```
53
53
 
54
- ## Package Structure
55
-
56
- ```
57
- 📁 packages/prompts/
58
- ├── 📁 src/
59
- │ ├── 📁 prompts/ # Built-in partials (identity, constraints, tools)
60
- │ ├── 📄 engine.ts # LiquidJS engine factory
61
- │ ├── 📄 registry.ts # Typed prompt registry
62
- │ ├── 📄 clean.ts # Frontmatter stripping pipeline
63
- │ ├── 📄 partials-dir.ts # PARTIALS_DIR export for CLI/consumers
64
- │ ├── 📄 types.ts # PromptModule, PromptNamespace, PromptRegistry types
65
- │ └── 📄 index.ts # Public exports
66
- └── 📁 docs/
67
-
68
- 📁 packages/cli/ # @funkai/cli — CLI binary (see @funkai/cli README)
69
- ├── 📁 commands/ # generate, lint, create, setup
70
- ├── 📁 src/lib/ # codegen, frontmatter, flatten, lint, paths
71
- └── 📄 index.ts # CLI entry point (kidd-cli)
72
- ```
73
-
74
- > **Note:** The CLI was extracted to `@funkai/cli`. Install it separately for the `prompts` binary.
75
-
76
54
  ## Dual Surface
77
55
 
78
56
  | Surface | When | What |
@@ -83,20 +61,15 @@ flowchart LR
83
61
  ## Quick Start
84
62
 
85
63
  1. Create a `.prompt` file with YAML frontmatter and a LiquidJS template body.
86
- 2. Run `prompts generate --out .prompts/client --roots src/agents` to produce typed modules.
64
+ 2. Run `prompts generate --out .prompts/client --includes "src/agents/**"` to produce typed modules.
87
65
  3. Import from the `~prompts` alias in your application code.
88
66
  4. Call `.render({ vars })` with full type safety derived from the Zod schema in frontmatter.
89
67
 
90
- ## References
68
+ ## Documentation
91
69
 
92
- - [File Format](file-format/overview.md)
93
- - [Frontmatter](file-format/frontmatter.md)
94
- - [Partials](file-format/partials.md)
95
- - [CLI](cli/overview.md)
96
- - [CLI Commands](cli/commands.md)
97
- - [Code Generation](codegen/overview.md)
98
- - [Library API](library/overview.md)
99
- - [Guide: Author a Prompt](guides/author-prompt.md)
100
- - [Guide: Setup Project](guides/setup-project.md)
101
- - [Guide: Add a Partial](guides/add-partial.md)
102
- - [Troubleshooting](troubleshooting.md)
70
+ | Topic | Description |
71
+ | --------------------------------------- | ------------------------------------------------------------------------- |
72
+ | [File Format](file-format.md) | .prompt anatomy, frontmatter, schema variables, partials, authoring guide |
73
+ | [Code Generation & Library](codegen.md) | Build pipeline, generated output, runtime API, consumer patterns |
74
+ | [Project Setup](setup.md) | VSCode, .gitignore, tsconfig, package.json configuration |
75
+ | [Troubleshooting](troubleshooting.md) | Common errors and fixes |
package/docs/setup.md ADDED
@@ -0,0 +1,76 @@
1
+ # Setup Prompt Development
2
+
3
+ ## Prerequisites
4
+
5
+ - Node 24
6
+ - pnpm workspace
7
+
8
+ ## Steps
9
+
10
+ 1. Install:
11
+
12
+ ```bash
13
+ pnpm add @funkai/prompts --workspace
14
+ ```
15
+
16
+ 2. Run interactive setup:
17
+
18
+ ```bash
19
+ prompts setup
20
+ ```
21
+
22
+ Or configure manually (steps 3-6).
23
+
24
+ 3. Add VSCode file association in `.vscode/settings.json`:
25
+
26
+ ```json
27
+ {
28
+ "files.associations": {
29
+ "*.prompt": "markdown"
30
+ }
31
+ }
32
+ ```
33
+
34
+ 4. Add `.prompts/client/` to `.gitignore`.
35
+
36
+ 5. Add `~prompts` path alias to `tsconfig.json`:
37
+
38
+ ```json
39
+ {
40
+ "compilerOptions": {
41
+ "paths": {
42
+ "~prompts": ["./.prompts/client/index.ts"]
43
+ }
44
+ }
45
+ }
46
+ ```
47
+
48
+ 6. Add generate script to `package.json`:
49
+
50
+ ```json
51
+ {
52
+ "scripts": {
53
+ "prompts:generate": "prompts generate --out .prompts/client --includes \"prompts/**\" \"src/agents/**\""
54
+ }
55
+ }
56
+ ```
57
+
58
+ ## Verification
59
+
60
+ Run `prompts generate` and verify `.prompts/client/` directory is created with an `index.ts`.
61
+
62
+ ## Troubleshooting
63
+
64
+ ### VSCode not highlighting `.prompt` files
65
+
66
+ **Fix:** Check `.vscode/settings.json` file association is set correctly.
67
+
68
+ ### TypeScript can't resolve `~prompts`
69
+
70
+ **Fix:** Verify `tsconfig.json` paths alias points to `./.prompts/client/index.ts`.
71
+
72
+ ## References
73
+
74
+ - [CLI](cli.md)
75
+ - [File Format](file-format.md)
76
+ - [Code Generation & Library](codegen.md)
@@ -14,7 +14,7 @@
14
14
 
15
15
  ## Invalid prompt name
16
16
 
17
- **Fix:** Names must match `^[a-z0-9-]+$` lowercase letters, digits, and hyphens only.
17
+ **Fix:** Names must match `^[a-z0-9-]+$` -- lowercase letters, digits, and hyphens only.
18
18
 
19
19
  ## Partial variable reference error
20
20
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@funkai/prompts",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "private": false,
5
5
  "description": "Prompt SDK with LiquidJS templating and Zod validation",
6
6
  "keywords": [
@@ -42,7 +42,7 @@
42
42
  },
43
43
  "dependencies": {
44
44
  "es-toolkit": "^1.45.1",
45
- "liquidjs": "^10.25.0",
45
+ "liquidjs": "^10.25.1",
46
46
  "zod": "^4.3.6"
47
47
  },
48
48
  "devDependencies": {
package/src/engine.ts CHANGED
@@ -21,6 +21,7 @@ export function createEngine(partialsDir: string, options?: Partial<CreateEngine
21
21
  ...options,
22
22
  // Safety defaults — applied after spread so callers cannot disable them
23
23
  strictFilters: true,
24
+ strictVariables: true,
24
25
  ownPropertyOnly: true,
25
26
  });
26
27
  }
@@ -36,5 +37,6 @@ export function createEngine(partialsDir: string, options?: Partial<CreateEngine
36
37
  */
37
38
  export const liquidEngine = new Liquid({
38
39
  strictFilters: true,
40
+ strictVariables: true,
39
41
  ownPropertyOnly: true,
40
42
  });