File-based prompt templates — pi-style slash-expandable markdown prompts.
A template is a *.md file whose body becomes the user message when
the user types /<name> [args…]. Discovery, project wins over global:
<workspace>/.vis/prompts/*.md (project)~/.vis/prompts/*.md (user-global)Frontmatter is the same minimal --- fenced key: value block the
harness discovery reads: name (defaults to the filename stem) and
description. The body is the template.
Argument handling matches the common harness convention: when the
body contains $ARGUMENTS every occurrence is substituted with the
raw argument string (empty when none given); otherwise non-blank
args are appended after the body on their own paragraph.
Extensions can contribute DYNAMIC templates through
register-provider! — e.g. the harness extension exposes every
discovered skill as /skill:<name>. File templates win on a name
collision; among providers, registration order wins.
Dispatch: the engine consults expand ONLY for slash texts no
registered extension slash claimed (slash/dispatch returned
:reason :unknown), so real slash commands always win — same
precedence pi uses.
File-based prompt templates — pi-style slash-expandable markdown prompts. A template is a `*.md` file whose body becomes the user message when the user types `/<name> [args…]`. Discovery, project wins over global: 1. `<workspace>/.vis/prompts/*.md` (project) 2. `~/.vis/prompts/*.md` (user-global) Frontmatter is the same minimal `---` fenced `key: value` block the harness discovery reads: `name` (defaults to the filename stem) and `description`. The body is the template. Argument handling matches the common harness convention: when the body contains `$ARGUMENTS` every occurrence is substituted with the raw argument string (empty when none given); otherwise non-blank args are appended after the body on their own paragraph. Extensions can contribute DYNAMIC templates through `register-provider!` — e.g. the harness extension exposes every discovered skill as `/skill:<name>`. File templates win on a name collision; among providers, registration order wins. Dispatch: the engine consults `expand` ONLY for slash texts no registered extension slash claimed (`slash/dispatch` returned `:reason :unknown`), so real slash commands always win — same precedence pi uses.
(dedup-by-name entries)First occurrence of each :name wins (precedence = input order).
First occurrence of each `:name` wins (precedence = input order).
(discover-in project-dir global-dir)Parse every *.md template under project-dir then global-dir
(project wins on a name collision). Pure I/O; exposed for testing
against fixture roots. Either dir may be nil/missing.
Parse every `*.md` template under `project-dir` then `global-dir` (project wins on a name collision). Pure I/O; exposed for testing against fixture roots. Either dir may be nil/missing.
(expand env text)Expand a /name args… prompt-template invocation against the
available templates. Returns {:name :text :path?} when a template
matched and produced non-blank text, else nil. Never throws — a
failing :expand-fn logs and yields nil so the engine falls back to
normal slash error handling.
Expand a `/name args…` prompt-template invocation against the
available templates. Returns `{:name :text :path?}` when a template
matched and produced non-blank text, else nil. Never throws — a
failing `:expand-fn` logs and yields nil so the engine falls back to
normal slash error handling.(file-templates)Discovered file templates, marker-cached: re-parsed only when the prompts dirs (or any file in them) change.
Discovered file templates, marker-cached: re-parsed only when the prompts dirs (or any file in them) change.
(parse-frontmatter content)Split a markdown doc into {:meta {kw str} :body str}. A leading
----fenced block is parsed as key: value lines. No frontmatter →
{:meta {} :body <whole>}. Keys are lower-cased keywords.
Split a markdown doc into `{:meta {kw str} :body str}`. A leading
`---`-fenced block is parsed as `key: value` lines. No frontmatter →
`{:meta {} :body <whole>}`. Keys are lower-cased keywords.(parse-invocation text)Parse /name args… into {:name "name" :args "args…"} or nil.
Pure tokenisation; does not consult the template registry.
Parse `/name args…` into `{:name "name" :args "args…"}` or nil.
Pure tokenisation; does not consult the template registry.(register-provider! id f)Register a dynamic template provider under id (idempotent —
re-registering replaces). f is a zero-arg fn returning a seq of
template maps {:name :description …} carrying either :body
(expanded like a file template) or :expand-fn (fn [env args] -> string). Providers are consulted after file templates.
Register a dynamic template provider under `id` (idempotent —
re-registering replaces). `f` is a zero-arg fn returning a seq of
template maps `{:name :description …}` carrying either `:body`
(expanded like a file template) or `:expand-fn` `(fn [env args] ->
string)`. Providers are consulted after file templates.(reload!)Drop the file-template cache and rescan. Returns the template vec.
Drop the file-template cache and rescan. Returns the template vec.
(templates)All available templates: file templates first (they win name collisions), then provider-contributed dynamic templates.
All available templates: file templates first (they win name collisions), then provider-contributed dynamic templates.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |