Architecture is the set of decisions
you wish you could change
but probably can't.So you'd better get them right the first time.

This is the story of the decisions that shape PropelCode. Not the marketing version. The real one, including the trade-offs we made and the things that keep us up at night.

PropelCode is a full IDE that runs on your phone, your tablet, your browser, and your desktop. Under the hood, it's five systems working together: a cross-platform client, an Express server, isolated Linux containers, a WebSocket bridge, and an AI agent loop. Here's how they fit together.

The Stack, in One Diagram

The system has three layers: the client app (what you see on your phone or browser), a coordination server (handles auth, billing, and AI routing), and an isolated container per user (where your code actually runs). Let me walk through each layer.

One Codebase, Four Platforms

We needed the app to run on iOS, Android, web browsers, and desktop — from a single codebase. We chose a cross-platform framework that lets us write components once and deploy them everywhere. The same code renders natively on mobile and as standard HTML in a browser.

One codebase. Four platforms.
Zero translation layers.iOS, Android, web, and desktop from the same source code.

The web build is what we wrap for the desktop app and serve directly from our server for the browser app. Same code everywhere. The framework gives us file-based routing, over-the-air updates, and managed build pipelines.

The trade-off: Cross-platform frameworks add overhead compared to fully native apps. On a modern phone this is imperceptible. On web, the bundles are slightly larger than a purpose-built web app. We accept this because maintaining four separate codebases would be insane for a small team.

Container-Per-User: The Foundational Bet

This is the most important architecture decision in the entire system. When you sign up for PropelCode, we provision an isolated Linux container just for you. It has a full development environment — shell, Git, package managers, build tools. It has its own filesystem and process space.

Think of it like an apartment building. Every user gets their own apartment with their own kitchen, their own bathroom, their own front door. Nobody shares walls. When you move out, the apartment is demolished.

0
Shared state between users. No shared filesystem. No shared processes. No shared network. Container isolation means one user's rm -rf / can't affect anyone else. Security through architecture, not just permissions.

The trade-off: Containers are expensive. Each one consumes memory and CPU even when idle. We mitigate this by suspending inactive containers and waking them on demand. Cold starts add a few seconds of latency. We're honest about this on our status page.

The WebSocket Bridge

Here's the problem: your phone needs to talk to your container. HTTP requests would work for file operations, but terminals need real-time bidirectional streaming. When you type ls in the terminal, you need the output to appear immediately, character by character. HTTP can't do that.

The solution is a WebSocket bridge at /ws/bridge. Your phone opens a persistent WebSocket connection to the Express server. The server opens a corresponding connection to your container. Every keystroke, file change, and terminal output flows through this bridge in real time.

The connection layer authenticates your session, routes messages to your container, and manages reconnection when your phone goes to sleep or switches networks. It's the nervous system of the entire application — every keystroke, file edit, and AI action flows through it.

The trade-off: Persistent connections are stateful. If the server restarts, all connections drop and clients must reconnect. We handle this with automatic reconnection and state recovery, but there's a brief interruption. We chose this approach because terminal streaming and real-time file sync require it.

Monaco in a Phone: The Editor Story

We use the same editor engine that powers VS Code. It provides syntax highlighting, code completion, multi-cursor editing, find-and-replace, minimap, bracket matching, and dozens of other features that developers expect. No other editor comes close in terms of features and reliability.

On desktop browsers, the editor renders directly in the page. On mobile, we embedded it within the native app so it feels natural on a touchscreen. Editor files are served locally, so there's no network latency for editing operations.

We didn't build a mobile editor.
We put the VS Code editor
inside a mobile app.

The trade-off: The embedded approach adds a small layer of indirection on mobile. This introduces a few milliseconds of latency to operations like "save file" — imperceptible on modern phones, slightly noticeable on budget devices. We compensate with a SmartToolbar — a floating bar with common coding characters — to make the phone keyboard less hostile to code.

The AI Agent Loop

The AI agent is not a chatbot bolted onto an IDE. It's a loop that runs inside your container. Here's the cycle:

  1. You send a message describing what you want
  2. The Express server calls Claude (via OpenRouter) with your message and a set of tools
  3. Claude responds with tool calls: read_file, create_file, edit_file, run_command
  4. The server executes each tool call in your container via the WebSocket bridge
  5. Tool results are sent back to Claude for the next iteration
  6. The loop continues until Claude has no more tool calls (task complete) or you stop it
4
categories of tools: file operations, terminal commands, version control, and network access. The agent can create, read, edit, and delete files. It can run shell commands and monitor processes. It can stage changes, diff branches, and push commits. It does almost anything a developer can do in a terminal.

The agent loop runs server-side, not on your phone. This means it continues working even if you close the app. You get a push notification when it's done. This was a deliberate design decision: background execution turns the phone from a constraint into an advantage. Start a task on the bus, put your phone away, arrive at your destination with the code written and tested.

The trade-off: AI operations consume credits. Every agent iteration calls an AI provider, and those calls cost money. We charge per-use through a prepaid credit system rather than a subscription because usage varies wildly between users. A heavy AI session might use $0.50 in credits. A session where you only edit files manually uses zero.

Single-Origin Architecture

The web app, the API, the real-time connection, and the marketing pages are all served from the same process on the same deployment. One origin. One domain. One TLS certificate.

Same origin = no CORS.
No CORS = no pain.The entire cross-origin surface area disappears.

This is the architecture decision we're most proud of. API calls, real-time connections, static assets, and page navigation all share the same origin. No preflight requests. No cross-origin headers. No cookie confusion. The browser treats everything as a single application because it is.

The trade-off: Static assets don't benefit from edge CDN caching. We use aggressive browser cache headers on hashed assets to compensate. If we need a CDN later, it's a DNS change, not a code change.

The Honest Trade-Offs List

Every architecture has costs. Here are ours, stated plainly:

  • Container cold starts: A few seconds when waking a suspended container. We keep frequently-used containers warm.
  • Connection resilience: Network switches (WiFi to cellular) can drop the connection. We auto-reconnect and recover state, but there's a brief flicker.
  • Embedded editor latency: A few milliseconds of indirection on native mobile. Imperceptible on modern phones, slightly noticeable on budget devices.
  • JavaScript-first: The default container is optimized for JavaScript/TypeScript. Other runtimes work through custom configurations, but JS is the first-class citizen.

We publish these because we believe honesty about constraints builds more trust than pretending they don't exist. Every system has trade-offs. The question is whether you chose the right ones. We think we did.

Good architecture isn't about
eliminating trade-offs.
It's about making them deliberately.

That's the architecture behind PropelCode. A cross-platform client, a coordination server, isolated containers, a real-time bridge, and an AI agent loop. Five systems, working together, to let you ship code from a phone.

Read the full API reference for a deeper technical dive, or try PropelCode yourself to see the architecture in action.