replay-self-healing-cli
v0.1.1
Published
Zero-dependency self-healing replay harness CLI for LLM runs
Maintainers
Readme
replay-self-healing-cli
Zero-dependency CLI to capture LLM runs as replay artifacts, auto-heal trace inconsistencies, and produce validation/report output.
Why this exists
- Prompt-first UX: run one prompt and get replay artifacts immediately.
- Runner is user-defined: framework choice stays outside this tool.
- Self-healing: the CLI preserves raw output, repairs common trace issues, and logs every repair action.
- LLM-friendly errors: failures are always emitted as machine-readable JSON with fix guidance.
Install
npm install -g replay-self-healing-cliOr run locally from this folder:
npm install
node ./bin/replay.mjs helpThis package has zero dependencies.
30-second quickstart
- Create a runner at
.replay/runner.mjs:
#!/usr/bin/env node
import process from 'node:process';
let input = '';
for await (const chunk of process.stdin) {
input += chunk;
}
const request = JSON.parse(input);
const now = new Date().toISOString();
const output = {
status: 'ok',
framework: 'custom',
response: `Echo: ${request.prompt}`,
events: [
{ seq: 1, timestamp: now, type: 'run_started', runId: request.runId, payload: {} },
{
seq: 2,
timestamp: now,
type: 'assistant_message',
runId: request.runId,
payload: { response: `Echo: ${request.prompt}` }
},
{ seq: 3, timestamp: now, type: 'run_completed', runId: request.runId, payload: {} }
],
sources: [],
usage: { inputTokens: 0, outputTokens: 0, costUsd: 0 }
};
process.stdout.write(JSON.stringify(output));- Run:
replay "What are my top holdings?"- Output files are created automatically under:
.replay/artifacts/YYYY-MM-DD/Command overview
Capture (default)
replay "your prompt"
echo "your prompt" | replayOptional flags:
--runner <path>override runner discovery--out <dir>override output directory--context '{"k":"v"}'inline JSON context--context-file ./context.jsonJSON context file--timeout-ms 120000runner timeout--no-healskip heal pass
Validate artifacts
replay validate --in .replay/artifactsRe-heal existing artifacts
replay heal --in .replay/artifacts --out .replay/healedReport summary
replay report --in .replay/artifactsRunner discovery (implied defaults)
If --runner is not provided, the CLI checks in this order:
REPLAY_RUNNERenv var.replay/runner.mjs.replay/runner.js.replay/runner.cjs.replay/runnerpackage.jsonscript:replay:runner
Runner input contract
Runner receives one JSON object via stdin:
{
"prompt": "What are my top holdings?",
"query": "What are my top holdings?",
"runId": "run_...",
"timestamp": "2026-03-01T12:00:00.000Z",
"context": {}
}Runner output contract
Runner must print one JSON object to stdout.
Success:
{
"status": "ok",
"framework": "langchain",
"response": "AAPL is your largest holding.",
"events": [
{
"seq": 1,
"timestamp": "2026-03-01T12:00:00.000Z",
"type": "run_started",
"runId": "run_123",
"payload": {}
}
],
"sources": ["portfolio_db"],
"usage": {
"inputTokens": 100,
"outputTokens": 40,
"costUsd": 0.0021
}
}Failure:
{
"status": "error",
"error": {
"code": "RUNNER_TOOL_TIMEOUT",
"message": "get_portfolio_summary timed out after 15s",
"retryable": true
},
"events": []
}Schema references:
Self-healing behavior
The CLI always writes a raw artifact first, then heals into a replay artifact.
Healing currently includes:
- type alias mapping (
tool_end->tool_completed, etc.) - missing
run_startedinsertion - missing terminal event insertion (
run_completed/run_failed) - non-object event payload normalization to
{} - sequence renumbering to strict monotonic order
- duplicate event dedupe (exact adjacent duplicates)
- synthetic
assistant_messageinsertion from final response when missing
All applied repairs are written to *.heal-log.json.
Custom heal rules
Optional file: .replay/heal.rules.json
{
"version": "v1",
"eventAliases": {
"tool_end": "tool_completed",
"llm_message": "assistant_message"
}
}Artifact files
For each run:
*.raw.jsonraw capture of runner process input/output*.artifact.jsonnormalized artifact before healing*.healed.jsonhealed replay artifact*.heal-log.jsonstructured healing log
Error model (LLM-friendly)
Errors are always JSON on stderr:
{
"error": {
"code": "E_RUNNER_EVENTS_INVALID",
"message": "Runner output field `events` must be an array.",
"path": "$.events",
"expected": "array",
"received": "object",
"howToFix": "Return `events: []` when there are no events."
}
}See full catalog: ERROR_CODES.md
Publish checklist
- Authenticate npm on this machine:
npm login
# or: npm adduser- Confirm identity and package name availability:
npm whoami
npm view replay-self-healing-cli version- Run pre-publish checks:
node ./bin/replay.mjs help
REPLAY_RUNNER=./examples/runner.mjs node ./bin/replay.mjs "test prompt"
node ./bin/replay.mjs validate --in .replay/artifacts
npm pack --dry-run- Publish:
npm publish- Verify:
npm view replay-self-healing-cli versionLicense
MIT
