VaultlineZero-trust context control for AI coding agents. Talk to your model through
Detection runs entirely locally. No telemetry, no accounts, nothing phoned home. How it worksYou type this:
The model receives this:
and you get the answer back with the real host and password already restored in
the code. The model reasons perfectly well about Note the path survives. Only the host identifies your infrastructure;
Placeholders are typed and stable: the same value gets the same token for the whole session, so multi-step tool loops keep working. Tool arguments are rehydrated before the tool runs, and every tool result is redacted before it goes back to the model. Credentials mentioned across turnsReal conversations split a credential over two messages:
The second message has no keyword to anchor on. Vaultline carries the credential
context forward for a couple of turns, so the value is still caught. Tune with
What it catches
Structural rules (regex) always run. Contextual detectors are gated by a local embedding model so they only run where they're plausibly relevant — and if that model is unavailable, detection fails open: every detector runs instead of being skipped. Syntax-aware suppression parses code with tree-sitter so low-precision rules stop firing inside comments, while unambiguous secret rules keep firing there — because commenting out a config line is one of the most ordinary ways a credential ends up in a file. In the editorIndependently of chat, Vaultline marks up what it finds in open files:
Highlighting is an affordance, not the enforcement point — it skips the two detectors that need an embedding call, so an unhighlighted value may still be redacted on its way out. Anonymize and restore
Mask asks for confirmation first, and restore refuses on a masked document rather than guessing. Commands
The anonymize/restore commands are also in the editor's right-click menu. Scope: what
|
| Setting | Default | Purpose |
|---|---|---|
enablePiiDetection / enableInfraDetection / enableConversationalSecretDetection / enableBusinessContentDetection |
true |
Toggle each detection layer |
enableCrossTurnSecretCarryover / crossTurnSecretTurns |
true / 2 |
Keep detecting credentials for N turns after one is mentioned. Lower to 1 if unrelated value-shaped strings (commit hashes, build IDs) get redacted |
blockOnHighSeverity |
false |
Block instead of redact on a high-severity match. Off by default: inside a tool loop one false positive aborts the whole task, and redaction already keeps the value from leaving |
enableToolCalling |
true |
Whether @vaultline exposes vscode.lm.tools to the model |
maxToolRounds |
25 |
How many model round trips one request may take while the model keeps calling tools. On reaching it, Vaultline says so and asks the model — with no tools available — to summarise what it found, so you get a partial answer rather than silence. Raise it for long agentic work; the Stop button cancels a run at any point |
maxTools / toolDenyList |
128 / [] |
Cap on tools offered per request, and names to exclude. Providers reject an over-long list outright, and VS Code's registry counts every built-in, extension and MCP tool you have installed |
enableSyntaxAwareRedaction |
true |
Stop low-precision rules firing inside code comments |
embeddingBackend |
"api" |
"api" (local model server, auto-managed) or "hashing" (zero-setup, no server) |
embeddingApiUrl |
local | Point at your own embedding service instead of the bundled one. Routing centroids are then rebuilt against your model automatically, once, and cached — see below |
trustCustomEmbeddingsForBlocking |
false |
Whether rebuilt centroids may block a whole message as confidential business content. Off until you've validated your model |
embeddingApiFormat / embeddingApiEmbedPath / embeddingApiHealthPath |
"vaultline" / "" / "/health" |
Shape, path and health route of a custom endpoint. "custom" describes any shape via embeddingApiRequestField / embeddingApiResponsePath. Set the health path to "" if yours has no health route — most hosted services don't |
persistSessionMappings |
false |
Write this session's token-to-value table to disk. Off: that file holds every detected secret in plain text |
auditLogIncludeValues |
false |
Off by default — turning it on makes the audit log itself a plaintext record of every secret caught |
anonymizeMode |
"placeholder" |
placeholder / hash (reversible) or mask (not) |
disabled*Rules |
[] |
Per-category checkbox lists for excluding individual rules |
Using your own embedding endpoint
Set embeddingApiUrl, and run Vaultline: Set Embedding API Token if it needs
a credential — that keeps the token in your OS keychain rather than in
settings.json.
embeddingApiFormat has two presets and an escape hatch:
"vaultline" POST {baseUrl}/embed-batch { "texts": [...] }
-> { "embeddings": [[...], ...] }
"openai" POST {baseUrl}/v1/embeddings { "input": [...], "model": "..." }
-> { "data": [{ "embedding": [...], "index": 0 }] }
"custom" describe your own shape with embeddingApiRequestField and
embeddingApiResponsePath
Nothing here is OpenAI-specific — the presets are just two fixed points of what
"custom" expresses, and either can be written out by hand:
// the vaultline preset, spelled out
"embeddingApiFormat": "custom",
"embeddingApiRequestField": "texts",
"embeddingApiResponsePath": "embeddings",
// your own service
"embeddingApiEmbedPath": "/input/text",
"embeddingApiRequestField": "sentences",
"embeddingApiResponsePath": "result.vectors", // nesting and arrays supported
The response path understands nesting and arrays: embeddings,
data[].embedding, result.vectors.
Override the path with embeddingApiEmbedPath if yours differs (/input/text,
say). If your endpoint has no health route, set embeddingApiHealthPath to
"" — Vaultline otherwise probes GET {baseUrl}/health before using the
endpoint, and a missing route means it silently falls back to the built-in
hashing embedder and never calls your service.
Routing works by comparing your message against precomputed category centroids, and those only mean anything if they came from the same model doing the comparing. So the first time Vaultline sees a new endpoint it rebuilds them against your model — 72 sentences, one batched call, cached per endpoint. Nothing happens for the default local setup.
Two things worth knowing:
- Rebuilt centroids don't block by default. They gate detection, but the
whole-message business-content block stays off until you set
trustCustomEmbeddingsForBlocking. An unvalidated model getting that wrong tells a developer their ordinary question is confidential. - Routing embeds your prompt before redaction. It has to, in order to decide
which detectors to run. Self-hosted inside your network, that's fine; a
third-party embedding API would see unredacted text, which inverts the point of
the tool. Use
"embeddingBackend": "hashing"to keep everything local instead — you lose semantic keyword matching and business-content detection, and all other detection is unaffected.
semanticMatchThreshold (default 0.5) was calibrated against MiniLM, so a
different model may want a different value.
Privacy
Everything runs locally. The embedding server binds loopback only
(127.0.0.1), starting at port 9000 and moving to the next free port if
something else already holds it. It is started and stopped by the extension
itself. There is no telemetry and no account. The audit log is a local file
that, by default, records what type of thing was redacted and never the
value.
Pointing embeddingApiUrl at a remote endpoint is the one way to change that,
and it is opt-in.
Licensing
Apache-2.0. Bundled third-party components — including sharp (LGPL-3.0) and
its vendored libraries — are listed with their licences in
THIRD-PARTY-NOTICES.md inside the extension.