What we store, and why
Optimus runs inside your editor, in your process, against your environment. Your data is anonymized on your machine before anything is stored or sent, and reading it back takes both your Optimus account and your repository — we never hold both. This page is the list of what reaches us — first from the product, and then, separately, from this website, which is a different thing and collects differently.
What Optimus reads, and where it reads it
Reading and sending are different things, and this page is mostly about the second. Here is the first, because you should not have to infer it: Optimus is pointed at a repository, and it reads.
- Your source. It is read to work out what your agent can do, which tools exist, and how they are wired — and, when a check calls for it, to read a tool’s implementation and see whether it does what it says. That is how it can tell a stub wired to a live channel from a working tool.
- Your prompts and your stated rules. They are part of your agent’s behaviour, so they are read like the rest of it. Prompts are data, and they are treated as yours.
- Your records, when you say so and only then. A query runs against your own data, written against your own schema, read-only, and either approved by you call by call or run by a command you gave us once.
One boundary worth being exact about: your coding assistant reads your files, your query results and your conversations raw, through its own tools, before Optimus anonymizes anything. What happens to what it reads is governed by your assistant’s provider and your agreement with them, not by Optimus. This page covers what Optimus itself sends and stores.
What never leaves your machine
- Your source code as files, and your repository’s history. With model scoring switched on (it is off by default), a scan can send short excerpts of risky-looking code, a few lines each, to our own GPU servers to be scored (see Model scoring). Names, emails, phone and card numbers and secrets in them are replaced by placeholders first; a prompt or a literal that sits inside an excerpt goes with it.
- Your tool names, in your data. They are your business logic, and not ours to know. A tool name that appears in a line of code as an identifier can travel inside a code excerpt.
- Your database. We never connect to it, and no full query result leaves — a case file may hold a few rows a query returned, as evidence, anonymized first (below).
- Your provider keys, your environment variables, and your infrastructure.
- Any full transcript of a conversation your agent had with a real customer. The test conversations Optimus drives are anonymized on your machine before anything is sent for reasoning, and are not kept. A case file may hold a few turns as evidence, anonymized first (below). When your assistant reads real conversations to make the probes sound real, it keeps a paraphrase of how customers open in
.optimus/, and that stays here unless you turn contributing on. - Your repository’s half of the anonymization key: its first commit, which every clone has and which never reaches us (we see only a digest of it). Each placeholder is the value itself, encrypted under a key with two halves — that one, and one we hold for your account, handed only to your Optimus key. Reading a placeholder back takes both, so not us, and not anybody who reached our database, can turn what we hold back into the values it replaced. Nothing anywhere maps placeholders to people. A repository that is public has given its half away, and then only your account’s half protects it.
- Any raw contact detail, number, reference or credential, and anything that was not anonymized. (A name in free text with no cue, field, CV or common first name around it is the gap, described under case files below.)
- Everything in
.optimus/, the directory beside your repository, which holds the bindings, the decisions your team has made, and the run history.
.optimus/ is yours. Commit it and your team shares its decisions the way it shares its tests. A .gitignore is written into it excluding the files that hold things of yours: session.json and last-report.json, which hold verbatim text from your agent’s conversations, and queries.json, which holds the read-only queries written against your own data; query-cache.json, the counts and samples read from your records, anonymized, so past days are not read twice; replays/, real conversations recorded for replay, anonymized; and proof-*.md, the evidence chain for each proven finding. None of them leaves your machine either way.One file is deliberately not excluded:
how-to-query.json, the command that runs a read-only query here. It is committed on purpose, because a scheduled run on another machine needs it. If your command points at an environment variable — psql "$DATABASE_URL" -c — there is nothing in it worth hiding. If you wrote a connection string into it literally, that is the one file here that would hold one, and you should fix the command rather than the file.The scan state we keep for repeat scans
So that a repeat scan rebuilds only what changed, the scan engine keeps a state for each workspace with us. It is sealed on your machine before it is sent (AES-256-GCM) and nothing in it is the text of your records: records and runs are identified by keyed hashes, field values are keyed hashes too, and numbers are kept inside the seal. Whatever a report quotes is read again from the scan’s own input on your machine.
The keys are ours to manage, so there is nothing for you to set up: our server holds one master key, which never leaves it, and derives two keys for each of your workspaces from it (a different pair per workspace and per account). It gives them only to your account’s Optimus key, and your machine holds them in memory for the scan. This means Optimus can technically decrypt the stored state. We never share it, and nothing in it is your records’ text.
- Per run: a fingerprint and the check results it finished cleanly with, in our database, owned by your account (not by a key: a revoked key does not orphan it).
- Bulk parts (per-record summaries, pair scores, pattern counts) in Cloud Storage, moved through short-lived signed links, so they never pass through our web functions.
- Late verdicts on findings (a hash and true or false positive).
It does not expire. Asking your assistant to wipe Optimus data (optimus_wipe), or deleting the workspace or your account through our API, removes it at once. Without an Optimus key no state is kept and every scan starts from nothing.
What reaches us, and when
Some of Optimus’s own reasoning runs on our side rather than on your machine. That is the reason anything leaves at all, and it is a short list.
| Sent | Why it has to be |
|---|---|
| the findings | What was found, and the evidence behind it — anonymized on your machine first. |
| probe conversations | Only the ones Optimus itself asked you to drive, anonymized on your machine first. |
| counts | How many, of what kind, and how long a run took. Named in our own vocabulary, never yours. |
| your reason | When you reject a finding, the reason — but only where it survives being said without naming anything in your repository. That check runs on your machine, before anything is sent. |
| your feedback on a report | When you answer the questions at the end of a report: a 1 to 5 rating, tags from a fixed list, how you answered each design question, and an optional short note. The note is anonymised on your machine first and dropped if it looks like code. It never changes a finding. |
| a run starting | One call when you ask Optimus to test, carrying only your key, so the run is counted against your plan. Nothing about the run itself. |
| how your customers open | Up to five paraphrased openers from a reading of your own conversations, and only those your machine has checked name nothing in your repository and carry no name, email, number or reference. It teaches our domain packs what real customers sound like. Listed on your data page, and deleted from there. |
| how far a session got | On each exchange: which of our own steps it has reached, what it is waiting on, and how long each piece of our work took. So we can see where people give up rather than only where they finish. Our step names, never yours — there is no field here a repository name could sit in. |
Anonymized means names, emails, phone and card numbers, order references, URLs, file paths and tool names are replaced with placeholders like [id-2] before anything is sent — the same value always getting the same one. The answer is put back on your machine before you read it, and the map never leaves. It works by pattern: thorough about anything with a shape, and unable to promise a business name written in plain prose.
The reasoning calls themselves are not stored at either end — what is kept from a run is your case file, described in the next section and anonymized the same way. Nothing here asks you for a second credential — your Optimus key is the whole of it. What is also kept is what each call cost, against your account and against a digest of your repository’s first commit: the free allowance is counted per repository as well as per account, so a new account does not bring a new one. The digest is the same in every clone and is never the commit, the path or the name.
Signing in from your editor
An install with no key signs itself in: your editor shows a code and a link, you approve it on this site, and a key is made for that editor. The code is held by us as a hash for at most ten minutes and deleted when it is used. To stop the sign-in being farmed, we count requests per address for an hour, under a hash of the address rather than the address itself. The key is saved on your machine in ~/.optimus/credentials.json, readable only by you, and listed on your keys page like any other.
None of the list above is a switch. There were three, and an opt-in for the fourth, and they are gone — not moved to a screen, removed.A key that exists is a key that sends what this page says it sends. The one thing that can be switched off is your case file, next.
What replaces the switches is that the boundary is enforced rather than promised. Your machine filters before anything leaves, our server filters again on the way in, and the database rules are closed — three independent layers, none of which can be turned off by accident. Everything above is either a count, one of our own names, or something a check on your machine has certified could have come from anybody. Delete any of it from your data page.
Your case files
Optimus investigates each repository as a case: who is involved, what was promised to whom, how things move through the system, which theories stood and which fell, and the evidence each rests on. So a second machine, or a colleague, can pick that case up where it was left, we store it against your account. It is anonymized on your machine before it is sent: contact details, numbers and references — emails, phone and card numbers, national identity numbers, IP and street addresses, long references and credentials — are replaced with placeholders that only somebody holding both your Optimus key and your repository can read back — on any machine. Our server checks again: a case carrying any of those outside a placeholder is refused whole and not stored.
The case also carries the conversations recorded for replay — up to twenty real conversations, every turn and tool result anonymized the same way — so the check on a pull request can replay them on a machine that never recorded them. A case too large for one request, such as the full map of a large agent’s code, is stored in parts; parts are kept, expire and are deleted together, as one case.
Names are the exception, and you should know it. A name is replaced when it comes from a field that holds names. A name that appears only in free text — one a customer typed in a chat, say — is not yet caught on your machine, and our server has no pattern for it either, so it can reach a stored case.
| Stored | What it is |
|---|---|
| the case | The dossier — the parties, the promises, the flows and the facts — anonymized. |
| theories | Each theory, its status, its verdict and the narrative behind it. |
| the docket | The list of cases open on the repository, and where each stands. |
| evidence excerpts | Short anonymized excerpts — a few rows, a few transcript turns — each with a fingerprint and a record of how it was obtained. A line of your code is never stored: only its fingerprint, and file paths and tool names are replaced. (Short anonymized excerpts go to our GPU servers to be scored, in memory only; see Model scoring.) A query is kept as a template, with no values in it. |
| the ledger | Which of our sources have been right and wrong, and how often. |
| the coverage matrix | What has been checked on the repository and what has not. |
| the repository brain | When a run keeps one, so a repeat run on another machine starts where the last left off: the contract, the standardisation rules, the frozen checks (hypothesis, family, grade, status, precision), the code sites read, how far through your data it got, and daily hit counts per check. Check code, hypotheses, families, the contract, rules, field lists, code sites and the last commit read are sealed on your machine — names, emails and numbers become typed placeholders first, then every word left (identifiers, field names, keywords, literals, comment words) and every number becomes a placeholder too; only punctuation and spaces stay. Daily counts are dates and numbers. Scanned again on our server like a case; same switch, retention, audit and delete. |
| an audit row per write | What was stored, how large, when, and from which run — never the content. You can read every row. |
What is never stored
- The whole anonymization key. We hold your account’s half and never your repository’s, so we cannot read a placeholder back; nor is there any map from placeholders to people, here or anywhere.
- Raw values — an email, a phone or card number, an identity number, an address, a reference, a credential. Names from name fields are replaced too; names in free text are replaced when a cue, a labelled field, a CV or a common first name gives them away, and can pass otherwise (above).
- Full transcripts, or full query results. An excerpt is capped: a quote at 2,000 characters, at most 20 rows and 12 turns.
- Anything that was not anonymized.
How long, and where
A case file, or a repository brain, is kept for 180 days after it was last updated, and then deleted — on the next read, or by a regular sweep, whichever comes first. Audit rows age out on the same clock. A workspace can set a shorter or longer period, from 1 to 365 days. It is held in Google Cloud Firestore, in TODO: data region.
Switching it off
Stored by default. To stop it for every machine on your workspace, use the switch on your data page, or send PUT /api/cases/settings with {"store": false} and your key; nothing new is stored from then on, not even an audit row. To stop it on one machine, set OPTIMUS_CASE_SYNC=off where the MCP runs, and that machine neither sends nor fetches a case or a brain. Switching off does not delete what is already held.
Deleting it
Send DELETE /api/cases?repo=all with your key to delete every case file on the workspace, or ?repo= and a repository’s digest to delete one; either also deletes that repository’s brain, frozen checks and daily counts, which DELETE /api/brain deletes on their own. Deleting removes the documents; an audit row records that it happened. GET /api/cases/audit lists every write, delete and expiry, and what is held now.
Model scoring
Model scoring is off by default: a scan runs on your machine and sends nothing to our models unless you switch it on with OPTIMUS_GPU=1. When it is on, some steps score text with our own models: NLI grading and labelling, embeddings, and grouping, and, for code, embeddings and a vulnerability score. Only anonymized text and code excerpts are sent, with your key, to /api/models. Our server scans it again, and refuses it if any personal data sits outside a placeholder. It then forwards the text to our model services on Google Cloud Run: the CPU service, and for GPU scoring optimus-gpu in us-east4. Neither we nor the services store or log the text. A service holds it in memory only while scoring it. A grouping job’s vectors (numbers, not text) stay in memory until the job runs, or for 15 minutes if it is left idle, and recent scores are kept in memory so a retried batch is not scored twice. On your machine the scores we send back are kept in an encrypted local file, as probabilities under a fingerprint of the anonymized pair and the model version, with no text, under 512 MB, so a repeat scan does not score unchanged pairs again; a new model version scores everything again, and OPTIMUS_SCORE_CACHE=off stops it. For GPU scoring we count the size of each request against a daily cap per account, and we keep the scan session (your account id and timestamps) only while the scan runs.
Test cases we write from your scans
After a scan, your own Claude turns each finding that was checked into a general description of the failure — what kind of tool, rule or field was involved and what went wrong — with no names, numbers, ids or quotes, and then writes invented test cases from it. A case that shares a phrase or an unusual word with your scan is thrown away on your machine. Only the descriptions and the invented cases reach us, with your key, to train our own models; our server refuses a description with a digit in it and anything that looks like personal data. Your records and the findings themselves are not sent. A real conversation your assistant read is treated the same way: only a description of what went wrong can leave. It runs after the report, uses a few cents of your own Claude (a cap of $0.10 a scan), and needs your key and a Claude on your machine. OPTIMUS_SYNTH=0 or OPTIMUS_CASE_SYNC=off stops one machine.
The shape of each proven incident
When a case on your repository is proven, Optimus keeps its signature — in .optimus/incidents.json on your machine, and against your account — so every workspace learns which shapes of failure turn out to be real. A signature is made only from fixed lists: the failure in words from a fixed list of plain English, every other word replaced by a slot; the kinds of step it passed through (a way in, a model step, a decision, a message); whether it is new, steady, came after a change, or comes and goes; the kind of fix, from a fixed list; and which kinds of evidence proved it. No name, value, file path, tool name, repository name, quote or commit message is in it, and our server refuses a signature with any word or field outside those lists.
No other workspace sees your signatures — only how many workspaces share each shape, and only once at least two do. They follow your case file’s switch and retention: with storing off for the workspace, none is stored, and once the retention period has passed since one was last shared it is no longer counted and is deleted the next time counts are read. OPTIMUS_INCIDENTS=off or OPTIMUS_CASE_SYNC=off stops one machine sending signatures or fetching counts. Send DELETE /api/incidents with your key to delete every signature you have shared.
What your account holds
| Held | What it is |
|---|---|
| identity | Your email address, display name and photo as your sign-in provider gave them, which providers you have used, when the account was created and when you last signed in. |
| keys | A SHA-256 digest of each key, a four-character hint, the label, when it was made and when it was last used. Your default key — the first, or one you chose when making it — is also kept encrypted (AES-256-GCM) with a secret held outside the database, so an editor that signs in is given that key rather than a new one. Revoking it deletes that copy. |
| usage | How many runs your account started this month and today — a count and a date, nothing about the run — so a plan limit can mean something. |
| subscription | Only if you pay: the plan, the number of seats, its status and renewal date, and Lemon Squeezy’s ids for you and the subscription. Never card details — Lemon Squeezy takes the payment. |
| run summaries | When sync is on: a run id, the repository label you chose, timestamps, which of our cause ids got which verdict, the coverage figure and the counts. A run may also carry its trace: how long each stage took, records per second, memory and disk used, the size class and engine, how long it ran in each memory mode (normal, gentle, low-memory, paused) and how often it was paused, how many sources were joined or kept as shared context, the scorecard tally and the graders’ accuracy on planted items — numbers and our own stage names only. No tool names, field or source names, evidence text or transcript; the server drops anything else. |
| your reasons | The free text you wrote when rejecting a finding, where it passed the check above. Up to 300 characters each. |
| case files | One anonymized case per repository, its brain when a run keeps one, and an audit row per write, as described above. Kept 180 days after the last update unless you set otherwise; off with one switch. |
| incident signatures | The shape of each proven incident, in fixed lists only, as described above. On the same switch and retention as case files. |
Why we keep the counts at all
One number. The share of findings a customer marks by-design is our false-positive rate, measured by real people on their own agents rather than on a benchmark. Nothing else will tell us, and a check that fires when it should not is the one defect a testing product cannot afford.
Your written reason is what makes it actionable. A count says a check was rejected; only the reason says whether our gate was wrong or your agent was right, and those want opposite work.
Visiting this website
Everything above is about the product — what Optimus sends from your machine when you run it. This section is about this website, which is a different thing and collects differently.
We use Google Analytics on these pages. It sets cookies in your browser and tells us which pages were read, which links were clicked, roughly where in the world you are, and what kind of browser and device you used. Once you are signed in we also send it your account’s internal identifier, so a visit and an account can be the same person to us. We never send it your email address, and it is never told anything about your repository, your agent or your runs.
We keep a copy of the same thing ourselves — which pages a visit read, in what order, and which of our own buttons were pressed — because Google will not let us ask some of the questions we need to ask of it. That copy is listed on your data page and can be deleted from there. When you sign in, approve an editor, or run Optimus from an editor the site opened, that visit is linked to your account, along with earlier visits from the same browser. The Open in links and copied install command carry the visit’s random id as OPTIMUS_REF, which stays in your editor’s MCP config and is sent with sign-in and runs. The visit also keeps Google Analytics’ id for your browser, so the editor’s sign-in steps count as the same visitor in Google Analytics.
We also record sessions with PostHog, on every page of the site including the signed-in ones: where the pointer moved, what was clicked and how far each page was scrolled, played back like a video, so we can see where people get stuck. Everything you type is masked before it leaves your browser, and your email address and API keys are blocked from the recording entirely — they appear as empty boxes. It also receives the same list of named events, so a recording can be found by what happened in it, and it is never told who is signed in. PostHog sets its own cookie to tell one visit from the next, and holds the recordings in the United States. We copy a summary of each recording into our own database — how long it was, how active, how many clicks, the country, device and pages — and never the recording itself.
| Recorded | Why |
|---|---|
| pages read | Which parts of the site people actually use, and where they stop reading. |
| where you arrived from | Which search, link or assistant sent you. Kept against your account so we know which of them brings people who go on to use the product. |
| which controls were pressed | From a fixed list of our own names. Never the words printed on a button, never anything you typed, and never the contents of any field. |
| roughly where you are | The country, worked out from the connection and then discarded. Your address is not stored. |
| your account identifier | Only once you are signed in, and only the internal one. Never your email. |
| session recordings | How a visit moved through the site, on every page. What you type is masked; your email and keys are blocked out. |
These are the two places we use something of somebody else’s, and it is worth being plain about the trade: we cannot see which part of this site is worth writing next, or where it loses people, without them. The advertising features of Google Analytics are switched off — it is not used to build an audience — and nothing here is sold.
There is no banner asking you to accept this, and there is an argument that there should be. A content blocker will stop Google Analytics, and nothing on this site behaves differently when it does. It will not stop the session recording or our own copy: both are sent to this site first and passed on from here, so a blocker cannot tell them apart from the page itself.
Seeing it, and deleting it
Everything above is listed on your data page, with what it is and where it came from. Deleting removes the documents rather than hiding them, and revoking a key removes both the key and the index entry that resolves it.
The exceptions are what Google Analytics and PostHog hold, which sit with them rather than with us and are not on that page. Write to us and we will delete your session recordings from PostHog.
Getting in touch
Write to hamd@kuailabs.ai for anything this page does not answer, including deleting an account outright.