A file-based LLM skill evaluation harness. It runs a prompt.md against one or more test cases in a temporary workspace, applies the resulting tool calls, runs pass/fail grep checks, grades the resulting files with a separate LLM grader, and writes one scored JSON result file per execution.
npm install(requires Node.js >= 18)npm testrunsnode --test, but there are no*.test.jsfiles yetnpx prompt-eval run <skill-name>— run a skill's test casesnpx prompt-eval list <skill-name>— list recent result files- Example:
npx prompt-eval run generate-four-files
- Do not run
npx prompt-evalyourself. The harness spawnsdevin.exe, which an agent cannot execute reliably. If you need to run an evaluation, ask the user to runnpx prompt-eval run <skill-name>and share the output. - Update this file with new findings. If you discover a convention, gotcha, or project-specific fact that would help the next agent make changes, append it to
devin.mdbefore finishing.
bin/prompt-eval.js— CLI entry pointsrc/— harness implementationcli.js—runandlistcommandsconfig.js— loadsconfig.yaml, merges defaults, validates schemarunner.js— creates sandbox, invokesdevin, parses the exported runchecks.js—grepchecks against workspace filesgrader.js— invokes grader LLM and parses{score, reasoning}JSONresults.js— writesresults/<timestamp>.jsonskill.js— loads prompt, discovers test cases and grader prompts
prompts/<skill-name>/— one directory per skill under testprompt.md— the prompt under testconfig.yaml— required; definesllm.runner,llm.grader,testCases,weights,checksinputs/<case>/— fixture files copied into the temporary workspacegrading/<metric>.md— grader prompt for each metricresults/— JSON artifacts; ignored by git
openspec/— spec-driven change artifacts (proposals, specs, tasks, archive).devin/skills/and.devin/workflows/— OpenSpec helper skills
- The prompt directory is
prompts/, notskills/.src/cli.jsresolvespath.resolve('prompts'). The spec archive mentionsskills/, but the running code usesprompts/. - Every runnable skill needs
prompt.md+config.yaml.dbtune-setupandgenerate-four-filesare complete.dbtune-startcurrently hasprompt.mdandinputs/default/but noconfig.yaml, so it cannot be run by the harness untilconfig.yamlis added. - Frontmatter in
prompt.mdis stripped.src/skill.jsremoves a leading--- ... ---block before sending the prompt to the runner. If a skill header is present and does not follow that exact frontmatter format, remove it manually; otherwise the literal header text will be passed to the runner and can break execution. - The runner requires
devinon PATH.src/runner.jsspawns:The runner LLM must signal completion by calling thedevin -p --model <model> --config <agent-config> --export <export-file> \ --permission-mode <mode> --respect-workspace-trust false -- <prompt>donetool.max_turnsis enforced. - Grader prompts must return JSON. Each
grading/<metric>.mdprompt is invoked withWorkspace:andInputs:lines appended plus the instruction to return{"score": number between 0 and 1, "reasoning": string}. Grader output is extracted from markdown code fences if necessary. - Checks are
greponly. Each check must be{name, type: 'grep', file: '<workspace-relative>', pattern: '<regex>', flags: ''}.patternis compiled as aRegExp. - Weights drive the aggregate score.
weightsinconfig.yamlmaps a check or metric name to a weight; anything not listed defaults to1. - Sandbox lives under
<temp>/prompt-eval/<skill-name>-<random>/.inputs/<case>/is copied in; the agent is granted read/write only inside that workspace. The generatedagent-configandexportJSON files are deleted after parsing so they do not contaminate grading. - Agent stdout is written to
.agent-output.txt. The runner writes the agent's stdout output to.agent-output.txtin the workspace before graders run. This allows graders to evaluate the agent's final response (e.g., PR comments, summaries) that are captured in stdout but not written to workspace files. Grader prompts should explicitly reference.agent-output.txtwhen they need to evaluate agent responses.
llm:
runner:
provider: devin
model: swe-1-6-fast
max_turns: 10
timeoutSeconds: 120
permissionMode: accept-edits
grader:
provider: devin
model: swe-1-6-fast
timeoutSeconds: 120
testCases:
default: {}
weights:
allFilesPresent: 2
checks:
- name: allFilesPresent
type: grep
file: a.txt
pattern: A- Create
prompts/<name>/ - Add
prompt.md(no frontmatter unless the harness should strip it) - Add
config.yamlwithllm,testCases,weights, andchecks - Add
inputs/default/with fixture files - Add
grading/<metric>.mdprompts for any metrics you want graded
- Do not add or remove comments unless asked.
- Keep dependencies pinned;
package.jsonpinsyamlto2.7.0. .gitignoreignoresnode_modules/,tmp-spike/, andprompts/**/results/*.json.- The runner export parser (
src/runner.js) inspectsexportData.steps, countssource === 'agent'steps, collectstool_calls, treatsfunction_name === 'done'as completion, and extracts the lastreasoning_content. - When asked to create a new prompt, also create a blank
prompt.mdand a defaultconfig.yaml.