README
¶
dotprompt-cli
Run local .prompt files against any OpenAI-compatible backend.
dotprompt-cli path/to/file.prompt
Install
go install github.com/spicyneuron/dotprompt-cli@latest
Quickstart
greet.prompt:
---
model: provider/model
config:
temperature: 0.3
input:
default:
language: English
---
{{role "system"}}
You are a terse assistant. Reply in {{language}}.
{{role "user"}}
Say hello to {{name}}.
echo '{"name": "Ada", "language": "French"}' | dotprompt-cli greet.prompt
# Bonjour Ada.
Add --dry-run to print the resolved request (messages, model, config) as JSON without calling a model.
Add --stream to print response text as it is generated. Add --metrics to
write request metadata as one JSON object to stderr while keeping stdout clean:
dotprompt-cli --stream --metrics greet.prompt >answer.txt 2>metrics.json
For example:
{
"request_id": "chatcmpl-abc123",
"model": "provider/model",
"prompt_tokens": 124,
"cached_prompt_tokens": 20,
"completion_tokens": 86,
"reasoning_tokens": 32,
"total_tokens": 210,
"ttft_ms": 241.397,
"total_time_ms": 1842.125,
"tokens_per_second": 46.685,
"cost_usd": 0.00123
}
total_time_ms measures the complete HTTP request locally and is always
present. tokens_per_second is completion tokens divided by that end-to-end
time. ttft_ms measures the first non-empty content delta and is therefore
only available with --stream. prompt_tokens is the full logical prompt;
cached_prompt_tokens is a subset and is not added again. Likewise,
reasoning_tokens is a subset of completion_tokens, so total_tokens is
always prompt_tokens + completion_tokens. cost_usd is reported by the
provider rather than estimated locally. Unavailable numeric metrics are
null; request IDs and model names are omitted when absent. With both flags
set, streaming requests ask compatible servers to include final usage data.
Input
Template variables are merged in precedence order (lowest to highest):
input.defaultin the prompt frontmatter--data file.json- stdin
Piped stdin that is a JSON object is merged as variables. Any other piped text is available to the template as {{stdin}}:
cat notes.txt | dotprompt-cli summarize.prompt
Providers
The model field is provider/model. openai and anthropic are built in and need only OPENAI_API_KEY / ANTHROPIC_API_KEY. Other providers are defined in ~/.config/dotprompt-cli/config.yaml:
default_model: local/<model>
providers:
local:
base_url: http://localhost:8080/v1
api_key: unused # or api_key_env: MY_KEY_VAR
headers: # optional extra request headers
X-Custom: value
insecure_skip_verify: true # optional; allow self-signed certs (TLS otherwise verified)
Anthropic is reached through its OpenAI-compatible endpoint, so every provider speaks the same chat-completions protocol.
Flags
--dry-run Print the resolved model request without calling a model
--stream Stream response text as it is generated
--metrics Print request metrics as JSON to stderr
--data <file> JSON file with template input variables
--model <ref> Override the model, as provider/model
--config <file> Config file (default ~/.config/dotprompt-cli/config.yaml)
--version Print version
Dotprompt subset
This tool implements a practical subset of the Dotprompt spec (frontmatter, templates):
Supported:
- YAML frontmatter:
model,config,input.default,input.schema,output.format(textorjson),output.schema - Handlebars templates with common control flow (
#if,#each, ...) {{role "system"}}/{{role "user"}}/{{role "model"}}message markers{{json value}}helper{{media url=...}}image parts (see below)
Not supported: tool calling, prompt variants, partials, named schema references, and prompt registries.
Deviations from the spec:
modelmust beprovider/modeland routes via the config file rather than a Genkit plugin registry.- Raw (non-JSON) stdin is exposed as
{{stdin}}— a CLI convenience, not part of Dotprompt.
Config passthrough
The Dotprompt names topP, topK, maxOutputTokens, and stopSequences are translated to their wire names (top_p, top_k, max_tokens, stop). Every other config field is sent to the provider verbatim, so provider-specific samplers just work:
config:
temperature: 0.7
min_p: 0.05 # sent as-is
seed: 42 # sent as-is
Use --dry-run to see the exact request body.
Schemas
input.schema validates merged input variables before rendering; a mismatch fails with a non-zero exit. output.schema implies JSON output, is sent as response_format: json_schema so capable servers enforce it during generation, and the response is validated locally after the fact (printed either way; validation failure sets a non-zero exit).
Schemas are written in Picoschema, Dotprompt's compact schema notation:
output:
schema:
language: string, the detected language
greeting: string
formality?(enum): [FORMAL, INFORMAL] # "?" marks optional fields
tags?(array): string
As in upstream Dotprompt, a schema whose top level contains type or properties is treated as raw JSON Schema instead — useful for constraints picoschema can't express (minLength, pattern, numeric ranges, ...).
Images and attachments
{{media url=...}} inserts a file into the surrounding message:
{{role "user"}}
What is in this image? {{media url=photo}}
echo '{"photo": "vacation.jpg"}' | dotprompt-cli describe.prompt
Local file paths (relative to the working directory, ~/ expands to your home directory) are embedded as base64 and shaped by MIME type: images as image_url parts, audio as input_audio, and everything else (e.g. PDFs) as file attachments. http(s):// URLs are passed through as image_url for the server to fetch. Whether a given type actually works depends on the server and model — vision-only backends will reject audio and file parts. --dry-run truncates embedded data for readability.
Documentation
¶
There is no documentation for this package.