Help us improve
Share bugs, ideas, or general feedback.
From spotlight
Generates a self-contained HTML review artifact with structured feedback support for investigation cycles. Accepts feedback as downloadable JSON and re-triggers investigator processing.
npx claudepluginhub buriedsignals/spotlight --plugin spotlightHow this skill is triggered — by the user, by Claude, or both
Slash command
/spotlight:reviewThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
The review skill closes the editorial feedback loop on a completed investigation. It produces a **single HTML file** that the journalist can open in any browser, inspect findings + verdicts, and submit structured feedback. When feedback is submitted, the orchestrator re-spawns the investigator to address it and regenerates the review artifact.
Drafts three journalist-grade deliverables from verified findings: findings-report.md, report.html (from template), and evidence-map.json. For use after Gate 1 approval in Phase 5.
Performs hierarchical bottom-up review of drafted documents, diagnosing structural problems and producing .planning/REVIEW.md for revision.
Verifies task completion with checklist: collects evidence like screenshots/videos in REPORT.md, asks report level via user question, initiates reviews (code-security, e2e, ui-ux). Use post-implementation.
Share bugs, ideas, or general feedback.
The review skill closes the editorial feedback loop on a completed investigation. It produces a single HTML file that the journalist can open in any browser, inspect findings + verdicts, and submit structured feedback. When feedback is submitted, the orchestrator re-spawns the investigator to address it and regenerates the review artifact.
No server required. The HTML is fully self-contained (inline CSS + JS). Feedback is exported as a downloadable review-feedback.json file that the user drops into the case's data/ directory.
The skill operates in one of two modes based on case state.
generateTriggered by the orchestrator at the end of Phase 4 (Gate 1 approved), OR invoked directly by the user.
Inputs:
{CASE_DIR}/data/findings.json{CASE_DIR}/data/fact-check.json{CASE_DIR}/data/summary.json (optional){CASE_DIR}/data/provenance-manifest.json (optional){CASE_DIR}/summary.md (optional)Outputs:
{CASE_DIR}/review.html — self-contained review artifactprocessTriggered when {CASE_DIR}/data/review-feedback.json exists and has not yet been processed (no matching data/review-feedback-processed.json marker).
Inputs:
{CASE_DIR}/data/review-feedback.json{CASE_DIR}/data/findings.json (current state){CASE_DIR}/data/fact-check.json (current state)Outputs:
{CASE_DIR}/data/findings.json (after investigator runs){CASE_DIR}/data/fact-check.json (after fact-checker runs){CASE_DIR}/review.html (Mode A runs automatically after processing){CASE_DIR}/data/review-feedback-processed.json — marker file recording when feedback was processedgenerate Stepsread-file("{CASE_DIR}/data/findings.json")
read-file("{CASE_DIR}/data/fact-check.json")
read-file("{CASE_DIR}/data/summary.json") # may not exist
read-file("{CASE_DIR}/data/provenance-manifest.json") # may not exist
read-file("{CASE_DIR}/summary.md") # may not exist
read-file("skills/review/references/template.html")
Assemble a single JSON object with the shape expected by the template (see references/feedback-schema.md):
{
"project": "<slug>",
"generated_at": "<ISO 8601>",
"summary": {
"headline": "N verified findings across M cycles",
"overview": "<2-3 paragraph synthesis from summary.md or derived>",
"scope": "<what was investigated, what was out of scope>",
"conclusions": ["..."],
"limitations": ["..."],
"confidence_assessment": "<margin narrative>"
},
"findings": [
{
"id": "F1",
"claim": "...",
"evidence": "...",
"confidence": "high|medium|low",
"confidence_rationale": "...",
"grounding": {
"support_type": "direct|indirect|inferred|contradicted|insufficient",
"source_role": "primary|secondary|contextual",
"claim_elements_supported": ["..."],
"missing_assumptions": ["..."],
"confidence_cap": "high|medium|low",
"misgrounding_risk": "...",
"grounding_rationale": "..."
},
"evidence_bundle_refs": ["E1"],
"perspective": "...",
"sources": [{"url": "...", "type": "...", "archive_url": "...", "access_method": "..."}],
"verdict": {
"verdict": "verified|unverified|disputed|false",
"confidence": "high|medium|low",
"grounding_assessment": {
"support_type": "direct|indirect|inferred|contradicted|insufficient",
"claim_elements_checked": ["..."],
"missing_assumptions": ["..."],
"confidence_cap": "high|medium|low",
"assessment": "..."
},
"evidence_for": [{"description": "...", "source": "...", "source_type": "primary|secondary"}],
"evidence_against": [{"description": "...", "source": "..."}],
"notes": "..."
}
}
],
"provenance_manifest": {
"status": "unsigned|signed|signing_failed",
"generated_at": "<ISO 8601>",
"signing": {"profile": "noosphere-c2pa", "receipt_path": "..."},
"case_artifacts": [{"kind": "findings", "path": "data/findings.json", "sha256": "..."}],
"claims": [{"finding_id": "F1", "support_type": "direct", "evidence_refs": ["E1"]}],
"sources": [{"evidence_id": "E1", "source_url": "...", "sha256": "...", "human_verification_required": false}]
},
"fact_check_summary": {
"total_claims": N,
"verified": N,
"unverified": N,
"disputed": N,
"false": N
},
"cycles": N,
"existing_feedback": null
}
Join each finding with its matching fact-check claim by finding_id. Preserve the investigator's grounding, the fact-checker's grounding_assessment, source local_file fields, and evidence_bundle_refs. If data/provenance-manifest.json exists, include it as provenance_manifest; if it does not exist, set provenance_manifest: null so the template can show that signing has not been generated yet.
The template contains a single marker:
<script id="investigation-data" type="application/json">
/*INVESTIGATION_DATA*/
</script>
Replace /*INVESTIGATION_DATA*/ with the JSON payload from step 3. Use edit-file with old="/*INVESTIGATION_DATA*/" and new=<json-payload>.
write-file("{CASE_DIR}/review.html", <populated template>)
"Review artifact written to {CASE_DIR}/review.html.
Open it in any browser to inspect findings and submit feedback.
If you submit feedback, save the exported review-feedback.json
into {CASE_DIR}/data/ and re-run /spotlight to process it.
Or proceed to ingestion now — review is optional."
process Stepslist-files("{CASE_DIR}/data/review-feedback.json")
list-files("{CASE_DIR}/data/review-feedback-processed.json")
If review-feedback.json exists AND review-feedback-processed.json does NOT exist (or is older than the feedback file) → proceed. Otherwise skip.
read-file("{CASE_DIR}/data/review-feedback.json")
Validate it against the schema in references/feedback-schema.md. Required fields: schema_version, project, submitted_at, and at least one of findings_feedback[], general_feedback, missing_angles.
Compose a focused spawn prompt. For each finding with feedback:
Finding {id}: {claim}
Current verdict: {verdict}
Editorial feedback:
- Challenge: {challenge}
- Deeper verification requested: {deeper_verification}
- Alternative framing suggested: {alternative_framing}
Action: address this feedback — seek additional evidence for the
challenge, pursue the deeper verification, consider whether the
alternative framing is supported by sources. Update findings.json
with any new evidence. If the verdict should change, say so
explicitly in the cycle notes.
For general_feedback and missing_angles, add a "general directives" section to the prompt.
handle = spawn-agent(
agent_id: "investigator",
prompt: "<spawn prompt from step 3, wrapped in EXECUTION-mode template>
MODE: EXECUTION
PROJECT: {project}
VAULT_PATH: {vault_path or 'none'}
CYCLE: <current cycle + 1>
This cycle addresses editorial feedback submitted through the review
artifact. Read {CASE_DIR}/data/review-feedback.json for the
full feedback. Focus narrowly on the items listed above.
Read methodology from {CASE_DIR}/data/methodology.json.
Write merged findings to {CASE_DIR}/data/findings.json.
Append to {CASE_DIR}/data/investigation-log.json with focus='review-feedback'.",
config: { iteration_limit: 80 }
)
wait-agent(handle)
Only for findings whose feedback requested deeper verification OR where the investigator updated evidence:
handle = spawn-agent(
agent_id: "fact-checker",
prompt: "PROJECT: {project}
CYCLE: <current cycle>
Re-fact-check findings that were updated in response to editorial
feedback. Specifically: {list of affected F-IDs}. Read the current
findings.json and apply SIFT per the usual methodology.
Write to {CASE_DIR}/data/fact-check.json (merge with existing).",
config: { iteration_limit: 50 }
)
wait-agent(handle)
write-file("{CASE_DIR}/data/review-feedback-processed.json",
'{"processed_at": "<ISO 8601>", "feedback_file": "review-feedback.json", "cycles_added": 1, "findings_updated": [<ids>]}')
Re-enter Mode A (generate) to produce a fresh review.html reflecting the updated findings.
"Feedback processed. {N} findings updated.
Regenerated review.html reflects the new state. Submit more
feedback, proceed to ingestion, or stop here — your call."
The orchestrator's Phase 4, after the user approves the findings and summary.md is written, includes:
5. invoke-skill("review") # Mode A auto — generates review.html
6. Offer the user: "Review artifact ready. Inspect and submit feedback,
or proceed to ingestion?"
When resuming an investigation, the orchestrator's Phase 0 should add a step (between 7 and 8):
Check for {CASE_DIR}/data/review-feedback.json:
- If exists AND review-feedback-processed.json missing/older:
invoke-skill("review") # Mode B auto — processes feedback
- Otherwise: proceed normally
The user can call this skill at any time to regenerate the review artifact (useful mid-investigation to see current state) or to force-process pending feedback.
The review-feedback.json schema is documented in references/feedback-schema.md.
Key invariants:
schema_version: "1.0" requiredproject must match the active casefindings_feedback[].finding_id must reference an existing finding IDThe self-contained template lives at references/template.html. Characteristics:
data/provenance-manifest.json, including signing status, artifacts, source hashes, evidence refs, and whether human verification is still requiredchallenge, deeper_verification, alternative_framinggeneral_feedback, missing_angles<a download>The template has exactly one substitution marker: /*INVESTIGATION_DATA*/ inside a <script type="application/json"> tag. Skill execution replaces this marker with the payload JSON from Mode A step 3.
Reads from:
{CASE_DIR}/data/findings.json
{CASE_DIR}/data/fact-check.json
{CASE_DIR}/data/summary.json (optional)
{CASE_DIR}/summary.md (optional)
{CASE_DIR}/data/review-feedback.json (Mode B only)
{CASE_DIR}/data/review-feedback-processed.json (Mode B only — existence check)
skills/review/references/template.html
Writes to:
{CASE_DIR}/review.html
{CASE_DIR}/data/review-feedback-processed.json (Mode B)
{CASE_DIR}/data/findings.json (Mode B, via spawned investigator)
{CASE_DIR}/data/fact-check.json (Mode B, via spawned fact-checker)
{CASE_DIR}/data/investigation-log.json (Mode B, appended)
In sensitive mode:
fetch/search), so the investigator can only address feedback using pre-scraped research in {CASE_DIR}/research/