Evidence & reports
How evidence is declared on a step, embedded in a manual, captured during a run, and turned into a report afterwards.
Evidence & Audit
- Evidence tracking - Document required evidence for each step
- Evidence results - Embed pre-captured evidence directly in generated manuals
- Git metadata - Complete traceability with commit info
- Structured documentation - Generate manuals with evidence requirements
- Audit-ready formats - Markdown and Confluence outputs
Note: Automatic evidence collection (screenshots, log capture, video recording) is planned for v2.0. See ROADMAP.md for details. Current v1.0 supports embedding pre-captured evidence via the
evidence.resultsfield.
Evidence Results (Pre-captured Evidence)
You can embed pre-captured evidence directly into generated manuals using the evidence.results field. This is useful for:
- Pre-approved procedures: Include evidence from rehearsal/staging runs
- Template manuals: Show expected outcomes with screenshots
- Post-execution documentation: Update manuals with actual results
- Audit compliance: Maintain complete evidence trail in version control
Example with file references:
steps:
- name: Deploy Application
type: manual
instruction: |
Deploy application to Kubernetes:
```bash
kubectl apply -f deployment.yaml -n ${NAMESPACE}
```
evidence:
required: true
types: [screenshot, command_output]
results:
staging:
- type: screenshot
file: ./evidence/staging-dashboard.png
description: Kubernetes dashboard showing 3 pods running
- type: command_output
file: ./evidence/staging-deploy.log
description: Deployment output from kubectl
production:
- type: screenshot
file: ./evidence/prod-dashboard.png
description: Kubernetes dashboard showing 5 pods running
- type: command_output
file: ./evidence/prod-deploy.log
description: Deployment output from kubectlExample with inline content:
steps:
- name: Verify Database Connection
type: manual
instruction: Check database connectivity
evidence:
required: true
types: [command_output, log]
results:
staging:
- type: command_output
content: |
deployment.apps/web-server created
service/web-server created
NAME READY STATUS RESTARTS AGE
pod/web-0 1/1 Running 0 10s
pod/web-1 1/1 Running 0 10s
description: Successful staging deployment output
- type: log
content: |
[2025-10-16 10:30:00] INFO: Application started
[2025-10-16 10:30:05] INFO: Database connection established
[2025-10-16 10:30:10] INFO: Ready to accept connections
description: Application startup logs
production:
- type: command_output
content: |
deployment.apps/web-server created
service/web-server created
NAME READY STATUS RESTARTS AGE
pod/web-0 1/1 Running 0 10s
pod/web-1 1/1 Running 0 10s
pod/web-2 1/1 Running 0 10s
description: Production deployment outputGenerated Manual Rendering:
Evidence results are automatically rendered in generated manuals:
- Screenshots/Photos (file): Rendered as embedded images
- Other files: Rendered as download links
command_output/logfiles: File content is read and embedded as a code block (all formats, including Confluence ADF)- Inline content: Rendered as code blocks (bash for command_output, text for others)
- Descriptions: Displayed above the evidence content
When command_output evidence is required (or optional) but no results have been captured yet, every format (Markdown, single-env Markdown, Confluence markup, and ADF) renders a # Paste command output here code block so the operator knows where to record the output. Other evidence types (e.g. screenshot, log) show only the evidence metadata, with no placeholder body.
Evidence Result Schema:
evidence:
required: true # Optional: whether evidence is required
types: [screenshot, log] # Optional: expected evidence types
results: # Optional: pre-captured evidence, keyed by environment name
staging: # Environment name (must match an environment defined in the operation)
- type: screenshot # Required: evidence type
file: ./path/to/file # Either 'file' OR 'content' required
description: Description text # Optional
- type: command_output
content: | # Inline content (alternative to 'file')
Command output here
description: Description text # Optional
production:
- type: screenshot
file: ./evidence/prod/dashboard.png
description: Production dashboardSupported Evidence Types:
screenshot- UI screenshots (renders as image if file path provided)photo- Photos (renders as image if file path provided)log- Log files or log contentcommand_output- Shell command outputvideo- Video recordingsdocument- PDF or document filesconfig- Configuration file snapshotscustom- Custom evidence types
See tests/fixtures/operations/features/evidence-with-results.yaml for a complete example.
Environment-Specific Evidence in Shared Steps
When defining shared steps that will be included via uses:, define evidence types in the step file as documentation. Each operation that includes the file adds its own evidence.results with environment-specific captured evidence:
# ./common/health-checks.yaml
- name: Check AFD Health
type: manual
instruction: |
Check AFD health status:
```bash
curl https://${AFD_ENDPOINT}/health
```
evidence:
required: true
types: [command_output, screenshot]# main-operation.yaml
steps:
- uses: ./common/health-checks.yaml
with:
AFD_ENDPOINT: ${AFD_ENDPOINT}
# Steps from the file expand inline; add evidence.results
# directly on individual steps or via variants for per-env evidenceSee tests/fixtures/operations/features/evidence-with-results.yaml for a complete example.
JSONL audit trail
Every action appends a line to the run's black box at <operation-dir>/.samaritan-runs/<id>/events.jsonl (the exact path is printed as 📝 Audit log: at the start of the run):
{"ts":"2026-04-18T10:00:00Z","type":"session_start","op":"deployment.yaml","session_id":"f3a9b2"}
{"ts":"2026-04-18T10:00:01Z","type":"session_open","name":"execution","host":"prod-bastion","pane":"samaritan-f3a9b2:0.1"}
{"ts":"2026-04-18T10:00:05Z","type":"step_start","step":0,"name":"Deploy","pic":"ops@example.com"}
{"ts":"2026-04-18T10:00:06Z","type":"command_sent","session":"execution","command":"kubectl apply -f deployment.yaml"}
{"ts":"2026-04-18T10:00:20Z","type":"pane_captured","session":"execution","output":"deployment.apps/web created"}
{"ts":"2026-04-18T10:00:22Z","type":"assert_result","step":0,"pass":true,"actual":"successfully rolled out","type":"contains"}
{"ts":"2026-04-18T10:00:30Z","type":"step_complete","step":0}
{"ts":"2026-04-18T10:02:00Z","type":"session_end","status":"completed"}Query with jq:
# All commands sent during the session
cat .samaritan-runs/f3a9b2/events.jsonl | jq 'select(.type=="command_sent")'
# Assertion failures only
cat .samaritan-runs/f3a9b2/events.jsonl | jq 'select(.type=="assert_result" and .pass==false)'Evidence report
Generate a human-readable Markdown report from any JSONL log. Two ways to get one:
# A report.md is ALWAYS written beside the operation; --report adds an extra copy
samaritan run deployment.yaml --env production --report ./reports
# Generate after the fact from an existing JSONL log
samaritan report .samaritan-runs/f3a9b2/events.jsonl
# Save to a specific file
samaritan report /tmp/samaritan-f3a9b2.jsonl --output evidence-report.mdThe report includes a summary (steps, duration, PIC/reviewer), per-step command + output, verification sign-offs, and a dedicated rollback events section. Attach it directly to a change ticket.
Verification shows the final state. Each step renders its last verify attempt (the full checklist plus the output it was checked against), with an attempt count when it was re-verified. A failure the operator accepted with o reads as overridden, with who, when and the reason. It is also flagged in the step heading and listed in the summary:
## Step 1: two lines ⚠️ (verification overridden)
**Verification**: ⚠️ OVERRIDDEN (2 attempts, 2 failed — last shown)
- ⚠️ Overridden by alice at Thu, 22 Oct 2026 18:14:46 UTC — reason: prompt line counted
- ❌ (line_count) — expected: `2`, actual: `3`The report is plain UTF-8 Markdown: terminal escapes are stripped and any remaining control byte (NUL, SI, a stray ESC, …) is removed, so Slack, GitHub and file treat it as text.
When several operators each ran their own slice of one operation with run --pic, merge their partial runs into a single consolidated report — each step attributed to the operator who actually ran it (see Multi-operator focus mode):
samaritan report merge <alice-session-id> <bob-session-id> --output merged-report.md