01 Documentation

Everything SofaCode does, and how to make it do it.

SofaCode is a remote control for the coding agent already running on your computer — Claude Code or GitHub Copilot Chat, inside VS Code. This page covers the whole thing: installing it, pairing a phone, every screen in the app, running it over the internet, the SofaNode, and the command line behind all of it.

Written against the shipping code. Where a feature is on one phone and not the other, it says so.

01 · The three pieces

Nothing about SofaCode runs in a cloud we own. There is no accounts server and no relay in the middle — the phone talks to your computer directly.

  • The daemon runs on the computer where your code and your agent live. It watches Claude Code's transcripts, talks to VS Code, synthesises speech, and is the only thing a phone ever connects to.
  • The VS Code extension is how the daemon reaches the editor: which window has focus, which session is running where, and the commands that type a prompt or answer a chat. It is installed for you and it is not optional in practice.
  • The app — Android or iOS — is the remote control. Optionally a SofaNode, the round desk device, which speaks the same protocol.
Requirements

Python 3.10+ on the computer, VS Code, and your own Claude Code or GitHub Copilot Chat subscription — SofaCode is the remote control, not the agent. The app needs Android 8.0+ or iOS 16+.

02 · Install and pair

One command on the computer, then one scan on the phone.

  1. 1

    Install the daemon

    macOS and Linux:

    curl -fsSL https://dl.codedatda.casa/sofacode/install.sh | bash

    Windows, in PowerShell:

    irm https://dl.codedatda.casa/sofacode/install.ps1 | iex

    The installer sets up a Python virtualenv, puts sofacode on your PATH, installs the VS Code extension, wires Claude Code's hooks, opens ports 17845/tcp and 5353/udp on a firewall you are already running, and registers it to start at login. Open a new terminal afterwards, then check it took:

    sofacode --version sofacode doctor
  2. 2

    Reload VS Code

    The extension is installed but a running window has not loaded it yet: Ctrl+Shift+P → Reload Window. If the installer said it could not find the code command, run Ctrl+Shift+P → Shell Command: Install 'code' command in PATH and re-run the installer.

  3. 3

    Pair the phone

    A pairing window opens by itself the first time. To bring it back at any point:

    sofacode pair

    That prints a QR code and a numeric code in the terminal and opens the same thing in a browser at http://127.0.0.1:17846/pair. In the app: Machines → Scan QR code, or Enter pairing code if the phone has no camera. Scanning it with the phone's own camera app works too — the link is a sofacode://pair deep link. Every device gets its own token, revocable on its own.

    Scan QR Enter code Scan network Add by IP
  4. 4

    Grant the microphone

    Push-to-talk needs it. The setup guide asks on first run; you can re-run it any time from Settings → Help → Setup guide.

Pair more than one

Pair as many machines as you like and as many devices as you like — two phones to one computer, or one phone to several computers. Trust is keyed to the machine's identity, not its IP address, so a new DHCP lease or a router reboot changes nothing.

03 · The deck

The home screen. A state ring you can read across a room, and everything else arranged around it. It is one drawn canvas rather than a stack of widgets, so it reflows the same way from a tablet down to a two-inch screen.

The ring

  • TapStart or stop voice dictation. While the agent is speaking, a tap interrupts it instead.
  • HoldSend what is in the agent's input box.
  • Two tapsMove to the next VS Code window.
  • Three tapsClear the input box and start over.

Swipes

  • Swipe upOpen the chat.
  • Swipe downClear the input box.
  • Swipe leftThe session picker — everything running in the current project.
  • Swipe rightSettings.

What else is on it

  • The machine pill at the top switches computers, with a badge counting sessions that need you anywhere.
  • The window pill picks which VS Code window prompts land in. Picking one pins it; Auto (follow focus) hands it back to whichever window has your keyboard.
  • The session pill at the bottom names what you are talking to.
  • Attention bubbles float between the machine pill and the ring for sessions elsewhere that need you (amber) or just finished (green). Tap one to jump straight into that conversation.
  • Approve and deny appear in their own reserved slot when a permission prompt is waiting, so the ring never jumps.
Small screens

Node mode Android strips the deck to ring, state, machine and chat, and turns the outer edge into a rim dial that scrubs sessions. It switches itself on for watch-class screens; Settings → Node → Node mode overrides either way.

04 · Chat

The running session, live. Code blocks render properly, the agent's task list ticks off as it goes, and its thinking is there if you want it.

  • Sending. Tap send to steer the running turn. Long-press send for Interrupt and send now or Type into input only.
  • The microphone in chat is the phone's own dictation — it types into the box for you to read before sending. The deck's ring is the wireless voice mode that goes straight into the editor. They are deliberately different things.
  • Attachments. Take a photo, choose an image, or add a file as text. Images are re-encoded down to the machine's size cap before they are sent, which strips their location data on the way.
  • Long-press any message for Read aloud from here, Speak this and Copy text. Select text inside a message and you get Speak too.
  • Fling the transcript up from the bottom for the full task checklist.
  • The bar across the very bottom is how much of the context window is gone — amber at 80%, red at 95%. Tap it for the full stats. It is hidden entirely for Copilot, which does not report context accounting, rather than shown as zero.
  • The action row holds files, terminal, approve/deny, stop, the permission mode, compact, and the speaker toggle. Anything the machine cannot do is absent, not greyed out.
  • The menu (top left) has switch session, provider, model, slash commands, skills, the system prompt, stats, Claude usage, and windows & projects.
Models

For Copilot the picker lists the models VS Code actually offers on that machine and switches with a real command. For Claude Code it types /model <name> at the session, because that is the only lever Claude Code exposes.

05 · Sessions

Every session on every paired computer, in one tree: machine, then folder, then session. Sort by recent, by what needs you, or by name. Search does not persist between visits; your sort and your collapsed folders do.

  • Star a session to pin it to the top and exempt it from the auto-archive sweep.
  • Archive hides a session everywhere — it is machine state, so every device paired to that computer agrees. There is a seven-second undo, and an Archived sessions screen that scans by an allowlist, so something archived months ago is still findable and unarchivable.
  • New session asks which computer, where, and which assistant. It can open a project or launch an empty VS Code window and wait for it to come up.

06 · Files and terminal

Both are confined to the session's project root by the daemon, not by the app — .. and symlink escapes are refused on the computer's side.

  • File browser. Browse, upload, download a file or a whole folder as a zip, rename and move. Controls the machine has not enabled are absent rather than disabled.
  • Code editor. A text editor, not an IDE: line numbers, find, wrap, undo. A save carries the checksum the file had when you opened it, so if something else changed it underneath you get a conflict with Overwrite / Reload / Cancel instead of a silent clobber. Files over 512 KB open read-only.
  • Terminal. Runs in that session's VS Code window or refuses — it is routed by session, never by "whatever was focused". There is a curated set of common commands, your own favourites, command recall, and a real interrupt button.

07 · Permissions

When the agent asks to run something, Claude Code blocks and the daemon holds the question open until somebody answers it. The answer can come from the phone, the SofaNode, or the computer — first answer wins, and the others are told it was already decided.

The full-screen card names the machine, the folder, the tool and the exact command, with a countdown. Nothing is auto-approved: if no device answers before the timeout, the request is denied.

Bypass mode

Settings → Permissions is the only place a machine's default can be set to a mode that stops asking, and it applies to new sessions only — nothing can push a running session into another mode from outside. When a machine is in bypass, the approvals screen says so plainly instead of just looking empty.

08 · Remote access — using it away from home

On your own network, nothing is exposed to the internet at all. Remote access is the opt-in that lets the same app reach the same computer from anywhere: a coffee shop, a hotel, a phone on mobile data. It is off until you turn it on, and it is turned on from the computer's command line — a paired phone deliberately cannot enable it.

What actually gets published

Exactly two routes: the device socket and the gateway relay. Pairing, the local API, /status, /config and file transfers live on a different listener that is not published at all, so a forwarded port cannot expose them even by accident.

Pairing never goes over the internet

Pair on your own network first, once, per device. A pairing request arriving from outside is refused, and there is no setting to loosen that. It also means you cannot finish setup while you are already away — do it before you travel.

Turning it on

  1. 1

    Pair on the LAN

    If the phone is already paired, this is done.

    sofacode pair
  2. 2

    Pick a way in

    Print the walkthrough with the details for your machine at any time:

    sofacode remote setup

    A Cloudflare tunnel is the usual answer: nothing to forward, nothing to open on the router, and the certificate is a real one. Install cloudflared, then either take the throwaway hostname:

    sofacode remote start

    …or use a named tunnel you own, so the hostname survives a restart:

    sofacode remote token <TUNNEL_TOKEN> sofacode config --set remote.hostname=sofa.example.com sofacode remote start

    Or forward a port yourself and let the daemon serve TLS from a certificate it generates once. The app is given that certificate's fingerprint over your own network and refuses anything else afterwards:

    sofacode config --set remote.mode=direct sofacode config --set remote.hostname=sofa.example.com sofacode remote start

    Then forward TCP 17847 to that machine.

  3. 3

    Check it

    sofacode remote status

    It prints the address clients will dial, the certificate fingerprint in direct mode, and — when the tunnel is not running — the last error and the last few lines cloudflared printed.

Your phone does not need re-pairing

The moment remote access comes up, the address is pushed to every device that is already paired, over the connection it already has. A phone or a SofaNode paired months ago simply learns the way in. Away from home it tries the local addresses first and falls back to the remote one.

Two rough edges, honestly

Use sofacode remote token for a tunnel token. Setting it through sofacode config --set remote.tunnel_token=… works until the next restart and then silently drops you back to a throwaway hostname — secrets are kept out of the config file on purpose, and only the dedicated command writes them where they survive.

Do not add a Cloudflare Access service token yet. The config keys exist, but no SofaCode client sends those headers — putting Access in front of the tunnel locks out your own phone.

One door for a whole house of machines

If you have several computers, you do not need a tunnel for each. Turn one of them into a gateway and the others are reachable through it:

sofacode remote gateway on # then restart the daemon — it reads this at startup

A device still authenticates to the machine it is actually talking to; the gateway only carries bytes. Android + SofaNode — the iOS app has no relay path yet, so an iPhone needs a direct address for each machine.

How it is kept safe

  • A connection from outside must use the mutual challenge-response handshake. A device offering a plain token is rejected, not quietly accepted — the token never crosses the internet in either direction.
  • "Is this connection remote?" is decided by the daemon, from the socket, and every signal it uses can only push a connection towards remote. A client cannot claim to be local.
  • In direct mode the app pins the exact certificate, handed to it on your own network. A swapped certificate fails.
  • Every device has its own token. Revoke one without touching the others: sofacode paired revoke.

Turning it off

sofacode remote stop sofacode remote status

The tunnel is terminated and the listener goes back to loopback only. Status will say it is disabled — the mode you chose is remembered for next time, but nothing is listening.

09 · The SofaNode

The optional round-screen desk device. It is not required — the app is the full product — and it runs on the same SofaCode subscription. Buying one includes 6 months free: a 6-month subscription code for Google Play or the App Store arrives with your order confirmation. The product page has the full story; this is how to drive it.

Setting one up

  • Flash it with the web flasher — Chrome and a USB-C cable, no terminal. It can set the Wi-Fi and the clock's timezone at the same time.
  • Or join its own Wi-Fi network and configure it from a browser.
  • Then scan the QR it shows from Settings → Node → Set up a SofaNode. Every machine you have paired is pushed to it at once, each with its own revocable credentials. A valid scan burns the code, so a failed setup needs a fresh QR rather than a retry.
  • It updates itself from then on — at boot, or from its own menu.

Its screens

  • DeckThe state ring. A badge top-right counts sessions that need you; a ringed pip on the left counts sessions holding a reply you have not heard.
  • Swipe upThe transcript. Swipe up again for the task list.
  • Swipe leftSessions.
  • Swipe rightThe menu — machines, pairing, Wi-Fi, assistant, update, power.
  • Turn the rimMove between VS Code windows; roll past either end to switch to the next paired computer.

Speaking, with more than one agent running

Only the session the Node is following is read aloud as it arrives — a dozen agents talking over each other is not a feature. When one of the others stops, it holds its last reply and raises a pip on the SESSIONS screen.

  • Tap a pip rowPlays that held reply.
  • Tap it againClears the pip.
  • Hold a rowFollows that session — ring, transcript, tasks and spoken replies — and stays there until you go back to your keyboard.

Turn the voice off and the pips go with it; they are an offer to play something. A tap during playback stops it, the way you would interrupt a person.

10 · Settings

Whole sections are hidden rather than greyed out when nothing you have paired supports them, so the list is only ever as long as it is useful.

  • LookSix themes — Ember (the default, matched to the SofaNode), Ice, Matrix, Plasma, Volt and LCARS. App language: English, 繁體中文, 简体中文, or follow the phone. "Assistant replies in" is separate and off by default, because both agents already mirror the language you write in.
  • SpeechRead replies aloud on the phone, with voice, rate and pitch. This is the phone's voice; the SofaNode's is set on the Node.
  • NodeNode mode Android, SofaNode setup, and the firmware version of every Node your machines can see.
  • XR glassesAndroid A heads-up display on USB-C glasses the phone already sees as an external screen. Placement, text size, and head tracking with a recentre.
  • FloatingAndroid A draggable orb over other apps: tap to talk, hold for mic, send, approve, deny and stop.
  • TransfersUpload and download limits, and where downloads land.
  • Remote accessThe guided setup, and the remote address per machine. Appears once a machine is paired.
  • PermissionsPer-machine default permission mode. See 07.
  • SessionsAuto-archive age, whether starred sessions are exempt, and the archived list.
  • AccountSubscription status, restore purchases, manage subscription.

11 · The command line

Everything the app does is available on the computer too, and a few things are only available there.

  • sofacode runRun the daemon in the foreground. Normally it is started for you at login.
  • sofacode pairOpen a pairing window: QR, code, and every address a device can reach this machine on.
  • sofacode pairedList paired devices; revoke one by name without disturbing the rest.
  • sofacode doctorCheck the install — Python, the extension, the hooks, the audio bridge, the ports — and print how to fix whatever is wrong.
  • sofacode remotesetup, start, stop, status, token, gateway. See 08.
  • sofacode configRead and write the config file — --set section.key=value to change one thing, no arguments to print it all. A secret (a tunnel token) is routed to the credentials sidecar automatically.
  • sofacode install-hooksRe-wire Claude Code's hooks (and uninstall-hooks to remove them). They are merged into your existing settings, which are backed up first.
  • sofacode install-serviceStart at login.

Where things live

  • Config~/.config/sofacode/config.toml — secrets are kept in a separate file with tighter permissions, never in here.
  • Paired devices~/.config/sofacode/paired.json
  • The daemon~/.sofacode/ (Windows: %LOCALAPPDATA%\SofaCode)
  • Ports17845 devices · 17846 local API, loopback only · 17847 remote ingress, loopback until you turn remote access on
Config from the phone

Most config sections can be read and written from the app. Remote access and voice cannot — remote because turning on internet access should need a hand on the computer, and voice because the SofaNode's own menu owns it.

12 · When it goes wrong

The app cannot find my computer+

Run sofacode doctor on the computer — it checks the ports, the extension and the hooks, and prints the fix for whatever it finds. If discovery is the problem (some networks block mDNS), use Machines → Add by IP with the address sofacode pair printed.

It connects, but prompts do not land in VS Code+

That is the extension. Reload the window (Ctrl+Shift+P → Reload Window) and check the window appears in the app's window picker. A window that is not listed has no extension loaded.

Remote access worked, then stopped after a reboot+

Almost always a tunnel token set the wrong way. Use sofacode remote token <TOKEN> rather than config --set, then sofacode remote start. Confirm with sofacode remote status, which names the hostname clients will actually dial.

I cannot pair while I am away from home+

Correct, and deliberate — pairing is refused over the internet and there is no setting to change that. Pair on your own network before you travel.

The SofaNode says NO ROUTE+

It cannot reach any address it knows for the machine. Check the daemon is running, and re-run Settings → Node → Set up a SofaNode to push a fresh list of addresses — that is also how it learns a remote address after you have turned remote access on.

The Node is not speaking+

Speech is synthesised on the computer, so the computer needs a synthesiser installed — piper-tts or espeak-ng. Without one the Node stays silent rather than erroring, and the unheard-reply pips do not appear at all. Check the voice switch in the Node's own menu too.

Is any of my code sent anywhere?+

No. The phone talks directly to the daemon on your own machine. There is no server of ours in the loop — there isn't one. With remote access on, the traffic goes through an encrypted tunnel you own to the same daemon.

Still stuck? Get in touch — include what sofacode doctor printed and it will be a much shorter conversation.