All posts
June 27, 2026 · inkode team

We never get your codebase — just metadata. And you can keep even that local.

A code scanner asks for a lot of trust: you're pointing it at your source. So here's exactly what ik does and doesn't send. Your source code never leaves the machine — uploads carry findings and metadata, not file contents — secret values are masked before they're stored, the AI runs locally, and if you want zero upload, local-only scanning is one setting away.

A code scanner asks for an unusual amount of trust. You point it at your source — often a private, proprietary repository — and let it read everything. The reasonable question is the first one everyone asks: what does it send back?

Here’s the precise answer. Not a privacy policy written by a lawyer — the actual behavior, field by field.


Your source code never leaves the machine

This is the load-bearing fact: ik never uploads your file contents. When a scan finishes and you’ve opted into a hosted report, what gets sent is a description of what was found, not the code it was found in.

A finding is four things: a file path, a line number, a short message (“function too long,” “unused import”), and a severity. There is no field for the offending source line. No snippet. No surrounding context. The struct that gets serialized and uploaded simply has nowhere to put your code, because we never put it there.

So the report can tell you complexity is high in internal/auth/session.go at line 142 — and to actually see line 142, you open your own editor. The map travels; the territory stays home.


Secrets are masked before they’re even stored

The one place this principle could leak is the secret scanner — its whole job is finding things like API keys, and a naive implementation would attach the matched value to the finding so you know what it caught.

We don’t. The matched value is redacted the moment it’s parsed, down to a first-and-last-character preview with a fixed mask in between — AK***LE — so the finding can say which credential tripped the rule without the credential itself ever entering the report. The mask is a constant width, so it doesn’t even leak how long the secret was. The raw value never makes it into the data structure that could be uploaded, which means it can’t leave the machine even by accident.

(We tightened this recently after auditing our own upload payload against the promise we make in the consent prompt — the kind of check-yourself discipline we try to apply everywhere.)


The AI runs on your hardware, not ours

Two of ik’s checks use a language model — semantic duplicate detection and magic-number labelling. Plenty of “AI-powered” tools would mean your code gets POSTed to an inference API for that. Ours doesn’t.

The model is a small one that ships inside the binary and runs in-process on your CPU. There is no inference endpoint, no API key, no network request for the AI features — your functions are embedded and labelled entirely on the machine they already live on. The smartest part of the scanner is also the most private.


Paths are relative, so they can’t leak your machine

A subtle one: every file path in a report is relative to the repository root. You’ll see src/main.go, never /Users/jane/work/client-project/src/main.go. Absolute paths would quietly disclose your username, your directory layout, sometimes a client’s name. We normalize them away — forward slashes, repo-root relative — before anything is written.


What does get uploaded (when you opt in)

Transparency cuts both ways, so here’s the full list of what a hosted report includes:

  • Scores and grade — the numbers and the letter.
  • Finding metadata — path, line, message, severity. (Not contents.)
  • Repository statistics — language mix, file count, repo age, commit count, and contributor information drawn from git history.
  • Project identity — the project name, and the contact email/company you entered during setup.

That’s it. It’s enough to render a report and track a project’s trend over time, and it’s deliberately not enough to reconstruct your code.

The consent prompt during ik init says the same thing, in fewer words:

inkode will collect and upload:
  • File paths of issues found (no file contents)
  • Aggregate scores and check summaries
  • Git history statistics (commit count, age, contributors)
  • Language and tech-stack signals

No source code or secrets are transmitted.

Or send nothing at all

If even metadata is more than you want to share, ik runs fully local. It’s not a degraded mode — every check still runs, you still get the full report as a self-contained HTML file on disk. The only thing you skip is the hosted copy.

Two ways to get there:

  • During setup, the wizard offers “No — local checks only” as a first-class choice. Pick it and no config that points at our API is written.
  • Any time after, set api.upload: false (or leave the API endpoint blank) in your .ik.yaml. The scan runs, the report renders locally, nothing is sent.

Local-only works offline, too — because the analysis and the AI are all in-process, you can scan on a plane with the wifi off and get an identical result.


Why we build it this way

The principle underneath all of this is simple: the tool should be trustworthy on a machine you didn’t set up and a repo you can’t email to a third party. That rules out “send the code to a server and trust us with it” as an architecture. So your source stays put, secrets are masked at the source, the AI is local, and the upload is opt-in metadata you can switch off entirely.

If you point ik at something and find a case where it sends more than this post describes, we want to know — tell us, and we’ll treat it as a bug. Holding ourselves to the promise is the whole point.

Want to try it — locally, with nothing uploaded? Install the CLI — one line, about a minute, no account required.

privacyengineeringtooling
Scan your repo

Know what you shipped.

Install the CLI and see your score in under a minute. No account required.

Get started Book a review