> what_is_this
three specialists read your brief at the same time and hand you one document with all three outputs.
each lane holds a model and a role: a title and a system prompt. the same brief reaches lane one as a technical architect and lane two as a security expert, so the answers diverge because the framing differs, not because you asked three different things.
this is not a model comparison tool, but you can use it like that too if you want. it is not asking which model wrote the better answer to one question. the lanes ask different questions of the same brief, and what comes out is a document, not a scoreboard.
every lane is configured on its own, so you can put openai against gemini against a local ollama, or run one model three times under three roles to see how much of an answer is the model and how much is the prompt.
shuffle_roles deals the roles out to different lanes. run the same brief again and the security role lands on a model that did not hold it last time. every run appends to the same markdown document, so the angles stack up in one file rather than three tabs.
bring your own key. there is no server, no account and no queue: the page is static and your browser talks straight to whichever api you point it at.
> why_it_exists
built to replace the copy-paste round trip: three tabs open, the same brief pasted three times, three answers stitched together by hand afterwards.
the useful part is not that three models answer. it is that they answer as different specialists, so the output stacks into something you can hand onward rather than three versions of the same paragraph.
currently this supports running 3 apis at once, but try also shuffle roles when you have run once and get more perspectives.
all runs will be stored in this session in the download .md file located in the bottom right corner.
> tech_specs
- no build step, pure vanilla js
- sse streaming with native fetch
- local storage persistence
- parallel promise fan-out execution
> privacy
your brief and every model response live in memory only. nothing about a run is written to disk, and reloading the page loses it.
your api keys are held only for as long as the tab is open. close it and the browser drops them; nothing is written to disk. a returning visit asks for them again.
what does persist is only your lane setup (endpoints and model names) and your boards (role names and system prompts). nothing else.
nothing here tracks you. no analytics, no telemetry, no cookies, no third party scripts, no fingerprinting, no beacons. the page loads nothing it does not ship itself, and sets no cookie of any kind. there is no consent banner because there is nothing to consent to.
the honest footnote: whatever web server hands you this page writes an ordinary access log, the same as every website on the internet. that is a line with a timestamp and an address. it is never joined to your brief, your keys or your runs, because those never reach it.
your brief goes to exactly one place per lane: the api endpoint you configured. there is nothing in between, because there is no server.
> security
while the tab is open, your keys are in the tab's memory in plain text. anything able to run javascript on this origin could read them during that window. that is the price of having no backend to hold them for you. closing the tab ends the window, and they are never written to disk, but use keys you can revoke.
the page ships a content security policy. script-src 'self' blocks inline and third party javascript. frame-ancestors 'none' stops the page being framed. form-action 'none' means nothing can be posted anywhere.
connect-src is deliberately wide, allowing https and localhost ports, because a static page cannot rewrite its own policy to cover a custom endpoint you type in. the trade is on you: a lane sends your key to whatever url you point it at, so only point it somewhere you trust.
referrer-policy is no-referrer. gemini carries its key in the url, and this keeps that url out of the referer header.
model output is written with textContent, never innerHTML, so a response cannot inject markup into the page. the same goes for the settings panel: the model list and error text your endpoint returns are escaped before display.