trust

You don't have to trust us. Here's proof.

Running the trial means pasting a system prompt, an API key, and an endpoint into a website. That's a reasonable thing to be careful about. Instead of asking you to take our word for what happens next, this page shows the actual code, with a permanent link to the exact version it quotes.

Code shown below is pinned to commit fb65cce. The live file can move on; this page's quotes never will.

What happens, in order

Every trial request goes through the same four steps. Nothing is skipped, nothing is added silently.

A serverless function starts freshEach request spins up its own short-lived function instance. There is no persistent server holding your key in memory between requests.
Your endpoint is checked, then called onceThe URL you gave it must be HTTPS and must not resolve to a private or internal address. If it passes, your key and prompt are sent directly to that endpoint, the one you specified, not a proxy or a relay to a different model.
The response is scored locally and returned to youScoring happens in the same function call, against a keyword heuristic. Nothing about the response is sent anywhere else.
The function exitsThe only thing written anywhere is a salted hash of your IP address, for the daily rate limit. Your key, your prompt, your endpoint, and the model's response are not part of that write.

The exact code, not a summary of it

Three excerpts from the file that runs on every trial request.

netlify/functions/trial-run.js · the endpoint guard view on GitHub, pinned →
async function isEndpointAllowed(rawUrl) { ... if (url.protocol !== 'https:') return { ok: false, reason: 'Endpoint must be HTTPS.' }; ... for (const { address, family } of addresses) { const blocked = family === 6 ? isPrivateOrLoopbackIPv6(address) : isPrivateOrLoopbackIPv4(address); if (blocked) return { ok: false, reason: 'Endpoint resolves to a private or internal address...' }; } return { ok: true }; }
netlify/functions/trial-run.js · the only database write view on GitHub, pinned →
supabase.from('trial_runs').insert({ ip_hash: ipHash }).then( () => {}, (e) => console.error('trial_runs insert failed (non-fatal):', e.message) );

Read that second excerpt closely: the only field in the insert is ip_hash, a one-way hash. There is no column, no field, no code path anywhere in this file that writes your key, your prompt, your endpoint, or the model's response to storage. The console.error calls in this file log failure messages about the rate-limit check itself, never the content of your request.

What this never does

×
Never logs your key, prompt, or endpointGrep the file yourself: the only identifiers written anywhere are a hashed IP and an error message on failure.
×
Never routes your call through a model of oursYour request goes to the endpoint you typed in, directly. contradish is not in the response path.
×
Never calls an internal or private addressThe endpoint guard above rejects loopback, private, and link-local ranges, including the cloud metadata address, before any request is made.

Rather not paste a key into a website at all?

That's a reasonable line to draw. You don't have to.

runs entirely on your own machine
pip install "contradish[anthropic]" export ANTHROPIC_API_KEY=sk-ant-... contradish

Same checks, same scoring logic, zero network calls to us. The full source for the underlying library is the same repository this page quotes from.

What this page doesn't cover

·
This is about the trial's own code, not our vendors' infrastructureThe function runs on Netlify and the rate-limit hash is stored in Supabase. We rely on both as vendors and have not independently audited their infrastructure security; this page can only speak to the code we wrote.
·
The full audit is a different code pathSigning in for the full 104-call audit uses a separate function with its own logic. This page describes the no-account trial specifically. If you want, ask us and we'll document the signed-in path the same way.

See it yourself