promptopskit 0.0.2 → 0.1.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 (41) hide show
  1. package/LICENSE +211 -211
  2. package/README.md +382 -335
  3. package/dist/{chunk-VYVEVJC3.js → chunk-B5UFGNDV.js} +2 -2
  4. package/dist/chunk-B5UFGNDV.js.map +1 -0
  5. package/dist/{chunk-5BI5FP5L.js → chunk-FSOJVXC4.js} +2 -2
  6. package/dist/chunk-FSOJVXC4.js.map +1 -0
  7. package/dist/{chunk-6KGBPHSY.js → chunk-HEFOFQ2K.js} +1 -1
  8. package/dist/chunk-HEFOFQ2K.js.map +1 -0
  9. package/dist/{chunk-NIZENC7D.js → chunk-HMYPMHTG.js} +90 -3
  10. package/dist/chunk-HMYPMHTG.js.map +1 -0
  11. package/dist/{chunk-UYTUGV7Z.js → chunk-V375NQ6C.js} +2 -2
  12. package/dist/chunk-V375NQ6C.js.map +1 -0
  13. package/dist/{chunk-PU3UPUND.js → chunk-YCRWYE6N.js} +2 -2
  14. package/dist/chunk-YCRWYE6N.js.map +1 -0
  15. package/dist/cli/index.js +167 -36
  16. package/dist/cli/index.js.map +1 -1
  17. package/dist/index.cjs +100 -14
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.cts +8 -1
  20. package/dist/index.d.ts +8 -1
  21. package/dist/index.js +7 -8
  22. package/dist/index.js.map +1 -1
  23. package/dist/providers/anthropic.cjs.map +1 -1
  24. package/dist/providers/anthropic.js +2 -2
  25. package/dist/providers/gemini.cjs.map +1 -1
  26. package/dist/providers/gemini.js +2 -2
  27. package/dist/providers/openai.cjs.map +1 -1
  28. package/dist/providers/openai.js +2 -2
  29. package/dist/providers/openrouter.cjs.map +1 -1
  30. package/dist/providers/openrouter.js +3 -3
  31. package/dist/testing.cjs +8 -0
  32. package/dist/testing.cjs.map +1 -1
  33. package/dist/testing.js +1 -1
  34. package/dist/testing.js.map +1 -1
  35. package/package.json +117 -116
  36. package/dist/chunk-5BI5FP5L.js.map +0 -1
  37. package/dist/chunk-6KGBPHSY.js.map +0 -1
  38. package/dist/chunk-NIZENC7D.js.map +0 -1
  39. package/dist/chunk-PU3UPUND.js.map +0 -1
  40. package/dist/chunk-UYTUGV7Z.js.map +0 -1
  41. package/dist/chunk-VYVEVJC3.js.map +0 -1
package/README.md CHANGED
@@ -1,335 +1,382 @@
1
- # PromptOpsKit
2
-
3
- [![npm version](https://img.shields.io/npm/v/promptopskit.svg)](https://www.npmjs.com/package/promptopskit)
4
- [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
5
- [![Node.js](https://img.shields.io/badge/node-%3E%3D20-brightgreen.svg)](https://nodejs.org)
6
-
7
- Open-source developer toolkit for managing prompts, system instructions, tools, and model settings **as code**. One `npm install` gives you both a runtime library and a CLI.
8
-
9
- PromptOpsKit treats every prompt as a Markdown file YAML front matter defines model settings, sampling parameters, reasoning levels, tool bindings, and override rules, while H1 headings separate system instructions from prompt templates. Variables use `{{ mustache }}` syntax, shared instructions are composed via `includes`, and environment/tier overrides let the same prompt target dev vs. prod or free vs. pro without duplication.
10
-
11
- Provider adapters for OpenAI, Anthropic, Gemini, and OpenRouter produce a ready-to-send **request body only** — no HTTP client, no auth, no headers. Your application owns transport, so PromptOpsKit slots into any stack without opinions about how you call the API.
12
-
13
- ### Why PromptOpsKit?
14
-
15
- - **Version-control your prompts** — plain Markdown files that diff, review, and merge like any other code.
16
- - **One prompt, many providers** — write once, render for OpenAI, Anthropic, Gemini, or OpenRouter with correct body shapes.
17
- - **Override without forking** — environment and tier overrides swap models and parameters without duplicating prompt files.
18
- - **Compose and share** — `includes` lets you define shared tone, policy, or safety instructions once and reuse them everywhere.
19
- - **Validate early** — Zod schema validation, Levenshtein-based "did you mean?" suggestions for typos, and variable usage checks catch mistakes before runtime.
20
- - **Compile for production** — pre-compile `.md` to JSON or ESM so deployments skip parsing entirely.
21
- - **No lock-in** — body-only output means you choose the HTTP client, auth strategy, and infrastructure.
22
-
23
- ## Install
24
-
25
- ```bash
26
- npm install promptopskit
27
- ```
28
-
29
- ## Quick Start
30
-
31
- ### 1. Scaffold starter prompts
32
-
33
- ```bash
34
- npx promptopskit init ./prompts
35
- ```
36
-
37
- This creates:
38
-
39
- ```
40
- prompts/
41
- ├── hello.md # Sample prompt with variables
42
- ├── hello.test.yaml # Test sidecar with sample inputs
43
- └── shared/
44
- └── tone.md # Shared system instructions (included via composition)
45
- ```
46
-
47
- ### 2. Write a prompt
48
-
49
- ```markdown
50
- ---
51
- id: support.reply
52
- schema_version: 1
53
- provider: openai
54
- model: gpt-5.4
55
- reasoning:
56
- effort: medium
57
- sampling:
58
- temperature: 0.7
59
- context:
60
- inputs:
61
- - user_message
62
- includes:
63
- - ./shared/tone.md
64
- ---
65
-
66
- # System instructions
67
-
68
- You are a helpful support assistant.
69
-
70
- # Prompt template
71
-
72
- {{ user_message }}
73
- ```
74
-
75
- ### 3. Render for a provider
76
-
77
- ```typescript
78
- import { createPromptOpsKit } from 'promptopskit';
79
-
80
- const kit = createPromptOpsKit({ sourceDir: './prompts' });
81
-
82
- const result = await kit.renderPrompt({
83
- path: 'support/reply',
84
- provider: 'openai',
85
- variables: { user_message: 'How do I reset my password?' },
86
- });
87
-
88
- // result.request.body is ready for fetch()
89
- const response = await fetch('https://api.openai.com/v1/chat/completions', {
90
- method: 'POST',
91
- headers: {
92
- 'Content-Type': 'application/json',
93
- 'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`,
94
- },
95
- body: JSON.stringify(result.request.body),
96
- });
97
- ```
98
-
99
- ## Features
100
-
101
- - **Prompts as Markdown** — YAML front matter for settings, H1 headings for sections (`# System instructions`, `# Prompt template`, `# Notes`)
102
- - **Variable interpolation** — `{{ variable }}` syntax with strict and permissive modes
103
- - **Composition** — `includes` to share system instructions across prompts, with circular detection
104
- - **Overrides** — Environment and tier-based overrides (base → env → tier → runtime)
105
- - **4 provider adapters** — OpenAI, Anthropic, Gemini, OpenRouter — body-only output
106
- - **Validation** — Zod schema validation, Levenshtein-based "did you mean?" for typos, variable usage checks
107
- - **Caching** — LRU cache with mtime-based invalidation
108
- - **CLI** — init, validate, compile, render, inspect, skill
109
- - **Compiled artifacts** — Pre-compile `.md` JSON or ESM for production
110
-
111
- ## Provider Adapters
112
-
113
- Each adapter produces a `{ body, provider, model }` object shaped for the target API. You handle the HTTP call.
114
-
115
- ```typescript
116
- // OpenAI
117
- import { createPromptOpsKit } from 'promptopskit';
118
- const kit = createPromptOpsKit({ sourceDir: './prompts' });
119
- const { request } = await kit.renderPrompt({ path: 'hello', provider: 'openai', variables: { name: 'World' } });
120
- // request.body { model, messages, temperature, reasoning_effort, ... }
121
-
122
- // Anthropic — system is a top-level field, max_tokens defaults to 4096
123
- const { request } = await kit.renderPrompt({ path: 'hello', provider: 'anthropic', variables: { name: 'World' } });
124
- // request.body → { model, messages, system, max_tokens, ... }
125
-
126
- // Gemini contents/systemInstruction/generationConfig structure
127
- const { request } = await kit.renderPrompt({ path: 'hello', provider: 'gemini', variables: { name: 'World' } });
128
- // request.body → { contents, systemInstruction, generationConfig, ... }
129
-
130
- // OpenRouter — same shape as OpenAI, different provider label
131
- const { request } = await kit.renderPrompt({ path: 'hello', provider: 'openrouter', variables: { name: 'World' } });
132
- ```
133
-
134
- Provider adapters are also available as direct imports:
135
-
136
- ```typescript
137
- import { openaiAdapter } from 'promptopskit/openai';
138
- import { anthropicAdapter } from 'promptopskit/anthropic';
139
- import { geminiAdapter } from 'promptopskit/gemini';
140
- import { openrouterAdapter } from 'promptopskit/openrouter';
141
- ```
142
-
143
- ## Overrides
144
-
145
- Define environment and tier overrides in front matter. Precedence: **base environment → tier → runtime**. Scalars and arrays are replaced, not merged.
146
-
147
- ```markdown
148
- ---
149
- id: support.reply
150
- schema_version: 1
151
- provider: openai
152
- model: gpt-5.4
153
- sampling:
154
- temperature: 0.7
155
- environments:
156
- dev:
157
- model: gpt-5.4-mini
158
- sampling:
159
- temperature: 0.2
160
- prod:
161
- model: gpt-5.4
162
- tiers:
163
- free:
164
- model: gpt-5.4-mini
165
- pro:
166
- model: gpt-5.4
167
- ---
168
- ```
169
-
170
- ```typescript
171
- const result = await kit.renderPrompt({
172
- path: 'support/reply',
173
- provider: 'openai',
174
- environment: 'dev',
175
- tier: 'pro',
176
- variables: { user_message: '...' },
177
- });
178
- ```
179
-
180
- ## Composition
181
-
182
- Share system instructions across prompts using `includes`. Included system instructions are prepended before local ones.
183
-
184
- ```markdown
185
- ---
186
- id: support.reply
187
- schema_version: 1
188
- includes:
189
- - ./shared/tone.md
190
- ---
191
-
192
- # System instructions
193
-
194
- Handle support requests carefully.
195
- ```
196
-
197
- ## CLI
198
-
199
- ```bash
200
- # Scaffold starter prompts
201
- promptopskit init [dir]
202
-
203
- # Validate all .md files in a directory
204
- promptopskit validate <dir> [--strict]
205
-
206
- # Compile .md → JSON/ESM artifacts
207
- promptopskit compile <src> <out> [--dry-run] [--format json|esm] [--no-clean]
208
-
209
- # Render a prompt preview (auto-loads .test.yaml sidecar)
210
- promptopskit render <file> [--env <name>] [--tier <name>] [--vars <file>] [--json]
211
-
212
- # Print normalized asset as JSON
213
- promptopskit inspect <file>
214
-
215
- # Deploy AI agent instructions into your project
216
- promptopskit skill [--target copilot|cursor|generic] [--force]
217
- ```
218
-
219
- ## AI Agent Instructions
220
-
221
- The `skill` command deploys a comprehensive instructions file so AI coding assistants (GitHub Copilot, Cursor, etc.) automatically understand how to create and manage prompts with promptopskit.
222
-
223
- ```bash
224
- # Deploy for GitHub Copilot (default)
225
- promptopskit skill
226
- # .github/instructions/promptopskit.instructions.md
227
-
228
- # Deploy for Cursor
229
- promptopskit skill --target cursor
230
- # .cursor/rules/promptopskit.mdc
231
-
232
- # Deploy a generic instructions file
233
- promptopskit skill --target generic
234
- # .ai/promptopskit-skill.md
235
-
236
- # Overwrite an existing instructions file
237
- promptopskit skill --force
238
- ```
239
-
240
- The deployed file covers the prompt format, front matter schema, variable interpolation, includes, overrides, the TypeScript API, provider adapters, and project conventions — everything an AI agent needs to write correct prompts on the first try.
241
-
242
- ## Inline Source
243
-
244
- Render prompts from strings without files:
245
-
246
- ```typescript
247
- const result = await kit.renderPrompt({
248
- source: `---
249
- id: inline
250
- schema_version: 1
251
- provider: openai
252
- model: gpt-5.4
253
- ---
254
-
255
- # Prompt template
256
-
257
- Hello {{ name }}!`,
258
- provider: 'openai',
259
- variables: { name: 'World' },
260
- });
261
- ```
262
-
263
- ## Testing Helpers
264
-
265
- ```typescript
266
- import { createMockAsset, createMockResolvedAsset, parseTestPrompt } from 'promptopskit/testing';
267
-
268
- const asset = createMockAsset({ model: 'gpt-5.4' });
269
- const resolved = createMockResolvedAsset();
270
- const parsed = parseTestPrompt('---\nid: test\nschema_version: 1\n---\n\nHello');
271
- ```
272
-
273
- ## API Reference
274
-
275
- ### `createPromptOpsKit(config)`
276
-
277
- Creates a `PromptOpsKit` instance.
278
-
279
- | Option | Type | Default | Description |
280
- |--------|------|---------|-------------|
281
- | `sourceDir` | `string` | — | Path to prompt `.md` files (required) |
282
- | `compiledDir` | `string` | — | Path to compiled artifacts |
283
- | `mode` | `'auto' \| 'compiled-only' \| 'source-only'` | `'auto'` | Resolution strategy |
284
- | `cache` | `boolean` | `true` | Enable LRU cache with mtime invalidation |
285
-
286
- ### `kit.renderPrompt(options)`
287
-
288
- Renders a prompt for a specific provider. Returns `{ resolved, request, warnings }`.
289
-
290
- | Option | Type | Description |
291
- |--------|------|-------------|
292
- | `path` | `string` | Prompt path (no extension), e.g. `'support/reply'` |
293
- | `source` | `string` | Inline prompt source (alternative to path) |
294
- | `provider` | `string` | `'openai'`, `'anthropic'`, `'gemini'`, `'openrouter'` |
295
- | `variables` | `Record<string, string>` | Template variables |
296
- | `environment` | `string` | Environment override name |
297
- | `tier` | `string` | Tier override name |
298
- | `history` | `Array<{ role, content }>` | Conversation history |
299
- | `strict` | `boolean` | Fail on missing variables |
300
-
301
- ### `kit.loadPrompt(path)` / `kit.resolvePrompt(path, options)` / `kit.validatePrompt(path)`
302
-
303
- Lower-level methods for loading, resolving (includes + overrides), and validating individual prompts.
304
-
305
- ### Standalone Functions
306
-
307
- ```typescript
308
- import { parsePrompt, interpolate, extractVariables, resolveIncludes, applyOverrides, validateAsset, getAdapter } from 'promptopskit';
309
- ```
310
-
311
- ## Schema
312
-
313
- Prompt files use YAML front matter with these fields:
314
-
315
- | Field | Type | Description |
316
- |-------|------|-------------|
317
- | `id` | `string` | Unique prompt identifier (required) |
318
- | `schema_version` | `number` | Schema version, currently `1` |
319
- | `provider` | `string` | `openai`, `anthropic`, `gemini` (or `google`), `openrouter`, `any` |
320
- | `model` | `string` | Model name |
321
- | `fallback_models` | `string[]` | Fallback model list |
322
- | `reasoning` | `object` | `{ effort, budget_tokens }` |
323
- | `sampling` | `object` | `{ temperature, top_p, frequency_penalty, presence_penalty, stop, max_output_tokens }` |
324
- | `response` | `object` | `{ format, stream }` |
325
- | `tools` | `array` | Tool references (string names or inline definitions) |
326
- | `mcp` | `object` | MCP server references |
327
- | `context` | `object` | `{ inputs, history }` declare expected variables |
328
- | `includes` | `string[]` | Paths to included prompt files |
329
- | `environments` | `object` | Named environment overrides |
330
- | `tiers` | `object` | Named tier overrides |
331
- | `metadata` | `object` | `{ owner, tags, review_required, stable }` |
332
-
333
- ## License
334
-
335
- [MIT](LICENSE)
1
+ # PromptOpsKit
2
+
3
+ [![npm version](https://img.shields.io/npm/v/promptopskit.svg)](https://www.npmjs.com/package/promptopskit)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
5
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D20-brightgreen.svg)](https://nodejs.org)
6
+
7
+ **Centralize prompts, system instructions, tools, and model settings without leaving your codebase.**
8
+
9
+ Your prompts are already in Git. PromptOpsKit makes them manageable. It replaces hardcoded strings and scattered provider-specific glue with structured Markdown files where prompt text, model settings, sampling parameters, tool bindings, environment overrides, and composable shared instructions all live together diffable, reviewable, and release-aware.
10
+
11
+ Provider adapters for OpenAI, Anthropic, Gemini, and OpenRouter produce a ready-to-send **request body only** — no HTTP client, no auth, no headers. Your application owns transport, so PromptOpsKit slots into any stack without opinions about how you call the API.
12
+
13
+ ### Why PromptOpsKit?
14
+
15
+ - **Centralized, not scattered** — each prompt is a single Markdown file that captures prompt text, model config, tool bindings, and context rules together.
16
+ - **Operational, not just templated** — model name, temperature, reasoning effort, tools, and response format are declared alongside the prompt they govern.
17
+ - **Reusable, not duplicated** — `includes` lets you define shared tone, policy, or safety instructions once and compose them into any prompt.
18
+ - **Layered defaults, not repetition** — `defaults.md` in any folder sets shared `metadata` and `# System instructions` for that subtree, with nearest-folder override behavior.
19
+ - **Release-aware, not ad hoc** — environment and tier overrides swap models and parameters without forking prompt files.
20
+ - **Provider-portable** — write once, render for OpenAI, Anthropic, Gemini, or OpenRouter with correct body shapes.
21
+ - **Validate early** — Zod schema validation, Levenshtein-based "did you mean?" suggestions for typos, and variable usage checks catch mistakes before runtime.
22
+ - **Compile for production** — pre-compile `.md` to JSON or ESM so deployments skip parsing entirely.
23
+ - **Repo-native, not dashboard-native** — no hosted service, no external admin tool. Everything lives in source control.
24
+
25
+ ## Install
26
+
27
+ ```bash
28
+ npm install promptopskit
29
+ ```
30
+
31
+ ## Quick Start
32
+
33
+ ### 1. Scaffold starter prompts
34
+
35
+ ```bash
36
+ npx promptopskit init ./prompts
37
+ ```
38
+
39
+ This creates:
40
+
41
+ ```
42
+ prompts/
43
+ ├── hello.md # Sample prompt with variables
44
+ ├── hello.test.yaml # Test sidecar with sample inputs
45
+ └── shared/
46
+ └── tone.md # Shared system instructions (included via composition)
47
+ ```
48
+
49
+ ### 2. Write a prompt
50
+
51
+ ```markdown
52
+ ---
53
+ id: support.reply
54
+ schema_version: 1
55
+ provider: openai
56
+ model: gpt-5.4
57
+ reasoning:
58
+ effort: medium
59
+ sampling:
60
+ temperature: 0.7
61
+ context:
62
+ inputs:
63
+ - user_message
64
+ - app_context
65
+ includes:
66
+ - ./shared/tone.md
67
+ ---
68
+
69
+ # System instructions
70
+
71
+ You are a helpful support assistant working in {{ app_context }}.
72
+
73
+ # Prompt template
74
+
75
+ {{ user_message }}
76
+ ```
77
+
78
+ ### 3. Render for a provider
79
+
80
+ ```typescript
81
+ import { createPromptOpsKit } from 'promptopskit';
82
+
83
+ const kit = createPromptOpsKit({ sourceDir: './prompts' });
84
+
85
+ const result = await kit.renderPrompt({
86
+ path: 'support/reply',
87
+ provider: 'openai',
88
+ variables: {
89
+ user_message: 'How do I reset my password?',
90
+ app_context: 'Account settings page',
91
+ },
92
+ });
93
+
94
+ // result.request.body is ready for fetch()
95
+ const response = await fetch('https://api.openai.com/v1/chat/completions', {
96
+ method: 'POST',
97
+ headers: {
98
+ 'Content-Type': 'application/json',
99
+ 'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`,
100
+ },
101
+ body: JSON.stringify(result.request.body),
102
+ });
103
+ ```
104
+
105
+ ## Features
106
+
107
+ - **Prompts as Markdown** — YAML front matter for settings, H1 headings for sections (`# System instructions`, `# Prompt template`, `# Notes`)
108
+ - **Variable interpolation** — `{{ variable }}` syntax with strict and permissive modes
109
+ - **Composition** — `includes` to share system instructions across prompts, with circular detection
110
+ - **Folder defaults** — `defaults.md` inheritance for shared metadata and system instructions
111
+ - **Overrides** — Environment and tier-based overrides (base → env → tier → runtime)
112
+ - **4 provider adapters** — OpenAI, Anthropic, Gemini, OpenRouter — body-only output
113
+ - **Validation** Zod schema validation, Levenshtein-based "did you mean?" for typos, variable usage checks
114
+ - **Caching** — LRU cache with mtime-based invalidation
115
+ - **CLI** — init, validate, compile, render, inspect, skill
116
+ - **Compiled artifacts** — Pre-compile `.md` → JSON or ESM for production
117
+
118
+ ## Provider Adapters
119
+
120
+ Each adapter produces a `{ body, provider, model }` object shaped for the target API. You handle the HTTP call.
121
+
122
+ ```typescript
123
+ // OpenAI
124
+ import { createPromptOpsKit } from 'promptopskit';
125
+ const kit = createPromptOpsKit({ sourceDir: './prompts' });
126
+ const { request } = await kit.renderPrompt({
127
+ path: 'hello',
128
+ provider: 'openai',
129
+ variables: { name: 'World', app_context: 'Welcome screen' },
130
+ });
131
+ // request.body { model, messages, temperature, reasoning_effort, ... }
132
+
133
+ // Anthropic — system is a top-level field, max_tokens defaults to 4096
134
+ const { request } = await kit.renderPrompt({
135
+ path: 'hello',
136
+ provider: 'anthropic',
137
+ variables: { name: 'World', app_context: 'Welcome screen' },
138
+ });
139
+ // request.body → { model, messages, system, max_tokens, ... }
140
+
141
+ // Gemini — contents/systemInstruction/generationConfig structure
142
+ const { request } = await kit.renderPrompt({
143
+ path: 'hello',
144
+ provider: 'gemini',
145
+ variables: { name: 'World', app_context: 'Welcome screen' },
146
+ });
147
+ // request.body → { contents, systemInstruction, generationConfig, ... }
148
+
149
+ // OpenRouter — same shape as OpenAI, different provider label
150
+ const { request } = await kit.renderPrompt({
151
+ path: 'hello',
152
+ provider: 'openrouter',
153
+ variables: { name: 'World', app_context: 'Welcome screen' },
154
+ });
155
+ ```
156
+
157
+ Provider adapters are also available as direct imports:
158
+
159
+ ```typescript
160
+ import { openaiAdapter } from 'promptopskit/openai';
161
+ import { anthropicAdapter } from 'promptopskit/anthropic';
162
+ import { geminiAdapter } from 'promptopskit/gemini';
163
+ import { openrouterAdapter } from 'promptopskit/openrouter';
164
+ ```
165
+
166
+ ## Overrides
167
+
168
+ Define environment and tier overrides in front matter. Precedence: **base → environment → tier → runtime**. Scalars and arrays are replaced, not merged.
169
+
170
+ ```markdown
171
+ ---
172
+ id: support.reply
173
+ schema_version: 1
174
+ provider: openai
175
+ model: gpt-5.4
176
+ sampling:
177
+ temperature: 0.7
178
+ environments:
179
+ dev:
180
+ model: gpt-5.4-mini
181
+ sampling:
182
+ temperature: 0.2
183
+ prod:
184
+ model: gpt-5.4
185
+ tiers:
186
+ free:
187
+ model: gpt-5.4-mini
188
+ pro:
189
+ model: gpt-5.4
190
+ ---
191
+ ```
192
+
193
+ ```typescript
194
+ const result = await kit.renderPrompt({
195
+ path: 'support/reply',
196
+ provider: 'openai',
197
+ environment: 'dev',
198
+ tier: 'pro',
199
+ variables: { user_message: '...' },
200
+ });
201
+ ```
202
+
203
+ ## Composition
204
+
205
+ Share system instructions across prompts using `includes`. Included system instructions are prepended before local ones.
206
+
207
+ ```markdown
208
+ ---
209
+ id: support.reply
210
+ schema_version: 1
211
+ includes:
212
+ - ./shared/tone.md
213
+ ---
214
+
215
+ # System instructions
216
+
217
+ Handle support requests carefully.
218
+ ```
219
+
220
+ ## Folder defaults
221
+
222
+ Define a `defaults.md` file in `prompts/` (and optional subfolders) to provide inherited defaults for prompts:
223
+
224
+ - Shared `metadata` defaults in front matter
225
+ - Shared `# System instructions` in body
226
+ - Nearest subfolder `defaults.md` overrides parent defaults
227
+ - Prompt-local values always win over defaults
228
+ - Included files (`includes`) are not affected by folder defaults
229
+
230
+ > `promptopskit init` scaffolds a starter `defaults.md` in the prompts root.
231
+
232
+ ```text
233
+ prompts/
234
+ ├── defaults.md
235
+ └── support/
236
+ ├── defaults.md
237
+ └── reply.md
238
+ ```
239
+
240
+ ## CLI
241
+
242
+ ```bash
243
+ # Scaffold starter prompts
244
+ promptopskit init [dir]
245
+
246
+ # Validate all .md files in a directory
247
+ promptopskit validate <dir> [--strict]
248
+
249
+ # Compile .md → JSON/ESM artifacts
250
+ promptopskit compile <src> <out> [--dry-run] [--format json|esm] [--no-clean]
251
+
252
+ # Render a prompt preview (auto-loads .test.yaml sidecar)
253
+ promptopskit render <file> [--env <name>] [--tier <name>] [--vars <file>] [--json]
254
+
255
+ # Print normalized asset as JSON
256
+ promptopskit inspect <file>
257
+
258
+ # Deploy AI agent instructions into your project
259
+ promptopskit skill [--target copilot|cursor|generic] [--force]
260
+ ```
261
+
262
+ ## AI Agent Instructions
263
+
264
+ The `skill` command deploys a comprehensive instructions file so AI coding assistants (GitHub Copilot, Cursor, etc.) automatically understand how to create and manage prompts with promptopskit.
265
+
266
+ ```bash
267
+ # Deploy for GitHub Copilot (default)
268
+ promptopskit skill
269
+ # .github/instructions/promptopskit.instructions.md
270
+
271
+ # Deploy for Cursor
272
+ promptopskit skill --target cursor
273
+ # .cursor/rules/promptopskit.mdc
274
+
275
+ # Deploy a generic instructions file
276
+ promptopskit skill --target generic
277
+ # .ai/promptopskit-skill.md
278
+
279
+ # Overwrite an existing instructions file
280
+ promptopskit skill --force
281
+ ```
282
+
283
+ The deployed file covers the prompt format, front matter schema, variable interpolation, includes, overrides, the TypeScript API, provider adapters, and project conventions — everything an AI agent needs to write correct prompts on the first try.
284
+
285
+ ## Inline Source
286
+
287
+ Render prompts from strings without files:
288
+
289
+ ```typescript
290
+ const result = await kit.renderPrompt({
291
+ source: `---
292
+ id: inline
293
+ schema_version: 1
294
+ provider: openai
295
+ model: gpt-5.4
296
+ ---
297
+
298
+ # Prompt template
299
+
300
+ Hello {{ name }}!`,
301
+ provider: 'openai',
302
+ variables: { name: 'World' },
303
+ });
304
+ ```
305
+
306
+ ## Testing Helpers
307
+
308
+ ```typescript
309
+ import { createMockAsset, createMockResolvedAsset, parseTestPrompt } from 'promptopskit/testing';
310
+
311
+ const asset = createMockAsset({ model: 'gpt-5.4' });
312
+ const resolved = createMockResolvedAsset();
313
+ const parsed = parseTestPrompt('---\nid: test\nschema_version: 1\n---\n\nHello');
314
+ ```
315
+
316
+ ## API Reference
317
+
318
+ ### `createPromptOpsKit(config)`
319
+
320
+ Creates a `PromptOpsKit` instance.
321
+
322
+ | Option | Type | Default | Description |
323
+ |--------|------|---------|-------------|
324
+ | `sourceDir` | `string` | | Path to prompt `.md` files (required) |
325
+ | `compiledDir` | `string` | | Path to compiled artifacts |
326
+ | `mode` | `'auto' \| 'compiled-only' \| 'source-only'` | `'auto'` | Resolution strategy |
327
+ | `cache` | `boolean` | `true` | Enable LRU cache with mtime invalidation |
328
+
329
+ ### `kit.renderPrompt(options)`
330
+
331
+ Renders a prompt for a specific provider. Returns `{ resolved, request, warnings }`.
332
+
333
+ | Option | Type | Description |
334
+ |--------|------|-------------|
335
+ | `path` | `string` | Prompt path (no extension), e.g. `'support/reply'` |
336
+ | `source` | `string` | Inline prompt source (alternative to path) |
337
+ | `provider` | `string` | `'openai'`, `'anthropic'`, `'gemini'`, `'openrouter'` |
338
+ | `variables` | `Record<string, string>` | Template variables |
339
+ | `environment` | `string` | Environment override name |
340
+ | `tier` | `string` | Tier override name |
341
+ | `history` | `Array<{ role, content }>` | Conversation history |
342
+ | `strict` | `boolean` | Fail on missing variables |
343
+
344
+ ### `kit.loadPrompt(path)` / `kit.resolvePrompt(path, options)` / `kit.validatePrompt(path)`
345
+
346
+ Lower-level methods for loading, resolving (includes + overrides), and validating individual prompts.
347
+
348
+ ### Standalone Functions
349
+
350
+ ```typescript
351
+ import { parsePrompt, interpolate, extractVariables, resolveIncludes, applyOverrides, validateAsset, getAdapter } from 'promptopskit';
352
+ ```
353
+
354
+ ## Schema
355
+
356
+ Prompt files use YAML front matter with these fields:
357
+
358
+ | Field | Type | Description |
359
+ |-------|------|-------------|
360
+ | `id` | `string` | Unique prompt identifier (required) |
361
+ | `schema_version` | `number` | Schema version, currently `1` |
362
+ | `provider` | `string` | `openai`, `anthropic`, `gemini` (or `google`), `openrouter`, `any` |
363
+ | `model` | `string` | Model name |
364
+ | `fallback_models` | `string[]` | Fallback model list |
365
+ | `reasoning` | `object` | `{ effort, budget_tokens }` |
366
+ | `sampling` | `object` | `{ temperature, top_p, frequency_penalty, presence_penalty, stop, max_output_tokens }` |
367
+ | `response` | `object` | `{ format, stream }` |
368
+ | `tools` | `array` | Tool references (string names or inline definitions) |
369
+ | `mcp` | `object` | MCP server references |
370
+ | `context` | `object` | `{ inputs, history }` — declare expected variables |
371
+ | `includes` | `string[]` | Paths to included prompt files |
372
+ | `environments` | `object` | Named environment overrides |
373
+ | `tiers` | `object` | Named tier overrides |
374
+ | `metadata` | `object` | `{ owner, tags, review_required, stable }` |
375
+
376
+ ## Website
377
+
378
+ The `website/` directory contains a standalone marketing website for PromptOpsKit.
379
+
380
+ ## License
381
+
382
+ [MIT](LICENSE)