ReviewOS

also looking at this

stacks/uplink

docs: the README describes two engines, not one

#56
Merged glennmichael123 wants to merge docs/readme-two-engines into main
1 file +44 -19
README.mdmodified+44-19
Changes to README.md
@@ -1,15 +1,18 @@
11# Uplink
22
3Text your Mac from anywhere, even over satellite with no data, and Claude answers.
3Text your Mac from anywhere, even over satellite with no data, and an agent answers.
44
55Newer iPhones can send iMessages over satellite when there is no cell or Wi-Fi signal, but nothing
6that needs the internet works. Uplink turns those texts into a way to reach Claude: it watches
7Messages on this Mac for texts from you, runs each one through Claude Code (on your Claude Max
8login, no API key), and texts the answer back.
6that needs the internet works. Uplink turns those texts into a way to reach a coding agent: it
7watches Messages on this Mac for texts from you, runs each one through Claude Code or Codex (on the
8plan you already have, no API key), and texts the answer back.
9
10Claude Code is the default. `UPLINK_ENGINE=codex` changes it for the whole installation, the
11menubar has a picker, and texting `codex` or `claude` switches one thread.
912
1013- "Whats the NFL score rn?" gets a web search and a two-line answer.
11- "please improve ~/Code/stacks with feature xyz" runs a full Claude Code session inside
12 `~/Code/stacks`, with that repo's CLAUDE.md, hooks and settings, and texts you a summary.
14- "please improve ~/Code/stacks with feature xyz" runs a full agent session inside
15 `~/Code/stacks`, with that repo's agent instructions, hooks and settings, and texts you a summary.
1316- Follow-ups continue the same conversation until you text `new`.
1417
1518## How it works
@@ -19,7 +22,8 @@ iPhone --(iMessage, maybe via satellite)--> Messages on this Mac --> ~/Library/M
1922 |
2023 Uplink.app polls it every 2s (Full Disk Access)
2124 |
22 claude -p ... --resume <thread session> (in the named repo)
25 claude -p ... or codex exec resume ... (in the named repo)
26 whichever this thread is set to
2327 |
2428iPhone <------------------------- Messages (AppleScript) <------- the reply, as plain text
2529```
@@ -27,8 +31,8 @@ iPhone <------------------------- Messages (AppleScript) <------- the reply, as
2731- **Who can command it:** only direct (never group) chats with an allowed handle. By default that is
2832 this Mac's own Messages handles, so you text yourself. `UPLINK_ALLOWED` sets it explicitly. A
2933 message is honored only if it passes `app/Uplink/filter.ts`; everything else is ignored.
30- **One task at a time per thread.** A second task queues. `status`, `stop`, `new`, `more`, `ping`
31 and `help` are answered immediately and never queue.
34- **One task at a time per thread.** A second task queues. `status`, `stop`, `new`, `more`, `ping`,
35 `help`, `claude` and `codex` are answered immediately and never queue.
3236- **Built for a thin link:** plain text, short answers, long replies split into up to 3 texts with
3337 the rest behind `more`, a "Working on it" after 20s and a progress line every 10 minutes.
3438- **Replies start with ��**, so they stand apart in a thread with yourself, and so Uplink never
@@ -40,10 +44,16 @@ iPhone <------------------------- Messages (AppleScript) <------- the reply, as
4044
4145**[Download Uplink for Mac](https://github.com/stacksjs/uplink/releases/latest/download/Uplink.dmg)**
4246(macOS 13 or later, signed and notarized). Drag it to Applications and open it: the menubar walks you
43through Full Disk Access, signing in to Claude with a token from `claude setup-token` (kept in your
44Keychain), and who may text it. Then text yourself `ping`.
47through Full Disk Access, signing in to the agent you picked, and who may text it. Then text
48yourself `ping`.
49
50You need one of the two CLIs and a plan for it:
4551
46You need the [Claude Code CLI](https://docs.claude.com/en/docs/claude-code) and a Claude plan.
52- [Claude Code](https://docs.claude.com/en/docs/claude-code), the default. The menubar takes a
53 long-lived token from `claude setup-token` and keeps it in your Keychain.
54- [Codex](https://developers.openai.com/codex/cli). Sign in once on the Mac with `codex login`, or
55 `codex login --device-auth` over SSH. Codex keeps its own credentials, so Uplink stores nothing
56 and needs no API key either.
4757
4858Uplink answers texts once it is activated: [$1.99 a month, $19.99 a year, or $29.99
4959once](https://uplink.stacksjs.com/pricing), and a code gets six months of Monthly free. The
@@ -78,7 +88,8 @@ its Full Disk Access grant is separate from the downloaded app's):
7888
79892. **Grant Full Disk Access to Uplink (source)** in System Settings > Privacy & Security.
8090
813. **Sign in to Claude** with a long-lived token for a background service:
913. **Sign in to the agent you want.** For Claude Code, a long-lived token, because a background
92 service cannot answer a browser prompt:
8293
8394 ```bash
8495 claude setup-token
@@ -88,6 +99,16 @@ its Full Disk Access grant is separate from the downloaded app's):
8899 ./buddy env:set CLAUDE_CODE_OAUTH_TOKEN "$(pbpaste | tr -d '[:space:]')"
89100 ```
90101
102 For Codex, sign in once and it keeps its own credentials:
103
104 ```bash
105 codex login # or: codex login --device-auth, over SSH
106 ```
107
108 ```bash
109 ./buddy env:set UPLINK_ENGINE codex
110 ```
111
911124. **Check it**, then text yourself `ping`:
92113
93114 ```bash
@@ -119,18 +140,22 @@ Pushing to `main` deploys https://uplink.stacksjs.com once CI passes (`.github/w
119140| `./buddy uplink:watch` | The watcher itself, in the foreground (needs Full Disk Access for your terminal) |
120141| `./buddy dev` | The dashboard: setup status, what it is doing, recent texts |
121142
122Configuration lives in `.env`; see the `UPLINK_*` block in `.env.example`. The service picks up edits by itself.
143Configuration lives in `.env`; see the `UPLINK_*` block in `.env.example`, which covers both
144engines (`UPLINK_ENGINE`, `UPLINK_CLAUDE_BIN`, `UPLINK_CODEX_BIN` and the rest). The service picks
145up edits by itself.
123146
124147## Layout
125148
126149- `app/Uplink/`: the daemon (`uplink.ts`), the chat.db reader (`messages-db.ts`,
127 `typedstream.ts`), the command filter (`filter.ts`), the Claude Code engine (`engine.ts`),
128 replies (`sender.ts`, `format.ts`), the launchd service and app bundle (`service.ts`,
129 `launcher.ts`) and setup checks (`doctor.ts`).
150 `typedstream.ts`), the command filter (`filter.ts`), the words it answers itself (`commands.ts`,
151 including `claude` and `codex`), the two engines and the choice between them (`engine.ts`,
152 `codex-engine.ts`, `engines.ts`), replies (`sender.ts`, `format.ts`), the launchd service and app
153 bundle (`service.ts`, `launcher.ts`) and setup checks (`doctor.ts`).
130154- `app/Commands/Uplink.ts`: the `buddy uplink:*` commands.
131- `app/Models/`: `Conversation` (a thread and its Claude session) and `Run` (one text, one run).
155- `app/Models/`: `Conversation` (a thread, its agent session and which agent) and `Run` (one text,
156 one run).
132157- `resources/views/index.stx`: the dashboard.
133- `tests/unit/uplink/`: against a real chat.db-shaped SQLite file and a stub `claude`.
158- `tests/unit/uplink/`: against a real chat.db-shaped SQLite file and stub CLIs.
134159
135160```bash
136161./pantry/.bin/bun test tests/unit/uplink