review-engine — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited review-engine (Agent Skill) and scored it 96/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 1 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 1 flagged
The text {match} tells the agent to skip the normal "ask the user first" gate. Used adversarially it removes the human-in-the-loop check before destructive or sensitive actions, turning a normally-gated agent into a fire-and-forget executor.
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Orchestration Log: When this skill is activated, append a log entry tooutputs/orchestration_log.md: ``### Skill Activation: Review Engine (Round [N]) **Timestamp:** [current date/time] **Actor:** AI Agent (review-engine) **Input:** [N] review points from [source] (annotated PDF / pasted text / reviewer report) **Output:** [N] changes implemented, paper recompiled, latexdiff generated **Human decisions:** [list of QUESTION items resolved by orchestrator]``
Academic revision is a structured, repeatable process: extract feedback -> interpret -> classify -> implement -> verify. This engine automates the entire loop. The human orchestrator approves the change plan; the engine executes it.
This skill was derived from 4 actual co-author revision rounds on a real paper (Blask & Funk, 2026). Every step reflects what we learned works — and what fails — when processing human feedback on AI-generated manuscripts.
paper.tex exists in latex/ and compiles successfully (this is the baseline)pdflatex and bibtex are availablelatexdiff is available (for visual change tracking)fitz) is available for PDF annotation extraction (pip install pymupdf)The first step is to get all review points into a structured format, regardless of how the reviewer provided them.
This is the most common case: a co-author annotates the PDF with highlights, sticky notes, and text comments. Use scripts/extract_annotations.py:
import sys
sys.path.insert(0, "scripts")
from extract_annotations import extract_annotations, annotations_to_markdown
annotations = extract_annotations("path/to/annotated.pdf")
print(annotations_to_markdown(annotations))
print(f"\nTotal: {len(annotations)} annotations found")If scripts/extract_annotations.py is not available, use inline PyMuPDF:
import fitz
doc = fitz.open("path/to/annotated.pdf")
annotations = []
for page_num, page in enumerate(doc, 1):
for annot in page.annots() or []:
entry = {
"page": page_num,
"type": annot.type[1], # "Highlight", "Text", "FreeText", "StrikeOut"
"content": annot.info.get("content", "").strip(),
"author": annot.info.get("title", ""),
"highlighted_text": "",
}
# Extract highlighted/marked text via quadpoints
if annot.type[0] in (8, 9, 10, 11) and annot.vertices: # Highlight, Underline, Squiggly, StrikeOut
quad_count = len(annot.vertices) // 4
text_parts = []
for i in range(quad_count):
quad = annot.vertices[i * 4:(i + 1) * 4]
rect = fitz.Rect(
min(p[0] for p in quad), min(p[1] for p in quad),
max(p[0] for p in quad), max(p[1] for p in quad),
)
text_parts.append(page.get_text("text", clip=rect).strip())
entry["highlighted_text"] = " ".join(text_parts)
if entry["content"] or entry["highlighted_text"]:
annotations.append(entry)
doc.close()Common pitfall: The user may send the wrong PDF (without annotations). If extraction returns 0 annotations, tell the user immediately and ask them to re-send. Do NOT proceed with an empty annotation list.
Parse reviewer comments by detecting common patterns:
Reviewer 1:
Major Comments:
1. The authors should clarify...
2. The methodology section lacks...
Minor Comments:
1. On page 5, the reference to...Split into individual review points by:
Parse the structured self-critique from self_review.md or the Phase 6 output. Each bullet point or numbered item becomes a review point.
Every extraction method produces the same structure:
{
"id": 1,
"source": "pdf_annotation" | "pasted_text" | "self_review",
"page": 5, # PDF page (if applicable)
"type": "Highlight", # Annotation type (if PDF)
"reviewer": "Burkhardt Funk", # Reviewer name (if known)
"reviewer_text": "just delete, I think ref to tab 1 is also wrong here",
"highlighted_text": "Following Hevner et al.'s guidelines, we evaluate in three steps",
"section_ref": null # Will be filled in Step 2
}For each review point, locate the corresponding position in paper.tex.
highlighted_text (or key phrases fromreviewer_text) and search paper.tex using grep/search. Handle:
\textit{...}, \citep{...})PDF page number to estimate which LaTeX section it corresponds to. Compile the paper, check page breaks, and narrow down the section.
mapping_confidence: low and present it to the user for manual location.
For each matched location, also extract:
\section{} or \subsection{} it belongs topaper.texEach review point is enriched:
{
...,
"tex_line": 256,
"tex_section": "\\subsection{Pipeline Implementation}",
"tex_context": "Following Hevner et al.'s guidelines, we evaluate in three steps...",
"mapping_confidence": "high" | "medium" | "low"
}For each review point, determine what the reviewer is asking for and how to respond.
| Type | Description | Automation | Example |
|---|---|---|---|
DELETE | Remove text entirely | Full auto | "just delete" |
REPLACE | Change specific text or terminology | Full auto | "systems -> agents" |
MOVE | Relocate content to different section | Guided auto | "belongs in conclusion" |
RESTRUCTURE | Reorganize section flow/argument | Needs plan approval | "Better: briefly describe each agent" |
FIX | Correct references, typos, formatting | Full auto | "is it 7.1?" |
FIGURE | Modify or regenerate a figure | Invoke figure-engine | "extend orchestrator zone" |
SHORTEN | Reduce or condense text | Guided auto | "zu kleinteilig" |
EXPAND | Add more detail or explanation | Invoke writing-engine | "elaborate on methodology" |
APPROVE | No action needed (positive feedback) | Log only | "fine with phases" |
QUESTION | Ambiguous -- needs human decision | Block + ask | "do we do that?" |
For each review point:
reviewer_text in context of highlighted_textaction_type and priorityproposed_change (1-sentence description)automation_level: can this be done automatically, or does it needhuman input or another engine (figure-engine, writing-engine)?
Reviewers may comment in any language (German is common in DACH academia). Interpret the comment in its original language; do not require translation. Common German review phrases:
Each review point is enriched:
{
...,
"action_type": "DELETE",
"priority": "MAJOR",
"automation_level": "full_auto" | "guided" | "needs_approval" | "needs_engine" | "needs_human",
"proposed_change": "Remove the three-step evaluation paragraph at line 256",
"depends_on": [] // IDs of other changes this depends on
}This is the QUALITY GATE. Do NOT proceed without user approval.
Present a structured overview of all review points and proposed changes:
📋 REVISION PLAN -- Round [N]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Source: [annotated PDF from Burkhardt Funk / Reviewer 1 report / ...]
Extracted: [N] review points
Actionable: [N] changes | Approved: [N] (no action) | Questions: [N] for you
# | Type | Priority | Section | Reviewer Said | Proposed Change
----|-------------|----------|---------|-----------------------------|--------------------------
1 | REPLACE | MINOR | global | "systems -> agents" | Global replace in 8 locations
2 | DELETE | MAJOR | S4.1 | "just delete" | Remove eval paragraph (L256)
3 | MOVE | MAJOR | S4.2 | "belongs in conclusion" | Move scope para to S8
4 | RESTRUCTURE | MAJOR | S4.2 | "briefly describe each agent"| Rewrite with phase summaries
5 | FIX | MINOR | S7.3 | "is it 7.1?" | Fix cross-reference
6 | FIGURE | MAJOR | Fig 1 | "extend orchestrator zone" | Regenerate via PaperBanana
7 | APPROVE | -- | S2.5 | "fine with phases" | No action -- logged
8 | QUESTION | MAJOR | S4.2 | "do we do that?" | ⚠️ Need your decision
⚠️ QUESTIONS requiring your input:
Q1 (#8): Burkhardt asks "do we do that? delete?" about Phase 5/6 descriptions.
-> Delete entirely, or shorten to one sentence each?
Execution order (respecting dependencies):
1 -> 2 -> 3 -> 4 -> 5 -> 6
🔄 Approve plan to proceed with implementation.
-> Override: modify any proposed change before I execute.For items classified as QUESTION:
Some changes depend on others:
already uses correct terms)
Build a dependency graph and present the execution order.
After the user approves the plan, execute changes in dependency order.
REPLACE with replace_all: true)DELETE)% [R{round}: {brief description} -- deleted per {reviewer}]MOVE)RESTRUCTURE)SHORTEN)FIX)\label{}, fix \ref{}FIGURE)paperbanana_direct.pylatex/figures/\includegraphics path if neededEXPAND)Every change gets a LaTeX comment marker for traceability:
% [R3: Moved scope paragraph to conclusion per Burkhardt]
% [R3-05: Fixed cross-reference Section 6.1 -> \ref{sec:task_redistribution}]
% [R4: Three-step evaluation paragraph deleted per Burkhardt]Format: % [R{round}: {brief description}] Or with ID: % [R{round}-{change_number}: {description}]
After all changes are implemented, verify the paper still compiles and looks correct.
Run the full LaTeX compilation cycle:
cd latex/
pdflatex -interaction=nonstopmode paper.tex
bibtex paper
pdflatex -interaction=nonstopmode paper.tex
pdflatex -interaction=nonstopmode paper.texTarget: 0 errors, 0 undefined references, 0 undefined citations.
If compilation fails:
.log file for the error\end{}, or bad \ref{})Generate a visual diff against the baseline:
latexdiff <(git show BASELINE_COMMIT:latex/paper.tex) latex/paper.tex > latex/paper_diff.tex
pdflatex -interaction=nonstopmode latex/paper_diff.tex
bibtex paper_diff
pdflatex -interaction=nonstopmode latex/paper_diff.tex
pdflatex -interaction=nonstopmode latex/paper_diff.texThe baseline commit should be:
indicate something went wrong (content accidentally deleted or duplicated).
grep "undefined" paper.log should return 0 matches.figures/.\citep / \citet keys should resolve.✅ REVISION ROUND [N] COMPLETE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📄 paper.pdf -- [N] pages, 0 errors
📊 Changes implemented: [N] of [N] planned
📝 paper_diff.pdf generated against baseline [commit hash]
Compilation: ✅ Clean (0 errors, 0 warnings)
References: ✅ All \ref{} and \citep{} resolved
Page count: [N] pages (was [N] before revision)
Figures: ✅ All [N] figures present
Review points:
✅ Implemented: [N]
ℹ️ Approved: [N] (no action needed)
❓ Deferred: [N] (marked for next round)Save a detailed change log for each round:
File: outputs/revision_log_r{N}.md
# Revision Log -- Round [N]
**Date:** [ISO 8601]
**Reviewer:** [name]
**Source:** [annotated PDF / pasted comments / reviewer report]
**Review points:** [N] total ([N] implemented, [N] approved, [N] deferred)
## Changes Implemented
### Change 1: [brief title]
- **Type:** REPLACE
- **Reviewer said:** "[exact quote]"
- **Action:** Global replacement of "research systems" with "research agents" (8 occurrences)
- **Files affected:** paper.tex (lines 118, 235, 255, ...)
### Change 2: [brief title]
...
## No Action Required
### Approval 1: [brief title]
- **Reviewer said:** "[exact quote]"
- **Reason:** Positive feedback, no change needed
## Deferred to Next Round (if any)
### Deferred 1: [brief title]
- **Reviewer said:** "[exact quote]"
- **Reason:** Needs empirical data / needs further discussionIf the review came from a journal, generate a formal revision letter:
File: outputs/revision_letter.md
# Response to Reviewers
Dear Editor,
Thank you for the opportunity to revise our manuscript "[title]" (MS-XXXX).
We have carefully addressed all reviewer comments as detailed below.
---
## Reviewer 1
### Comment 1.1
> [Exact quote of reviewer comment]
**Response:** [How we addressed it]
**Change:** [Specific change made, with section/page reference]
### Comment 1.2
> [Exact quote]
**Response:** ...
---
## Reviewer 2
...Append to outputs/orchestration_log.md:
## Phase 8: Revision (Round [N])
**Timestamp:** [ISO 8601]
**Actor:** AI Agent (review-engine)
**Action:** Processed [N] review points from [reviewer], implemented [N] changes
**Key metrics:** [N] review points, [N] changes, [N] approvals, [N] questions resolved
**Output artifacts:** paper.pdf, paper_diff.pdf, revision_log_r[N].md
**Quality Gate Decision:** [Approved / Redirected]
**Orchestrator Feedback:** "[user's response to change plan]"
**Scope Changes:** [any modifications to proposed changes]If the user approves:
git add latex/paper.tex latex/paper.pdf latex/paper_diff.pdf outputs/revision_log_r*.md
git commit -m "Round [N]: implement [reviewer] review ([N] changes)
Changes: [1-line summary of each change]
Co-Authored-By: Claude <[email protected]>"correct file. Do NOT proceed with empty annotations.
Present to user with the reviewer's comment and ask them to locate it manually.
If persistent, present the error and the problematic change to the user.
Do not make the decision autonomously.
changes. Flag the figure change as "deferred" in the change log.
The review engine orchestrates other skills when needed:
| Change Type | Engine Invoked | Purpose |
|---|---|---|
| FIGURE | figure-engine | Regenerate diagrams via PaperBanana |
| EXPAND | writing-engine | Draft new text following academic templates |
| RESTRUCTURE | writing-engine | Rewrite sections following paragraph formulas |
| FIX (citations) | verification-engine | Verify corrected citations are accurate |
| COMPILE | latex-engine | LaTeX compilation and PDF generation |
This phase is designed to repeat:
Round 1: Major structural feedback -> implement -> send back
Round 2: Terminology and flow -> implement -> send back
Round 3: Minor corrections -> implement -> send back
Round 4: Final approval + cosmetics -> implement -> doneEach round:
R1, R2, R3, R4)revision_log_r1.md, revision_log_r2.md, ...)~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.