Customer source code gets expensive the moment you keep it
Semfora deletes the repository clone after every analysis run, including failed runs. That decision makes the product harder to build, and I want to explain why I made it anyway, and be precise about what we do keep.
Keeping the full source checkout around would make retries cheaper and debugging more convenient. Several future features would be easier to ship because the expensive part of analysis would already be sitting somewhere, ready to load.
I still chose deletion.
The worker creates a unique temporary workspace, obtains a run-scoped GitHub credential, checks out the intended commit, runs the deterministic engine, validates the output through explicit schemas and field allowlists, posts an authenticated result, and removes the workspace, clone, and transient credentials on every exit path: success, failure, cancellation, timeout. Your source code does not exist on our systems between runs.
Retained source code is a second product
Storing customer source sounds like a storage decision. It becomes an access-control system, a key-management system, a backup policy, a restore test, a retention schedule, a deletion process, an incident-response scope, and a recurring procurement answer.
Encryption adds another system on top. Someone has to define which data is covered, where the keys live, who can use them, how rotation works, what backups contain, how restores preserve the boundary, and what evidence exists when a customer asks. Encryption protects retained data. It does not remove the obligations created by retaining it.
I don't have a responsible dollar figure to publish for that full chain, so I won't invent one. The cost is visible in the work before it ever shows up as a line item.
The cheapest artifact to encrypt, rotate, audit, back up, restore, and eventually delete is the one you never save. So the source checkout is the thing we never save.
What a code analysis product actually needs to store
Deleting everything would make the product useless, so here is the full inventory.
Derived records. Symbol, module, and file names; counts, scores, and graph metrics; commit SHAs, branch names, PR titles; run status and metadata; work items, chat records, generated summaries; billing and operational records. The metrics schema has no field that can carry source text: a run result is names and numbers.
A structural index. We also retain a compact structural index derived from your code (symbol names and relationships, not source text) so the next run can build incrementally instead of re-analyzing history from scratch. It's stored per tenant, and only the most recent versions are kept; older ones are deleted. This is the honest cost of making repeated analysis fast, and it's disclosed in our privacy policy, not buried here.
Derived does not mean harmless. A symbol name, a relationship map, or a generated summary can still be sensitive. Retained records still need access controls, transport and storage protection, logging discipline, retention rules, and deletion behavior. Because the retained set is names, numbers, and structure rather than source text, that obligation set is one we can actually enumerate. How the indexing works is documented if you want the mechanics.
Does AI read the code? Where the boundary moves
The repository-analysis engine is deterministic. Parsing, graphing, and scoring your repository does not involve an LLM.
Some explicitly invoked features do read code with AI. Those route relevant excerpts through OpenRouter with two centrally enforced settings: zero-data-retention routing, and exclusion of any provider that trains on request inputs. So the accurate claim is narrower than "source never leaves the analysis environment," and I'd rather state it precisely: the deterministic analysis requires no LLM; the clone is deleted after every run; invoked AI features send relevant excerpts under retention and no-training controls.
Zero-data-retention is a routing control. Assurance documents are procurement evidence. Those are different jobs and a buyer needs both; we're collecting vendor assurance documentation now, and I'm not presenting vendor paperwork as a Semfora certification.
Deletion has an engineering cost
Removing the source-bearing workspace pushes complexity elsewhere. Retries must be idempotent because the worker may rebuild the analysis. Callbacks must be authenticated and scoped to the correct repository and run. A late failure or duplicate delivery can't overwrite good data. Raw engine output is treated as source-sensitive until it passes the field allowlist. Cleanup has tests for success, failure, cancellation, and timeout paths.
Debugging gets less convenient too. The easiest artifact to inspect after a failed job is the one you kept. We instead preserve enough scrubbed operational state to diagnose a run without turning source-bearing output into a debugging archive.
That's the trade: more compute and more operational discipline, in exchange for not growing a permanent source-storage product inside the analysis product.
Current limits are part of the security answer
Semfora is SaaS-only today. It does not currently offer air-gapped deployment, customer-managed keys, regional pinning, dedicated customer storage, SAML, SCIM, or a completed SOC 2 attestation.
Those gaps matter in procurement, and they keep this post honest: you should be able to tell shipped controls from current configuration from work in progress without decoding marketing language. The security page states what's shipped; this post is the reasoning behind it.
Semfora is open for signups. Connect a repository, let a run build the analysis, and inspect the derived evidence yourself after the source-bearing workspace is gone: semfora.ai.
Comments
to join the conversation.