also looking at this
docs: the documentation the README points at
#63
9 files
+509
-10
| @@ -0,0 +1,66 @@ | ||
| 1 | # Security | |
| 2 | ||
| 3 | Uplink lets a text message run a coding agent on your Mac with no one there to approve anything. | |
| 4 | That is the product, and it is worth understanding before you point it at a machine that matters. | |
| 5 | ||
| 6 | ## What a text can do | |
| 7 | ||
| 8 | A text that passes the filter becomes an agent run with approvals turned off: | |
| 9 | `bypassPermissions` for Claude Code, `bypass` for Codex. Nobody is at the Mac to answer a prompt, | |
| 10 | so there are no prompts. | |
| 11 | ||
| 12 | Inside the directory your text names, that agent can read files, write files and run commands, with | |
| 13 | your permissions. It is the same authority you have at a terminal on that Mac. | |
| 14 | ||
| 15 | **So an iPhone with access to the allowed thread is an unlocked door.** If your phone is stolen and | |
| 16 | unlocked, whoever holds it can text your Mac. Treat the allow list the way you would treat SSH keys. | |
| 17 | ||
| 18 | You can narrow this. `UPLINK_CODEX_PERMISSION` takes `read-only` and `workspace-write` as well as | |
| 19 | `bypass`, at the cost of tasks that need to write failing instead of asking. | |
| 20 | ||
| 21 | ## What cannot reach it | |
| 22 | ||
| 23 | The filter refuses by default rather than allowing by default. A message has to pass all of these: | |
| 24 | ||
| 25 | - **iMessage only.** SMS is rejected outright, because a forwarded SMS sender id can be spoofed | |
| 26 | through bulk-SMS gateways, and the other side of that door is an agent with approvals disabled. | |
| 27 | - **Direct chats only.** A group chat never reaches it, whoever is in it. | |
| 28 | - **An allowed handle.** Empty means this Mac's own Messages handles, so the default install | |
| 29 | answers only you. | |
| 30 | - **Not a tapback, not a system item, not Uplink's own reply.** | |
| 31 | - **Not stale.** A text older than `UPLINK_CATCH_UP_MS` is not run, so a Mac waking up cannot | |
| 32 | replay a day of instructions. | |
| 33 | ||
| 34 | ## What leaves your Mac | |
| 35 | ||
| 36 | Three things, and nothing else. | |
| 37 | ||
| 38 | **The prompt and whatever the agent reads go to the agent's vendor**, Anthropic or OpenAI, under | |
| 39 | your own account and their privacy terms. That is what running Claude Code or Codex means, and it | |
| 40 | is the same as running them yourself at a terminal. | |
| 41 | ||
| 42 | **Your texts go through Apple**, as any iMessage does. | |
| 43 | ||
| 44 | **A licence check goes to `uplink.stacksjs.com`**, at launch and every six hours. It sends the | |
| 45 | licence key and nothing else. A licensed Mac keeps working for two weeks without reaching it, so an | |
| 46 | off-grid Mac is not cut off. Buying a licence involves Stripe, which holds your email and payment | |
| 47 | details; Uplink stores the key, your email and Stripe's customer and subscription ids. | |
| 48 | ||
| 49 | Nothing else is sent anywhere. Runs, prompts, replies and their costs are recorded in a SQLite file | |
| 50 | on the Mac and go nowhere. | |
| 51 | ||
| 52 | ## What is stored, and where | |
| 53 | ||
| 54 | Two secrets are in the Keychain, not in a file: your Claude Code token and your licence key, both | |
| 55 | under the service `com.stacksjs.uplink`. They are there rather than in | |
| 56 | `~/Library/Application Support` because anything running as you can read a file there, and files | |
| 57 | get swept into backups and dotfile repositories. | |
| 58 | ||
| 59 | Everything else is under `~/Library/Application Support/Uplink`. See | |
| 60 | [Configuration](./configuration.md#where-things-live). | |
| 61 | ||
| 62 | ## The dashboard is local | |
| 63 | ||
| 64 | `resources/views/dashboard.stx` lists who may text the Mac and every prompt they sent. It answers | |
| 65 | 404 wherever the site is deployed, and the deploy checks that on every release, because a 200 there | |
| 66 | would be a privacy failure rather than a bug. | |