Guessless Guessless
{{ m.label }}
npm GitHub

Agents shouldn't grade their own homework.

Jack Shelton Jack Shelton · August 2026 · 6 min read

You'd give the agent bigger jobs if checking them didn't take longer than doing them. Checking means comparing everything it touchedthe list you have against everything it should have touchedthe list you don't — and only one of those two lists exists.

Guessless builds the second list. It readsJavaScript andTypeScript the way a compiler does, following every import through to what it actually points at — so a file that renamed it still counts, and an unrelated function with the same name doesn't. What comes back is areceipt: that's all of themstate: complete, that's all but thesestate: partial · gaps named, or I can't answer this safelystate: refused.


Install

{{ line.tool }}{{ line.verb }}{{ line.flag }}{{ line.pkg }} {{ line.comment }}

Requires Node.js 22+.


60 seconds

The question is: where is save actually used? Run the first file — the word appears three times in it, and not one of them is the answer.

{{ demoFilename }}
{{ demoSource }}
receipt
{{ line.text }}
{{ statePillText }} {{ stateCaption }}
State
Meaning
What it licenses
complete
The result set is exhaustive
The word “all”
partial
Results plus every unresolved site named, with one of 20 machine-readable reasons
A qualified answer that knows its own gaps
refused
Not answerable safely (e.g. unsupported language)
Nothing, and that's the point
{{ s.name }}
{{ s.meaning }}
Licenses
{{ s.licenses }}

Anyone can re-verify a saved receipt byte-for-byte: guessless reproduce bundle.json. Sites are semantic anchors, not line numbers, so citations survive code moving.


When you actually want this

Transforms at scale
13.5% of grep hits were the wrong binding
Nothing falsely reported, every gap named

In a 635-file / 161k-line trial, word-boundary grep for one symbol returned an answer where 13.5% of hits were a different same-name binding, indistinguishable without reading every file.

Guessless returned zero of them, named every site it couldn't resolve by its exact import specifier, and did it in ~5 seconds.

{{ l.text }}
Code that doesn't build
{{ fileCopy.sub }}

{{ fileCopy.body }}

repo/
Language server
{{ treeDetail.lsp }}
Guessless
{{ treeDetail.state }} {{ treeDetail.result }}
Agent harnesses
Gate the claim, don't trust it
The hook refuses unsigned claims

Don't hope the agent double-checks. Gate it with a ~20-line stop-hook. See INTEGRATION.md.

No receipt, no accepted claim. CI verifies it again on the way in.

agent: “renamed all 12 call sites of answer
{{ hookResult.verdict }} {{ hookResult.text }}

Grep is still the right search tool; this is not a search tool. Guessless exists for the one sentence grep can't sign.


Query surface

{{ queryDetail.signature }}

{{ queryDetail.body }}

Returns {{ queryDetail.returns }}

Strings and comments are never structural evidence (run one rg at the end for those). export * hides nothing. The full semantics live in each receipt, not in prose.


Library and MCP

import { GuesslessEngine } from "@guessless/engine";

const engine = new GuesslessEngine();
engine.addFile("api.ts", "export const answer = 42;");
engine.link();
const receipt = engine.referencesOf(engine.anchor("api.ts", "answer")!);

The MCP server (npx -p @guessless/mcp guessless-mcp) gives any MCP harness the question worth asking before a change lands: what breaks if I rename this, delete this, or make this an entry point. The answer is the same receipt, with summary and paged views so a full impact set fits inside an agent's context budget.


How honest is it, really?

Everything above is measured, not estimated. When Guessless gets something wrong, that goes on this page next to what it got right.

  • It never pointed at the wrong place. Every location it reported really was a use of that symbol. We checked all of them by hand against a list we had verified ourselves.
  • It never missed a place without saying so. When it can't see somewhere, the receipt names that gap instead of quietly dropping it from the results. Getting there meant fixing six distinct classes of bug — one of which our own tests caught partway through. We fixed the defect and re-ran that test unchanged. It passed.
51 real-repo queries, hand-audited
Hover a query
{{ auditRead.name }} {{ auditRead.sites }} {{ auditRead.state }} {{ auditRead.note }}

Limitations

{{ l.label }}
Languages
JS/TS/JSX/TSX only, via the Yuku analyzer. Anything else is refused, not guessed.
Blind spots
Structural analysis can't see strings, comments, or runtime dynamism. Those boundaries come back named.
Scope
A complete receipt is scoped to the exact snapshot it hashes.