01
Perspica — reviews a diff by what changed, and finds the callers a rename missed
Perspica (MIT, Rust, 24 stars, 7 commits, one author, created Wednesday, v0.1.1 the same night) reads a diff the way a careful reviewer would. It parses both sides with tree-sitter, matches functions and methods across the two versions, and labels each change: rename, signature change, move, extraction, or a real logic change. Formatting, comment-only edits, rename-only lines, unchanged moves and generated files are folded away. Then it reports three things a line diff hides: a renamed or removed name that is still used somewhere in the repository, callers of a changed function that were not updated, and code the change left unused. It also gives a reading order, from entry points down to the changed functions they call, and shows which of them the changed tests actually reach. All of that runs locally without a model, in a few hundred milliseconds on a typical PR. cargo install perspica, then perspica on a branch or perspica --pr 123 --web.
The LLM pass is optional and kept apart from the rest. With Claude Code, an API key or Ollama, it groups changes by intent and rates risk, labeled in the viewer as less certain than what the parser found. If the change came from your own Claude Code or Codex session, it reads your prompts and marks each group as "asked" or "agent's call", and every "asked" quote is checked word for word against the prompts. In the Show HN thread, a commenter asked how often matching renamed-and-edited functions across files goes wrong. The author's reply was flagged dead, and another user reposted it. Within a file, two versions are paired when they are 75% the same code. Across files, they must be identical, or keep the same name and be at least 60% identical. A function that was renamed, edited and moved is never matched. Every label sits on top of the line diff rather than replacing it, so a wrong label cannot hide a change.
Reach for it if you merge large agent-written PRs and have caught yourself approving them without reading. Delete the grep -rn oldName you run after every rename. Tradeoffs: semantic analysis covers TypeScript, JavaScript, Python, Rust, Go, Java, Scala and C, and everything else is a plain line diff; the author calls the parser analysis "deliberately conservative" and admits the similarity thresholds "are a bit arbitrary"; the repo is one day old, from one author, with 14 HN points; and it reads ~/.claude/projects and ~/.codex/sessions by default for your own commits, which --no-sessions turns off.