Skip to content

Feedback for “Scriptura (working title)”: privacy specifics in the shipped completion path (prompt scope, plaintext API key, no redaction on the remote path) #56

Description

@will-lamerton

The privacy section makes a strong claim:

The default deployment is honest about exactly which bytes go where. [...] the editor surfaces clearly which requests it is about to send and to where.

Checking that against the completion path that already ships in src/plugins/aiinlinecompletion.cpp. Three specifics, in rough order of importance.

1. What actually gets sent, and how often.

The prompt is the entire buffer prefix up to the cursor, truncated to the last 4000 characters, sent 400ms after the user stops typing:

QString prompt = text.left(pos);
...
usr["content"] = extractSuffixContext(prompt);   // right(4000)

Against the default local Ollama endpoint this is fine and exactly what local first should look like. Against a remote endpoint it is continuous source code egress with no redaction pass: every pause in typing ships up to 4KB of the file. That is a defensible behaviour for a tool the user has explicitly pointed at a remote model, but it deserves to be described in the whitepaper rather than discovered in the code, because it is more than a reader would infer from "remote is opt-in".

The natural composition here is prompt-scrubber (published as @nanocollective/prompt-scrub), which strips emails, secrets, paths and other identifying content before a prompt reaches a cloud model and rehydrates the response locally. The Composition section names Nanocoder, the Private Inference Proxy and Sentinel but not this one, and it is the most directly relevant of the four for the remote completion path. Worth adding, at minimum as a v1 option on remote providers.

2. The API key is stored in plaintext.

mainwindow.cpp:888 reads settings straight out of QSettings:

QSettings().value("ai/apiKey", {}).toString()

QSettings writes to a plain INI file under ~/.config on Linux, a plist on macOS, and the registry on Windows. None of those are secret storage. For a project whose first principle is privacy, and which is asking users to trust it with a provider credential, the key belongs in the OS keychain (libsecret / Keychain Services / Windows Credential Manager, or a Rust crate such as keyring in the backend, which fits the existing architecture).

Small fix, but the kind of detail a reviewer checks when a document says "prove, not promise", and cheap to do before v1 rather than after.

3. What is already right, and should be said out loud.

The defaults are genuinely good and the whitepaper does not take credit for them:

  • ai/enabled defaults to false, so a fresh install makes no model calls at all.
  • ai/endpoint defaults to http://localhost:11434/api/chat, so the first thing it reaches for is a local model.
  • ai/provider defaults to ollama.
  • The plugin manifest declares network.access rather than assuming it.

That is the "no remote calls on a default install" claim in "What it is not", already true in code. Worth citing.

Suggested fix: add a short subsection to Principles or Architecture describing the actual data flow of a completion request (what is sent, how much, how often, to where, and what happens on the remote path), plus a v1 commitment on key storage and on redaction for remote providers.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions