← ~/blog

I Have Never Done an Open Mic. I Built a Tool for Comedians Anyway.

 /  ai  /  964 words

I write jokes. I have never told one into a microphone.

There is a notes app on my phone with years of bits in it and a running count of open mics attended, which is zero. Not because I decided against it. Because of one specific and fairly stupid fear: what if the bit I think is mine is just a bit I heard in 2019 and forgot I heard.

That fear is not irrational, it is just how memory works. Something goes in, the source falls off it, and what is left feels like an original idea. Comics call the honest version of this parallel thinking, and it is real, there are only so many premises in the world. The dishonest version has a worse name and it ends careers. Sitting on your own couch, the two feel exactly the same.

I also build AI systems for a living. So instead of going outside and finding out the normal way, I did what people like me do, which is turn a feeling into a retrieval problem.

The DejaBit notebook with a draft bit, punch up ready and checked against the record

Everything between the idea and the mic

DejaBit has three parts that get equal weight.

Write. A notebook that thinks in standup, not grocery lists. Bits, tags, set lists, timings, every version of a joke saved as it evolves, set lists one drag away.

Punch up. AI assistance that acts like a writing partner, not a ghostwriter. Stuck on the turn? Ask for alternate turns in your voice, keep what is funny, cut the rest. It suggests, you decide. Nothing goes in the act unless you put it there.

Check. The part that started everything, and the part that turned out to be two questions instead of one.

A set list with per bit timings and drag to reorder

Two questions wearing one coat

"Has this been done" splits cleanly once you try to build it.

Have I written this before is about you, and it shows up daily once a notebook gets past a few hundred bits. You have rewritten your own joke without noticing. Everyone has.

Does this already exist out there is about everybody else, and it is the one that keeps a person off the stage for years.

They sound like one feature. They need completely different machinery, and trying to serve both with one mechanism was the first month I wasted.

Have I written this before

Every bit you check gets embedded with gemini-embedding-001 and stored in pgvector behind an hnsw index over cosine distance. A new bit gets embedded the same way and compared against your own notebook, and nothing else. Your drafts never turn up in anybody else's results.

Two details that cost me real time.

The vectors are truncated to 768 dimensions rather than the full width. For a question this narrow the extra width buys nothing I could measure and costs three times the storage, so it goes.

And the similarity floor sits at 0.82, which I had to raise. At 0.72 an unrelated one liner matched a bit about a smoke alarm at 0.733, which is the kind of false positive that teaches somebody to ignore the feature forever. A genuine near rewrite of your own joke lands around 0.95. The distance between those two numbers is the entire product.

Does it already exist

This one cannot be a vector search, because the thing you are searching is not in your database. It is in specials and clubs and podcasts and a thousand sets nobody ever transcribed.

So it is a search grounded model call instead. The model searches the web, reads what comes back, and reports whether a version of your bit is already out there and who it belongs to.

It runs as two separate calls, and it has to. This is the part I would like to save somebody else a day on. If you attach a response schema to the call that searches, the search is silently suppressed. The model quietly stops searching, answers from memory, returns no grounding metadata at all, and hands you a confident attribution with nothing behind it. It looks like it worked. That is the worst kind of bug, the kind that fails successfully.

So the first call searches, with no schema, and writes a plain paragraph about what it found. The second call turns that paragraph into JSON and is given no tools at all. Two round trips, slower, and correct.

The two signals behind a DejaBit check, a vector search over your own notebook and a two call search grounded verdict

Receipts, not rulings

What comes back is a score from 0 to 100 where high means original to you, a verdict under forty words, and an attribution.

That attribution rule is the part I care most about. The model may only name a comedian it actually found in a search result. Never one it remembers. Telling somebody their joke is not theirs is a serious accusation, and a model that has half remembered a name will make that accusation with total confidence. If the research turned up no source, the field comes back empty, whatever the model believes it knows.

Finding nothing is a normal and useful answer, and the tool says so plainly. You get receipts, not rulings. Parallel thinking is real, so it shows you what it found and the reasoning, and you decide.

A close match result, a known gym membership bit next to a new draft with the same premise and turn

What is next

More signal on the second question, which is the hard one and always will be. Better handling of act outs and crowd work, which embed terribly, because the funny part was never in the words. And a stage mode for the writing side, because the notebook should follow a joke all the way to the mic.

Which is, I am told, a real place that exists. I will get there. Right after I check one more thing.

If you write jokes, it is at dejabit.app. If you steal them, it is also at dejabit.app, consider this a warning.