Part of #6.
Uplink asks for Full Disk Access, the most invasive permission macOS grants, and then reads every message in the Messages database. What it does with that access is defensible and verifiable from the code: it makes no outbound request of its own, the token lives in the Keychain, run history stays in a local SQLite file, and the only thing that talks to Anthropic is the Claude CLI it spawns. Someone deciding whether to grant that permission cannot learn any of it without reading the source.
What is there today
- The only
fetchinapp/is the popover calling its own agent,app/Uplink/menubar.html#L139, and that agent binds loopback only,app/Uplink/desktop-agent.ts#L278. There is no telemetry, no crash reporting and no update check. - The Claude token is kept in the Keychain rather than in the settings file, for the reason written at
app/Uplink/settings.ts#L9. - Run history is a local SQLite file,
app/Uplink/settings.ts#L16, and it holds the full text of every prompt and reply,app/Uplink/sqlite-store.ts#L35. - The homepage states none of this. The footer at
resources/views/index.stx#L374carries two links, Stacks and GitHub, and no privacy statement. - The FAQ entry at
resources/views/index.stx#L73answers what Uplink can do on the Mac without saying what is transmitted, and the Full Disk Access entry atresources/views/index.stx#L65explains why the Messages database is read, not where its contents go. - The README is the same. Its diagram names
claude -patREADME.md#L22and never names Anthropic, andREADME.md#L36says runs are recorded in therunstable without saying that the table stays on the Mac. config/analytics.ts#L11selects the Fathom driver andconfig/analytics.ts#L19carries a real site id,WOLZMJDL, while nothing inresources/injects an analytics script and the page renders standalone under@nolayoutatresources/views/index.stx#L87. A reader who checks the config will find a tracker declared, which contradicts any claim of zero telemetry.
Proposal
- Add a "What leaves your Mac" block to the existing
resources/views/index.stx, next to the FAQ. Four points: the prompt and whatever repository context Claude Code reads go to Anthropic through the Claude Code CLI on the user's own plan, nothing else is sent, the run history including prompts and replies stays in the local SQLite file, and the token is in the Keychain rather than on disk. - Add the same statement to
README.mdas a section after "How it works". - Name the local paths in that README section so a reader can go and look: the data directory, the SQLite file at
app/Uplink/settings.ts#L16, the log atapp/Uplink/settings.ts#L17, and thecom.stacksjs.uplinkKeychain item atapp/Uplink/settings.ts#L19. - Settle the analytics question. Either inject the Fathom script into
resources/views/index.stxand say on the page that the site counts page views, or deleteconfig/analytics.ts.
Requirements
- No new route and no new page. The block goes into
resources/views/index.stx. A separate privacy page is out of scope. - Every claim has to be checkable in the repository. "Makes no outbound request of its own" is true because
app/Uplink/menubar.html#L139is the only fetch inapp/. Write it so that a reader can verify it, not as a promise. - The update check will falsify the absolute form. A daily latest-release fetch is planned, and it becomes the app's first outbound request, so this copy is revisited when that lands. Prefer wording that can name that one request rather than wording that has to be retracted.
- The site and the app are separate claims. If Fathom stays, the copy must distinguish page views on the marketing site from the app, because the app is the thing holding Full Disk Access.
- No em-dash or en-dash in the new copy, per
AGENTS.md.
Acceptance
- A reader of the homepage, without opening the source, can say what is sent, where it goes, and what stays on the Mac.
README.mdcarries the same statement and names the local paths.config/analytics.tsmatches what the page does: either the script is in the page and the copy says so, or the config is gone../buddy lintpasses and the new copy contains no em-dash or en-dash.