ReviewOS

stacks/uplink

docs: nothing states what leaves the Mac, while a Fathom site id sits in config

#37
Closed glennmichael123 opened this 9 days ago ·
9 days ago

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 fetch in app/ 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#L374 carries two links, Stacks and GitHub, and no privacy statement.
  • The FAQ entry at resources/views/index.stx#L73 answers what Uplink can do on the Mac without saying what is transmitted, and the Full Disk Access entry at resources/views/index.stx#L65 explains why the Messages database is read, not where its contents go.
  • The README is the same. Its diagram names claude -p at README.md#L22 and never names Anthropic, and README.md#L36 says runs are recorded in the runs table without saying that the table stays on the Mac.
  • config/analytics.ts#L11 selects the Fathom driver and config/analytics.ts#L19 carries a real site id, WOLZMJDL, while nothing in resources/ injects an analytics script and the page renders standalone under @nolayout at resources/views/index.stx#L87. A reader who checks the config will find a tracker declared, which contradicts any claim of zero telemetry.

Proposal

  1. 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.
  2. Add the same statement to README.md as a section after "How it works".
  3. 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 at app/Uplink/settings.ts#L17, and the com.stacksjs.uplink Keychain item at app/Uplink/settings.ts#L19.
  4. Settle the analytics question. Either inject the Fathom script into resources/views/index.stx and say on the page that the site counts page views, or delete config/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#L139 is the only fetch in app/. 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.md carries the same statement and names the local paths.
  • config/analytics.ts matches what the page does: either the script is in the page and the copy says so, or the config is gone.
  • ./buddy lint passes and the new copy contains no em-dash or en-dash.
9 days ago

Closing as superseded. Every part of this either shipped elsewhere or rested on a premise that is no longer true, and the one live item is handled in #64.

The premise is gone

This issue rests on Uplink making no outbound request of its own, and expected a future update check to be what falsified it. Licensing got there first, in f326bde. app/Uplink/license.ts:89 POSTs to https://uplink.stacksjs.com/api/license/check at launch and every six hours.

Anyone implementing the proposal verbatim would have put a false claim on the homepage while /privacy, one click away, said the true thing.

Where each part went

Proposal item 1, the "what leaves your Mac" statement. Shipped in 83e455f, on /privacy, and it is better than what this issue specified: it also covers Apple carrying the message, Stripe, and the licence check. The requirement here that there be "no new route and no new page" was written before that page existed.

The homepage statement. #64 adds a security section that says what a text can do and what leaves the Mac, linking /privacy for the detail rather than keeping a second copy.

The README section. Also #64's territory in spirit, though the README now points at docs/security.md, added in #63, which covers the same ground at more length.

Item 4, config/analytics.ts. The one part still live and unaffected by the premise. Fixed in #64: it declared Fathom with a real site id while /privacy said the site loads no analytics, and nothing injected either. It is enabled: false now, with the reasoning in the file.

One thing this issue did not know, now fixed

Every page fetched its fonts from Google, so every visitor's IP address and browser reached Google on page load, while /privacy said "no analytics and no tracking scripts". Literally true and incomplete. The fonts are self-hosted in #64.

Two smaller corrections for the record

The Keychain holds two secrets, not one: claude-oauth-token and license-key, both under com.stacksjs.uplink. And there is a third local file the path list here predates, the licence cache at ~/Library/Application Support/Uplink/license.json. Both are documented in docs/configuration.md and docs/uninstall.md.

Sign in to comment on this issue.