CI result JSON contract
Homeboy CI results are exposed through the existing global --output <path> flag.
The flag writes the same JSON envelope Homeboy prints to stdout, but without log
text, group markers, timestamps, or GitHub Actions annotations. CI wrappers should
upload those files as artifacts instead of asking downstream tools to scrape logs.
This document names the stable contract a PR review agent can consume.
Envelope
Every artifact file is a standard Homeboy CLI response:
{
"success": true,
"data": { "...": "command-specific payload" }
}Failures use the same envelope:
{
"success": false,
"error": {
"code": "validation.invalid_argument",
"message": "Human-readable message",
"details": {},
"hints": []
}
}Consumers should treat the envelope as stable:
successis the top-level pass/fail signal for the command invocation.datais present when Homeboy produced a command payload.erroris present when Homeboy failed before producing a command payload.error.codeis a stable machine-readable error code.error.messageis for humans and should not be parsed.
The command-specific payload may grow additive fields. Consumers should ignore unknown fields.
Preferred PR artifact
For PR review agents, the preferred artifact is a single homeboy review output:
mkdir -p "$RUNNER_TEMP/homeboy-results"
homeboy
--output "$RUNNER_TEMP/homeboy-results/review.json"
review "$COMPONENT_ID"
--path "$GITHUB_WORKSPACE"
--changed-since "$BASE_REF"
--summaryUpload $RUNNER_TEMP/homeboy-results as a GitHub Actions artifact named
homeboy-ci-results.
Recommended artifact layout:
homeboy-ci-results/
review.json
review.logThe log is optional and human-facing. Agents should read review.json first and
only fetch logs when they need extra debugging context.
review.json payload
review.json wraps ReviewCommandOutput under data:
{
"success": false,
"data": {
"command": "review",
"summary": {
"passed": false,
"status": "failed",
"component": "data-machine",
"scope": "changed-since",
"changed_since": "origin/main",
"total_findings": 3,
"changed_file_count": 7,
"hints": []
},
"audit": {
"stage": "audit",
"ran": true,
"passed": false,
"exit_code": 1,
"finding_count": 2,
"hint": "Deep dive: homeboy audit data-machine --changed-since=origin/main",
"output": { "...": "AuditCommandOutput" }
},
"lint": { "...": "ReviewStage<LintCommandOutput>" },
"test": { "...": "ReviewStage<TestCommandOutput>" }
}
}Stable fields for PR review agents:
data.command: alwaysreviewfor the preferred artifact.data.summary.passed: aggregate pass/fail across stages that ran.data.summary.status: stable string status (passedorfailed).data.summary.component: component label used for the run.data.summary.scope:changed-since,changed-only, orfull.data.summary.changed_since: git ref used for PR scoping, when present.data.summary.total_findings: aggregate findings across ran stages.data.summary.changed_file_count: scoped changed-file count, when known.data.summary.hints: machine-preserved human guidance.data.<stage>.ran: whetheraudit,lint, ortestran.data.<stage>.passed: stage pass/fail when it ran.data.<stage>.exit_code: stage exit code.data.<stage>.finding_count: normalized count for quick triage.data.<stage>.skipped_reason: why the stage did not run, when skipped.data.<stage>.hint: exact deep-dive command shape for humans.data.<stage>.output: full structured stage payload.
Stage payloads preserve the same structured data as invoking the stage directly:
data.audit.output:AuditCommandOutput, including baseline comparison and changed-since scoped audit findings when those modes are active.data.lint.output:LintCommandOutput, including lint findings and baseline comparison when available.data.test.output:TestCommandOutput, including test counts, failures, drift, and coverage fields when those modes are active.
Legacy per-command artifacts
Existing CI wrappers may still run individual commands and upload one JSON file per command. That shape remains valid, but it is a lower-level contract:
homeboy --output "$RUNNER_TEMP/homeboy-results/audit.json" audit "$COMPONENT_ID" --path "$GITHUB_WORKSPACE" --changed-since "$BASE_REF" --json-summary
homeboy --output "$RUNNER_TEMP/homeboy-results/lint.json" lint "$COMPONENT_ID" --path "$GITHUB_WORKSPACE" --changed-since "$BASE_REF" --summary
homeboy --output "$RUNNER_TEMP/homeboy-results/test.json" test "$COMPONENT_ID" --path "$GITHUB_WORKSPACE" --changed-since "$BASE_REF" --json-summaryRecommended artifact layout for per-command mode:
homeboy-ci-results/
audit.json
audit.log
lint.json
lint.log
test.json
test.logReview agents should prefer review.json when present, then fall back to
per-command files for older action runs.
GitHub check linkage
Homeboy core does not know the GitHub run URL. The GitHub Action layer should add that metadata beside the Homeboy payload, either in a manifest file or check-run output summary.
Recommended manifest:
{
"schema": "homeboy.ci-results.v1",
"producer": "homeboy-action",
"repo": "Extra-Chill/data-machine",
"head_sha": "abc123",
"run_id": "1234567890",
"run_attempt": "1",
"artifact_name": "homeboy-ci-results",
"check_url": "https://github.com/Extra-Chill/data-machine/actions/runs/1234567890"
}The manifest is action-owned metadata. review.json, audit.json, lint.json,
and test.json stay Homeboy-owned payloads.
Consumer rules
PR review agents should:
- Wait while the GitHub check is pending instead of reviewing stale results.
- Fall back to
audit.json,lint.json, andtest.jsonwhenreview.jsonis absent. - Use
success,data.summary.passed, and per-stagepassedfields for status. - Use
finding_countfor quick triage and the nested stageoutputfor details. - Use
changed-sincescoped payloads to avoid repeating unrelated baseline findings. - Keep a link to the GitHub check or run URL from action-owned metadata.
- Ignore unknown additive fields.
- Avoid scraping human logs unless the JSON envelope is absent or malformed.