Build a competitor comparison table from your own notes only
Build a three-competitor feature and price table from pasted notes only, with a source sentence in each cell, and check each one against the notes by script.
A competitor table is due today, and if you only give the AI three product names, it may add plans and features that do not exist. Paste the pricing pages and feature pages you copied yourself, and tell it to use nothing else. Services A, B and C below are made up for this article.
The input: three notes with deliberate gaps
Each note is missing something different. A has no free trial, integrations or mobile app. B has no integrations. C has no file limit and no mobile app.
[Service A pricing page — copied]Starter: $9/month per user. Up to 5 projects.Team: $19/month per user. Unlimited projects, file attachments up to 200 MB per file.Enterprise: contact sales.All prices are the monthly equivalent when billed annually. Monthly billing adds 20%.[Service B feature page — copied]- 14-day free trial, no credit card required- Basic $12/month / Pro $24/month (monthly billing; flat per-team pricing regardless of seats)- Mobile apps for iOS and Android- File attachments up to 50 MB per file (Basic), 500 MB (Pro)- No limit on projects[Service C overview — copied]C is a task manager for small teams. The free plan allows up to 3 users and 2 projects.Paid plan: $15 per user per month. Integrates with Slack and Google Calendar.Paid plans come with a 30-day money-back guarantee.What the short prompt does
One line plus the notes, run twice (claude -p --model claude-sonnet-5-5 --max-turns 1 --tools "" --setting-sources "" --strict-mcp-config):
Build a feature and pricing comparison table for Services A, B and C. Notes:(the three notes)It invented no features, and it marked gaps as "Not stated". The problems are elsewhere.
- It added work nobody asked for: a 5-person monthly cost table in both runs (A Team $114 and so on) and, in one, a "B is cheapest" verdict. That is more numbers to verify outside the table.
- It asserted things the notes do not say. One run wrote "No" under B's free plan (the note only mentions a trial). Both computed monthly-billing prices for A ($10.80 and $22.80 per user) that appear nowhere in the notes.
- No cell carries a source, so you cannot tell which ones to check.
Notes only, and a source sentence in every cell
Four rules: no knowledge from outside the notes, "No data" for gaps, a word-for-word sentence from the notes in every filled cell, and "No data" again if that sentence cannot be found. Telling the model to answer from the supplied documents, attach a quote to each claim, and retract any claim it cannot back with a quote is the method in Anthropic's guide to reducing hallucinations. The six fixed columns stop the table from growing on its own.
Inside <memo> are notes on Services A, B and C. Build a comparison table using only what those notes say. Rules:- Do not fill gaps with general knowledge or guesses. If the notes do not say, write "No data" in the cell.- Markdown table. Rows: Service A, B, C. Columns, exactly these six: Lowest paid plan (monthly price) | Billing basis | Free trial / free plan | File attachment limit | Integrations | Mobile app- Every cell that is not "No data" must end with a supporting sentence copied word for word from the notes, in square brackets like [Starter: $9/month per user.]. If you cannot find a supporting sentence in the notes, change that cell to "No data".- Below the table, give one line with the number of "No data" cells per service. Write nothing else. <memo>Change only the number of services and the column names. Append the notes and the closing tag, then run it:
$ { cat head.txt; for x in a b c; do cat memo-$x.txt; echo; done; echo "</memo>"; } > prompt.en.txt$ claude -p --model claude-sonnet-5-5 --max-turns 1 --tools "" --setting-sources "" --strict-mcp-config < prompt.en.txt > out.en.1.txtResult
First run. Most source sentences are shortened to ….
| | Lowest paid plan (monthly price) | Billing basis | Free trial / free plan | File attachment limit | Integrations | Mobile app ||---|---|---|---|---|---|---|| Service A | Starter, $9/month per user [Starter: $9/month per user.] | Per user; prices are the monthly equivalent when billed annually […] | No data | Team plan: up to 200 MB per file […] | No data | No data || Service B | Basic, $12/month […] | Monthly billing; flat per-team pricing regardless of seats […] | 14-day free trial, no credit card required [- 14-day free trial, no credit card required] | Up to 50 MB per file (Basic), 500 MB (Pro) […] | No data | iOS and Android apps […] || Service C | $15 per user per month (the only paid plan listed) […] | Per user per month […] | Free plan, up to 3 users and 2 projects […] | No data | Slack and Google Calendar […] | No data | "No data" cells: Service A = 3; Service B = 1; Service C = 2.All six gaps in the notes are "No data", and nothing follows the table. The second run had the same gaps and the same six "No data" cells.
Check: find each source sentence in the notes
Doing this by hand means copying 12 sentences and pressing Ctrl+F twelve times. The script does it: it looks for every bracketed sentence in the notes and exits with 1 if one is missing.
import re, sysnorm = lambda s: " ".join(s.split())memos = norm(" ".join(open(p, encoding="utf-8").read() for p in sys.argv[2:]))out = open(sys.argv[1], encoding="utf-8").read()quotes = re.findall(r"\[([^\]]+)\]", out)miss = [q for q in dict.fromkeys(quotes) if norm(q) not in memos]for q in miss: print("MISS:", q)cells = sum(l.count("No data") for l in out.splitlines() if l.startswith("|"))print(f"{len(quotes)} quotes, {len(miss)} not found in memos; 'No data' cells: {cells}")sys.exit(1 if miss else 0)$ python3 -I check.py out.en.1.txt memo-*.txt; echo "exit $?"12 quotes, 0 not found in memos; 'No data' cells: 6exit 0For a failing case, B's sentence was edited by hand (the model did not make this error): "no credit card required" became "no credit card needed".
$ python3 -I check.py out-bad.txt memo-*.txt; echo "exit $?"MISS: - 14-day free trial, no credit card needed12 quotes, 1 not found in memos; 'No data' cells: 6exit 1Where it still slips
A passing check proves less than it looks.
- It only shows that the sentence exists in the notes, not that it supports the value in the cell. In the first run, A's "Billing basis" cell says the prices are annual-billing equivalents but leaves out the 20% surcharge for monthly billing, which sits in the next sentence of the note. Read the price and billing columns side by side with the notes.
- Whether "No data" is right is a manual search. Search A's note for "trial" and C's note for "mobile". Both should return nothing.
The AI cannot know a price that is not in your notes. Before the table leaves your team, reopen each vendor's pricing page: the notes are a snapshot from the day you copied them. The same paste-and-quote approach for summaries is in Make Claude quote the source in a summary and check it with grep.