/anti-autoresearch — the orchestrator
SkillDocs & knowledgeEnd-to-end substantive-integrity forensic sweep of a research paper (especially autoresearch / AI-Scientist-style output). Orchestrates the whole pipeline: ingest (arxiv-id | pdf | dir → working dir + pdftotext for L0) → /evidence-ledger (artifact manifest + observability level L0/L1/L2 + span-anchored claims.json) → fan out the integrity auditor skills (consistency, citation, baseline, experiment, presentation, proof-derivation, eval-design — each reads the ledger, emits span-anchored findings) + the zero-verdict-weight AIS writing-style track → advisory memos (/adversarial-case-builder + /novelty-duplication-advisory, no verdict weight) → deterministic tools/adjudicate_findings.py (--ledger REQUIRED) → reviewer-ready Integrity Forensics Report. Cross-model (fresh codex per dimension) and reviewer≠adjudicator: the model proposes findings, the deterministic adjudicator decides the verdict. Observability-aware, detect-only, never an opaque AI-text classifier (a separate zero-weight AIS section lists AI writing-style impressions, never moving the verdict). Triggers: \"anti-autoresearch\", \"integrity audit this paper\", \"forensic review\", \"audit a submission\", \"审一篇投稿的诚信\".
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the /anti-autoresearch — the orchestrator skill
What this skill tells your AI
The instructions your AI receives, as published by wanshuiyin/anti-autoresearch in workflows/anti-autoresearch/SKILL.md and read by ahel’s review.
Run a full substantive-integrity forensic pass on $ARGUMENTS and hand a human reviewer / area chair an evidence-first Integrity Forensics Report.
🔒 External cadence: the verdict is not a poll. The pipeline is the verdict-producing path — its output changes only when the paper / repo / ledger changes, not with the clock. Do not wrap
/anti-autoresearch(or any auditor sub-skill) in/loop//schedule/CronCreateto "re-check". A heartbeat may only wait on the external steps that precede the verdict (an arXiv download, a citation web lookup) — never re-fire the adjudicated verdict, and never "decide the paper is fine now." Re-run the sweep when the inputs change; that is the only honest trigger.
🛡️ The dual of ARIS. ARIS ships an internal audit stack so its own autoresearch output stays honest; Anti-Autoresearch is that same audit DNA pointed outward at a third party's submission. This is decision support for a human — it surfaces span-anchored discrepancies to investigate. It is not an AI-text detector and it does not judge misconduct (
DESIGN.md§1;references/).
Why this exists
A machine-driven research pipeline (or rushed human) writes the abstract, the tables, the method section, the bibliography, and the appendix in separate passes and never reconciles them. The result is a paper that disagrees with itself, cites papers that do not exist or argue the opposite, claims SOTA while omitting the obvious baseline, or reports numbers the code never computed. Six LLMs each re-reading the PDF would hallucinate six different structures and invite the obvious dismissal — "an LLM grading another LLM's paper is just slop."
This orchestrator answers that structurally. One deterministic pass turns the paper into a hashed, span-anchored evidence ledger; six auditors read only that ledger and propose findings; a deterministic adjudicator decides the verdict by fixed rules; observability levels are recorded on every finding so a claim that needs code cannot pass as confirmed from a PDF; and every proposal is reported rather than silently dropped. Same artifacts → same ledger → same summary.
Pipeline role (what this run does, and never does)
[0] ingest arxiv-id | pdf | dir → working dir (+ pdftotext text for L0)
│
▼
[1] /evidence-ledger tools/build_manifest.py + tools/build_claim_ledger.py
│ → artifact_manifest.json (derives observability level L)
│ → claims.json (span-anchored, hashed; the ONLY structure auditors read)
▼
[2] fan out auditors (each reads the ledger, emits <skill>.findings.json):
consistency-audit (always · flagship · deterministic arithmetic + semantic)
citation-forensics (if ≥1 citation claim)
baseline-comparison-audit (if ≥1 comparison / SOTA scope claim)
experiment-forensics (always · L0/L1 = info "could-not-verify" · L2 = full code audit)
presentation-signals (always · AUXILIARY · surface-class label)
ai-style-impressions (always · AIS track · NOT integrity · zero verdict weight)
proof-derivation-forensics (if ≥1 theorem/proof/derivation claim · verdict-bearing · dim=proof · L1 source, CAN reach HARD_FLAGS; L0 PDF-only → info)
eval-design-forensics (if ≥1 comparison/eval claim · family H · dim=evaluation · L0/L1 stated-tells: leakage / judge-validity / selective-reporting)
│
▼
[3] advisory memos (each reads the ledger + merged findings · NO verdict weight):
/adversarial-case-builder → adversarial-case-builder.memo.md (strongest evidence-bound objection)
/novelty-duplication-advisory → novelty-duplication-advisory.memo.md (if ≥1 contribution claim · MEMO-ONLY · prior-work overlap · zero verdict weight)
│
▼
[4] tools/adjudicate_findings.py --ledger REQUIRED → report.json + REPORT.md
│ anchor check moves severity; observability / FP-risk / surface /
│ needs-external-check / zero-weight are recorded as annotations
│ overall_verdict ∈ {CLEAN_GIVEN_EVIDENCE, SOFT_FLAGS, HARD_FLAGS} (rules, no model)
▼
[5] present REPORT.md to the human (verdict + level first; state what could NOT be checked)
- Auditors propose; the adjudicator decides. No auditor (and not this orchestrator)
ever computes
overall_verdict; onlytools/adjudicate_findings.pydoes, by fixed rules (references/reviewer-independence.mdLayer 2;DESIGN.md§3). - Detect-only. No step ever edits the audited paper or repo. This is a third-party
forensics tool, never a co-author (no
Editis granted; the reviewer sandbox isread-only). - Observability caps everything. L0 (PDF-only) / L1 (source) cannot assert
code/result-level fraud — those need L2 (repo + results). The adjudicator demotes any
finding above the run's level (
references/observability-levels.md;DESIGN.md§4).
Constants & conventions
REVIEWER_MODEL = gpt-5.6-sol (via mcp__codex__codex) — a DIFFERENT model family from the executor (Claude)
REVIEWER_REASONING = xhigh — always; the effort knob never lowers reviewer quality
REVIEWER_SANDBOX = read-only — detect-only; the reviewer never mutates the paper
THREAD_POLICY = FRESH mcp__codex__codex per dimension / per cited key; NEVER codex-reply across them
(codex-reply is deliberately NOT in allowed-tools — the bias guard)
RUN_THREADS = serial — one codex thread at a time; concurrent codex MCP calls can hang
LEDGER_VERSION = 0.1 (stamped by tools/build_claim_ledger.py)
TAXONOMY_VERSION = 0.5 (references/hack-pattern-taxonomy.md; 46 integrity patterns A–H + 13 AIS impressions + 2 ADV advisory; stamped into every report)
OBSERVABILITY = derived L0 (pdf/text) · L1 (latex, no results) · L2 (repo + results); L3 NEVER (no reproduction)
ADJUDICATOR = deterministic-rules-v2 (tools/adjudicate_findings.py — the ONLY verdict source)
DETECT_ONLY = true · EMITS_VERDICT = true (computed by code, not by a model)
REAL TOOLS (resolve ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)):
tools/build_manifest.py · tools/build_claim_ledger.py · tools/check_numeric_consistency.py
· tools/check_presentation.py · tools/adjudicate_findings.py (confirm flags with --help; never invent flags)
OUTPUTS (in PAPER_DIR) — artifact_manifest.json · claims.json · <skill>.findings.json (+ *.deterministic.findings.json)
· adversarial-case-builder.memo.md · report.json · REPORT.md · .aris/traces/<skill>/<date>_run<NN>/
Overrides (pass after —): effort: balanced (default) | max (auditors fan the
checklist into more fresh threads for breadth) · enrich: true (default; the ledger's
additive semantic pass) | false · human checkpoint: false (default) | true (pause
after Step 1 to confirm L, and before Step 5). Example:
/anti-autoresearch ~/papers/submission — effort: max, human checkpoint: true.
⚠️ Shell state does not persist between Bash calls (cwd + env reset each call). Every block below re-derives
ROOTandPAPER_DIRat its top and readsL/PAPER_IDfromclaims.json(the authoritative source after Step 1). Never rely on a variable set in an earlier block, and nevercdinto the paper dir. KeepPAPER_DIRspace-free (simplest way to stay safe across the inline*.tex/*.findings.jsonglobs).
Execution modes & the Reviewer Calling Convention
Pick the mode automatically — both produce the identical file set, and Step 4 (the verdict) is byte-deterministic given those files + the ledger.
- Delegation (default — if the
Skilltool is available): invoke/evidence-ledger, the six auditors, and the two advisory memos (/adversarial-case-builder+/novelty-duplication-advisory). Each sub-skill runs its own deterministic tools + its exact codex reviewer prompt + its own anchor validation, and writes its<skill>.findings.json. The orchestrator validates the emitted files and adjudicates. This mirrors ARIS/research-pipelinedelegating all GPT review to/auto-review-looprather than prompting GPT itself. - Inline (fallback — only shell + Read/Write + codex MCP): run the deterministic
tools yourself with the exact commands below; for each cross-model dimension open a
fresh
mcp__codex__codexthread, send the verbatim reviewer-prompt block — the fencedprompt:/ checklist inside that sub-skill's## Step … — Cross-model …section inskills/<dim>/SKILL.md(Read it — the single source of truth; fill its[...]inputs fromclaims.json), save the raw reply, then run the shared anchor gate (Step 2) to produce the validated<dim>.findings.json.
The orchestrator's job is to guarantee the envelope and the independence invariants every reviewer call obeys:
- Envelope (every auditor instantiates this exact shape):
mcp__codex__codex: model: gpt-5.6-sol config: {"model_reasoning_effort": "xhigh"} sandbox: read-only cwd: <absolute PAPER_DIR> # so the reviewer reads claims.json + sources directly prompt: | <the auditor's per-dimension checklist + the SIX HARD RULES below> - The executor passes only structured inputs — paths + the ledger (
claims.json) + the per-dimension checklist + the run levelL. It never summarizes the paper, pre-judges, leaks a hunch, or whispers "this is probably AI-generated" (references/reviewer-independence.mdLayer 1; the tool is agnostic to authorship). - Six hard rules the orchestrator requires in every auditor's prompt (a finding that
breaks one is structurally worthless): (1) ANCHOR — every above-
infofinding carries ≥1evidence{claim_id, span}whereclaim_idexists inclaims.jsonandspanis a verbatim, whitespace-normalized substring of that claim'stext_span(span in claim, neverclaim in span); (2) DISCREPANCY, NOT ACCUSATION — describe what to check/ask, never "reject"/"fabricated"; (3) OBSERVABILITY — setobservability_level_requiredto the lowest tier at which the discrepancy is decidable (code/result confirmation ⇒2); (4) HONEST FP RISK — setfalse_positive_risktruthfully (legit "best config", labeled pilots, rounding, deterministic metrics are common FPs); (5) HAND OFF EXTERNAL CLAIMS — "first / SOTA" the text cannot settle ⇒verdict_local: needs_external_check+requires_external_check: true; (6) pattern_id ∈ taxonomy v0.5 only. - Reviewer ≠ adjudicator. The reviewer proposes findings; only
tools/adjudicate_findings.pydecides the verdict (Layer 2). The model is demoted from judge to evidence-extractor. - Fresh thread per dimension, serial. A new
mcp__codex__codexcall per auditor (and per cited key insidecitation-forensics); nevercodex-replycarrying one dimension's conclusions into another (the bias guard). Keep the calls serial — concurrent codex threads can hang; fan-out buys breadth of dimensions, not parallelism. On a stall, re-invoke the identical prompt in a fresh thread (nevercodex-reply); if it still fails, write[], record"<skill>": "review_unavailable"in$PAPER_DIR/coverage.json, and continue — a dead reviewer must never become a fabricated finding, and an empty file must never masquerade as a completed review (the adjudicator's--coveragegate turns a would-be CLEAN intoREVIEW_UNAVAILABLEwhen any verdict-bearing dimension never ran; zero-weight tracks only add a limitation). Skills that legitimately find nothing to audit recordnot_applicable; completed dimensions recordcompleted.
Re-entrancy: resuming a partial / re-run sweep
The pipeline is a pure function of PAPER_DIR's contents — every step writes a
predictable file, so a crashed or repeated run resumes by probing what already exists.
There is no run-state file and no "accepted vs done" gate, because Step 4 recomputes
the verdict deterministically from whatever findings are present every time. Probe
completeness and staleness before redoing work:
PAPER_DIR="<from Step 0>"
python3 - "$PAPER_DIR" <<'PY'
import json, os, glob, sys
D = sys.argv[1]
def is_array(p):
try: return isinstance(json.load(open(p, encoding="utf-8")), list)
except Exception: return False
def is_ledger(p):
try:
d = json.load(open(p, encoding="utf-8")); return isinstance(d, dict) and "claims" in d
except Exception: return False
def newest_source(d):
s = []
for ext in ("*.tex", "*.txt", "*.bib"):
s += glob.glob(os.path.join(d, ext)) + glob.glob(os.path.join(d, "**", ext), recursive=True)
return max((os.path.getmtime(p) for p in s), default=0.0)
led = os.path.join(D, "claims.json"); have = is_ledger(led)
stale = have and os.path.getmtime(led) < newest_source(D)
print(f"STEP1 ledger : {'present' if have else 'MISSING'}{' ⚠ STALE → rebuild (sources changed)' if stale else ''}")
covp = os.path.join(D, "coverage.json")
try: cov = json.load(open(covp, encoding="utf-8"))
except Exception: cov = {}
for f in ("consistency-audit.deterministic", "consistency-audit", "citation-forensics",
"baseline-comparison-audit", "experiment-forensics",
"presentation-signals.deterministic", "presentation-signals",
"proof-derivation-forensics", "eval-design-forensics",
"ai-style-impressions.deterministic", "ai-style-impressions"):
p = os.path.join(D, f + ".findings.json")
skill = f.replace(".deterministic", "")
# a findings file alone is NOT completion — the coverage entry decides.
# (deterministic sub-files ride on their skill's coverage key)
done = (os.path.isfile(p) and is_array(p)
and cov.get(skill) in ("completed", "not_applicable"))
print(f"STEP2 {f:<32}: {'ok' if done else 'todo'}")
print(f"STEP3 adversarial memo : {'present' if os.path.isfile(os.path.join(D,'adversarial-case-builder.memo.md')) else 'todo'}")
print(f"STEP3 novelty advisory memo : {'present' if os.path.isfile(os.path.join(D,'novelty-duplication-advisory.memo.md')) else 'todo'}")
print(f"STEP4 report.json : {'present' if os.path.isfile(os.path.join(D,'report.json')) else 'todo'}")
PY
Rule: a stale ledger forces a full rebuild (Step 1 → re-fan Step 2 → re-adjudicate)
— stale findings anchored to an old ledger are worse than none. A full rebuild also
deletes coverage.json (the Step-2 init re-creates it all-review_unavailable;
stale completed entries must not survive a rebuild). If the ledger is fresh,
skip Step 1 and only re-run the auditors marked todo. Always re-run Step 4 (cheap,
deterministic, the only verdict source). Re-running from scratch is always safe — same
inputs → same outputs.
Step 0 — Ingest: resolve the input to a working dir
Turn $ARGUMENTS (a directory, a PDF, or an arXiv id) into a single working
directory (PAPER_DIR) that contains the best source the level allows. Prefer LaTeX
(stable file:line spans → L1) over PDF text (best-effort → L0); leave any code/ +
results/ in place so the manifest can derive L2.
ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
test -f "$ROOT/tools/adjudicate_findings.py" || { echo "FATAL: not inside the Anti-Autoresearch checkout (point ROOT at it)."; exit 1; }
ARG="$ARGUMENTS"
if [ -d "$ARG" ]; then # ---- DIRECTORY ----
PAPER_DIR="$(cd "$ARG" && pwd)"
# if only a PDF is present, extract text so the ledger has an L0 source.
# Deterministic primary-PDF pick (issue #11) — never lexicographic-first: a dir
# holding only figure/supplement PDFs yields NO pick (exit 1, honest) instead of
# extracting a figure as the paper. Only exit 1 is tolerated.
if ! ls "$PAPER_DIR"/*.tex >/dev/null 2>&1 && ! ls "$PAPER_DIR"/*.txt >/dev/null 2>&1; then
P=$(python3 "$ROOT/tools/select_primary_pdf.py" "$PAPER_DIR"); rc=$?
[ "$rc" -le 1 ] || { echo "FATAL: select_primary_pdf.py failed (rc=$rc)"; exit 1; }
[ -n "$P" ] && pdftotext -layout "$P" "$PAPER_DIR/paper.txt"
fi
elif [ -f "$ARG" ] && case "$ARG" in *.pdf) true;; *) false;; esac; then # ---- PDF FILE ----
PAPER_DIR="$(cd "$(dirname "$ARG")" && pwd)"
pdftotext -layout "$ARG" "$PAPER_DIR/paper.txt" \
|| echo "WARN: pdftotext failed/missing — try: mutool draw -F txt, or pip install pdfminer.six (pdf2txt.py)."
else # ---- ARXIV ID (e.g. 2401.01234) ----
ID=$(printf '%s' "$ARG" | grep -oE '[0-9]{4}\.[0-9]{4,5}(v[0-9]+)?' | head -1)
[ -n "$ID" ] || { echo "FATAL: '$ARG' is not a dir, a .pdf, or an arXiv id."; exit 1; }
PAPER_DIR="$(pwd)/aar-$ID"; mkdir -p "$PAPER_DIR"
# LaTeX source first (best spans → L1). e-print may be a tarball OR a single gzipped .tex.
if curl -fsSL "https://arxiv.org/e-print/$ID" -o "$PAPER_DIR/src.tgz"; then
tar -xzf "$PAPER_DIR/src.tgz" -C "$PAPER_DIR" 2>/dev/null \
|| gunzip -c "$PAPER_DIR/src.tgz" > "$PAPER_DIR/main.tex" 2>/dev/null
fi
if ! ls "$PAPER_DIR"/*.tex >/dev/null 2>&1; then # fallback: PDF → text (L0)
curl -fsSL "https://arxiv.org/pdf/$ID.pdf" -o "$PAPER_DIR/paper.pdf" \
&& pdftotext -layout "$PAPER_DIR/paper.pdf" "$PAPER_DIR/paper.txt"
fi
fi
echo "PAPER_DIR = $PAPER_DIR"
ls -1 "$PAPER_DIR"/*.tex "$PAPER_DIR"/*.bib "$PAPER_DIR"/*.txt "$PAPER_DIR"/*.pdf 2>/dev/null
ls -d "$PAPER_DIR"/code "$PAPER_DIR"/src "$PAPER_DIR"/results "$PAPER_DIR"/outputs 2>/dev/null # L2 candidates
Validation gate. PAPER_DIR must now contain anchorable text — at least one
*.tex or *.txt. A bare *.pdf is not enough: the ledger builders accept only
--latex / --pdf-text, so Step 0 must have extracted paper.txt. If extraction failed
or no source is present, stop and report exactly what was searched — there is nothing
to anchor spans against, so there can be no ledger (see Failure handling below).
Failure handling.
- No
pdftotext→ fall back tomutool draw -F txt in.pdf out.txtorpip install pdfminer.six && pdf2txt.py in.pdf > out.txt. If text extraction is impossible, you cannot build an L0 ledger from a PDF — ask the user for the LaTeX. - arXiv unreachable (network gated / proxy needed) → say so and ask the user to drop the source or PDF into a local dir, then re-invoke with that paper-dir. Never fabricate a ledger from an absent paper. (A heartbeat may wait on this download — a pre-verdict external step — but only the sweep, run once the source lands, produces the verdict.)
- arXiv
.texextracted but no obviousmain.tex→ fine;/evidence-ledgerglobs*.tex. (PAPER_IDis set authoritatively by the ledger in Step 1 — do not hand-pick it here.)
Step 1 — Build the evidence ledger (always first; the spine)
Delegate to /evidence-ledger, which runs the real deterministic tools
(tools/build_manifest.py → artifact_manifest.json + observability level L;
tools/build_claim_ledger.py → claims.json) and, by default, one additive
span-anchored semantic-enrichment pass. Everything downstream reads these two files.
/evidence-ledger "<PAPER_DIR>" # add "— enrich: false" to ship the deterministic backbone alone
Then read L and PAPER_ID back from the ledger — it is the source of truth for every later block (re-derive, never persist):
PAPER_DIR="<from Step 0>"
test -f "$PAPER_DIR/claims.json" || { echo "FATAL: /evidence-ledger did not produce claims.json — re-run Step 1."; exit 1; }
L=$(python3 -c 'import json,sys;print(json.load(open(sys.argv[1]))["observability_level"])' "$PAPER_DIR/claims.json")
PAPER_ID=$(python3 -c 'import json,sys;print(json.load(open(sys.argv[1]))["paper_id"])' "$PAPER_DIR/claims.json")
python3 - "$PAPER_DIR/claims.json" "$PAPER_DIR/artifact_manifest.json" <<'PY'
import json, sys, collections
L = json.load(open(sys.argv[1], encoding="utf-8")); M = json.load(open(sys.argv[2], encoding="utf-8"))
assert L["observability_level"] == M["observability_level"], "ledger level != manifest level"
t = collections.Counter(c["type"] for c in L["claims"])
print(f"PAPER_ID={L['paper_id']} L={L['observability_level']} claims={len(L['claims'])} types={dict(t)}")
PY
Validation gate.
claims.jsonexists andclaimsis non-empty. Zero claims on a paper that visibly has numbers/citations means the ingest source was wrong (e.g. a PDF with no usable text, or a dir with no.tex/.txt) → fix Step 0 and re-run/evidence-ledger.- The ledger's
observability_levelmatches the artifacts present (a PDF-only run MUST beL=0; never hand a higher level to anything because a repo "exists somewhere else"). The level is the honesty contract for the whole run — carry thisLforward; it caps every finding's severity in Step 4. — human checkpoint: true→ presentL, the claim-type histogram, and the source list, and pause for confirmation before fanning out.
Failure handling. If /evidence-ledger is unavailable, build the ledger directly
with the real tools (exact flags — confirm via --help):
ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd); PAPER_DIR="<from Step 0>"
SLUG=$(basename "$PAPER_DIR" | tr -cs 'A-Za-z0-9.' '-')
TXT=(); [ -f "$PAPER_DIR/paper.txt" ] && TXT=(--pdf-text "$PAPER_DIR/paper.txt")
python3 "$ROOT/tools/build_manifest.py" --paper-id "$SLUG" --dir "$PAPER_DIR" "${TXT[@]}" --out "$PAPER_DIR/artifact_manifest.json"
L=$(python3 -c 'import json,sys;print(json.load(open(sys.argv[1]))["observability_level"])' "$PAPER_DIR/artifact_manifest.json")
if ls "$PAPER_DIR"/*.tex >/dev/null 2>&1; then
python3 "$ROOT/tools/build_claim_ledger.py" --paper-id "$SLUG" --latex "$PAPER_DIR"/*.tex --observability-level "$L" --out "$PAPER_DIR/claims.json"
else
python3 "$ROOT/tools/build_claim_ledger.py" --paper-id "$SLUG" --pdf-text "$PAPER_DIR/paper.txt" --observability-level "$L" --out "$PAPER_DIR/claims.json"
fi
Step 2 — Fan out the six auditors (breadth; the verdict is NOT decided here)
Decide which auditors apply from the ledger's claim types, then run each applicable
skill. Each reads claims.json, opens a fresh codex thread per dimension (a
different model family from the executor), proposes span-anchored findings, validates its
own spans, and writes <skill>.findings.json (the deterministic auditors also write
<skill>.deterministic.findings.json). The orchestrator only sequences these calls and
enforces the Reviewer Calling Convention above — it authors no finding.
Resolved-pair provenance. Right after each dimension's reviewer call succeeds,
export the pair that actually ran (export ARIS_RESOLVED_MODEL=... ARIS_RESOLVED_REASONING=...
— the fallback pair if one fired); the validator blocks read these and crash if unset
(references/reviewer-independence.md).
Coverage state machine (init FIRST, before any auditor runs). Initialize
$PAPER_DIR/coverage.json with EVERY expected skill pre-marked review_unavailable,
then let each skill's terminal branch overwrite its own key (completed on a finished
sweep — including a genuinely empty []; not_applicable when its Step-1 gate says
there is nothing to audit; leave review_unavailable when the reviewer died). A key
that is never overwritten therefore reads as never ran — the fail-closed default. On
re-entry, treat a missing key or review_unavailable as TODO (an existing [] findings
file alone does NOT mean the dimension completed). A skill whose per-item sub-calls
partially failed for good (e.g. one citation key still unparseable after the retry) also
stays review_unavailable — a partial sweep must not read as a completed one.
Shortened here. Read the whole file on GitHub.
Signals
- GitHub stars
- 152
- Forks
- 8
- Last commit
- Sep 2026
ahel review
K1binfo
installs-packages
Automated review, not a security audit. Ruleset v1+k2.
Advanced
- Catalog kind
- skill
- Gateway key
anti-autoresearch- Source
- github.com/wanshuiyin/anti-autoresearch