Skip to content
bitsmonk
Writing

What happens when I hit send

After Shipping this site from my phone and How the pieces connect, one question kept coming up: when I type a message on my phone, how does it actually reach the server on AWS, and in what form?

The short answer is that my phone and the server never talk to each other. Both talk to Anthropic over plain HTTPS, and the server is the one that calls out.

PhoneClaude app
AnthropicAPI and model
EC2Claude Code
  1. 1. Claude Code on the EC2 server opens an outbound HTTPS connection to Anthropic and waits for work.
  2. 2. I send a message from the Claude app on my phone to Anthropic over HTTPS.
  3. 3. Anthropic delivers the message down the connection the server already opened.
  4. 4. Claude Code sends the conversation to the Claude model at Anthropic.
  5. 5. The model replies with text and requests to run tools.
  6. 6. Claude Code runs those tools on the server, inside its sandbox.
  7. 7. Claude Code sends progress and results back to Anthropic.
  8. 8. Anthropic streams the progress to the app on my phone.
One message, from my phone to the server and back. Steps 4 to 6 repeat until the task is done.

Step by step

Before I type anything (1). When Claude Code starts in Remote Control mode on the server, it signs in, registers with the Anthropic API and keeps an outgoing connection open, asking whether there's work for it. Think of a taxi driver checking in with dispatch, rather than dispatch driving around looking for taxis.

Sending (2 and 3). My message goes from the Claude app to Anthropic over HTTPS and is saved to the session's transcript. Anthropic then hands it to the server through the connection the server already opened. Claude Code's docs put it plainly: when you connect from another device, Anthropic "routes messages between the web or mobile client and your local session over a streaming connection."

The loop (4 to 6). This is where the work happens, and it surprised me. The model doesn't run on my server. Claude Code on EC2 sends the conversation to the Claude model at Anthropic. The model answers with text and with tool calls: requests like "run this command" or "edit this file". Claude Code carries those out on the server and sends the results back to the model, which decides what to do next. A single message from me can go around this loop dozens of times: edit a file, build, run the tests, read the output, fix something, build again.

Coming back (7 and 8). As it works, Claude Code reports each step back to Anthropic, and Anthropic streams it to the app. That's why I can watch progress live on my phone, and why the same conversation shows up on any device I open it from.

Thinking vs doing

The clearest way I've found to picture it:

Anthropic's cloudThe thinking
  • Runs the Claude model
  • Reads the conversation and decides the next step
  • Stores the transcript so every device stays in sync
My EC2 serverThe doing
  • Runs Claude Code, the agent
  • Holds the code and runs every command
  • Builds, tests and pushes, inside a sandbox
The model decides; Claude Code acts.

What a tool call looks like

Messages between Claude Code and the model are structured data, not keystrokes or screen captures. Claude Code talks to the model through Anthropic's Messages API, so a tool call has the shape the API documents. Simplified, the model's reply looks like this:

The model asks for a command (simplified)
{
  "role": "assistant",
  "content": [
    { "type": "text", "text": "I'll build the site to check it." },
    {
      "type": "tool_use",
      "id": "toolu_01…",
      "name": "Bash",
      "input": { "command": "npm run build" }
    }
  ]
}

Claude Code runs npm run build on the server, then answers with the output:

Claude Code returns the result (simplified)
{
  "role": "user",
  "content": [
    {
      "type": "tool_result",
      "tool_use_id": "toolu_01…",
      "content": "✓ Compiled successfully"
    }
  ]
}

The model reads the result and decides what's next: another command, a file edit, or a reply to me.

The protocol, in one list

  • HTTPS on port 443, encrypted with TLS, for every hop. There's no SSH, no VPN and no custom port.
  • Structured events, not a screen share. User messages, tool calls, tool results and progress updates all travel as data.
  • Short-lived credentials. Per the docs, the connection uses "multiple short-lived credentials, each scoped to a single purpose and expiring independently."
  • Streaming in both directions. The Messages API streams model output with server-sent events. For the Remote Control link, the docs say "streaming connection" without naming the exact mechanism, so I won't guess.

Why outbound-only is the clever part

The server never accepts a connection. It only makes them. That one choice has a few nice consequences:

  • Nothing to open in AWS. The EC2 security group needs no inbound rule for any of this. (I keep SSH for myself, and that's separate.)
  • Nothing to scan. There's no listening port for an attacker to find.
  • It works anywhere. The same setup would work on a laptop behind a home router or a corporate firewall, because outgoing HTTPS is almost always allowed.
  • It recovers on its own. If the server goes offline, the session shows as offline in the app. When the server comes back, Claude Code reconnects automatically.

See it for yourself

On the server, these two commands show the design:

# Claude Code's outbound connections on port 443
sudo ss -tnp | grep -i claude
 
# Listening ports: Claude Code isn't among them
sudo ss -tlnp

When I asked Claude to run them from inside the session, it couldn't see any of this. Its sandbox has its own network view, and the only thing in it is the filtering proxy that every request goes through. Even the tool doing the work can't see past its own fence, and that's the point.