Technical documentation of the Code Remote system design.
Code Remote enables AI assistants to execute commands on your Mac by combining:
- MCP Server - Exposes tools to AI clients via SSE (Server-Sent Events)
- WebSocket Relay - Bridges AI requests to the Mac agent
- Mac Agent - Executes commands and returns results
+------------------+ HTTPS/SSE +-------------------+
| |<------------------>| |
| AI Client | MCP Protocol | Unified Server |
| (iOS/Web) | | (Fly.io) |
| | | |
+------------------+ +-------------------+
| |
SQLite WebSocket
| |
v v
+------------------+
| |
| Mac Agent |
| (Daemon) |
| |
+------------------+
A single Starlette application that handles:
GET /sse- SSE endpoint for MCP connectionPOST /messages- Message handling for MCP
Exposed tools:
run_shell_command- Execute shell commandsread_file- Read file contentswrite_file- Write to fileslist_directory- List directory contentscheck_agent_status- Verify agent connection
WS /ws/agent- WebSocket endpoint for Mac agent
Handles:
- Agent authentication via query parameter token
- Command dispatch to agent
- Result collection and storage
GET /health- Health check with agent statusGET /commands- List recent commands (authenticated)
Headless Python daemon that:
- Connects to server via WebSocket
- Authenticates with token
- Receives and executes commands
- Returns results to server
| Handler | Function |
|---|---|
execute_shell() |
Run shell commands via subprocess |
read_file() |
Read file contents with size limits |
write_file() |
Write content, create parent dirs |
list_dir() |
List directory with type/size info |
1. User → AI Client: "list my downloads folder"
2. AI Client → Server (/sse):
{
"method": "tools/call",
"params": {
"name": "list_directory",
"arguments": {"path": "~/Downloads"}
}
}
3. Server:
- Generate command ID
- Insert into SQLite (status: pending)
- Send to agent via WebSocket
4. Server → Agent (WebSocket):
{
"type": "execute",
"id": "abc123",
"command_type": "list_dir",
"path": "~/Downloads"
}
5. Agent:
- Validate path is allowed
- Execute list_dir()
- Format results
6. Agent → Server (WebSocket):
{
"type": "result",
"id": "abc123",
"status": "completed",
"output": "dir\t0\tDocuments\nfile\t1234\timage.png\n...",
"exit_code": 0
}
7. Server:
- Update SQLite record
- Return result to AI via SSE
8. Server → AI Client (/sse):
{
"content": [{"type": "text", "text": "dir\t0\tDocuments\n..."}]
}
9. AI Client → User: "Your Downloads folder contains..."
All connections require a shared secret token:
AUTH_TOKEN (env var on server)
|
├── WebSocket: ?token=xxx query parameter
└── REST API: Authorization: Bearer xxx header
Token is:
- Set via Fly.io secrets
- 256-bit random value recommended
- Compared using constant-time comparison
The agent restricts file operations to safe directories:
ALLOWED_PATHS = [
Path.home(), # /Users/username
Path("/tmp"),
Path("/var/tmp"),
]All file operations verify paths resolve within allowed directories.
- Maximum output size: 1MB
- Truncation with warning for larger outputs
- Prevents memory exhaustion
- All traffic over HTTPS/WSS
- Fly.io handles TLS termination
- No plaintext communication
SQLite database at /data/code_remote.db:
CREATE TABLE commands (
id TEXT PRIMARY KEY, -- Random URL-safe ID
type TEXT NOT NULL, -- shell, read_file, write_file, list_dir
status TEXT NOT NULL, -- pending, running, completed, failed, timeout
command TEXT, -- Shell command (for shell type)
path TEXT, -- File/dir path (for file operations)
content TEXT, -- File content (for write_file)
working_dir TEXT, -- Working directory (for shell)
timeout INTEGER DEFAULT 60, -- Command timeout in seconds
output TEXT, -- Command output
error TEXT, -- Error message
exit_code INTEGER, -- Process exit code
created_at TEXT NOT NULL, -- ISO timestamp
started_at TEXT, -- When agent started execution
completed_at TEXT -- When result was received
);
CREATE INDEX idx_commands_status ON commands(status);
CREATE INDEX idx_commands_created ON commands(created_at DESC);The agent implements automatic reconnection:
while True:
try:
await connect_and_run()
except ConnectionClosed:
pass # Normal disconnect
except Exception as e:
log_error(f"Connection error: {e}")
await asyncio.sleep(RECONNECT_DELAY) # 5 secondsWebSocket connections maintained via:
- Server-side: Starlette's built-in ping/pong
- Agent-side: Application-level ping every 25 seconds
When agent connects, server sends any pending commands:
async with db.execute(
"SELECT * FROM commands WHERE status = 'pending' ORDER BY created_at ASC"
) as cursor:
pending = await cursor.fetchall()
for row in pending:
await manager.send_command(row["id"], {...})Current design assumes single machine (for WebSocket state):
- Agent connects to one machine
- Commands routed to that machine
- SQLite on local volume
For multi-region:
- Would need Redis/external queue
- Session affinity for WebSocket
- Shared database (e.g., Turso, Supabase)
Minimal footprint:
- CPU: shared-cpu-1x sufficient
- Memory: 512MB handles typical load
- Storage: 1GB volume (commands are small)
- Health checks - Monitor
/healthendpoint - Log aggregation - Fly.io logs or external service
- Agent uptime - launchd keeps agent running
- Command latency - Track time from created_at to completed_at