Where it started
I usually come up with some ideas, write them into a backlog and forget about them. So, I decided what if these ideas were worth something and venture-assistant was created. Adding a pipeline for my ideas so they can actually do something!
It ingests six sources (Hacker News, Lobsters, GitHub, Reddit via RSS syndication, a curated feed registry and my idea backlog itself), these go through the pipeline which in the first deduplicates with pgvector, then runs through a Local LLM classifying, enriching and scoring every idea. Each idea gets four scores over four lenses (side_income, freelance, startup and b2b). These never get blended as a single number would hide facts where the lenses disagree.
Day one was setting up constraints, I am a database engineer by trade, so there was no ORM and no agent framework, and the analytical work was pure SQL, the pairwise ranking fit, the weight stack and work queues are all PostgreSQL. All of this is run locally on my own GPU (a 24GB AMD Radeon Rx 7900 XT). The one exception, which went against an ADR and later amended in the second commit, lets an indecisive feasibility study escalate to Claude (Batches API) under a hard monthly spending cap, which as of writing is 26p worth of Opus 5.
Collecting the ideas has been the easy half, ranking so far has yielded no worthwhile pursuits as most have been parked or rejected on the lack of evidence, largely due to the Local LLM filling in the evidence.
The decision
Grammar-constrained sampling is the method I chose so that the model is forced to put a string in every field. So that when an idea proposed nothing, the scorer judged on an offering that was not there. One feasibility study spent seven of its dimensions on costing a job board no-one has proposed. My first fix added a clause to the axis descriptions to instruct the scorer that nothing was proposed ([ADR-0008]), and it looked like a win.
Before I put any trust in it, I froze the measurement’s definition outside the prompt’s own words, since a detector built from the prompt’s vocabulary just counts it back ([ADR-0010]). Run across the corpus, paired before and after, it showed the clause had substituted its own sentence for the judgement the model was already working on, and it’s the one tier that priming cannot manufacture, it fell from one rationale in six to one in seventy ([ADR-0011]). My first reading had that tier rising, because the detector knew one primed stem and the prompt was handing over eighteen, so the mistake ran in the direction which made the change look good.
The fix was actually removing from the prompt, not adding ([ADR-0012]). Four axes now force that a question cannot be asked when nothing is proposed, and the reader drops it in that case. Eight for a numeric scale in place of an instruction, because the scale cannot translate to a sentence as there’s no words to copy. Deliberately leaving the other three working axes alone.
What it buys
Every scoring run updates its record from the enrichment that was judged and a fingerprint of the exact prompt that judged it, and a prompt change archives the old generation and leaves history intact, so a number on the dashboard can always answer what it was looking at. That reasoning also kept the startup lens wide when b2b arrived, narrowing its prompt would have silently changed the meaning of every score already computed under it ([ADR-0013])!
The same ADR wrote its own reversal test in advance, and I actually ran it. If the new lens was just re-ranking startup, it should go. Measuring it against a control, b2b agrees with startup less than the two closest obligatory lenses that agree with each other, so it stays, and the test surfaced two defects on the way, including that ORDER BY idea_id is not a sample…
Where it’s going
Ranking found nothing I wanted to build both from the numbers and my own personal thoughts on what had been suggested. I had said as much at the start of September, there was a real lack of actual results being pursue-able and that was the whole point of venture-assistant, to find and propose ideas based on merit, but none ever hit the fabled mark.
Across all 49 feasibility studies the result read conditional 46 times and viable never, and with the launch stories stripped out the best of what was left in the side_income lens was a cordless pressure washer and a Yearly Bing, a New Year’s resolution app! The ranking was doing its job. Hacker News and the rest carry launched products, tools, news and complaints, nobody posts a good unbuilt idea, and what I had actually built was a ranker of other people’s announcements. The material I wanted was already in the database, 1,229 pain signals the enricher had been pulling out all along. Every one sat at the bottom of every lens, pinned by a rule that fixed the scorer, because a brief may not invent an offering its source never proposed ([ADR-0006]). So I built the proposer ([ADR-0020]). It clusters those signals into themes, asks the local 24B what offering would answer one, and writes the answer back as a new idea that goes round the ordinary loop, which lets the classifier throw out the proposer’s own output.
The first eight proposals came back through thirteen studies in September, every verdict conditional again, and all thirteen demand conditions turned out to be one instruction in thirteen phrasings, go and ask customers, which I did not want to do. Eleven of the thirteen then reported no competitors were named and called the empty space a niche, while at least two had actual established rivals listed in their search results! That is the axis clause coming back to bite me, one model on and with a web search tacked on the front, and I have not decided yet which layer to fix. Calibration stays unbuilt while that runs. idea_decision holds two whole rows, and two decisions cannot calibrate a ranking. Proposals accrue at a rate of three every four nights, so the next stretch is reading them as they arrive and find out whether the thing that proposes can put up something I would finally record a pursue against.