open-dots / mobile
AGENTS.md6.9k starsChanged 6 days agoApache-2.0View on GitHub
This is the native phone app for Suparagent: Expo (managed) and React Native, TypeScript, Expo Router. It pairs with the user's own server and talks to the same /api/v1 API as the web UI, as a paired device with the chat scope (see docs/AUTH.md). It adds no server of its own. Do not trust memory for Expo, EAS or React Native APIs. Read the major version of expo in package.json, then use the matching docs at https://docs.expo.dev/versions/v<major>.0.0/ and the index…
Adopted by
Steady: 0 new projects took it in the last 4 weeks, none the 4 weeks before.thin data
Who's talking about Anil-matcha/open-dots
- A Hacker News story“Open Dots: Open-Source Alternative to OpenAI Dots”Hacker News · Sep 29, 2026 · 3 points
- reacher-z/Awesome-CUA“Add Open Duet (open-dots) (Anil-matcha/open-dots)”GitHub · Nov 7, 2026
- reacher-z/Awesome-CUA“Curate CUA resources batch w1-031 (Codex Bridge to ChatGPT, Open Duet (open-dots), +3 more)”GitHub · Nov 7, 2026
- sudosubin/agents.nix“agent-skills.github.anil-matcha.open-dots: 0-unstable-2026-10-16 → 0.1.0”GitHub · Oct 16, 2026
- sudosubin/agents.nix“agent-skills.github.anil-matcha.open-dots: 0-unstable-2026-10-15 → 0-unstable-2026-10-16”GitHub · Oct 16, 2026
The biggest 5 of 15 mentions linking to the repository that our crawl found. Each line is their own headline.
See all 15
Talked about on GitHub and Hacker News (15 times).
On GitHub · 14
- Nov 7, 2026Add Open Duet (open-dots) (Anil-matcha/open-dots) — reacher-z/Awesome-CUA0 reactions
- Nov 7, 2026Curate CUA resources batch w1-031 (Codex Bridge to ChatGPT, Open Duet (open-dots), +3 more) — reacher-z/Awesome-CUA0 reactions
- Oct 16, 2026agent-skills.github.anil-matcha.open-dots: 0-unstable-2026-10-16 → 0.1.0 — sudosubin/agents.nix0 reactions
- Oct 16, 2026agent-skills.github.anil-matcha.open-dots: 0-unstable-2026-10-15 → 0-unstable-2026-10-16 — sudosubin/agents.nix0 reactions
- Oct 15, 2026agent-skills.github.anil-matcha.open-dots: 1bb35ae → 64e48f6 — sudosubin/agents.nix0 reactions
9 more on GitHub
- Oct 15, 2026agent-skills.github.anil-matcha.open-dots: 0-unstable-2026-10-14 → 0-unstable-2026-10-15 — sudosubin/agents.nix0 reactions
- Oct 14, 2026agent-skills.github.anil-matcha.open-dots: 741aa6e → 9f2b473 — sudosubin/agents.nix0 reactions
- Oct 14, 2026agent-skills.github.anil-matcha.open-dots: 0-unstable-2026-10-13 → 0-unstable-2026-10-14 — sudosubin/agents.nix0 reactions
- Oct 13, 2026agent-skills.github.anil-matcha.open-dots: 0-unstable-2026-10-07 → 0-unstable-2026-10-13 — sudosubin/agents.nix0 reactions
- Oct 7, 2026agent-skills.github.anil-matcha.open-dots: 0-unstable-2026-10-05 → 0-unstable-2026-10-07 — sudosubin/agents.nix0 reactions
- Oct 5, 2026agent-skills.github.anil-matcha.open-dots: 0-unstable-2026-10-03 → 0-unstable-2026-10-05 — sudosubin/agents.nix0 reactions
- Oct 3, 2026agent-skills.github.anil-matcha.open-dots: init at 0-unstable-2026-10-03 — sudosubin/agents.nix0 reactions
- Sep 30, 2026📰 Hacker News AI 社区动态日报 2026-09-30 — 96loveslife/big_model_radar0 reactions
- Sep 30, 2026Open Dots — 承認ゲート付きのセルフホスト AI ワークスペースのビジュアル解説 — 53able/docs-site0 reactions
On Hacker News · 1
- Sep 29, 2026Open Dots: Open-Source Alternative to OpenAI Dots3 points
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 31,843 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository3 other files it gives its agents.
- AGENTS.mdAGENTS.md
- frontend/AGENTS.mdAGENTS.md
- frontend/CLAUDE.mdCLAUDE.md
The file
We split this AGENTS.md into the rules it gives an agent
6 rules. About 1 is common, 1 is distinctive, and 4 are very specific to this project.
≈1
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- could be automatic: a setting could enforce it
- Very specific: line 7
Do not trust memory for Expo, EAS or React Native APIs.
- Very specific: line 9
Add packages with npx expo install <package>, not npm install, so versions match the SDK.
- Very specific: line 11
Run npx expo install --check after dependency changes.
- Very specific: line 12
Never create or edit ios/ or android/ by hand.
- Distinctive: line 25
All of these work on Windows, macOS and Linux.
- Common: line 47
No secrets in the repo. Signing keys, store credentials and push credentials are CI secrets only.
≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Mobile app instructions
This is the native phone app for Suparagent: Expo (managed) and React Native, TypeScript, Expo Router. It pairs with the user's own server and talks to the same /api/v1 API as the web UI, as a paired device with the chat scope (see docs/AUTH.md). It adds no server of its own.
Expo changes every release
Do not trust memory for Expo, EAS or React Native APIs. Read the major version of expo in package.json, then use the matching docs at https://docs.expo.dev/versions/v<major>.0.0/ and the index at https://docs.expo.dev/llms.txt.
- Add packages with
npx expo install <package>, notnpm install, so versions match the SDK. Dev tools go indevDependencies. react,react-domandreact-test-renderermust stay on the exact same version.- Run
npx expo install --checkafter dependency changes. - Never create or edit
ios/orandroid/by hand; they are generated fromapp.jsonand config plugins. They are Git-ignored. - Routes live in
src/app/. Keep other code (components, hooks, API client) and all tests outside it: every file insrc/app/is bundled as a route, so a test there breakscheck:bundle. Tests live insrc/tests/.
Checks (run from this directory)
npm ci
npm run lint
npm run typecheck
npm test
npm run check:bundle # exports the JS bundle for iOS and Android; no device or Xcode neededAll of these work on Windows, macOS and Linux. Building or running the iOS app needs macOS; say which OS a check was actually run on. Running on a device needs a development build or Expo Go.
Layout
src/app/: screens only (Expo Router)._layout.tsxguards the routes: paired phones seeindex(the conversation list),thread/[id]andsettings; unpaired ones seepairandscan.src/components/: pieces shared by screens (transcript-row,composer,approval-card,keyboard-screen,markdown). Attachments:lib/attachments.ts(limits, the multipart body, readingturn.started's list) andlib/pick-attachments.ts(the two system pickers). The multipart body is built by hand becauseexpo/fetchcannot send{ uri }parts. Agents:lib/agents.tsandapp/new.tsx(the picker, a modal route).New conversationgoes straight to a new conversation when the server has no agents, and opens the picker otherwise. A phone paired with themanagescope ("Chat, files and agents") can also create and edit agents:app/agents/(the list, and the editor at/agents/newand/agents/<id>),lib/agent-draft.ts(fields, the server's limits, what is sent, refusals in words),lib/engines.ts(the engines and models for the pickers) andcomponents/form.tsx(the form controls). The editor sends only what changed and never a workspace folder, "Accept edits", connected apps or the lead role: the server refuses those from any device withoutadmin(field_requires_admin), and the screens do not offer them. Deleting an agent stays in the web app. The same scope can make, change and delete rooms:app/room-settings.tsx(?id=newor a room id),app/room-details.tsx(instructions, routing, members, hold or resume, delete after typing the name),lib/room-draft.tsandcomponents/member-picker.tsx; a change to the members sends the roster the form was opened with (expected_member_ids) so the server can refuse a stale edit.canManageAgents(scopes)only decides what to show; the server enforces it. Rooms:lib/rooms.ts(the feed reducer, mentions, approvals),lib/use-room.tsandapp/rooms/. A room's messages are the stored events of its own thread, so the phone follows that thread with the same stream as a conversation. A chat-only device cannot create or edit rooms (docs/AUTH.md), so there is no such screen. The room lists its pending approvals without a thread id, soloadRoomApprovalsasks each member's own thread; an answer goes to that thread. Colors: never write a color in a component. Take it fromlib/theme.ts(useStyles(createStyles)); its values are the web app's tokens fromfrontend/app/globals.cssandtheme-drift.test.tsfails when they differ, so change a color in the web file first, then intheme.ts(warnBackgroundis the only phone-only color); the camera overlay and the translucent chip on the person's bubble are the only exceptions, andtheme.test.tsxchecks every text and background pair for a 4.5:1 contrast in both looks.lib/markdown.tsis the Markdown reader: no HTML, and onlyhttp(s)links are followed.src/lib/: everything else.server-url,pairing-link,pairing-api,api,sseandtranscriptare plain TypeScript with no React Native imports, so they are easy to test;credentialsis the only place the token is stored;auth-contextholds the pairing state;use-apianduse-threadtie the API to React.- The chat reads a thread by following its event stream from the last event seen (
sse.ts). A reconnect sendsLast-Event-ID, andtranscript.tsapplies each stored event at most once, so a replay can never show anything twice. If the platform cannot read a response as it arrives,followThreadfalls back to pagingGET /threads/{id}/events. Event types the app does not draw become one muted row; metadata-only types are skipped. - Approvals: the oldest pending approval is pinned above the composer with every input of the call (long values cut, with "Show all") and Allow and Deny. The card never decides for the person: it waits for the stream's
approval.resolvedto show the result. "Always allow" rules are not part of the app. - Hosted workspace (the paid cloud workspace at suparagent.ai, an alternative to pairing with your own server): a hosted phone is a
pairedphone whoseserveris the hosted origin and whosetokenis its own workspace token, withhosted: { email, accountToken }on the auth state, so every screen andcreateApiwork unchanged.lib/hosted.tsis the account API (email code sign-in, status, wake, foreground signal, this phone's workspace token; plain TypeScript, one fixed origin that a release build cannot change, every answer read tolerantly, no token ever logged or put in a URL),lib/hosted-flow.tswaits for a sleeping workspace and recovers a rejected token (time is injected),lib/hosted-credentials.tskeeps the account session and the install id in the secure store apart from the workspace token (lib/credentials.tsmarks ithosted),components/hosted-gate.tsxshows the app only while the workspace is ready and sends the foreground signal,app/hosted.tsxis the sign-in. Rules that the tests pin: reading the state never starts anything; only an explicit wake does, once, when the app opens or the person asks; a blocked state (plan ended, hours used up) is shown and never retried by itself; a 503 from a call or stream only reports that the workspace is asleep (onUnavailable), it never wakes it; a 401 asks the service for a new token at most every 30 seconds and signs out only if the account sign-in ended too; the two tokens are never mixed; a hosted phone has no agent or room editing (the service never grantsmanageto it). File access is opt-in: a hosted phone starts withchat, and the Settings switch "File access" callshostedSetFilesinauth-context.tsx, which asks for a new token (filesorchat) with the account session and replaces the old one; it needs a running workspace and never wakes it, and a renewed token keeps the chosen scope. src/tests/: Jest tests. Jest's React Native environment replacesfetchwith a stub, so unit tests pass a fakefetchinto thelibfunctions. To check against a real server, run the compiledlibcode under plain Node against a throwaway backend (SQLite file, the CI test key,python -m app.auth.cli pairing-code --scope chat).
Rules for this package
- Scope is fixed by the maintainer's design note: pair, threads, chat with stop, approvals, plus the features added one by one afterwards (Markdown, attachments, dark theme, agent picker, rooms, conversation search, and the hosted workspace, decided as M-D5 on 2026-11-06). Do not add voice, push, settings editing or other features without a decision.
- Touch targets: a control the person taps is at least
touch.min(44) points inlib/theme.ts; a smaller-looking one getshitSlopto that size.touch-targets.test.tsxchecks the main ones. - Release builds shrink and rename code (R8), which Expo Go does not. The QR scanner needs
extraProguardRulesfor ML Kit inapp.json(app-config.test.tschecks it): without them the camera shows and never reads a code, and a rule narrower than all ofcom.google.mlkit.**crashed the app at launch. Check a change that adds a native library in a signed release build on a phone, not only in Expo Go. - Typeface: Geist and Geist Mono, as on the web. Import
TextandTextInputfrom@/components/text, never from React Native, so a style'sfontWeightbecomes the right font file (lib/fonts.ts,lib/font-assets.ts); writefontFamily: MONOfor code. A new weight needs its file added tofont-assets.tsand a name inFAMILY;fonts.test.tsxchecks they match. The fonts load once in_layout.tsxand the app falls back to the system font if they cannot. - The app is a chat-scope client. It must reject a pairing session that has admin scope, and must not rely on hiding screens as authorization.
- The bearer token goes only into the OS secure store, never into logs, URLs or plain storage.
- The app talks to the server over HTTPS, or over plain HTTP when the host is on the person's own network (
isLocalHostinlib/server-url.ts: localhost, loopback, 10/8, 172.16/12, 192.168/16, 169.254/16,::1,fc00::/7,*.local), in dev and release builds alike (D-025).normalizeServerUrlis the one rule:pairDevice,createApiand a saved session all re-check it, and a reply from plain HTTP on a non-local host (a redirect) is not used. The OS cleartext settings (usesCleartextTraffic,NSAllowsLocalNetworking, set inapp.json) only make this possible; they cannot match IP ranges, so the JS rule is the real limit. Do not widen it (any other host,100.64/10) without a maintainer decision. - Decode API responses tolerantly: ignore unknown fields and show unknown event types as a generic row.
- No secrets in the repo. Signing keys, store credentials and push credentials are CI secrets only; a contributor must be able to build and run against their own server without any of them.
- Bundle id
ai.suparagent.appand URL schemesuparagentare fixed. The display name inapp.jsonis Suparagent and can still be changed before a store release.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

