CodeDeck

com.codedeck.app
by Jeroen ✅ jeroen@nostrplebs.com

Control Claude Code sessions on your laptop from your phone over encrypted Nostr.

CodeDeck is a multi-session agentic coding interface for your phone. Run Claude Code on your laptop and drive it from anywhere: review plans, approve tool permissions, switch models and effort levels, and chat with multiple coding sessions at once — all from your Android device. CodeDeck talks to a companion VSCode extension (Codedeck Bridge) over end-to-end encrypted Nostr relays (NIP-44). No accounts, no central server: your phone and laptop pair directly by scanning a QR code. Features: - Multiple concurrent Claude Code sessions, switchable from one app - Plan approval, permission cards, and AskUserQuestion prompts on your phone - Per-session model selection (Opus, Sonnet, Haiku, Fable) and effort levels - Encrypted Nostr direct messages - Designed for the Pixel Fold landscape split-panel; works on any Android phone Pairs with the Codedeck Bridge VSCode extension: https://github.com/JeroenOnNostr/codedeck-bridge-vscode

First release: Jun 15, 2026, 11 total releases.

Most recent release: Aug 4, 2026.

Repo

Appears in 3 app stacks.

69 sats / 1 zaps received in the past year.

Sats Received

Underlying data available via MCP: app_zaps, app_releases.

Zap Count

Underlying data available via MCP: app_zaps, app_releases.

Releases

  • Aug 4, 2026 2026.8.4
    # CodeDeck 2026.8.4 Pair a phone that has no camera, and two settings sections gone. Needs **Codedeck Bridge `2026.8.4`** for the new pairing path ([release](https://github.com/JeroenOnNostr/codedeck-bridge-vscode/releases/tag/v2026.8.4)). Protocol **v9**, unchanged — older bridges keep working, they just don't offer the copy button. ## Pair a phone that has no camera
    More…
    **CD-061** — the bridge hands out one `codedeck://pair?...` URL, and until now the app only ever consumed it through the OS deep-link handler. That means **only by scanning**: there is no barcode dependency and no CAMERA permission in the app, so scanning is delegated entirely to the phone's camera app. A phone whose camera doesn't work had no way in. The manual field was not a substitute. It took a bridge npub and a machine name, and that path *cannot pair* — a pair-request needs the one-time `token` that exists only in the URL. A hand-added machine stayed one-way and permanently disconnected unless you also walked over to the desktop and pasted the phone's npub into the bridge's own manual form. So: **Settings → Remote Machines → Pairing link**. Paste the link, tap **Link machine**. In VSCode, `Codedeck: Pair phone` now has a **Copy pairing link** button (bridge CDB-039) that copies the full URL — mesh invite included — without ever rendering the secret on screen. Scanning is unchanged. `handleDeepLink` was already a complete parser, just trapped in `App.tsx` behind the deep-link event; it moved to `services/pairingLink.ts` and both entry points now run the same code. The npub form is still there under *Advanced — add by npub*, now stating plainly why it can't pair on its own. Pasting tolerates what a link survives on the way to a phone: prose prefixes, wrapping newlines, glued-on sentence punctuation. **Pairing failure is visible now.** A rejection was `console.warn`-only and an expired window produced no ack at all — the bridge tears down the listening subscription when the window closes, so there is nobody left to reject you. A stale link therefore looked exactly like a working one that hadn't connected yet. Expired now shows *"Pairing link expired — generate a new one in VSCode."*, and 20s of silence shows *"No response from {machine} — is the Pair phone tab still open in VSCode?"*. The bridge's pairing window also went from 3 to 10 minutes, because a copied link has to travel through a chat app before anyone can paste it. ## Two settings sections removed **CD-062 — Voice Mode.** Never used, and not cheap to keep: a vendored speech-recognizer plugin, a TTS plugin, and an Android **`RECORD_AUDIO` permission on an app that never listened**. Gone: the settings section, the speaker toggle in the session header, the dictation mic buttons in the input bar and the DM view, seven frontend modules, the whole plugin directory, both capability entries. This APK **requests no microphone permission at all** — verified with `aapt dump permissions`, which is worth stating because the first build of this release still carried it: the permission turned out to be hardcoded in the generated Android manifest rather than merged in from the plugin, so deleting the plugin did not remove it. Filed as **CD-065**, since that manifest sits in a gitignored directory and the fix will not survive a `cargo tauri android init`. **CD-063 — Authentication.** The Anthropic API key, GitHub PAT and GitHub username fields, never used: remote sessions run Claude Code on the paired machine and authenticate there. Gone with them: the Send Key / Update Key button and the "No API key" line (both read the key field and would have been permanently dead), the key-test command, and — once its last caller went — **Stronghold** encrypted storage entirely. > **Behaviour change:** local (non-bridge) sessions now read `ANTHROPIC_API_KEY` from the > environment instead of Stronghold. Remote sessions are unaffected. Existing installs keep an > orphaned Stronghold vault and `salt.txt` on disk; nothing reads them, and a `config.json` from an > older install still loads (covered by a regression test). Together these close **CD-002** and deliver most of **CD-019**. ## Fixes **CD-064** — scrolling back through old output would yank the viewport to the newest message. Three separate faults: `autoScrollRef` was mirrored from state during render, so a `ResizeObserver` firing in the same frame as a scroll event read a stale `true`; re-arming keyed on "is at bottom" alone, which a row re-measured shorter makes true by shrinking `scrollHeight` while you are parked in old output; and the scroll listener was attached in an effect with only stable deps while the list mounts conditionally, so a session that started empty never got a listener and stayed latched on forever. Touch and wheel now hold a guard for 200ms after events stop, so a fling is not fought by its own momentum. **CD-060** — the project folder picker was an `<input list=…>` datalist, which the WebView renders as a floating popup: on the phone it painted over the "PROJECT FOLDER" label above it and only showed what the typed prefix matched — a picker you had to already know the answer to use. It is a `<select>` now, so the phone renders its own full-screen list with all folders visible before a key is pressed, plus an explicit "Other" entry for typing a new folder name. ## Verification `./dev.sh check` clean (TypeScript, Vite, Rust). 159 vitest tests across 10 files (+13 for the pairing-link parser, +the scroll-decision tests) and 53 Rust tests. arm64-v8a only, as always. versionCode `20260804`. Everything user-visible here is marked **device-verify owed** in `TODO.md`, each with a self-contained run-sheet: the pairing paste path and its failure toasts (CD-061), the absence of the settings sections and of `RECORD_AUDIO` in the APK (CD-062/063), and the scroll behaviour (CD-064).
  • Jul 29, 2026 2026.7.31
    # CodeDeck 2026.07.31 — starting a GSD project from the phone actually works `versionCode 20260731` · needs bridge **protocol v8** (`2026.7.30`, already shipped — **no bridge upgrade required for anything below**). The one exception is the workspace listing in the folder picker, which asks a **v9** bridge for data and falls back to the old behaviour without one. ## The problem The last three releases built a GSD stage strip, a start button, a per-session cwd and a folder field — and it was still not possible to start a GSD project from the phone. The route existed but
    More…
    nothing pointed at it: *Project folder* never mentioned GSD, the "create it if it doesn't exist" checkbox never mentioned GSD, the opt-in was an item in an overflow menu, and the button at the end of that trail was **disabled at the workspace root** with no disabled styling — so it looked live and swallowed every tap without a word. ## Start a new GSD project New Session now opens with a named entry point: > ☑ **Start a new GSD project** > Guided plan-driven workflow: GSD interviews you, writes a roadmap, then plans and executes it > phase by phase — and the stage strip drives it from here. Give it a project name and tap **Start GSD Project**. One tap then does the five things that previously had to be assembled by hand: 1. creates `<workspace>/<name>` and `git init`s it (GSD needs a repo, and giving it one of its own is what keeps it out of the sibling projects), 2. roots the session there, 3. takes the session **out of plan mode** — GSD's workflows write, and in plan mode Claude Code plans them instead of running them, 4. sends `/gsd-new-project`, 5. shows the stage strip immediately, so it is there *for* the interview rather than after it. The command is held until the mode change is confirmed. Sent together, the first turn can run in the wrong mode, which looks exactly like the button doing nothing. **Run hands-free** (on by default) auto-approves tools. GSD runs its own CLI, git and sub-agents constantly; approving each from a phone would stall the interview. You still answer every question it asks, and the header switches modes in one tap. ## The strip stops lying - **Disabled buttons look disabled.** `.gsd-bar-action:disabled` had no styling at all — the single line that made "Start GSD does nothing" possible. - **A non-repo directory is not a disabled button, it's the wrong directory.** The workspace root now reads *"GSD needs its own folder — this one isn't a git repo"* and offers **New GSD project**, which opens the flow above. It still never offers to `git init` there. - **Mid-turn it reports, it doesn't pretend.** *"Setting GSD up…"* while a turn is in flight, *"GSD is waiting on you"* when it is blocked — instead of buttons that ignore taps. - **The buttons say what they do.** *Map codebase* → **Map existing code** ("Analyse the existing code into `.planning/codebase/`"); *Start GSD* → **Start GSD here** ("Interview → requirements → roadmap"). - **No accidental restarts.** GSD writes nothing to `.planning/` until its interview is well under way, so the project keeps reporting "not set up" throughout. The primary now reads **Restart GSD setup** once setup has been sent — the old label read as *continue* and would have thrown a half-finished interview away. - **The strip appears on a session that is already busy.** It used to poll only when the session was idle, so a session running from its first second — which "New GSD project" always is — rendered nothing until it stopped. Also in the ⋯ menu: **New GSD project…**, reachable from any session, so starting one never depends on standing in the right directory first. ## The Project folder picker offers your projects, not the workspace The list behind **Project folder** was built from the sessions already running, so on a workspace where every session starts at the root it held exactly one entry — the name of the workspace itself. Choosing a project meant typing its folder name from memory, on a phone, which is the one place that is hardest to do. It now lists what the workspace actually holds, sent alongside the session list by a **v9** bridge: folders that already host a session float to the top — the likeliest next pick — and typing narrows the rest. **"Create it if it doesn't exist"** appears only for a name the workspace does not already have; for a folder the bridge just said exists, it was a question about nothing. The field stays free text, because typing a new name is how "Start a new GSD project" begins. Against a v8 bridge the picker falls back to exactly the old list, so nothing here breaks by not upgrading — you simply don't get the listing. ## Verified Driven end to end on a Pixel 9 Pro Fold against the live bridge: folder created and `git init`ed, session rooted, mode switched, `/gsd-new-project` sent, ~10 question groups answered by tapping, `.planning/` written and committed, and the strip flipped itself to `v1.0 · Plan first phase · 0%` with **Discuss the first phase** as a tappable chip. Full results: `docs/CD-058-GSD-DEVICE-VERIFY-RESULTS.md`. 131 phone tests, 198 bridge tests, `tsc` clean on both. The folder picker (above) ships with host tests only — its on-device check is still owed. ## Companion bridge `2026.7.31` (optional) Only the workspace listing in the folder picker needs it (protocol **v9**, CDB-035 — the bridge now sends the workspace's project folders with every session list). It also fixes **CDB-034**: the bridge appends a metadata request to a session's first message, and Claude Code treats everything after a slash command's name as that command's arguments — so `/gsd-execute-phase 2` was arriving as phase `"2\n\n<!-- emit-session-meta: … -->"`. Slash commands are now left byte-identical, and the metadata is asked for on the first ordinary message instead. Installing it needs a VSCode window reload.
  • Jul 28, 2026 2026.7.30
    # CodeDeck 2026.07.30 The last two releases put a GSD stage strip on your phone and gave it a Start button. This one makes it actually usable: you can now **start a new GSD project from your phone**, and the strip stops telling you things that aren't true. ## Start a new project from your phone Until now every CodeDeck session opened in the same place — your VSCode workspace root. If that root is a folder holding many separate projects, GSD had nothing real to look at, so the strip
    More…
    could only ever offer to initialise the whole workspace as one giant project. There was no way to point a session at a single repo, and no way at all to begin a new one. - **New Session** gains a **Project folder** field. Leave it blank for the workspace root (exactly as before), or name a subdirectory to root the session in that one project. - Tick **"Create it if it doesn't exist"** and the laptop creates the folder and initialises a git repo in it — so you can go from nothing to a new GSD project without touching the laptop. - The folder is confined to your workspace root. A path trying to escape it is refused and the session opens at the root instead. ## Start GSD no longer offers to do something destructive `Start GSD` runs GSD's project initialisation, which runs `git init` when the directory isn't already a repo. Offered at a folder full of sibling repositories, that meant creating a repository on top of all of them. - The button is now **disabled outside a git repository**, and the strip says **"GSD needs a git repository"** instead of pretending it's ready. ## The strip stops claiming you're finished On a five-phase project with one phase done, the strip read **"Phase 1 of 1 · 100%"** — it counted only the phases that had been planned, so finishing the first one looked like finishing everything. - It now reads the real phase count from your roadmap: **"Phase 1 of 5 · 20%"**. ## Taps while the session is busy aren't silently swallowed Tapping a strip button mid-turn used to post the command into the conversation and then quietly drop it — it looked sent, and nothing happened. - Strip buttons are now disabled while a turn is running or waiting on you, with the reason in the tooltip, instead of accepting a tap that goes nowhere. ## Requires The companion **Codedeck Bridge** VSCode extension at **protocol v8** (2026.7.30). On an older bridge the Project folder field is hidden rather than shown-but-ignored, so nothing silently misbehaves — you just don't get the new capability until the extension is updated.
  • Jul 28, 2026 2026.7.29
    # CodeDeck 2026.07.29 Follows yesterday's release, which introduced the GSD stage strip. This one makes it usable from a phone rather than just readable. ## Start GSD on a project that doesn't have it yet Previously the strip only appeared for projects already running GSD — there was no way to bootstrap one from your phone.
    More…
    - The **⋯ menu** now offers **"Enable GSD for this session"**, which reveals **Start GSD** and **Map codebase** buttons. - It's **per session, opt-in**: projects that already use GSD still show the strip on their own, and the sessions that will never use GSD stay exactly as they were. - The choice sticks across restarts. ## The strip tells you what's happening while a phase runs Previously it froze. During `/gsd-execute-phase` the phase counters don't move — GSD batches its state writes until a whole wave of parallel plans finishes — so a fifteen-minute run showed the same stale line throughout. - **Live task progress**: `Phase 2 · plan 1/2 · task 2/3 · add payment session`, moving as each task lands. - **"Waiting on you"** when a checkpoint or question blocks the run, so a stalled phase is obvious rather than looking idle. - The action button **hides itself** while a phase is running or blocked — tapping "Execute phase 2" *during* phase 2 would have run it twice. ## Getting unstuck Paused work, blockers and failed verifications now appear as buttons that run the command to resolve them (`/gsd-resume-work`, `/gsd-debug`, `/gsd-verify-work`) instead of being buried in a status word. ## Know the cost before you tap Phase rows read **"Ready to execute · 2 plans · 1 needs you"**. Knowing a phase will stop and ask you something is the difference between starting it on the bus and waiting until you're at a desk. **Requirements:** **Codedeck Bridge 2026.7.29** or newer on your laptop, plus GSD installed there. Non-GSD sessions and older bridges are unaffected — the strip simply doesn't appear.
  • Jul 28, 2026 2026.7.28
    # CodeDeck 2026.07.28 ## Drive a GSD workflow from your phone If you run [GSD](https://github.com/open-gsd/gsd-core) on your laptop, CodeDeck now shows where you are in it — and gets you to the next step in one tap. - **A stage strip under the session header** reads `v1.0 — MVP · Phase 2/3 · Executing · 50%`, with a progress meter. No more scrolling back to work out which phase you're on. - **The next command is a button.** The chip on the right sends the command GSD recommends —
    More…
    `/gsd-execute-phase 2`, `/gsd-plan-phase 3` — instead of you typing it on a touch keyboard. - **Tap the strip for the whole roadmap.** A sheet lists every phase with GSD's own Discuss/Plan/Execute marks, so `✓ ✓ ○` reads as "discussed, planned, not yet executed" exactly as it does in `/gsd-manager` on the desktop. Any phase with a next step is tappable too. - **"Verification required" stays visible.** A phase whose plans are all written but not yet verified is called out rather than being lumped in with "complete". A tapped command behaves exactly like typing it: it appears in the conversation and runs there, so nothing happens invisibly. **Requirements:** **Codedeck Bridge 2026.7.28** or newer on your laptop, plus GSD installed there. Sessions that aren't GSD projects — and older bridges — look exactly as they did before: the strip simply doesn't appear.
  • Jul 28, 2026 2026.7.25
    # CodeDeck 2026.07.25 ## Claude Opus 5 - **Opus 5 is now in the model picker — and is the new default** for sessions you start from the phone. Pick it when you create a session, or switch mid-session as usual. - Needs **Codedeck Bridge 2026.7.25** (or newer) on your laptop — the bridge ships the Claude Code build that knows the model. ## Start sessions without the wait - **Tapping Start Session is instant.** The new session appears in the list right away and fills in when the laptop confirms — no more staring at a blocking "Starting…" dialog for ~17 seconds. If the bridge never answers, the row turns into a Retry banner instead of hanging.
    More…
    - **You can type your first message immediately** — it's buffered and sent as soon as the session is live, and it becomes the session title. - **Mode, effort and model changes show a pending pulse** while the laptop confirms, and roll back on their own if the change doesn't land. ## Knowing what needs you - **One clear attention dot.** Sessions waiting on a plan approval, a permission, or a question now show a bold, always-visible dot in the session list — including the session you're currently looking at. (It respects reduce-motion.) - **Context usage in the header.** The model badge now carries a live context-window percentage, read straight from the same meter the Claude Code terminal shows, so it no longer jumps around at the start of a session. - **Usage chip with reset countdowns.** The 5-hour and weekly subscription rows each show how long until they reset, ticking once a minute. - **A `/compact` button** in the session header to summarize history without typing the command. ## Fixes - **Typed answers to multi-question prompts no longer wedge the session.** Answering an AskUserQuestion group by typing (rather than tapping) used to deliver only the first answer and leave the session stuck on "Waiting for your answer". - **Swiping between sessions now slides only the conversation.** The input box and buttons stay put instead of sliding along with it. - **Microphone dictation is reliable.** The first-ever permission grant no longer fails, and speech errors surface inline instead of failing silently. - **Mobile polish:** overflow menu for the session header, aligned usage badge, a bigger SEND button, and no accidental pinch-zoom.
  • Jun 20, 2026 2026.6.20
    # CodeDeck 2026.6.20 ## Pick your model up front — and less clutter everywhere - **Choose the model when you create a session.** The New Session screen now has a model dropdown, so each session starts on the model you want instead of switching it per message. - **The current model is always shown.** It lives in the top-right of the session header, next to your subscription-usage chip and token counts. - **A calmer compose bar and session list.** Removed the in-bar model popup and the YOLO / model chips from the session cards — same information, far less noise. ## Fixes
    More…
    - **The sidebar and the "new DM" box no longer hide behind the keyboard.** Opening the drawer or starting a new direct message while the on-screen keyboard is up now keeps everything in view.
  • Jun 18, 2026 2026.6.18
    # CodeDeck 2026.6.18 ## One-QR setup for multi-device mesh testing Setting up a phone — and a second phone as a remote test device — used to be three separate, fiddly steps (pair, paste a mesh invite, type a mesh IP). Now it's **one QR scan**. - **Scan the bridge's Pair QR once.** The phone auto-pairs *and* auto-joins your private mesh from the same code — no invite to copy/paste. - **One question:** the phone asks whether it's your **controller** or a **test device**. That's the only choice you make. - **Pick "test device"** and it just works: Wireless Debugging turns on, the device joins the mesh, and it registers itself with the bridge automatically — **no mesh IP or serial to type**. The laptop can then install & drive dev builds on it over the mesh. - **Controllers stay private:** a phone you set as a controller never joins the mesh, so a shoulder-surfed QR can't grant mesh access.
    More…
    Under the hood: the Pair QR now bundles a fresh mesh invite; the bridge auto-whitelists a paired phone on your private relay (so pairing can use an open relay while high-frequency session traffic stays on your private one); and the phone reports its real mesh identity so the bridge can reach it with zero manual config. ## Known issue A test device's mesh link can go stale if the CodeDeck app is backgrounded for a long time, which can interrupt a large install-over-mesh until you re-open the app. A fix for automatic reconnection is in progress.
  • Jun 17, 2026 2026.6.17
    Remote on-device app testing over an encrypted mesh. CodeDeck now embeds the nostr-vpn FIPS mesh as its own Android VPN, so your laptop can build, install, launch and drive dev builds on a physical test phone from anywhere via Claude Code test sessions. New: per-device "test target" opt-in (off by default, with a Wireless-Debugging indicator), autonomous device-test sessions, and self-healing adb over the mesh. Security hardening: signing-keystore deny-list for test sessions, scoped + secret-redacted logcat, device-screenshot expiry, and mesh-only split-tunnel routing. Pairs with Codedeck Bridge v2026.6.171.
  • Jun 15, 2026 2026.6.15
    **CodeDeck — Claude subscription usage on mobile** See your Claude subscription limits on your phone. A new usage badge in the session header shows your rolling 5-hour session and weekly usage at a glance (`5h 42% · wk 18%`), turning amber then red as you approach a limit. Tap it for the full breakdown: every window (session, weekly all-models, weekly Opus, weekly Sonnet) with live reset countdowns, your plan tier, and session cost. The numbers come straight from the Claude Agent SDK — the same data the desktop `/usage` command shows — so they match. Usage updates automatically (the bridge pushes on focus and every ~60s) with a manual Refresh too. Hidden automatically for API-key / non-subscription sessions. Requires the matching Codedeck Bridge (`2026.6.152`+). Toggle via Settings → *Show usage badge*. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
  • Jun 15, 2026 2026.06.15