docs(privacy): PRIVACY.md describes what is on main now
Summary
Approved by Dean (relayed by the orchestrator): "looks good to me unless we can make it shorter. Let's get it merged either way." A second commit tightens the policy for length, from 7,970 to 6,566 words: repetition cut, the two unauthenticated GitHub bullets merged, long sentences shortened. No disclosure is dropped and no meaning changes; the per-change list below still holds.
Brings PRIVACY.md (rendered as tryluke.dev/privacy through apps/web/src/PrivacyPage.tsx) up to date with what is on main at 248f568f. This is the product's privacy policy; Dean approved the wording (above). Nothing else changes.
I audited every data flow named in the task against the code, then had a second pass check each changed sentence against the code. The policy states only what the code does. It never claims more protection than the code gives, and where the code does less than a reader might expect, the policy says so. The structure and voice are unchanged. Each change below gives its reason and the code behind it.
Code gaps the policy now states plainly (Dean: decide whether to fix the code instead)
These are true on main today, so the policy discloses them. If you would rather fix the code, the sentences can be removed in the PR that fixes it.
- Deleting an account does not revoke the Linear grant at Vercel Connect. Only Disconnect revokes (
apps/web/server/linear-app.ts:209-230, the one.revoke(call site). Account deletion only cascadeslinear_connectionaway (packages/database/src/models/account-store.ts:62-72,schemas/linear.ts:24). - Deleting a plan does not delete its call records.
voice_sessions.plan_idis a plain column with no foreign key (packages/database/src/schemas/voice.ts:62-71).deletePlan(apps/web/server/hosted/plan-store.ts:640-661) and the 30-day purge (models/soft-delete.ts) only touch conversations. Sovoice_transcript_segments, which hold the words, stay until the account is deleted, and no screen shows them after the plan is gone (hosted/transcript-store.ts:36). - Starting a new plan opens a call with the microphone live, and the plan's microphone button is a toggle, not hold-to-talk.
apps/desktop/src/main/ipc/planning-acts.ts:123-135,packages/voice/src/orchestrator/live-voice-orchestrator.ts:300-366. The old text said the microphone listens only while the talk key is held, and that a call opens only on the talk key or the plan's microphone. - eve session history on Vercel Workflow is never deleted. Every planning and coding-agent session runs as a durable eve workflow, and on Vercel that is Vercel Workflow (eve
docs/concepts/execution-model-and-durability.mdx:16,24;docs/concepts/security-model.md:50). It keeps the messages, files and tool output the model works from. Nothing inapps/webdeletes an eve session, and the policy never mentioned this store. - Deleting a plan does not stop a coding agent that is running.
deletePlanstops no turn. - One voice log path can carry error detail.
apps/web/server/voice/live-record.ts:76logs a defect's full cause through Effect's logger, outside the restrictedvoice/log.ts. The old "logs only status codes and byte counts" was too strong.
Every change, with reason and code
Header
- Last updated: 13 October 2026.
On your Mac
- Exception: the Mac now reads a file the user hands it to attach to a coding-agent message. The old "nothing reads file contents from your Mac's own disk" was false. Code:
apps/desktop/src/renderer/planning/attached-files.ts:9-21,70(file.arrayBuffer()),agent-composer.tsx:269-274. - Who starts agents: Luke can start an agent on a call (#1985). Code:
apps/web/server/hosted/coding-agent-tools.ts:238-247.
Your conversation with Luke
- The coding-agent default now includes context size (#2046). Code:
packages/database/src/schemas/preferences.ts:26-28. - During a call the planning model can list, read (a tail of the last turns), message and start coding agents (#1960, #1985). A message it sends is kept as the user's line in the agent's transcript. Code:
coding-agent-tools.ts:79-82,207-248,coder-host/steer.ts,database/models/writer.ts:1949-1953. - The broken cross-reference "Usage data and screen recordings" now points to "Screen recordings".
Feature plans (plan as one document, #2182–#2281)
- "a Markdown body and a list of assumptions" becomes one Markdown document copied from the template. Code: migration
0095_plan_drop_template_columns.sql;schemas/plan.ts:35-47. - Writers: coding agents started on the plan, and a restore. Code:
hosted/plan-store.ts,models/plan-revisions.ts. - History now says close saves by one writer form one revision. Code:
models/plan-revisions.ts:30-33,50,306-313. - Deletion removes the inbox, does not remove call records (gap 2), and does not stop a running agent (gap 5).
- Pinning and archiving a plan store a timestamp and delete nothing. Code:
schemas/plan.ts:55-58.
Your plan template (new paragraph, #2182/#2220)
- It is kept in
account_preference.plan_template, up to 20,000 characters, with a built-in default. It is copied into a new plan, no model reads it, and it is deleted with the account. Code:schemas/preferences.ts:29-35,packages/hosted/src/plan-document-template.ts:19-57,plan-store.ts:487-497,account-app.ts:270-320.
A plan's inbox
- An image keeps the agent's description of up to 300 characters. Code:
packages/hosted/src/inbox-wire.ts:78. - A turn that ends also raises a Mac notification, with the plan, the agent title, and finished, failed, or the branch's PR number. Code:
apps/desktop/src/main/agent-notices.ts:50-61,270-285.
Files you attach to a coding agent (new paragraph, #2083/#2116/#2119)
- Limits: images, PDFs up to 3 MB, text up to 100 KB, 10 files, 3 MB a message. Code:
packages/hosted/src/coding-agent-wire.ts:62-73,143-161. - A PNG, JPEG or WebP up to 1.5 MB is sent byte for byte, so its metadata goes with it. Any other image is re-encoded to WebP on the Mac. Code:
apps/desktop/src/renderer/feedback-images.ts:30-40,96-98. - Files go to the model on every later call, and images and PDFs are copied into the sandbox. Code:
apps/web/server/hosted/attached-files.ts,apps/web/coder/sandbox.ts:13-17. - They are stored in the transcript as
data:URLs. A task's first message keeps images and PDFs by name only. Code:database/models/attached-file-parts.ts:56-71,attached-files.ts:85-128.
Your own API keys
- The hint is
sk-plus one word plus the last four characters, not "first characters". Code:hosted/provider-key-check.ts:40-46,85-93. - "When you added it" becomes "when you last saved it", because the row is replaced on each save. Code:
provider-key-store.ts:99-110. - The status has four values (
verified,invalid,quota_exceeded,unreadable), with a time, and a coding agent's call updates it. Code:packages/hosted/src/provider-key-wire.ts:26-35,coder-host/account-keys.ts:52-63. - Only coding agents and their workers use the key. Planning, voice, the notetaker, dictation and titles always run on Luke's keys. Code:
coder-host/account-keys.ts,coder-host/model.ts:216-221.
A plan's whiteboard
- The policy said "reads the board as text" and that the board "can hold no image or file". That was incomplete: the Mac also uploads a PNG of the board, at most 1,200 px a side, and
look_at_boardshows it to the model. The PNG is not copied into the planning conversation, though eve's session history may keep it. Code:schemas/plan.ts:94,hosted/board-look.ts:9-30,apps/desktop/src/renderer/planning/plan-board.tsx:120-145,packages/hosted/src/board-vocabulary.ts:41. The user still cannot add an image:whiteboard/index.tsx:86-97,317.
How the planning model reads your repository
- Each command's description is stored (#2222). Code:
hosted/command-description.ts:4-29.
A whole file opened from a snippet
- Copy and download read the whole file, up to 1 MB, with lines uncut, and a download is written where the user saves it. Code:
hosted/plan-file.ts:44-47,register-desktop-ipc.ts:76-86. - The File tab's folder tree (#2082) is read through the service and not stored. A
.envfile's name can be listed, but the file is never read. Code:hosted/plan-tree.ts:29-75,github/repository-folder.ts.
How the plan is written during a planning call
- "saves the fields" becomes the three kinds of note the notetaker applies. Code:
packages/hosted/src/plan-template.ts:233-249,517-531.
Your account
- Sign-in also stores the profile picture's address, plus each session's IP address and user agent (Better Auth defaults). Code:
schemas/auth.ts:47-48;admin/admin-queries.tsshowsimage. - Google sign-in tokens are kept and used for nothing after sign-in. Code:
schemas/auth.ts:60-70,auth.ts:72. - The GitHub App permissions now include checks, statuses and Actions read where the installation grants them (#2058). Code:
github/github-app.ts:92-111. - "A daily count of how much voice and review" was wrong: there is no review counter. The count covers voice sessions, each planning or research model call, each web search, each notetaker run and each dictated clip, plus dictated seconds. Code:
database/models/quota.ts:85-116,schemas/usage.ts:19-22,brain-host/model.ts:5-50,public-research.ts:520,voice/plan-scribe.ts:232. - The admin page also shows the picture and the admin flag. Code:
admin/admin-users.ts:44-66,admin-user.ts:222-283. - Turn rows: "the ids of OpenAI's responses" is no longer written (
relay.ts:1059writes[]). Effort and timings are listed, and older rows are noted. Code:schemas/storage.ts:221-273. - The call record (#2242) lists the plan, OpenAI's session id, start and end, close reason, model, and billed seconds (or Luke's own count), plus timed segments. Code:
schemas/voice.ts:54-121,call-card.tsx:48-85. Gap 2 is stated here too. - The Linear paragraph moved out of the middle of "Your account". #2070 had inserted it between "a daily count…" and "Luke's own maintainers can see that record", so "that record" pointed at Linear.
Linear, if you connect it (tightens #2070's draft; there was no "draft" marker in the file itself)
- The token is never written down. It is fetched from Connect per use, held in memory, and sent only to
https://mcp.linear.app/mcp. Code:hosted/linear-connection.ts:46,82-115,149-161,hosted/linear-connect.ts:4-6,164-173. - What Luke stores: the connection's state and when it changed (
schemas/linear.ts:18-36), not just "whether connected". - Users: the planning model and its worker, and each coding agent and its worker, with no approval step. Code:
{eve,coder}/connections/linear.ts,{eve,coder}/subagents/worker/connections/linear.ts,linear-connection.ts:10-12. - Results go to the model and are stored whole. Code:
hosted/connection-tools.ts,brain-host/relay.ts:448-463,493-523. - Disconnect takes effect from the next step. Code:
linear-connection.ts:27-29. Account deletion does not revoke (gap 1).
Screen recordings (#2273)
- The plan's name is left out of recordings entirely. It was listed as masked. Code:
plan-document-editor.tsx:233. - The left-out list is replaced to match every
ph-no-captureonmain: feedback, plan name, document while editing, whiteboard, transcript, Work, Code, File tabs and tree, Inbox and pictures, agent tabs and composer, attachment viewer, transcript code blocks, version history, Settings API keys and Plan template, and tooltip cards. The deleted "editor you edit a field of a plan in" is gone. - Masked attributes are mentioned. Code:
session-replay.ts:260-271. - The recorder loads just after first paint. Masking is unchanged. Code:
session-replay.ts:301-334.
Who we send it to
- OpenAI voice: the toggle and new-plan microphone behavior (gap 3). Release mutes at once, and the device closes when OpenAI confirms, within 5 s (
live-call.ts:64,256-279,782-791). The policy previously said "the moment you let go nothing does". Logging is now described accurately (gap 6). The record keeps model and close reason. Web search runs on OpenAI (public-research.ts:425-436). - OpenAI dictation: the recording stays in memory only (
use-dictation.ts:75,197). Each clip also adds 1 to the daily count (quota.ts:90-95). - Anthropic and OpenAI, coding agent: Luke can start one, workers may run on the other provider, attachments travel, command descriptions are stored, and archiving keeps everything (#2252/#2276:
coding-agent-store.ts:658-667,coding-agents-app.ts:681-692). - New: Anthropic, for titles (#2150, #2069).
claude-haiku-5-5runs on Luke's Anthropic key whatever key the agent uses. On a completed turn, for the first three turns at most, it gets the first message (the plan text for a plan-started agent), the latest message and the latest answer, each cut to 2,000 characters. A worker's whole task is sent too, including the planning worker's, so planning text now reaches Anthropic. Code:coder-host/title.ts,coder-host/model.ts:48,216-222,bounds.ts:61,brain-host/host.ts:459-476,coder/hooks/store.ts:137-139. - GitHub: the agent reads CI and failed logs with the same firewall token (#2058:
coder-host/instructions.ts:84). The signed webhook (#2073) reads the event, repository and branch, then refreshes PR metadata for up to 10 agents with the owner's token, stored incoding_agent.published. Code:github-webhook-app.ts:75-156,255-261,coder-host/published.ts:66-126. - New: Vercel and Neon: hosting and the database, plus Vercel Workflow session history (gap 4). Neon:
apps/web/server/README.md:5,server/db/index.ts. - Not added: Vercel AI Gateway. No model call goes through it, and the only use is an unauthenticated fetch of its public model catalog (
hosted/model-catalog.ts:31-40), which carries nothing about the user. Sentry is unchanged: it runs on the desktop only, and the web server has none.
Storage
- The database is hosted by Neon.
Your choices
- The microphone bullet is rewritten for the toggle, call card, shortcut, new-plan auto-open, and the indicator timing (gap 3).
- Account deletion now lists everything the user-row cascade removes. It says the GitHub App and the Linear grant are not revoked, and that sandbox snapshots and Workflow history stay.
Google user data
- The profile picture is listed among the data Google returns.
Evidence
- Platform-independent checks:
./scripts/check.shexit 0. - macOS Electron verification (
./scripts/verify.sh):not run. This PR only changes text and touches no Mac code. CI cannot verify the Mac and builds nothing for it; LUKE-159 is the manual Mac pass.
Visual evidence
- Fixture screenshots inspected:
not attached(documentation only).
Invariants
-
./scripts/check.shgreen. No renderer change, soverify.shdoes not apply. - JSON Schema goldens unchanged.
- No behavior change, so no test; no change-detector test added.
- Gateway envelope goldens unchanged.
- No new
astype assertion. - No
Effect.runPromise/runSync/runForkchange. - No new raw async primitive.
- No discarded Effect.
- Test count unchanged.
- No hand-rolled file replaced.
-
CLAUDE.md/AGENTS.mduntouched. -
PRIVACY.mdchanged. A product decision, approved by Dean, called out above. - No dependency change.
- No barrel or door change.
Notes
- Dean approved; enqueued through
scripts/queue-watch.sh --press. - Code follow-ups worth considering are gaps 1, 2, 4, 5 and 6 above. Small stale comments:
apps/desktop/src/renderer/session-replay.ts:22-33still lists "Ten elements" and a field editor, andpackages/hosted/src/plan-document-template.ts:15says nothing reads the template.
🤖 Generated with Claude Code