airpocket 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/CHANGELOG.md +85 -0
  2. package/LICENSE +21 -0
  3. package/README.md +256 -2
  4. package/SECURITY.md +114 -0
  5. package/package.json +42 -4
  6. package/src/agentconfig.js +300 -0
  7. package/src/behind.js +86 -0
  8. package/src/bridges.js +270 -0
  9. package/src/cli.js +92 -0
  10. package/src/doctor.js +215 -0
  11. package/src/hook.js +198 -0
  12. package/src/loginitem.js +122 -0
  13. package/src/models.js +173 -0
  14. package/src/ownterm.js +299 -0
  15. package/src/ports.js +48 -0
  16. package/src/proc.js +184 -0
  17. package/src/public/app.css +581 -0
  18. package/src/public/app.js +1729 -0
  19. package/src/public/fonts/OFL-B612.txt +93 -0
  20. package/src/public/fonts/OFL-IBM-Plex.txt +93 -0
  21. package/src/public/fonts/b612-400.woff2 +0 -0
  22. package/src/public/fonts/b612-700.woff2 +0 -0
  23. package/src/public/fonts/b612-mono-400.woff2 +0 -0
  24. package/src/public/fonts/b612-mono-700.woff2 +0 -0
  25. package/src/public/fonts/plex-400.woff2 +0 -0
  26. package/src/public/fonts/plex-500.woff2 +0 -0
  27. package/src/public/fonts/plex-600.woff2 +0 -0
  28. package/src/public/icon-180.png +0 -0
  29. package/src/public/icon-512.png +0 -0
  30. package/src/public/icon-maskable-512.png +0 -0
  31. package/src/public/index.html +46 -0
  32. package/src/public/launch/375x667@2.jpg +0 -0
  33. package/src/public/launch/375x812@3.jpg +0 -0
  34. package/src/public/launch/390x844@3.jpg +0 -0
  35. package/src/public/launch/393x852@3.jpg +0 -0
  36. package/src/public/launch/402x874@3.jpg +0 -0
  37. package/src/public/launch/414x736@3.jpg +0 -0
  38. package/src/public/launch/414x896@2.jpg +0 -0
  39. package/src/public/launch/414x896@3.jpg +0 -0
  40. package/src/public/launch/420x912@3.jpg +0 -0
  41. package/src/public/launch/428x926@3.jpg +0 -0
  42. package/src/public/launch/430x932@3.jpg +0 -0
  43. package/src/public/launch/440x956@3.jpg +0 -0
  44. package/src/public/manifest.webmanifest +31 -0
  45. package/src/public/map.svg +1 -0
  46. package/src/public/md.js +162 -0
  47. package/src/public/qr.js +605 -0
  48. package/src/public/sw.js +35 -0
  49. package/src/public/where.js +22 -0
  50. package/src/secrets.js +8 -0
  51. package/src/server.js +1744 -0
  52. package/src/service.js +541 -0
  53. package/src/setup.js +837 -0
  54. package/src/shellalias.js +109 -0
  55. package/src/store.js +122 -0
  56. package/src/tailscale.js +139 -0
  57. package/src/tmux.conf +64 -0
  58. package/src/uploads.js +124 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,85 @@
1
+ # Changelog
2
+
3
+ Every change people using Airpocket would notice, newest first. The form is
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions follow
5
+ [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## 0.1.1 - 2026-11-06
8
+
9
+ A fix for typing from the phone. Reported from a real install: the
10
+ conversation kept updating on the phone, and a reply answered "Something went
11
+ wrong on the Mac."
12
+
13
+ ### Fixed
14
+
15
+ - **A terminal that fails as the keys land now says which terminal, and what
16
+ its own program said**, instead of the one message nobody can act on. Reading
17
+ a session and typing into it are different paths: the conversation comes from
18
+ hook events and session files and never touches a terminal, so a failure was
19
+ always in the last step, and that step had nothing around it. Sending a
20
+ message, pressing a key and running a session command are all guarded now,
21
+ and point at `airpocket doctor`.
22
+ - **A session in a Superset terminal is read-only up front when Superset isn't
23
+ installed**, rather than looking writable and failing at the keystroke.
24
+ Airpocket was choosing that route from the ids on record without asking
25
+ whether Superset was still there. The list now says why in a few words, and
26
+ says the thing that helps rather than suggesting `airpocket run`, which
27
+ wouldn't.
28
+
29
+ ### Added
30
+
31
+ - **`airpocket doctor` says when sessions in Superset terminals are
32
+ read-only**, counting only the ones that would really lose their route: an
33
+ agent started with `airpocket run` inside a Superset terminal is reached
34
+ through its tmux pane and is left alone.
35
+
36
+ ## 0.1.0 - 2026-09-17
37
+
38
+ The first version. Airpocket runs on each Mac where you use Claude Code or
39
+ Codex and makes those sessions reachable from a web app on your phone, over
40
+ your own Tailscale network. There is no Airpocket server, account or relay.
41
+ macOS only, Node 20 or newer.
42
+
43
+ ### Added
44
+
45
+ - **One list** of every Claude Code and Codex session on every paired Mac,
46
+ with the ones waiting on you first: finished, waiting for input, needing
47
+ permission. Each row shows the model, effort, permission mode and whether a
48
+ turn is running. Agents running on the Mac that Airpocket hasn't heard from
49
+ yet are counted, with a line on how to bring them in.
50
+ - **The conversation**, read from the agents' own session files rather than the
51
+ terminal: your messages, the replies, and one short label per step, updated
52
+ live. Codex turns are shown while they run.
53
+ - **Reply and control** from the phone: send messages and photos, press keys,
54
+ pick options in on-screen menus, and change model, effort, permission mode
55
+ and fast mode from each agent's own model list. Commands such as compact,
56
+ resume and clear come from a fixed table on the Mac, and are refused while a
57
+ turn runs, a menu is open or unsent text sits in the box.
58
+ - **New sessions** in a project, on a new branch or in an existing workspace,
59
+ for Claude Code or Codex, when Superset is installed.
60
+ - **Files a session wrote, edited or linked**: text, Markdown, code, images,
61
+ PDFs and HTML pages, limited to the session's own folder and checked by
62
+ content. PDFs and pages open from a separate file-only origin through
63
+ two-minute links, and pages there run no scripts.
64
+ - **`airpocket run claude|codex`**: starts the agent in a tmux session of
65
+ Airpocket's own, so the phone can answer a session started in any terminal.
66
+ `airpocket attach` brings back one whose window was closed. Sessions in
67
+ Superset or an existing tmux pane can be answered without it; anything else
68
+ is shown read-only.
69
+ - **`airpocket setup`**: checks the Mac first and stops before changing
70
+ anything if something is missing, then installs the hooks for Claude Code
71
+ and Codex (merged into their settings, with a backup), a login item, the app
72
+ published inside the tailnet with `tailscale serve`, optional `claude` and
73
+ `codex` shell aliases, and a pairing code with its QR. `--dry-run` prints
74
+ the plan.
75
+ - **`airpocket doctor`**: checks the install and says what to do about each
76
+ problem. **`airpocket uninstall`** removes what setup added, taking only its
77
+ own entries out of the agents' config files.
78
+ - **Pairing** with a six-digit code or its QR, one token per phone and per
79
+ Mac, stored on the Mac only as a hash. `airpocket devices` lists paired
80
+ phones and `airpocket revoke` cuts one off at once.
81
+ - **A home-screen web app** with no App Store. It still opens when the Mac
82
+ that served it is asleep, follows Reduce Motion and Reduce Transparency, and
83
+ ships its own fonts.
84
+ - **Security documentation**: [SECURITY.md](SECURITY.md) for reporting a
85
+ problem, and a threat model and review checklist in the repository's `docs`.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Oncel Ozgul
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,257 @@
1
- # Temporary Holding Version
1
+ <h1 align="center"><img src="docs/images/banner.png" width="100%" alt="Airpocket: the dart and the wordmark on a dark chart, over the line &quot;Your agents fly the missions. This is the cockpit.&quot;"></h1>
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ <p align="center">
4
+ <a href="#install-macos">Install</a> ·
5
+ <a href="https://airpocket.sh/#how">How it works</a> ·
6
+ <a href="#security-in-one-paragraph">Security</a> ·
7
+ <a href="https://airpocket.sh/#faq">FAQ</a> ·
8
+ <a href="https://airpocket.sh">airpocket.sh</a> ·
9
+ <a href="https://github.com/airpocket-sh/airpocket/releases">Releases</a>
10
+ </p>
11
+
12
+ <p align="center">
13
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-D7C49E?style=flat-square&labelColor=1B2118" alt="License: MIT"></a>
14
+ <a href="https://github.com/airpocket-sh/airpocket/actions/workflows/test.yml"><img src="https://github.com/airpocket-sh/airpocket/actions/workflows/test.yml/badge.svg?branch=main" alt="Tests on main"></a>
15
+ <img src="https://img.shields.io/badge/platform-macOS-D7C49E?style=flat-square&labelColor=1B2118" alt="Platform: macOS">
16
+ <img src="https://img.shields.io/badge/node-20%2B-D7C49E?style=flat-square&labelColor=1B2118" alt="Node 20 or newer">
17
+ <img src="https://img.shields.io/badge/dependencies-none-8FD14F?style=flat-square&labelColor=1B2118" alt="Dependencies: none">
18
+ </p>
19
+
20
+ Your coding agents, on your phone. Every Claude Code and Codex session on every
21
+ one of your Macs, in one list, with the ones waiting on you first. Read the
22
+ conversation, reply, answer questions, switch models, start new sessions and
23
+ open the files they made, from anywhere.
24
+
25
+ Nothing sits in between: your phone talks to your Macs over your own
26
+ [Tailscale](https://tailscale.com) network. There is no Airpocket server, no
27
+ account and no relay. It works in the terminal you already use. What it needs:
28
+ a Mac with Node 20 or newer and Claude Code or Codex, and Tailscale on the Mac
29
+ and on the phone.
30
+
31
+ <p align="center"><img src="docs/images/phones.png" width="100%" alt="Three phones running Airpocket. First, the session list: three sessions need you (one asking permission to use Bash, one asking which Stripe API version to target, one finished) above two open ones. Second, a session asking &quot;Do you want to proceed?&quot; with three numbered answers and a reply box. Third, a TypeScript file the agent wrote, open with line numbers."></p>
32
+
33
+ > **Status: 0.1.1, young.** It does what this page says and it is tested, but
34
+ > it has run on few Macs other than its author's. See
35
+ > [docs/PLAN.md](docs/PLAN.md) for how it was built, and
36
+ > [CONTRIBUTING.md](CONTRIBUTING.md) to send a change.
37
+
38
+ ## What it will do
39
+
40
+ - **One list** of every session on every paired Mac: needs you, open, earlier.
41
+ - **The conversation**, not the raw terminal: messages, answers, one line per
42
+ step, updated live, including Codex mid-turn.
43
+ - **Reply and control**: send messages, press keys, pick options on screen,
44
+ change model, effort and permission mode, compact, resume and more.
45
+ - **Start sessions** in a project, on a new branch or an existing workspace
46
+ (with Superset).
47
+ - **Open files** a session wrote or linked: text, Markdown, code, images,
48
+ PDFs, pages, under strict rules.
49
+ - **Send a photo**: a screenshot, a whiteboard, the thing on your desk, from
50
+ the phone's camera or its library, with or without a message.
51
+ - **A web app**, added to your home screen. No App Store.
52
+
53
+ <p align="center">
54
+ <img src="site/shots/mfd1-sessions-one-waiting.png" width="280" alt="The session list for one Mac: under Needs you, a Claude Code session needing permission to use Bash and a Codex session asking which Stripe API version to target; under Open, a Claude Code session working, on Opus 5 with high effort.">
55
+ &nbsp;
56
+ <img src="site/shots/mfd3-controls-model-effort.png" width="280" alt="The Controls sheet for a Claude Code session: Opus 5 active and Sonnet 5 picked to apply next, effort set to high, permission mode buttons, and session commands including Compact, Resume and Clear.">
57
+ </p>
58
+
59
+ ## Any terminal
60
+
61
+ It works in the terminal you already use: Terminal, iTerm2, Ghostty, Warp, a VS
62
+ Code or Cursor pane. The one change is how you start the agent:
63
+
64
+ ```sh
65
+ airpocket run claude # instead of claude; anything after the name goes to it
66
+ airpocket run codex resume --last
67
+ airpocket attach # back to one you closed the window on
68
+ ```
69
+
70
+ Setup offers to alias `claude` and `codex` to that, and then you type exactly
71
+ what you typed before. Sessions in Superset or tmux need no change: the phone
72
+ answers them as they are.
73
+
74
+ <p align="center">
75
+ <img src="site/shots/mfd2-question-answered.png" width="280" alt="A Claude Code session on the phone, asking before it runs a shell command: &quot;Do you want to proceed?&quot; with the numbered answers Yes; Yes, and don't ask again for npm test commands; and No, and tell Claude what to do differently. A reply box sits underneath.">
76
+ </p>
77
+
78
+ Why `run` is there: the phone can watch a session from its transcript and hooks
79
+ alone, but to answer one Airpocket has to type into its terminal, and a tmux
80
+ pane or a Superset terminal is what lets it. `run` starts the agent in a tmux
81
+ session of Airpocket's own (its own socket in Airpocket's data folder, never
82
+ your tmux server or `~/.tmux.conf`), tuned to stay out of sight: no status bar,
83
+ no prefix key, Esc with no delay, Shift+Enter, the mouse wheel for scrollback,
84
+ copying to the clipboard. Closing the window doesn't stop the agent: the phone
85
+ can still answer it, and `airpocket attach` brings it back. Inside tmux or
86
+ Superset already, `run` starts the agent there directly.
87
+
88
+ A session started the plain way, outside all of that, still shows on the phone,
89
+ read-only, with a line saying how to bring it in.
90
+
91
+ ## Install (macOS)
92
+
93
+ **Airpocket runs on each Mac whose sessions you want to see.** Install it and
94
+ run setup on every one of them, and pair your phone with each. There is no
95
+ shared server and nothing passes between your Macs: the phone keeps one token
96
+ per Mac and asks each one itself.
97
+
98
+ You need, on each Mac: macOS, Node 20 or newer,
99
+ [Tailscale](https://tailscale.com/download/mac) signed in with **MagicDNS and
100
+ HTTPS certificates turned on for your tailnet**, and Claude Code or Codex. On
101
+ the phone: Tailscale, signed in to the same tailnet. Setup also checks for tmux,
102
+ which `airpocket run` uses (above); if it's missing, `brew install tmux`.
103
+
104
+ ### Which tailnet you land in
105
+
106
+ Tailscale sorts people by the email domain they sign in with, so signing in
107
+ with a **work address puts you in your company's tailnet**, not one of your
108
+ own. There you are a member: an admin has to approve your device, the admin
109
+ console won't open for you, and MagicDNS and HTTPS certificates — both
110
+ tailnet-wide, both needed here — are someone else's switch to flip. Setup stops
111
+ with that in plain words rather than half-installing.
112
+
113
+ Signing in with a **personal account** gives you your own tailnet where you are
114
+ the admin, and turning HTTPS certificates on is one switch on the
115
+ [DNS page](https://console.tailscale.com/admin/dns). Either is fine — a shared
116
+ tailnet only needs its admin to do it once, for everyone. Issuing a certificate
117
+ publishes the machine's DNS name in public certificate-transparency logs; what
118
+ it serves stays inside your tailnet.
119
+
120
+ Sharing a tailnet doesn't share sessions: every Mac still asks the phone for a
121
+ pairing code of its own, and hands out its own token.
122
+
123
+ ### Install it
124
+
125
+ ```sh
126
+ npm install -g airpocket
127
+ airpocket setup --dry-run # every change it would make; changes nothing
128
+ airpocket setup
129
+ ```
130
+
131
+ No dependencies: the tarball is Airpocket and the fonts the phone app uses,
132
+ and nothing else.
133
+
134
+ ### Or from a clone
135
+
136
+ To read the code as you run it, or to send a change:
137
+
138
+ ```sh
139
+ git clone https://github.com/airpocket-sh/airpocket.git
140
+ cd airpocket
141
+ npm install -g . # the airpocket command, from your clone
142
+ airpocket setup
143
+ ```
144
+
145
+ Either way, setup copies Airpocket into its data folder and runs that copy, so
146
+ the service keeps working if you move or delete the clone (see
147
+ [Keeping it up to date](#keeping-it-up-to-date)).
148
+
149
+ Setup checks first and stops with a plain explanation if something is
150
+ missing. Then it:
151
+
152
+ - adds Airpocket's hooks to `~/.claude/settings.json` and `~/.codex/hooks.json`
153
+ (or under `$CLAUDE_CONFIG_DIR` and `$CODEX_HOME`). It merges: every other
154
+ setting and hook stays as it was, a timestamped backup is written next to the
155
+ file first, and a file that isn't valid JSON is left alone. Running it again
156
+ adds nothing twice.
157
+ - adds a login item (`~/Library/LaunchAgents/sh.airpocket.service.plist`) that
158
+ starts Airpocket at login and brings it back after a crash. It runs the copy
159
+ of Airpocket kept in its data folder, not your clone, so moving or deleting
160
+ the clone doesn't stop it.
161
+ - publishes the app and its file-only origin inside your tailnet with
162
+ `tailscale serve` (never `funnel`), on ports nothing else uses: 443 and
163
+ 8443 when they are free.
164
+ - asks whether to add two aliases to your shell profile (`~/.zshrc` or
165
+ `~/.bash_profile`), so `claude` and `codex` start where the phone can
166
+ answer them (above). `--alias` or `--no-alias` decides without asking.
167
+ Marked, backed up first, and removed by uninstall.
168
+ - prints a pairing code and its QR.
169
+
170
+ Codex asks you to review new hooks the next time it starts: choose to trust
171
+ Airpocket's, or open `/hooks`. A Codex session shows up on the phone once
172
+ you've sent it a first message. In Superset it's different: Superset's `codex`
173
+ wrapper starts Codex with the trust check bypassed, so the hooks run there
174
+ without the review (and the phone's "not trusted yet" line is about Codex
175
+ started anywhere else).
176
+
177
+ Claude Code picks up the hooks while it runs, so sessions started before setup
178
+ need no restart: each appears the next time you prompt it. Codex reads its
179
+ hooks only when it starts, so restart a Codex session that was running before
180
+ setup. Until then the phone says how many Claude Code and how many Codex
181
+ agents are running that haven't checked in, and whether Codex's hooks still
182
+ need trusting; setup prints the same when it finishes.
183
+
184
+ ```sh
185
+ airpocket doctor # checks everything, says what to do; exits 1 if something is broken
186
+ airpocket pair # a new pairing code
187
+ airpocket devices # paired phones; airpocket revoke <id> cuts one off
188
+ airpocket uninstall # removes exactly what setup added; asks before deleting paired phones
189
+ ```
190
+
191
+ **Tested so far:** setup, doctor and uninstall against a temporary home folder
192
+ (with the real launchd in a trial), Claude Code end to end with real
193
+ sessions, and Codex against recorded session files and a real Codex's hooks
194
+ (installed, trusted, firing). Codex with real model replies driven from the
195
+ phone has not been run end to end yet. `airpocket run` with a real Claude in a
196
+ hidden terminal window (keys, paste, resize, scrollback, detach and attach).
197
+
198
+ ### Keeping it up to date
199
+
200
+ ```sh
201
+ cd airpocket
202
+ git pull
203
+ airpocket setup
204
+ ```
205
+
206
+ The `airpocket` command runs from your clone, but the service, the hooks and
207
+ the login item run the copy setup made in the data folder. A `git pull` alone
208
+ changes the command and nothing else; running setup again replaces the copy
209
+ and restarts the service on it. Paired phones stay paired; the pairing code
210
+ setup prints at the end can be ignored.
211
+
212
+ `airpocket doctor` warns when the version the service runs differs from the
213
+ command's. It compares the version numbers in `package.json`, so a pull that
214
+ doesn't change the version passes unnoticed: run setup after every pull.
215
+
216
+ ## Photos
217
+
218
+ The message box has a photo button. Pick from the library or take one, up to
219
+ four to a message, and send it with or without words.
220
+
221
+ The phone shrinks each photo to 2200px and re-encodes it before it goes, which
222
+ also drops what the camera wrote into the file, the place it was taken
223
+ included. The Mac keeps it in Airpocket's own data folder
224
+ (`~/Library/Application Support/Airpocket/uploads`, 0600), never in the project
225
+ the agent is working in, and types the path into the session as part of your
226
+ message, so the agent reads it with the tools it already has. Photos are
227
+ deleted after a week, and only the last forty are kept.
228
+
229
+ Because they sit outside the project, the agent may ask before reading one —
230
+ answer that from the phone like any other prompt. To stop it asking, allow that
231
+ one folder in `~/.claude/settings.json`:
232
+
233
+ ```json
234
+ { "permissions": { "allow": ["Read(//Users/you/Library/Application Support/Airpocket/uploads/**)"] } }
235
+ ```
236
+
237
+ ## Security in one paragraph
238
+
239
+ Airpocket listens on 127.0.0.1 and is published only inside your tailnet. Each
240
+ phone gets its own token for a one-time pairing code; the Mac keeps only
241
+ hashes. The phone never sends a file path or command text: it names a session
242
+ and an action, and the Mac looks up the rest in its own records. Files are
243
+ limited to what a session made or mentioned, inside its own folder, checked by
244
+ content, and PDFs and pages open from a separate file-only origin through
245
+ two-minute links.
246
+
247
+ **Know this before you pair.** A paired phone can type anything into your
248
+ agents, including shell commands (in Claude Code and Codex, a message that
249
+ starts with `!` runs as one), and start new sessions. Its token doesn't expire:
250
+ it works until you revoke it on that Mac. `airpocket devices` lists the paired
251
+ phones, and `airpocket revoke <id>` cuts one off at once. Pair only phones you
252
+ control, and revoke a lost one straight away.
253
+
254
+ ## License
255
+
256
+ MIT. The fonts in `src/public/fonts` (B612, B612 Mono, IBM Plex Sans) are under the
257
+ SIL Open Font License; their licences sit next to them.
package/SECURITY.md ADDED
@@ -0,0 +1,114 @@
1
+ # Security policy
2
+
3
+ Airpocket lets a phone read and type into coding agents on your Macs, so its
4
+ security matters more than its size suggests. Thank you for looking.
5
+
6
+ ## Reporting a vulnerability
7
+
8
+ **Please don't open a public issue, discussion or pull request for a security
9
+ problem.**
10
+
11
+ Report it privately through GitHub: on this repository, open the **Security**
12
+ tab and choose **Report a vulnerability**. Only the maintainers can see the
13
+ report and the conversation that follows.
14
+
15
+ If that route isn't open to you — GitHub only offers it on a public
16
+ repository, and not everyone wants a GitHub account to report a bug — email
17
+ **info@airpocket.sh** instead. It reaches the same people.
18
+
19
+ A good report says:
20
+
21
+ - what the problem is, and what someone could do with it;
22
+ - where it is (file, function, route or command);
23
+ - the version or commit you tested;
24
+ - how to see it happen on your own Mac, phone and tailnet.
25
+
26
+ Leave out real device tokens, pairing codes, hook secrets, tailnet names,
27
+ email addresses and anyone's conversations or files. Replace them with
28
+ placeholders.
29
+
30
+ ## What to expect
31
+
32
+ - **Within 7 days:** we confirm we received the report.
33
+ - **Within 14 days:** a first assessment: in scope or not, how serious, and
34
+ what happens next.
35
+ - **Until it's fixed:** an update at least every 14 days.
36
+ - **A fix** as soon as its severity calls for it, released with a GitHub
37
+ security advisory that describes the problem and the fix.
38
+ - **Disclosure:** please keep the details private until the advisory is out,
39
+ or 90 days after your report, whichever comes first. If a fix needs longer,
40
+ we'll ask you and agree on a date together.
41
+ - **Credit** in the advisory, under the name you choose, if you want it.
42
+
43
+ Airpocket is a free project. There is no bug bounty.
44
+
45
+ ## Supported versions
46
+
47
+ Only the latest release gets security fixes. Fixes are not backported. Until
48
+ the first release, that means the `main` branch.
49
+
50
+ ## Scope
51
+
52
+ In scope:
53
+
54
+ - The Airpocket service: the phone app server and its API, the file-only
55
+ server and the hook endpoint.
56
+ - The hook (`src/hook.js`), the `airpocket` command, and the setup and
57
+ uninstall steps once they ship.
58
+ - The phone web app (`src/public`).
59
+ - Anything that breaks a promise in [docs/THREAT-MODEL.md](docs/THREAT-MODEL.md)
60
+ or in the posture below. For example: reaching the API without a valid
61
+ token; opening a file outside the file rules; typing into a terminal that
62
+ isn't the agent's; a token, secret or file's contents in a log; data leaving
63
+ the user's own machines.
64
+
65
+ Out of scope:
66
+
67
+ - A Mac account that is already compromised, including any process running as
68
+ that user.
69
+ - Physical access to an unlocked phone.
70
+ - What a user's own agent chooses to do.
71
+ - Bugs in Tailscale, Claude Code, Codex, Superset, tmux, macOS or iOS. Please
72
+ report those to their makers. If Airpocket *uses* one of them unsafely, that
73
+ is in scope.
74
+ - Setups Airpocket doesn't make: `tailscale funnel`, listening on addresses
75
+ other than 127.0.0.1, another proxy in front of it.
76
+ - Denial of service by someone already on your tailnet or your Mac.
77
+ - The residual risks already listed in the threat model, unless you show one
78
+ is worse than written there.
79
+
80
+ When testing, use only Macs, phones and tailnets that are yours. Don't read,
81
+ change or keep other people's data; if you come across any, stop and tell us.
82
+ We won't pursue anyone who follows this policy in good faith.
83
+
84
+ ## Standing posture
85
+
86
+ These hold for every release. A change that breaks one of them won't be
87
+ accepted.
88
+
89
+ - **Tailnet only.** Every server listens on 127.0.0.1. `airpocket setup`
90
+ publishes the app and the file-only origin with `tailscale serve`, which
91
+ reaches only devices on your tailnet. Airpocket never uses `tailscale
92
+ funnel` and never publishes anything to the public internet. The hook
93
+ endpoint is never published at all.
94
+ - **No cloud.** There is no Airpocket server, relay or hosted service. Your
95
+ phone talks straight to your Macs over your own Tailscale network.
96
+ - **No account.** Nothing to sign up for. Each phone pairs with each Mac using
97
+ a short-lived code shown on that Mac, and gets its own token; the Mac keeps
98
+ only a hash of it.
99
+ - **Nothing leaves your machines.** Airpocket has no telemetry, analytics,
100
+ crash reporting or update checks, and makes no network requests except
101
+ between your phone and your Macs. Your conversations, files and tokens stay
102
+ on your devices. Your agents still talk to their own providers, as they do
103
+ without Airpocket, and Tailscale's coordination service knows which devices
104
+ you have, not what they send.
105
+ - **The phone asks, the Mac decides.** The phone names a session and an
106
+ action. It never sends a file path, a terminal, or the text of a Controls
107
+ command; the Mac looks those up in its own records and fixed tables.
108
+ - **One way in, one place to land.** The only thing a phone can put on the Mac
109
+ is a photo for a session, and it lands in Airpocket's own data folder, 0600,
110
+ never in a project. The bytes have to be an image the agents can read, the
111
+ phone gets a ref rather than a path, and old photos are swept.
112
+
113
+ How Airpocket defends each of these, and what it knowingly doesn't, is in
114
+ [docs/THREAT-MODEL.md](docs/THREAT-MODEL.md).
package/package.json CHANGED
@@ -1,6 +1,44 @@
1
1
  {
2
2
  "name": "airpocket",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.1",
4
+ "description": "Your Claude Code and Codex sessions, from every Mac, on your phone.",
5
+ "keywords": [
6
+ "claude-code",
7
+ "codex",
8
+ "tailscale",
9
+ "iphone",
10
+ "terminal",
11
+ "agents",
12
+ "macos"
13
+ ],
14
+ "homepage": "https://airpocket.sh",
15
+ "bugs": {
16
+ "url": "https://github.com/airpocket-sh/airpocket/issues"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/airpocket-sh/airpocket.git"
21
+ },
22
+ "license": "MIT",
23
+ "author": "Oncel Ozgul",
24
+ "main": "src/server.js",
25
+ "bin": {
26
+ "airpocket": "src/cli.js"
27
+ },
28
+ "files": [
29
+ "src/",
30
+ "SECURITY.md",
31
+ "CHANGELOG.md"
32
+ ],
33
+ "os": [
34
+ "darwin"
35
+ ],
36
+ "engines": {
37
+ "node": ">=20"
38
+ },
39
+ "scripts": {
40
+ "start": "node src/server.js",
41
+ "test": "node --test",
42
+ "smoke": "node .github/smoke.js"
43
+ }
44
+ }