Data handling
What happens to a file you upload, in one page: where the bytes go, what the language model receives, who can reach it, how long it stays, and what we do not have yet.
Last updated 31 August 2026. This page describes the running system. The legal statement of the same processing is the privacy notice, and the contract is the terms of use. Where this page and the notice ever disagree, the notice governs and this page is the one with the bug: tell us.
- Where your data goes
- What the language model receives
- What ends up in the report
- What we log
- Who can reach it
- How long it stays, and deleting it yourself
- Who else is involved
- What we do not have yet
Where your data goes
Four places, in this order. Everything below is how the system is built today, not how we intend to build it.
| Step | What happens |
|---|---|
| 1. Upload |
Your browser asks us for a one-time upload link and then sends the file
straight to cloud object storage. The file does not pass
through our application servers. The server accepts only .h5ad and
10x .h5, and it refuses anything else before a link is issued.
|
| 2. Storage |
Amazon S3, in the us-east-1 region in Northern Virginia.
Unencrypted connections are refused by the storage itself, not merely
discouraged, and objects are encrypted at rest with Amazon-managed keys. There
is no customer-managed key today, so there is no key you hold or can revoke.
|
| 3. The run | One container, on one GPU machine, which the run has to itself because the job reserves that machine's only GPU. Your file, everything the run computes from it, and the finished outputs all live on that machine's temporary disk for the length of the run. The machine and its disk are destroyed when the run ends, and the fleet scales to zero between runs. |
| 4. Results |
Written back to the same bucket under a folder named for the run. You download
them through a link that works for one hour and is issued only after we check
the run belongs to your account. The download bundle is an allowlist: the
report, predictions.csv, annotated.h5ad, the run
summary and the per-analysis outputs. Our reference data and the model are
never in it.
|
One thing in step 4 is worth stating plainly, because a retention table hides it. The
results folder holds copies of your expression data, not only summaries:
annotated.h5ad is your matrix with our labels attached, and the run also
leaves a gene-harmonized copy of your matrix beside the report so it can be rebuilt
without a rerun. That copy is not in your download bundle, but it is in our storage. So
the window that governs your expression data is the 30 day one for results, not the
7 day one for the uploaded file. Deleting the run removes both at once.
Your own cell metadata comes back to you unchanged: every obs column in
the file you uploaded is in annotated.h5ad exactly as you supplied it, and
nothing we add overwrites one.
What the language model receives
Parts of the pipeline call a language model, Claude Opus 5, through Amazon Bedrock — the same Amazon Web Services account, in the United States, that runs everything else here. This is the question most labs ask first, so here is the exact answer, step by step.
.h5ad or a 10x .h5, and no step sends your file.
Some of your metadata does leave, and it is not only column names. Up to three real example values from each metadata column go with the column name, so if a column holds donor identifiers, three of them go too.
Your data never leaves AWS at any step. That is what changed on 9 September 2026: the model used to be called at Anthropic, over the public internet, under a second company's terms. It is now called inside our own AWS account. Nothing on this page goes to a second processor any more.
| Step | When | What is sent |
|---|---|---|
| Column roles | Only when you press the button that asks for it, and it is priced separately. | For each metadata column: its name, its data type, how many distinct values it holds, how full it is, and up to three real example values from it. Plus the number of cells. |
| Label matching | Only if you bring your own cell-type labels. | Your distinct cell-type label strings, as text, and the reference's own vocabulary. No counts, no values from any other column. |
| Interpretation | Only if you tick "Interpret results". | Statistics the run already computed: cell and gene counts, composition percentages, confidence and out-of-distribution statistics, quality medians across samples, benchmark numbers, up to eight gene symbols per cell type, cell-type names, the condition column's name and its values, the donor column's name, and the question you typed in the focus box. |
What never reaches the model, on any of those three paths: any expression
value, and any donor or sample identifier. The interpretation
step reduces the per-sample quality table to medians and carries the column's
name, never its rows, and it is written never to read
predictions.csv. Ages are a special case: no age value is read into the
model, into a statistical design or into the report anywhere in the pipeline, because
age arrives in too many incompatible formats to parse safely, and a covariate parsed
wrong is worse than one left out. The exception is the column-roles button above, which
sends three example values from every column, an age column included.
no_llm makes no language-model call anywhere. It is not a request to skip
the optional steps: any analysis that needs a model is refused before the run starts,
naming what conflicts, so nothing is quietly missing from your report. The run needs no
credential of ours to reach any model, and the report you receive carries the line
"No language model was used in this run", taken from a count kept at the one point in
the code every model call passes through. The upload form does not show it as a
tick-box yet, so ask us to set it, or send it on the API.
One thing it does not cover, because it happens before a run exists: the column-roles button in the table above. That step is a separate press, priced separately, and simply not pressing it sends nothing.
Two further steps exist in the command-line engine and cannot be reached from this application: a layout resolver that reads the first rows of an ambiguous spreadsheet, and an error explainer that reads the start of a file that failed to load. The upload endpoint accepts neither format that would reach them, and the explainer is switched off in the deployed job.
AWS's side: Amazon Bedrock's stated default is zero data retention — it does not store what is sent to a model or what comes back, and the company that built the model receives neither. AWS runs the model in accounts the provider has no access to, so, in AWS's own words, model providers "don't have access to Amazon Bedrock logs or to customer prompts and completions". For a small number of named models AWS does have to keep inputs and outputs for as long as 30 days to detect abuse; when it does, they stay inside AWS and are still not shared with the model's provider. Claude Opus 5, the model we call, is not on that list today, and we re-check it before changing models.
It is not used to train anything. AWS's service terms carry a service-improvement instruction that lets AWS learn from what you send — and it applies to a named list of services that does not include Amazon Bedrock. The clause says so itself: it "does not apply to ... any AI Service that is not listed". So nothing you send here trains an AWS model, and nothing you send here reaches the company that built the model, so model providers may not train models on customer content submitted through Bedrock — they never receive it.
One honest exception, and it is about billing rather than content. AWS may tell a model's provider information about your use of that model — usage, not what you sent. AWS's terms are explicit that this information "does not include Your Content". Your data still never leaves AWS; the fact that a call happened does.
One geographic detail, because it is the kind of thing that matters to a data steward and not to anyone else: we call the model through a United States routing profile, so a request made in Northern Virginia may be processed in one of two other US AWS regions instead. It stays on the AWS network, it stays in the United States, and it is encrypted the whole way.
What ends up in the report
The report is a single self-contained HTML file, and it is the artifact that gets forwarded. Almost everything in it is aggregate: differential expression tables print donor counts rather than donor names, and disease sections print condition values such as "Alzheimer's disease" and "healthy", which describe a cohort rather than a person.
One table is not aggregate, and it is deliberate rather than
accidental: the per-sample quality table prints one row per value of your sample or
donor column, as those values appear in your file. If you named no sample column, we
pick one for you from the usual names, donor_ID among them. The report now
says so next to that table and names the column it used, so nothing about it is a
surprise to whoever you send it to. If you would rather those values did not travel,
rename or replace them before uploading.
What we log
Operational logs, kept 30 days, read when something breaks. What they contain, measured against the code rather than intended:
- Column names, yes. The name of the sample or donor column we detected, the condition and donor column names, and, when we cannot find a sample column, the first twelve column names in your file.
- Condition values, yes. The list of levels in your condition column, for example the equivalent of "Alzheimer's disease" and "healthy". These are cohort attributes rather than per-person ones.
- Donor and sample values, no. Nothing on the query path writes the contents of those columns to a log.
- Expression values, no. Never, on any path.
- Language model prompts and responses, no. Not logged at all, in either direction.
Who can reach it
One person: Leonardo Golinelli, who founded VarnaOps, operates it, and answers the contact address. He holds the administrative credential on our cloud account, and that credential can reach any file the platform stores. There is no second administrator and no support team with a way in. Since 31 August 2026 that access is logged: an audit trail records administrative actions and, separately, reads and writes of the individual objects holding uploads and results, so which file was opened and when is an answerable question. Nothing before that date is recorded. If your run fails we may open your file inside that account to see why; that access is logged and we tell you. We never copy your file to any machine outside the account.
The service itself reaches your data through one credential shared by all runs rather than one scoped to your run. That is a real limitation and it is listed under what we do not have yet.
How long it stays, and deleting it yourself
| What | How long |
|---|---|
| Your uploaded file | 7 days, then deleted automatically. Not the answer to "when is my expression data gone": see the results row. |
| Your results, including the copies of your matrix described above | 30 days, then deleted automatically. |
| The run record (run id, status, timings, your email, the file name you uploaded) | No automatic expiry today. Deleting the run or the account is what removes it. |
| Logs | 30 days. |
| Security audit records (which principal read or wrote which stored object, and when) | 400 days, in a separate audit store, as a security measure: an incident found at the end of a year still has the window that started it. They hold no content from your file. |
| Database backups | A rolling 35 day window, from which a deleted record stays restorable by us until it ages out. |
| Anything sent to the language model | Nothing is kept. Amazon Bedrock's default is zero retention, and it runs inside our own AWS account, so there is no second copy anywhere to age out or to ask about. Before 9 September 2026 this row read "30 days on Anthropic's side"; that path is gone. |
| Billing records | Kept indefinitely, on purpose, because accounting law requires it. |
| Terms acceptance record | Your user id, the version of the terms you accepted, the date and time, and the network address and browser you accepted from. Kept until you delete your account, which deletes it too. |
You can delete things yourself, before any of those clocks run out. Each of the three has its own control on the site: an upload from the upload step, a run from My runs, the account from your account page. None of them needs an email to us. Deleting an upload removes that object. Deleting a run stops it if it is still executing, removes the whole results folder and removes the record. Deleting your account does that for every run you have and removes your uploads, your access-request details and your login. Deletion is done by every stored version of an object rather than only the current one, and deleting something already gone succeeds rather than erroring, so a retry after a timeout is safe. The full account of what survives an erasure, and why, is in the privacy notice.
Who else is involved
Two companies now, not three. Amazon Web Services hosts everything, in our own account; Amazon Web Services (Amazon Bedrock) serves the language model the three steps above call, and it is listed separately because it is a different service engaged on different occasions, not a different company; Stripe handles credit purchases and never sees your data. Until 9 September 2026 the language model came from a genuinely separate company, Anthropic. The full list, with what each one receives and the legal instrument that carries the transfer, is on the privacy notice. Your data is never used to train our models, which are built only on public reference atlases, and never sold.
What we do not have yet
The point of this page is that a data steward can decide in five minutes, so the gaps belong on it as plainly as the controls.
| Item | Where it stands |
|---|---|
| A data processing agreement | In place. The Data Processing Agreement is incorporated into the terms of use and accepted by ticking the box when you sign in; we record the version and the date, and a counter-signed copy is available on request. |
| A deletion attestation | Live, deployed 1 September 2026. Closing an account, which you do yourself from your account page, produces a written destruction record: how many stored objects and storage prefixes were deleted, when, and that every prefix was listed again afterwards and found empty. It ends in a statement you can forward to a data access committee, and it lists what deletion does not reach. It is held in our separate audit store, outside the storage the deletion empties, and a copy comes back in the response. |
| A per-run credential for the service | Half built. Since 2 September 2026 a run can read only its own uploaded file: the shared credential no longer reaches the upload area, and each run is handed a one-hour link to its own input. Results are still written and read with one credential shared by all runs, which is why the access statement above says "the service" rather than "your run only". |
| Encryption of the run machine's temporary disk | Live since 31 August 2026. Object storage is encrypted at rest, and since 31 August 2026 the run machine's disk is encrypted too (verified against the account). |
| Customer-managed encryption keys, a choice of region, on-premises deployment | Not available. None of these is offered today; the privacy notice says so too. |