promptopskit 0.2.0 → 0.2.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.
- package/README.md +7 -5
- package/dist/{chunk-QDGJFINW.js → chunk-CX6KVBW4.js} +10 -3
- package/dist/chunk-CX6KVBW4.js.map +1 -0
- package/dist/cli/index.js +21 -10
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +9 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/testing.cjs +3 -1
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-QDGJFINW.js.map +0 -1
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ Provider adapters for OpenAI, Anthropic, Gemini, and OpenRouter produce a ready-
|
|
|
15
15
|
- **Centralized, not scattered** — each prompt is a single Markdown file that captures prompt text, model config, tool bindings, and context rules together.
|
|
16
16
|
- **Operational, not just templated** — model name, temperature, reasoning effort, tools, and response format are declared alongside the prompt they govern.
|
|
17
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 `
|
|
18
|
+
- **Layered defaults, not repetition** — `defaults.md` in any folder sets shared `provider`, `model`, `metadata`, and `# System instructions` for that subtree, with nearest-folder override behavior.
|
|
19
19
|
- **Release-aware, not ad hoc** — environment and tier overrides swap models and parameters without forking prompt files.
|
|
20
20
|
- **Provider-portable** — write once, render for OpenAI, Anthropic, Gemini, or OpenRouter with correct body shapes.
|
|
21
21
|
- **Validate early** — Zod schema validation, Levenshtein-based "did you mean?" suggestions for typos, and variable usage checks catch mistakes before runtime.
|
|
@@ -40,6 +40,7 @@ This creates:
|
|
|
40
40
|
|
|
41
41
|
```
|
|
42
42
|
prompts/
|
|
43
|
+
├── defaults.md # Folder-level defaults (provider, model, metadata, system instructions)
|
|
43
44
|
├── hello.md # Sample prompt with variables
|
|
44
45
|
├── hello.test.yaml # Test sidecar with sample inputs
|
|
45
46
|
└── shared/
|
|
@@ -50,7 +51,7 @@ prompts/
|
|
|
50
51
|
|
|
51
52
|
```markdown
|
|
52
53
|
---
|
|
53
|
-
id: support
|
|
54
|
+
id: support/reply
|
|
54
55
|
schema_version: 1
|
|
55
56
|
provider: openai
|
|
56
57
|
model: gpt-5.4
|
|
@@ -107,7 +108,7 @@ const response = await fetch('https://api.openai.com/v1/chat/completions', {
|
|
|
107
108
|
- **Prompts as Markdown** — YAML front matter for settings, H1 headings for sections (`# System instructions`, `# Prompt template`, `# Notes`)
|
|
108
109
|
- **Variable interpolation** — `{{ variable }}` syntax with strict and permissive modes
|
|
109
110
|
- **Composition** — `includes` to share system instructions across prompts, with circular detection
|
|
110
|
-
- **Folder defaults** — `defaults.md` inheritance for shared metadata and system instructions
|
|
111
|
+
- **Folder defaults** — `defaults.md` inheritance for shared provider, model, metadata, and system instructions
|
|
111
112
|
- **Overrides** — Environment and tier-based overrides (base → env → tier → runtime)
|
|
112
113
|
- **4 provider adapters** — OpenAI, Anthropic, Gemini, OpenRouter — body-only output
|
|
113
114
|
- **Validation** — Zod schema validation, Levenshtein-based "did you mean?" for typos, variable usage checks
|
|
@@ -169,7 +170,7 @@ Define environment and tier overrides in front matter. Precedence: **base → en
|
|
|
169
170
|
|
|
170
171
|
```markdown
|
|
171
172
|
---
|
|
172
|
-
id: support
|
|
173
|
+
id: support/reply
|
|
173
174
|
schema_version: 1
|
|
174
175
|
provider: openai
|
|
175
176
|
model: gpt-5.4
|
|
@@ -206,7 +207,7 @@ Share system instructions across prompts using `includes`. Included system instr
|
|
|
206
207
|
|
|
207
208
|
```markdown
|
|
208
209
|
---
|
|
209
|
-
id: support
|
|
210
|
+
id: support/reply
|
|
210
211
|
schema_version: 1
|
|
211
212
|
includes:
|
|
212
213
|
- ./shared/tone.md
|
|
@@ -221,6 +222,7 @@ Handle support requests carefully.
|
|
|
221
222
|
|
|
222
223
|
Define a `defaults.md` file in `prompts/` (and optional subfolders) to provide inherited defaults for prompts:
|
|
223
224
|
|
|
225
|
+
- Shared `provider` and `model` in front matter
|
|
224
226
|
- Shared `metadata` defaults in front matter
|
|
225
227
|
- Shared `# System instructions` in body
|
|
226
228
|
- Nearest subfolder `defaults.md` overrides parent defaults
|
|
@@ -63,6 +63,8 @@ var SectionsSchema = z.object({
|
|
|
63
63
|
notes: z.string().optional()
|
|
64
64
|
});
|
|
65
65
|
var PromptDefaultsSchema = z.object({
|
|
66
|
+
provider: z.enum(["openai", "anthropic", "google", "gemini", "openrouter", "any"]).optional(),
|
|
67
|
+
model: z.string().optional(),
|
|
66
68
|
metadata: MetadataSchema.optional(),
|
|
67
69
|
sections: z.object({
|
|
68
70
|
system_instructions: z.string().optional()
|
|
@@ -97,7 +99,7 @@ var SECTION_MAP = {
|
|
|
97
99
|
"notes": "notes"
|
|
98
100
|
};
|
|
99
101
|
function extractSections(body) {
|
|
100
|
-
const lines = body.split(
|
|
102
|
+
const lines = body.split(/\r?\n/);
|
|
101
103
|
const sections = {};
|
|
102
104
|
let currentKey = null;
|
|
103
105
|
let currentLines = [];
|
|
@@ -206,6 +208,8 @@ function parseDefaults(content) {
|
|
|
206
208
|
}
|
|
207
209
|
function mergeDefaults(base, local) {
|
|
208
210
|
return {
|
|
211
|
+
provider: local.provider ?? base.provider,
|
|
212
|
+
model: local.model ?? base.model,
|
|
209
213
|
metadata: {
|
|
210
214
|
...base.metadata ?? {},
|
|
211
215
|
...local.metadata ?? {}
|
|
@@ -219,7 +223,8 @@ function mergeDefaults(base, local) {
|
|
|
219
223
|
function applyDefaults(asset, defaults) {
|
|
220
224
|
const hasDefaultMetadata = defaults.metadata && Object.keys(defaults.metadata).length > 0;
|
|
221
225
|
const hasDefaultSystem = !!defaults.sections?.system_instructions;
|
|
222
|
-
|
|
226
|
+
const hasDefaultScalars = defaults.provider !== void 0 || defaults.model !== void 0;
|
|
227
|
+
if (!hasDefaultMetadata && !hasDefaultSystem && !hasDefaultScalars) {
|
|
223
228
|
return asset;
|
|
224
229
|
}
|
|
225
230
|
const mergedMetadata = {
|
|
@@ -231,6 +236,8 @@ function applyDefaults(asset, defaults) {
|
|
|
231
236
|
const sections = asset.sections ? { ...asset.sections, system_instructions: systemInstructions } : systemInstructions ? { system_instructions: systemInstructions } : void 0;
|
|
232
237
|
return {
|
|
233
238
|
...asset,
|
|
239
|
+
provider: asset.provider ?? defaults.provider,
|
|
240
|
+
model: asset.model ?? defaults.model,
|
|
234
241
|
metadata,
|
|
235
242
|
sections
|
|
236
243
|
};
|
|
@@ -243,4 +250,4 @@ export {
|
|
|
243
250
|
parsePrompt,
|
|
244
251
|
loadPromptFile
|
|
245
252
|
};
|
|
246
|
-
//# sourceMappingURL=chunk-
|
|
253
|
+
//# sourceMappingURL=chunk-CX6KVBW4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/schema/schema.ts","../src/parser/sections.ts","../src/parser/parser.ts","../src/parser/loader.ts"],"sourcesContent":["import { z } from 'zod';\n\n// --- Tool definitions ---\n\nexport const InlineToolDefSchema = z.object({\n name: z.string(),\n description: z.string().optional(),\n input_schema: z.record(z.unknown()).optional(),\n});\n\nexport type InlineToolDef = z.infer<typeof InlineToolDefSchema>;\n\nexport const ToolRefSchema = z.union([z.string(), InlineToolDefSchema]);\n\n// --- MCP ---\n\nexport const MCPServerRefSchema = z.union([\n z.string(),\n z.object({\n name: z.string(),\n config: z.record(z.unknown()).optional(),\n }),\n]);\n\nexport type MCPServerRef = z.infer<typeof MCPServerRefSchema>;\n\n// --- Reasoning ---\n\nexport const ReasoningSchema = z.object({\n effort: z.enum(['low', 'medium', 'high']).optional(),\n budget_tokens: z.number().int().positive().optional(),\n});\n\n// --- Sampling ---\n\nexport const SamplingSchema = z.object({\n temperature: z.number().min(0).max(2).optional(),\n top_p: z.number().min(0).max(1).optional(),\n frequency_penalty: z.number().optional(),\n presence_penalty: z.number().optional(),\n stop: z.array(z.string()).optional(),\n max_output_tokens: z.number().int().positive().optional(),\n});\n\n// --- Response ---\n\nexport const ResponseSchema = z.object({\n format: z.enum(['text', 'json', 'markdown']).optional(),\n stream: z.boolean().optional(),\n});\n\n// --- Context ---\n\nexport const HistorySchema = z.object({\n max_items: z.number().int().positive().optional(),\n});\n\nexport const ContextSchema = z.object({\n inputs: z.array(z.string()).optional(),\n history: HistorySchema.optional(),\n});\n\n// --- Metadata ---\n\nexport const MetadataSchema = z.object({\n owner: z.string().optional(),\n tags: z.array(z.string()).optional(),\n review_required: z.boolean().optional(),\n stable: z.boolean().optional(),\n});\n\n// --- MCP block ---\n\nexport const MCPSchema = z.object({\n servers: z.array(MCPServerRefSchema).optional(),\n});\n\n// --- Overrides (subset allowed in environments/tiers) ---\n\nexport const PromptAssetOverridesSchema = z.object({\n model: z.string().optional(),\n fallback_models: z.array(z.string()).optional(),\n reasoning: ReasoningSchema.optional(),\n sampling: SamplingSchema.optional(),\n response: ResponseSchema.optional(),\n tools: z.array(ToolRefSchema).optional(),\n});\n\nexport type PromptAssetOverrides = z.infer<typeof PromptAssetOverridesSchema>;\n\n// --- Source tracking ---\n\nexport const SourceSchema = z.object({\n file_path: z.string().optional(),\n checksum: z.string().optional(),\n});\n\n// --- Sections (populated by parser) ---\n\nexport const SectionsSchema = z.object({\n system_instructions: z.string().optional(),\n prompt_template: z.string().optional(),\n notes: z.string().optional(),\n});\n\n// --- Defaults files (folder-level inheritance) ---\n\nexport const PromptDefaultsSchema = z.object({\n provider: z.enum(['openai', 'anthropic', 'google', 'gemini', 'openrouter', 'any']).optional(),\n model: z.string().optional(),\n metadata: MetadataSchema.optional(),\n sections: z.object({\n system_instructions: z.string().optional(),\n }).optional(),\n});\n\nexport type PromptDefaults = z.infer<typeof PromptDefaultsSchema>;\n\n// --- Top-level PromptAsset ---\n\nexport const PromptAssetSchema = z.object({\n id: z.string(),\n schema_version: z.number().int().positive().default(1),\n description: z.string().optional(),\n\n provider: z.enum(['openai', 'anthropic', 'google', 'gemini', 'openrouter', 'any']).optional(),\n model: z.string().optional(),\n fallback_models: z.array(z.string()).optional(),\n\n reasoning: ReasoningSchema.optional(),\n sampling: SamplingSchema.optional(),\n response: ResponseSchema.optional(),\n\n tools: z.array(ToolRefSchema).optional(),\n mcp: MCPSchema.optional(),\n\n context: ContextSchema.optional(),\n\n includes: z.array(z.string()).optional(),\n\n environments: z.record(PromptAssetOverridesSchema).optional(),\n tiers: z.record(PromptAssetOverridesSchema).optional(),\n\n metadata: MetadataSchema.optional(),\n\n // Populated by parser, not authored in YAML\n sections: SectionsSchema.optional(),\n source: SourceSchema.optional(),\n});\n\nexport type PromptAsset = z.infer<typeof PromptAssetSchema>;\n\n// --- Resolved asset (after includes, overrides applied) ---\n\nexport interface ResolvedPromptAsset extends PromptAsset {\n sections: {\n system_instructions?: string;\n prompt_template?: string;\n notes?: string;\n };\n source: {\n file_path?: string;\n checksum?: string;\n };\n}\n","export interface Sections {\n system_instructions?: string;\n prompt_template?: string;\n notes?: string;\n}\n\nconst SECTION_MAP: Record<string, keyof Sections> = {\n 'system instructions': 'system_instructions',\n 'prompt template': 'prompt_template',\n 'notes': 'notes',\n};\n\n/**\n * Extract named sections from the markdown body using H1 headings.\n * Case-insensitive. H2+ within a section is treated as content.\n * If no H1 headings are found, the entire body is treated as prompt_template.\n */\nexport function extractSections(body: string): Sections {\n const lines = body.split(/\\r?\\n/);\n const sections: Sections = {};\n\n let currentKey: keyof Sections | null = null;\n let currentLines: string[] = [];\n let foundAnyH1 = false;\n\n for (const line of lines) {\n const h1Match = line.match(/^#\\s+(.+)$/);\n if (h1Match) {\n // Flush previous section\n if (currentKey) {\n sections[currentKey] = currentLines.join('\\n').trim();\n }\n\n foundAnyH1 = true;\n const heading = h1Match[1].trim().toLowerCase();\n currentKey = SECTION_MAP[heading] ?? null;\n currentLines = [];\n } else {\n currentLines.push(line);\n }\n }\n\n // Flush last section\n if (currentKey) {\n sections[currentKey] = currentLines.join('\\n').trim();\n }\n\n // If no H1 headings found, treat entire body as prompt_template\n if (!foundAnyH1) {\n const trimmed = body.trim();\n if (trimmed) {\n sections.prompt_template = trimmed;\n }\n }\n\n return sections;\n}\n","import matter from 'gray-matter';\nimport { PromptAssetSchema } from '../schema/index.js';\nimport type { PromptAsset } from '../schema/index.js';\nimport { extractSections } from './sections.js';\n\nexport interface ParseResult {\n asset: PromptAsset;\n raw: {\n frontMatter: Record<string, unknown>;\n body: string;\n };\n}\n\n/**\n * Parse a prompt markdown string (YAML front matter + markdown body)\n * into a validated PromptAsset.\n */\nexport function parsePrompt(content: string, filePath?: string): ParseResult {\n const { data: frontMatter, content: body } = matter(content);\n\n const sections = extractSections(body);\n\n const raw = {\n ...frontMatter,\n sections,\n source: filePath ? { file_path: filePath } : undefined,\n };\n\n const asset = PromptAssetSchema.parse(raw);\n\n return {\n asset,\n raw: {\n frontMatter: frontMatter as Record<string, unknown>,\n body,\n },\n };\n}\n","import { readFile } from 'node:fs/promises';\nimport { dirname, join, resolve } from 'node:path';\nimport matter from 'gray-matter';\nimport { parsePrompt } from './parser.js';\nimport type { ParseResult } from './parser.js';\nimport { extractSections } from './sections.js';\nimport { PromptDefaultsSchema } from '../schema/index.js';\nimport type { PromptDefaults } from '../schema/index.js';\n\nconst DEFAULTS_FILE_NAME = 'defaults.md';\n\nexport interface LoadPromptOptions {\n /**\n * Optional boundary directory for defaults discovery.\n * If provided, defaults are loaded from this directory down to the prompt directory.\n */\n defaultsRoot?: string;\n}\n\n/**\n * Load and parse a prompt file from disk.\n */\nexport async function loadPromptFile(filePath: string, options: LoadPromptOptions = {}): Promise<ParseResult> {\n const content = await readFile(filePath, 'utf-8');\n const parsed = parsePrompt(content, filePath);\n // Default the boundary to the file's own directory so traversal never\n // walks above the prompt tree when no explicit root is provided.\n const root = options.defaultsRoot ?? dirname(filePath);\n const defaults = await loadDefaultsForPath(filePath, root);\n const asset = applyDefaults(parsed.asset, defaults);\n\n return {\n ...parsed,\n asset,\n };\n}\n\nasync function loadDefaultsForPath(filePath: string, defaultsRoot?: string): Promise<PromptDefaults> {\n const directories = getDirectoriesToCheck(filePath, defaultsRoot);\n let merged: PromptDefaults = {};\n\n for (const dir of directories) {\n const defaultsPath = join(dir, DEFAULTS_FILE_NAME);\n try {\n const defaultsContent = await readFile(defaultsPath, 'utf-8');\n const defaults = parseDefaults(defaultsContent);\n merged = mergeDefaults(merged, defaults);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw error;\n }\n }\n }\n\n return merged;\n}\n\nfunction getDirectoriesToCheck(filePath: string, defaultsRoot?: string): string[] {\n const dirs: string[] = [];\n let current = resolve(dirname(filePath));\n const boundary = defaultsRoot ? resolve(defaultsRoot) : undefined;\n\n while (true) {\n dirs.unshift(current);\n if ((boundary && current === boundary) || current === dirname(current)) {\n break;\n }\n current = dirname(current);\n }\n\n return dirs;\n}\n\nfunction parseDefaults(content: string): PromptDefaults {\n const { data: frontMatter, content: body } = matter(content);\n const sections = extractSections(body);\n\n return PromptDefaultsSchema.parse({\n ...frontMatter,\n sections: {\n system_instructions: sections.system_instructions,\n },\n });\n}\n\nfunction mergeDefaults(base: PromptDefaults, local: PromptDefaults): PromptDefaults {\n return {\n provider: local.provider ?? base.provider,\n model: local.model ?? base.model,\n metadata: {\n ...(base.metadata ?? {}),\n ...(local.metadata ?? {}),\n },\n sections: {\n ...(base.sections ?? {}),\n ...(local.sections ?? {}),\n },\n };\n}\n\nfunction applyDefaults(asset: ParseResult['asset'], defaults: PromptDefaults): ParseResult['asset'] {\n const hasDefaultMetadata = defaults.metadata && Object.keys(defaults.metadata).length > 0;\n const hasDefaultSystem = !!defaults.sections?.system_instructions;\n const hasDefaultScalars = defaults.provider !== undefined\n || defaults.model !== undefined;\n\n // Short-circuit: nothing to merge\n if (!hasDefaultMetadata && !hasDefaultSystem && !hasDefaultScalars) {\n return asset;\n }\n\n const mergedMetadata = {\n ...(defaults.metadata ?? {}),\n ...(asset.metadata ?? {}),\n };\n const metadata = Object.keys(mergedMetadata).length > 0 ? mergedMetadata : undefined;\n\n const systemInstructions = asset.sections?.system_instructions ?? defaults.sections?.system_instructions;\n\n const sections = asset.sections\n ? { ...asset.sections, system_instructions: systemInstructions }\n : systemInstructions\n ? { system_instructions: systemInstructions }\n : undefined;\n\n return {\n ...asset,\n provider: asset.provider ?? defaults.provider,\n model: asset.model ?? defaults.model,\n metadata,\n sections,\n };\n}\n"],"mappings":"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","names":["matter","matter"]}
|
package/dist/cli/index.js
CHANGED
|
@@ -72,6 +72,8 @@ var SectionsSchema = z.object({
|
|
|
72
72
|
notes: z.string().optional()
|
|
73
73
|
});
|
|
74
74
|
var PromptDefaultsSchema = z.object({
|
|
75
|
+
provider: z.enum(["openai", "anthropic", "google", "gemini", "openrouter", "any"]).optional(),
|
|
76
|
+
model: z.string().optional(),
|
|
75
77
|
metadata: MetadataSchema.optional(),
|
|
76
78
|
sections: z.object({
|
|
77
79
|
system_instructions: z.string().optional()
|
|
@@ -106,7 +108,7 @@ var SECTION_MAP = {
|
|
|
106
108
|
"notes": "notes"
|
|
107
109
|
};
|
|
108
110
|
function extractSections(body) {
|
|
109
|
-
const lines = body.split(
|
|
111
|
+
const lines = body.split(/\r?\n/);
|
|
110
112
|
const sections = {};
|
|
111
113
|
let currentKey = null;
|
|
112
114
|
let currentLines = [];
|
|
@@ -214,6 +216,8 @@ function parseDefaults(content) {
|
|
|
214
216
|
}
|
|
215
217
|
function mergeDefaults(base, local) {
|
|
216
218
|
return {
|
|
219
|
+
provider: local.provider ?? base.provider,
|
|
220
|
+
model: local.model ?? base.model,
|
|
217
221
|
metadata: {
|
|
218
222
|
...base.metadata ?? {},
|
|
219
223
|
...local.metadata ?? {}
|
|
@@ -227,7 +231,8 @@ function mergeDefaults(base, local) {
|
|
|
227
231
|
function applyDefaults(asset, defaults) {
|
|
228
232
|
const hasDefaultMetadata = defaults.metadata && Object.keys(defaults.metadata).length > 0;
|
|
229
233
|
const hasDefaultSystem = !!defaults.sections?.system_instructions;
|
|
230
|
-
|
|
234
|
+
const hasDefaultScalars = defaults.provider !== void 0 || defaults.model !== void 0;
|
|
235
|
+
if (!hasDefaultMetadata && !hasDefaultSystem && !hasDefaultScalars) {
|
|
231
236
|
return asset;
|
|
232
237
|
}
|
|
233
238
|
const mergedMetadata = {
|
|
@@ -239,6 +244,8 @@ function applyDefaults(asset, defaults) {
|
|
|
239
244
|
const sections = asset.sections ? { ...asset.sections, system_instructions: systemInstructions } : systemInstructions ? { system_instructions: systemInstructions } : void 0;
|
|
240
245
|
return {
|
|
241
246
|
...asset,
|
|
247
|
+
provider: asset.provider ?? defaults.provider,
|
|
248
|
+
model: asset.model ?? defaults.model,
|
|
242
249
|
metadata,
|
|
243
250
|
sections
|
|
244
251
|
};
|
|
@@ -796,9 +803,6 @@ Options:
|
|
|
796
803
|
`.trim();
|
|
797
804
|
var HELLO_PROMPT = `---
|
|
798
805
|
id: hello
|
|
799
|
-
schema_version: 1
|
|
800
|
-
provider: openai
|
|
801
|
-
model: gpt-5.4
|
|
802
806
|
context:
|
|
803
807
|
inputs:
|
|
804
808
|
- name
|
|
@@ -822,7 +826,7 @@ Current app context: {{ app_context }}.
|
|
|
822
826
|
Say hello to {{ name }} and ask how you can help them today.
|
|
823
827
|
`.trimStart();
|
|
824
828
|
var TONE_INCLUDE = `---
|
|
825
|
-
id: shared
|
|
829
|
+
id: shared/tone
|
|
826
830
|
schema_version: 1
|
|
827
831
|
---
|
|
828
832
|
|
|
@@ -831,6 +835,8 @@ schema_version: 1
|
|
|
831
835
|
Always be polite, professional, and concise. Avoid jargon unless the user uses it first.
|
|
832
836
|
`.trimStart();
|
|
833
837
|
var DEFAULTS = `---
|
|
838
|
+
provider: openai
|
|
839
|
+
model: gpt-5.4
|
|
834
840
|
metadata:
|
|
835
841
|
owner: my-team
|
|
836
842
|
review_required: true
|
|
@@ -851,7 +857,7 @@ var TEST_SIDECAR = `cases:
|
|
|
851
857
|
app_context: "Settings page"
|
|
852
858
|
`;
|
|
853
859
|
var EXAMPLE_USAGE = `// Example: render the hello prompt and send it to OpenAI
|
|
854
|
-
// Full docs: https://promptopskit.com/docs
|
|
860
|
+
// Full docs: https://promptopskit.com/docs/index.html#/
|
|
855
861
|
|
|
856
862
|
import { createPromptOpsKit } from 'promptopskit';
|
|
857
863
|
|
|
@@ -1122,16 +1128,21 @@ folder:
|
|
|
1122
1128
|
|
|
1123
1129
|
\`\`\`text
|
|
1124
1130
|
prompts/
|
|
1125
|
-
\u251C\u2500\u2500 defaults.md # global metadata + system instructions
|
|
1131
|
+
\u251C\u2500\u2500 defaults.md # global provider, model, metadata + system instructions
|
|
1126
1132
|
\u2514\u2500\u2500 support/
|
|
1127
1133
|
\u251C\u2500\u2500 defaults.md # overrides for support/*
|
|
1128
1134
|
\u2514\u2500\u2500 reply.md # inherits from support/defaults.md
|
|
1129
1135
|
\`\`\`
|
|
1130
1136
|
|
|
1131
1137
|
Supported default fields:
|
|
1138
|
+
- \`provider\` (front matter) \u2014 default provider for the folder
|
|
1139
|
+
- \`model\` (front matter) \u2014 default model for the folder
|
|
1132
1140
|
- \`metadata\` (front matter) \u2014 merged with prompt-local metadata
|
|
1133
1141
|
- \`# System instructions\` (body section) \u2014 used when the prompt has none
|
|
1134
1142
|
|
|
1143
|
+
This lets you configure app-wide settings like \`provider\` and \`model\`
|
|
1144
|
+
in a single root \`defaults.md\`, so individual prompts only declare what\u2019s unique to them.
|
|
1145
|
+
|
|
1135
1146
|
Rules:
|
|
1136
1147
|
- Nearest subfolder \`defaults.md\` overrides parent defaults
|
|
1137
1148
|
- Prompt-local values always take precedence over defaults
|
|
@@ -1312,14 +1323,14 @@ Hello {{ name }}
|
|
|
1312
1323
|
## Conventions to follow
|
|
1313
1324
|
|
|
1314
1325
|
1. **One prompt per file** \u2014 each \`.md\` file is a single prompt asset
|
|
1315
|
-
2. **Always set \`id\` and \`schema_version: 1\`** in front matter
|
|
1326
|
+
2. **Always set \`id\` and \`schema_version: 1\`** in front matter (or inherit \`schema_version\` from \`defaults.md\`)
|
|
1316
1327
|
3. **Declare all variables** in \`context.inputs\` that appear in templates
|
|
1317
1328
|
4. **Use includes** for shared system instructions (tone, safety, formatting)
|
|
1318
1329
|
5. **Keep prompt templates focused** \u2014 compose behavior via includes, not duplication
|
|
1319
1330
|
6. **Use environment overrides** for dev/staging/prod model differences
|
|
1320
1331
|
7. **Add test sidecars** (\`.test.yaml\`) for critical prompts
|
|
1321
1332
|
8. **Run \`promptopskit validate\`** before committing changes
|
|
1322
|
-
9. **Use \`defaults.md\`** to share metadata and system instructions across a folder
|
|
1333
|
+
9. **Use \`defaults.md\`** to share provider, model, metadata, and system instructions across a folder
|
|
1323
1334
|
10. **Variable names** should be \`snake_case\`
|
|
1324
1335
|
11. **Prompt file names** should be \`kebab-case.md\`
|
|
1325
1336
|
`.trimEnd();
|