CRUMB a card from devarno-cloud

Prompt Artefact Directory Layout

eva beginner 4 min read

ELI5

Each prompt is a single shoebox on a shelf: the label (meta.yml), the recipe (prompt.xml), and optional pockets for sample ingredients, taste-tests, a doorman, and a sniff-test. EVA refuses to open a shoebox missing the label or recipe.

Technical Deep Dive

Layout

prompts/<id>/
├── meta.yml # required
├── prompt.xml # required
├── examples/<case>/inputs.yml # optional, loaded by --case
├── eval.yml # optional, eva eval reads this
├── guard.sh # optional, executed pre-send
├── verify.sh # optional, executed post-send
├── aliases # optional, one shell verb per line
└── .usage.jsonl # auto-managed; appended on every kick run

bin/kick resolves prompts/<id>/{meta.yml, prompt.xml} and refuses if either is missing (bin/kick:130-131). No status subdirectories — meta.yml.status is the single source of truth (the historic prompts/{ready,tested,draft}/*.md layout is what eva migrate rewrites away from at bin/eva:887).

Class Diagram

classDiagram
class PromptArtefact {
+id : string
+meta.yml
+prompt.xml
}
class Examples { +cases/inputs.yml }
class Eval { +cases[]; +triggering }
class Guard { +stdout: KEY=VALUE }
class Verify { +exit code }
class Aliases { +shell verbs }
class Usage { +jsonl rows }
PromptArtefact "1" --> "0..*" Examples
PromptArtefact --> Eval
PromptArtefact --> Guard
PromptArtefact --> Verify
PromptArtefact --> Aliases
PromptArtefact --> Usage

Resolution Flow

flowchart LR
cli["kick <id> --case happy --send"] --> find["find_prompt() — bin/kick:24"]
find -->|missing meta.yml| die1["die: prompt not found"]
find --> xml{prompt.xml exists?}
xml -- no --> die2["die: missing prompt.xml"]
xml -- yes --> caseV["load examples/case/inputs.yml"]
caseV --> guard["guard.sh hook"]
guard --> render["render {{vars}}"]
render --> claude["claude CLI"] --> verify["verify.sh hook"] --> log[".usage.jsonl"]

Key Terms

  • Artefact → a single self-contained prompt directory under prompts/<id>/.
  • Case → a named subdirectory of examples/ whose inputs.yml becomes vars under --case.
  • Aliases file → newline-separated shell-identifier verbs that eva index materialises in bin/kick-aliases.sh.

Q&A

Q: Which two files are the bare minimum for a runnable prompt? A: meta.yml and prompt.xml. bin/kick dies at line 130–131 if either is missing.

Q: Where do per-case input variables live on disk? A: prompts/<id>/examples/<case-name>/inputs.yml. Loaded by --case <name> at lower precedence than --var flags (bin/kick:150-159).

Q: How does kick locate the prompts directory without a config file? A: It reads $PROMPT_LIB_ROOT if set, else walks one directory up from BASH_SOURCE[0] and uses <root>/prompts (bin/kick:15-20).

Examples

Listing the smallest valid artefact:

prompts/hello/
├── meta.yml # 7 required fields
└── prompt.xml # may contain {{name}} placeholders

kick hello --var name=world renders to stdout; adding --send pipes through claude.

neighbors on the map