Two equivalent surfaces
Authoring in a curly-brace .prompt DSL parsed with Chevrotain, or in plain YAML. Convert in either direction without losing semantics.
Promptel is a small, declarative framework for production LLM prompts. Author them in a typed DSL or in YAML, pick the technique as a block, run them across OpenAI, Anthropic, or Groq from the same source.
npm install promptel Authoring in a curly-brace .prompt DSL parsed with Chevrotain, or in plain YAML. Convert in either direction without losing semantics.
One prompt, three SDKs. OpenAI, Anthropic Claude, and Groq are wired in. Switch by changing a flag, not by rewriting templates.
Chain-of-Thought, Few-Shot, Zero-Shot, Tree-of-Thoughts, ReAct, Self-Consistency. Declared, not concatenated.
Multi-channel responses (final / analysis / commentary) addressed in the DSL, surfaced as structured fields on the result.
Declare params with types, defaults, and optionality. The executor refuses prompts that don't bind, before any token leaves your machine.
Execute or convert prompts from a terminal. Pipe results, feed evals, wire into CI — without owning the runtime in your test harness.
The DSL is for humans reading prompts during review. The YAML is for tooling: schema validation, codegen, diff-driven evals. Both parse to the same AST and execute identically.
parsePrompt(src) — string to ASTexecutePrompt(src, params, opts) — end-to-endFormatConverter — promptToYaml / yamlToPromptcreateProvider({ provider }) — pluggableprompt CodeReviewer {
meta {
name: "Code Reviewer"
version: "1.0"
}
params {
code: string
language?: string = "javascript"
}
body {
text`Review the following ${params.language} code
for security, correctness, and clarity:
${params.code}`
technique {
chainOfThought {
step("Security") { text`Check for vulnerabilities` }
step("Logic") { text`Identify bugs` }
step("Style") { text`Suggest improvements` }
}
}
}
constraints { maxTokens: 800; temperature: 0.2 }
} name: CodeReviewer
params:
code: { type: string, required: true }
language: { type: string, default: "javascript" }
body:
text: |
Review the following ${params.language} code
for security, correctness, and clarity:
${params.code}
technique:
chainOfThought:
steps:
- { name: "Security", text: "Check for vulnerabilities" }
- { name: "Logic", text: "Identify bugs" }
- { name: "Style", text: "Suggest improvements" }
constraints:
maxTokens: 800
temperature: 0.2 The reason to put a layer between your application and the SDK is not novelty — it is the day you swap a provider for cost, latency, or capability and nothing else in your codebase needs to move.
GPT-class models, JSON mode, Harmony channels
await executePrompt(p, args, {
provider: 'openai'
}); Anthropic SDK, long-context jobs, tool-use blocks
await executePrompt(p, args, {
provider: 'claude'
}); Groq SDK, fast inference, eval-loop friendly
await executePrompt(p, args, {
provider: 'groq'
}); Most prompt techniques are recipes pasted between repos. Promptel turns the recipe into a node in the AST, so reviewers can see which technique is in play without reading the entire string.
prompt Analyzer {
technique {
chainOfThought {
step("Understand") { text`Parse the input` }
step("Analyze") { text`Find patterns` }
step("Conclude") { text`Form a hypothesis` }
}
}
} Promptel is small enough to read in an afternoon and opinionated enough to outlast the next provider rotation. The docs are the next stop.