There's a small project floating around a Chinese dev forum that stuck with me. Someone was agonizing over whether to switch jobs, couldn't articulate why they wanted to leave, so one night they voice-dictated roughly 13,000 words of raw internal monologue. The next day they fed it to an AI and it pointed out the places where they were arguing against themselves. Their own words, contradicting each other. The author says the conclusion matched what they felt inside — which is worth flagging as an unverified, subjective read, but the mechanic underneath is what caught my attention.
They turned it into a local plugin. Data stays on the machine, retrieval runs on an open-source stack combining vector search and BM25, and the logic deliberately hunts for "logical opposition" and "self-contradiction" first, then looks for logical associations (wanting a new phone links to checking your finances). It's explicitly a vibe-coded thing, built over a couple of days, and the author openly asked the community what to build next. That honesty is the right starting point, because the interesting part isn't the polish. It's the core idea.
The signal worth isolating
Strip away the personal-diary framing and you find the same theme showing up elsewhere in the evidence. One builder shipped a playground experimenting with "primitives" like structured choice between candidates and scoring of results, arguing that LLM apps too often just guess an answer when the input is ambiguous, when they should stop and judge instead. Same instinct: don't ask the model to generate a verdict out of thin air. Ask it to score, compare, and expose where the tension actually lives.
That reframing is what makes the contradiction finder buildable and honest at the same time. The tool's job is not to tell you whether to quit your job. Its job is to retrieve the two passages where you said opposite things and put them side by side. The author of the original plugin made the same point with a nice analogy — even fortune-telling gives some people a reference they can act on "without regret," not a correct answer. Surface the conflict. Let the person decide.
What the winnable core actually needs
Three moving parts, and none of them require the local-plugin scaffolding:
- A place for raw, messy entries to land — long dictated rambles included.
- Semantic retrieval that can pull passages arguing against each other, not just passages about the same topic.
- A scoring step that quantifies how much two retrieved passages actually conflict, so the output is ranked tension rather than a wall of maybes.
The original used vector plus keyword retrieval locally. On VicroCode you'd drop the raw entries into a LanceDB knowledge base and let semantic retrieval do the heavy lifting of finding candidate pairs. The trick that makes it a contradiction finder rather than a search box: you don't just retrieve passages similar to a query, you retrieve passages that are topically close but stance-divergent. Same subject, opposite conclusion. That candidate generation is a retrieval problem, and it's the part a knowledge base earns its keep on.
Retrieval alone will over-fire, though. Two passages about "the job" will surface even when they agree. So the scoring pass matters. You'd run Python online to take each candidate pair, call a model through the platform's Model Center to judge the direction and strength of the conflict, and reduce that to a tension score. Python is also where you'd handle the boring-but-essential glue: deduplicating near-identical pairs, filtering out pairs where one side is just a restatement, and sorting so the sharpest contradictions rise to the top instead of drowning in noise.
For the structured side — entry timestamps, tags, which pairs the user has already reviewed or dismissed, the computed scores — a lightweight relational store is enough. The SQLite editor lets you inspect and correct that state directly while you're tuning the scoring thresholds, which you will be doing a lot early on, because "how conflicting is conflicting enough to show" is a judgment call you'll get wrong before you get right.
Wiring it together
A rough shape of the build: an entry lands, gets chunked into passage-sized units, and goes into the knowledge base for embedding and retrieval. A background Python routine walks recent entries, pulls topically-related-but-divergent candidates from the knowledge base, scores each pair for tension, and writes the ranked results plus metadata into SQLite. The front end is a plain HTML app — hosted and published on the platform — that shows the user their own contradictions ranked by tension, with both raw passages quoted verbatim so nothing is paraphrased away.
The AI coding assistant is genuinely useful here for the connective code — the chunking, the retrieval-to-scoring pipeline, the SQLite reads and writes — which is exactly the kind of plumbing that eats a solo builder's evening. The original was two days of vibe-coding on borrowed open-source components; the hosted version trades the local retrieval stack for the knowledge base and swaps the manual environment setup for in-platform execution.
I want to be precise about what's proven and what isn't. I haven't built and measured this, so I'm making no claims about accuracy, latency, or how often the surfaced contradictions feel meaningful — all of that is unverified until someone actually runs it. The original author's sense that the output matched their inner state is one person's subjective impression, not a benchmark.
The line you shouldn't cross
Here's the boundary, and it's a design decision, not a disclaimer bolted on at the end. The tool surfaces conflict. It does not decide. The moment you let it output "you should stay" or "you should leave," you've built something that pretends to a certainty it doesn't have, using someone's most vulnerable, unfiltered thoughts as fuel. The scoring quantifies tension between two things you said. It says nothing about which one is true, or right, or what you'll regret less.
So the output stays as a reference: here are the places you argued against yourself, ranked, quoted, and left for you to sit with. If a pair genuinely has merit on both sides, the honest move is to say so and let the person open a fresh thread on that specific tension rather than resolve it for them. That's not a weaker product. For anything touching personal decisions, it's the only version worth shipping.
The practical scope also stays inside what the platform confirms. This is a hosted HTML app with a Python backend, a LanceDB knowledge base, a SQLite store, and models reached through the Model Center. It is not a mobile app, not a local-first plugin, and not integrated with any outside voice-input or note-taking service — those would fall outside the capabilities I can rely on, and I'd rather draw that line clearly than imply reach the platform doesn't give me.
What you're left with is small, specific, and buildable by one person: a private space where your own words get to disagree with each other in the open, scored honestly, decided by nobody but you.