Weft turns your phone into a secure control surface for GitHub Copilot CLI. Follow live work, send prompts, approve tool calls, resume sessions, and open a shared terminal while the actual process keeps running on your laptop.
Open the app · Read the docs · Try the in-browser demo · View releases
|
|
| Stay in the loop | Stay in control | Stay private |
|---|---|---|
| Watch replies, tool calls, edits, and status stream live. | Prompt, steer, stop, change mode, and answer native approvals from your phone. | Session traffic is encrypted end to end; the relay forwards ciphertext and stores no session content. |
| Resume existing work or launch a session in a registered project. | Use voice, image attachments, clipboard tools, keep-awake controls, and a shared terminal. | Pairing keys, transcripts, and session metadata remain on your devices. |
Weft is not a remote desktop and it does not move your workspace to the cloud. Copilot and your tools continue to run under your account on the laptop; the phone provides a focused, mobile-first interface to that work.
Install the prebuilt extension and Device Station. No repository clone, mobile app-store download, or relay account is required.
# Windows (PowerShell)
irm https://useweft.netlify.app/install.ps1 | iex# macOS / Linux
curl -fsSL https://useweft.netlify.app/install.sh | bashStart the Device Station:
weft startThen open useweft.netlify.app on your phone, choose
Scan QR to pair, and scan the code shown in the terminal. Leave weft start running
while you use the phone.
Already paired? Run
weft startnormally. Useweft start --new-deviceonly when replacing the trusted phone or after clearing the phone browser's storage.
- Live Copilot sessions — stream replies and tool calls, send follow-ups, attach up to six images, and use Vox for hands-free prompting.
- Native approval relay — allow once, allow for the session, or deny the exact action Copilot requested.
- Session control — stop an active turn, queue the next instruction, and use supported slash
commands through one searchable command flow. Commands can run directly, request text, or offer
a curated option list;
/modelexposes supported model choices without leaking internal IDs. Weft reports command failures from Copilot instead of claiming a model change succeeded. - Multi-device workspace — use one phone to move among paired laptops, registered projects, and active or historical sessions.
- Safe launch recovery — reconnect to slow Start and Resume operations instead of silently creating duplicate Copilot processes.
- Shared terminal — open and resume one real shell on supported Windows laptops. See terminal controls and access boundaries.
- Explore between turns — use compact header tiles for Discover, Watch, Play, and Unwind, or swipe left from the right edge of Chat to open Discover and return with one Back. A concise Copilot presence tile shows the current activity and useful live response context without turning Explore into a second debug log. Discover provides a balanced animated swipe deck of 50 offline cards, alongside two lightweight games, guided rest activities, and an optional explicitly loaded third-party short-video widget.
- AES-256-GCM end-to-end encryption. Pairing uses ECDH and a fresh handshake nonce.
- Content-free relay. Supabase Realtime or a self-hosted Dev Tunnel carries encrypted envelopes without storing session content.
- Local continuity. Device configuration and persistent pairing material live under
~/.weft/; phone session data remains in local device storage. - Explicit authority. The phone receives the same approval boundaries exposed by the underlying Copilot session. Weft does not invent an automatic approval policy.
- Explore stays local by default. The live Copilot dock projects data already present in the active encrypted session, while the shuffled Discover deck, reading progress, Play, Unwind, and scores remain on the phone. Attention states return to the canonical chat controls. The optional Watch provider loads only after an explicit tap and receives no Weft prompt, repository, filename, tool, or session context.
Read the full security model, privacy policy, and pairing protocol.
- Every dormant Copilot extension publishes one small user-local presence record and holds one idle local lifecycle endpoint. It performs no remote/network access, pairing cryptography, QR work, logging, diagnostics, polling, heartbeat, retry timer, or other timer.
- Filesystem state provides discovery and crash recovery; the Windows named pipe or Unix-domain socket provides authenticated live commands such as activate, status, controller replacement, and quiesce. Station connects only for a command and then disconnects.
- After pairing, prompts, events, approvals, streaming, and terminal traffic flow directly between the phone and session over the encrypted relay. Active phone traffic does not pass through Device Station or the local lifecycle endpoint.
/clearends the current phone attachment. The replacement Copilot session starts dormant and requires fresh activation through Station or/weft.- Completed lifecycle operations and unclaimed recovery identities are retained for three days, unless still referenced by a live runtime or unresolved operation.
- A confirmed takeover of a responsive runtime replaces the current phone controller immediately without restarting Copilot. Restart-and-Resume is reserved for a separately confirmed, revalidated unresponsive-owner flow.
+------------------------------+ +------------------------------+ +-------------------------------+
| Weft Mobile | | Encrypted relay | | Laptop terminal |
| (React PWA + Capacitor) | | Supabase or Dev Tunnel | | copilot (parent) |
| | | private:weft:<channelId> | | └─ extension.mjs (child) |
| • scans QR (channel + grant)| WSS | • in-memory pub/sub | WSS | • joinSession() |
| • ECDH → AES-256-GCM | <----> | • zero DB persistence | <----> | • onPermissionRequest→relay |
| • decrypts token stream | | • RLS-gated private chan | | • on(assistant.message)→push|
| • native-style approval UI | | | | • session.send(phone prompt)|
| • prompt + mode controls | | | | • QR via session.log() |
+------------------------------+ +------------------------------+ +-------------------------------+
all payloads E2E-encrypted; Supabase sees ciphertext only
Three layers, one monorepo:
| Workspace | What it is |
|---|---|
extension/ |
The Copilot CLI extension (joinSession) + a local test harness that mimics the phone with no Supabase needed. |
shared/ |
Contracts imported by both ends: message schema, E2E crypto (ECDH→AES-GCM), and pluggable local, Supabase, and WebSocket relay transports. |
mobile/ |
React + Vite + Capacitor app shipped as the supported PWA (useweft.netlify.app), with in-browser camera QR scanning and an Android development shell. |
- Approval = pure relay of native Copilot behavior. The extension forwards the native
permission prompt to the phone via
onPermissionRequestand resolves with the user's tap. No custom policy or automatic decision timeout; the prompt stays pending until answered or the session ends. - Content-free relay storage. Relay infrastructure forwards encrypted envelopes and does not store session content. Providers may still process ordinary connection metadata such as IP addresses, timestamps, and channel identifiers.
- End-to-end encrypted. The QR carries the laptop public key plus a short-lived, single-use pairing grant; ECDH + a fresh handshake nonce derives the AES-256-GCM key. Supabase only ever sees ciphertext.
- Local continuity. The phone stores session metadata, transcript history, preferences,
and pairing keys locally. Persistent Device Station keys and configuration stay under
~/.weft/on the laptop. Removing a session deletes its locally cached phone transcript. - stdout is sacred. The CLI reserves stdout for JSON-RPC; all extension UX uses
session.log().
- The extension is authored in
extension/src/and bundled (esbuild) to a singleextension/dist/extension.mjsplus the lazily importedextension/dist/activeRuntime.mjs.@github/copilot-sdkis marked external (the CLI provides it at runtime); everything else (e.g.@supabase/supabase-js,shared/) is bundled in. - Install copies
extension/dist/into~/.copilot/extensions/weft/, where Copilot CLI auto-discovers it (seesetup.*/install.*) — that directory holds installed code only. All user config lives separately in~/.weft/:weft.config.json(registered projects, transport choice, device name) andsupabase.json(relay URL + anon key). There is no.env/ env-var override — reinstalling or rebuilding never touches either file, so your chosen transport always survives. Crypto uses Web Crypto — no native deps. - For local development you do not need to install into
~/.copilot: run the harness (extension/harness/) which drives the extension logic againstLocalTransport.
Source builds require Node.js 20 or newer.
npm install --workspaces --include-workspace-root # resolve shared, extension, and mobile
npm test -w @aasis21/weft-shared # crypto + pairing + transport + message tests
node extension/harness/harness.mjs --auto # full relay loop vs a simulated phone (no Supabase)
npm run build -w @aasis21/weft-extension # bundles -> extension/dist/extension.mjs + activeRuntime.mjs
npm run build -w @aasis21/weft-mobile # Vite production build
cd mobile && npm run dev # then pick "Demo / Simulator"
node design/capture.mjs # refresh product screenshots from the hosted appSee docs/setup.md for the full developer guide.
| Doc | What |
|---|---|
docs/setup.md |
install, verify, run, and Supabase wiring |
docs/advanced.md |
/weft, transports, pairing modes, and command reference |
docs/pairing.md |
the ECDH pairing handshake |
docs/security.md |
threat model & cryptography |
docs/mode-switching.md |
runtime interactive/plan/autopilot switching |
docs/hosting.md |
public instance vs self-hosting; operating a relay |
docs/releases.md |
supported PWA, checksums, and laptop updates |
CHANGELOG.md |
notable user-facing changes by release |
CONTRIBUTING.md |
development and pull-request guidance |
PRIVACY.md |
what is stored locally and what the relay can observe |
SECURITY.md |
supported releases and private vulnerability reporting |
SUPPORT.md |
troubleshooting and issue-reporting checklist |
npm test at the root fans out to every workspace. Tests come in two tiers that answer
different questions, so a change is proven where it's cheapest and most reliable:
| Tier | Runner | Lives in | Answers |
|---|---|---|---|
| Contracts + extension | node:test |
shared/**/*.test.mjs, extension/**/*.test.mjs |
Is the crypto / pairing / transport / message protocol and the extension relay logic correct? |
| Mobile unit + scenario | Vitest + jsdom | mobile/src/**/*.test.{ts,tsx} |
Is the logic right for a given message / timer / edge — fast, deterministic, fully mocked? |
| Mobile real-browser e2e | Playwright | mobile/tests/*.spec.ts |
Does the real production build render, scroll, and navigate for a user? |
What goes where (mobile):
- Vitest = breadth. The exhaustive scenario matrix — join, resume-dedupe, remove→re-join,
network drop→catch-up, state snapshot, approvals, elicitations, streaming, the 20s/30s heartbeat
watchdog, persistence-across-restart — drives the real
SessionManagerthrough a mocked transport (FakeWeftClient) with fake timers, so no network, crypto, or Supabase is touched. Plus pure-logic (reduceTimeline,sessions,transcripts,storage) and React component tests (RTL). - Playwright = depth. A few bigger journeys against
dist/in a real phone viewport (412×915), driven by the in-app demo simulator:journey-connect(Landing→Join→Session navigation),journey-stream(a live streaming turn),journey-session-management(drawer + leave-confirm + routing), andjourney-smoke(production boot + layout). It answers what only a real browser can. - Not automated (manual): the real Supabase relay + real WebCrypto E2E + real cross-device pairing. Vitest mocks the transport; Playwright uses the demo. Neither hits the network.
npm test # all workspaces: shared + extension + mobile
npm test -w @aasis21/weft-mobile # just the mobile Vitest unit/scenario suite
npm run coverage -w @aasis21/weft-mobile # mobile coverage table (report-only, no gate)
npm run test:e2e -w @aasis21/weft-mobile # build dist/ + run the Playwright journeys- Releases and changelogs: https://github.com/aasis21/weft/releases
- Update the laptop installation:
weft update --check, thenweft update - General questions and reproducible bugs:
SUPPORT.md - Sensitive vulnerability reports:
SECURITY.md - Data handling:
PRIVACY.md
Apache-2.0 — permissive, with an explicit patent grant and trademark
reservation; see NOTICE for attribution. Operating a hosted relay is a
separate concern from the code license — see docs/hosting.md and
TERMS.md.




