1const g=`--- 2title: "The Mobile Coding Landscape" 3subtitle: "An objective comparison of Omnara, alternatives, and the shift toward untethered development" 4seoTitle: "Omnara vs Claude Code, Devin, and More: Mobile Coding Agents in 2026" 5seoDescription: "Compare 5 ways to run coding agents from your phone, from terminal clients and cloud sandboxes to Omnara's local-first hybrid approach." 6date: "2026-03-02" 7author: "Ishaan Sehgal" 8thumbnail: "./assets/thumbnail.png" 9draft: false 10archiveNote: "This comparison covers Omnara's previous remote coding product and is retained for historical reference. Omnara is now an open-source managed-agent platform." 11--- 12 13The mobile coding interface landscape is evolving quickly. As coding agents become more capable, developers are looking for ways to manage them from outside the terminal. Today, there are five primary approaches to controlling coding agents from mobile. Here is a breakdown of how they compare. 14 15## 1. Mobile Terminal Clients & Emulators 16 17Since popular agents like Claude Code and Codex are terminal-native, the most direct way to use them on your phone is via a mobile terminal emulator like Blink, Termius, or a browser-based terminal. You connect back to your machine using whatever networking stack you prefer, whether it's a public IP + SSH, a Tailscale mesh network, or a remote web shell. 18 19To make this viable for mobile, most setups include \`tmux\` or \`screen\` to keep the agent process alive on the host machine even if the mobile app disconnects. A typical stack looks like Tailscale for networking, SSH for auth, tmux for session persistence, and a terminal emulator like Termius running the agent CLI. 20 21**The Appeal:** It is the "purest" form of control. You have total environment fidelity because you are interacting directly with your own machine. Your secrets, dependencies, and local workflows are exactly where you left them. 22 23**The Reality Gap:** The terminal is a high-bandwidth tool being forced through a low-bandwidth straw. Navigating tmux panes on a 6-inch screen is a "fat-finger" nightmare. Agents often output hundreds of lines of logs, tool calls, and/or file changes. Scrolling through a raw terminal buffer on mobile to find where an agent got stuck is slow and mentally taxing. 24 25Moreover, since these are general-purpose emulators, they lack coding-specific UX on mobile. There is no native way to view rendered Markdown, see side-by-side diffs, or easily manage multiple worktrees and sessions. You're essentially trying to manage your agents through an interface designed to be used on your laptop. 26 27--- 28 29## 2. General Computer Assistants 30 31*(OpenClaw, Zo.Computer, Manus)* 32 33This category represents a shift from "chatbots" to "AI-powered computers." You interact with a persistent, stateful environment, either a local machine or a dedicated cloud server (Zo, Manus), via a simple chat interface like WhatsApp, Telegram, or a web/desktop dashboard. 34 35These assistants have full "Computer Use" capabilities. They don't just answer questions; they control a file system, run terminal commands, and can even spin up their own sub-agents to handle background research while you're away. 36 37**The Appeal:** The friction to start and the quality of integrations vary, but the core idea is simple: if you can send a text, you can manage your server. It feels like having a digital assistant who has 24/7 access to your work computer. Because they are generalists, they can handle non-coding tasks too, like monitoring a database or summarizing your emails. 38 39**The Reality Gap:** The "Generalist" UI eventually hits a wall when it comes to coding agents. Chatting with a computer is great for high-level intent ("Deploy the latest build"), but it's a "leaky" container for the specialized needs of a developer. Because mobile developer UX is not the primary audience, you lose essential primitives: there's no native way to select models or harnesses, spin up new sessions, create worktrees, or interactively view code changes. You're trying to manage the needs of a developer through a general-purpose interface. 40 41--- 42 43## 3. Cloud-Based Environments 44
45*(Claude / Codex Web, Cursor Background Agents, Devin, Replit, Lovable)* 46 47This category moves execution entirely off your local hardware to a remote cloud environment. Today, this manifests in two distinct workflows. 48 49**Ephemeral Agents:** Tools like Cursor Background Agents, Claude, and Codex Web spin up "disposable" containers, cloning your GitHub repo for quick tasks, but destroying the environment when the session ends. 50 51Tools like Devin go a step further by requiring an initial "devbox" setup that gets snapshotted. This VM image is used as the baseline for every session. However, just like the others, manual changes (like an \`npm install\`) in one session won't persist across sessions unless codified in your persistent setup steps. 52 53**End-to-End Platforms:** Tools like Replit and Lovable host the entire application, acting as self-contained ecosystems where the agent builds, tests, and deploys in one place. 54 55**The Appeal:** Zero-friction starts. You can go from idea to running app on a plane with just a phone. Since the agent runs in the cloud, it doesn't matter if your laptop is closed, dead, or non-existent. It's the ultimate "laptop-off" workflow for greenfield prototyping. 56 57**The Reality Gap:** These solutions often feel like "disconnected worlds" from your actual development machine. While great for new projects or one-off changes, cloud sandboxes struggle with complex, pre-existing local setups. If you have a dev environment that isn't easily replicable (say due to specific secrets, dependencies, or workflows) the agent is going to have a hard time. 58 59For PR-based agents (like Cursor background agents and Devin), the feedback loop is asynchronous. You aren't "steering" the code as it's written; you are reviewing a finished product. If the agent makes a wrong architectural turn in the first ten minutes, you might not catch it until the PR lands an hour later, leading to a frustrating loop of comments and re-runs between disconnected environments. 60 61--- 62 63## 4. Remote Control Apps 64 65*(Claude Code Remote Control / HappyCoder)* 66
67Instead of moving your code to the cloud, these tools "remote control" into a session already running on your laptop. 68 69The major differentiator here compared to a terminal client is the **Native Mobile Interface**. You aren't just looking at a terminal emulator; you are using a purpose-built mobile app meant to be used for agentic interaction. HappyCoder, for example, wraps the CLI in an encrypted relay so you can text your local agent through a dedicated interface. 70 71**The Appeal:** This is the cleanest bridge between your desk and the world. The massive benefit over a terminal client is the UX Leap. You get native mobile primitives, chat, structured diffs you can actually read, and easy-to-tap buttons to interrupt or approve tasks, instead of fighting with a virtual keyboard in a tmux pane. There's no onboarding friction or re-installing dependencies. 72 73**The Reality Gap:** The "Closed Laptop" problem. Because the session lives on your physical hardware, it inherits all of its fragility. Close the lid, it pauses. Let the laptop sleep, it drops. If your Wi-Fi blips, the agent hangs. 74 75You aren't truly untethered; you're just stretching a cord. Newer entries like Claude Code Remote Control are still in early stages and face reliability issues, with developers reporting failed sessions. You're effectively babysitting a local process from a distance. It's a meaningful step forward, but it doesn't yet solve the core problem: true mobility requires the agent to keep running even when your laptop doesn't. 76 77--- 78 79## 5. The Hybrid Approach 80 81*(Omnara, Claude Teleport + Remote Control)* 82 83The hybrid model attempts to reconcile two competing truths: developers want full fidelity to their local environment, but agents need to survive beyond a single device. 84 85Instead of choosing between a local session that dies when your laptop closes or a cloud session that lacks your local setup, these tools attempt to synchronize state between both. 86 87**Omnara's Implementation:** Omnara is a remote control for your local machine, but with a built-in option to migrate to the cloud. Upon enablement, Omnara syncs your session state, including uncommitted changes, worktrees, and conversation context. If your laptop closes, your Wi-Fi drops, or you walk away from your desk, the session doesn't hang or die. It prompts you to transition to a cloud-backed continuation, allowing your agent to keep running while you're untethered. 88 89**The Teleport Alternative:** Claude Code's \`/teleport\` feature offers a partial implementation of this idea. It allows a local session to be moved to the cloud, but the transfer must be initiated manually from the laptop before leaving (it cannot be triggered from a phone). The local machine must also remain active during the transition and meet certain environment constraints. 90 91This makes \`/teleport\` useful for planned handoffs, though it does not yet provide seamless, device-independent continuity. 92 93**The Goal:** A true hybrid system aims to combine: 94 95- Local environment fidelity 96- Purpose-built mobile UX 97- Persistent execution independent of any single device 98 99The aspiration is simple: your agent continues building whether or not your laptop is open. 100 101**The Reality Gap:** Seamlessly synchronizing state between a local machine and the cloud is technically challenging. Because real-world codebases involve complex worktrees, uncommitted changes, and active conversation contexts, maintaining a "zero-friction" handoff is an incredibly hard engineering problem. 102 103While this architecture is designed to keep you in flow without being tethered to a running local process or stuck in an asynchronous PR dance, the complexity of state-syncing means technical gaps can still occur during transitions. It remains an early-stage solution as the industry works to bridge the divide between local fidelity and cloud availability. 104 105--- 106 107## The Landscape at a Glance 108 109| Core Dimension | DIY SSH | General Assistants | Cloud Envs | Remote Control | Hybrid (Omnara) | 110| --- | --- | --- | --- | --- | --- | 111| Execution Lives | Local | Cloud/Local | Cloud | Local | Local + Cloud | 112| Survives Closed Laptop | â | â (if cloud) <br> â (if local) | â | â | â | 113| Environment Fidelity | â | Varies | â | â | â | 114| Mobile Optimized UX | â | â (for coding agents) | â | â | â | 115 116--- 117 118## Where This Is Heading 119 120Every category above is converging toward the same underlying question: *Should agent execution be tied to a specific device?* 121 122- Terminal clients prioritize fidelity. 123- Cloud environments prioritize availability. 124- Remote control prioritizes UX.
125- Hybrid systems attempt to reconcile all three. 126 127As agents become more autonomous and sessions run longer, the ability to monitor, steer, and continue work without being physically present is shifting from a convenience to a necessity. 128 129The landscape is still evolving, but one thing is increasingly clear: 130 131> **Mobility is no longer about location. Itâs about continuity.** 132 133--- 134 135## Try Omnara 136 137If this perspective resonates, try Omnara for free. 138 139Install Omnara in your terminal: 140 141\`\`\`bash 142curl -fsSL https://omnara.com/install.sh | bash 143\`\`\` 144 145Then run Omnara in the directory you want to work from: 146 147\`\`\`bash 148omnara 149\`\`\` 150 151Join the [Discord](https://discord.gg/Dc46sYk6e3) to ask questions, share feedback, and discuss ideas with the community. 152 153â Ishaan, Kartik, and Christian 154`,m=`--- 155title: "Portability Problems: How Omnara Syncs Coding Agent State Across Machines" 156subtitle: "The tech behind our cloud sandboxing features" 157seoTitle: "Omnara's AI Cloud Sandbox Syncing" 158seoDescription: "The tech behind Omnara's cloud sandbox syncing for Claude Code and Codex" 159date: "2026-04-06" 160author: "Christian Sparks" 161thumbnail: "./assets/hero.png" 162draft: false 163archiveNote: "This post covers sandbox syncing in Omnara's previous remote coding product and is retained for historical reference. Omnara is now an open-source managed-agent platform." 164--- 165 166You kick off a codex xhigh refactor on your laptop. 15m later, you realize you need to leave, and codex is only halfway done. You want to pick it up on your phone with the same code changes and conversation. This is an obviously reasonable request. It is also something no one has built well. 167 168There are a litany of inferior approximations. You can work entirely from a persistent VM. But you must accept the latency and environment management pain. You can resume via teleporting. But you need to have [completed this checklist ahead of time](https://code.claude.com/docs/en/claude-code-on-the-web#requirements-for-teleporting). You can use remote control, but your laptop needs to stay open. 169 170Each solution partially solves the problem. However, the solution isnât unachievable\\! A combination of resumable chat sessions, smart code checkpointing, and sandboxes solve the portability problem. 171 172## Resuming chat sessions 173 174Letâs start the easy part: a primer on how most LLM harnesses interact with a /completions (or /responses or /messages) API. 175 176Each time you send a message to a coding agent, this results in a chat turn. Each chat turn consists of one or more steps. There is usually one step per tool call. 177 178 179 180The above consists of 1 turn, and 3 steps (one for each tool call) 181 182The coding agent harness saves some state of the conversation at each turn because it needs to make a subsequent API call until the agent has completed its generation. In Claude Code, this is just a JSONL session file that looks roughly like this: 183 184\`\`\`jsonl 185{ 186 "uuid": "<uuid>", 187 "timestamp": "2026-03-13T22:18:39.490Z", 188 "cwd": "<cwd>", 189 "sessionId": "<uuid>", 190 "gitBranch": "<branch>", 191 "message": { 192 "role": "user", 193 "content": [ 194 { 195 "type": "text", 196 "text": "When we create a worktree..." 197 } 198 ] 199 }, 200} 201{ 202 "uuid": "<uuid>", 203 "timestamp": "2026-03-13T22:18:42.562Z", 204 "cwd": "<cwd>", 205 "sessionId": "<uuid>", 206 "gitBranch": "<branch>", 207 "message": { 208 "model": "claude-opus-4-6", 209 "id": "<id>", 210 "type": "message", 211 "role": "assistant", 212 "content": [ 213 { 214 "type": "text", 215 "text": "\\n\\nI'll start by researching the codebase..." 216 } 217 ], 218 "stop_reason": null, 219 "stop_sequence": null, 220 "usage": { 221 "input_tokens": 3, 222 "cache_creation_input_tokens": 19537, 223 "cache_read_input_tokens": 0, 224 "cache_creation": { 225 "ephemeral_5m_input_tokens": 19537, 226 "ephemeral_1h_input_tokens": 0 227 }, 228 "output_tokens": 2, 229 "service_tier": "standard", 230 "inference_geo": "global" 231 } 232 } 233} 234\`\`\` 235 236In Omnara, we persist those messages to our database. As long as we can reconstruct that session file from the messages in our database, we can resume the chat later on any machine\\! The way Claude Code stores messages isnât a public interface, but we do a best effort reconstruction of the session file. 237 238## Code checkpointing: weird git commands that you probably shouldnât use 239
240Now, we need to recover the code at some point in time in the conversation. Conceptually, this is simple. What if, after every write action (i.e. any Edit, Bash, or other writable tool call), we save a checkpoint of the codebase. 241 242 243 244Most coding agents have support for hooking into tool call actions by default. The harder part is actually constructing the checkpoints, even if the user is already using source control. 245 246We need to reconstruct: 247- The userâs working directory 248- The git repository itself (and the current ref the user is on) 249 250The key primitives here are [\`git write-tree\`](https://git-scm.com/docs/git-write-tree) and [\`git commit-tree\`](https://git-scm.com/docs/git-commit-tree). 251 252This requires us to capture 4 things: 2531. **headCommit** -- the current HEAD SHA (\`git rev-parse HEAD\`) 2542. **headRef** -- the current branch name, or null if detached (\`git symbolic-ref --short HEAD\`) 2553. **indexTree** -- staged changes as a tree (\`git write-tree\`) 2564. **worktreeTree** -- the working directory as a tree, including untracked files 257 258\`\`\`typescript 259private async captureWorktreeTree(): Promise<string> { 260 const tempIndexPath = \`\${gitDir}/omnara-temp-index-\${uniqueId}\`; 261 const gitEnv = { ...process.env, GIT_INDEX_FILE: tempIndexPath }; 262 263 // Step 1: Copy real index -> temp index (preserves tracked files, even gitignored ones) 264 await fs.copyFile(realIndexPath, tempIndexPath); 265 266 // Step 2: Update temp index with working tree modifications to tracked files 267 execSync('git add --update', { env: gitEnv }); 268 269 // Step 3: Add NEW untracked files (respecting .gitignore) 270 execSync('git add .', { env: gitEnv }); 271 272 // Step 4: Write the temp index as a tree object 273 const result = execSync('git write-tree', { env: gitEnv }); 274 return result.trim(); 275} 276\`\`\` 277 278Then, with the worktreeTree, we can commit with \`commit-tree\` and attach important metadata to the commit to reconstruct the repository at some point in time. 279 280## Cloud storage 281 282Thereâs one final piece: uploading the conversation and code to the cloud so it can be pulled down later on a different machine. For the conversation, thatâs easy -- we already store that data in our database. The code part is only marginally harder, since git is designed to bundle and push changes remotely. Though we donât want to push directly to a userâs git remote, as that causes clutter and risks pushing unintentional changes (particularly dangerous if we accidentally push a userâs .env). Our solution is to manually upload [git bundles](https://git-scm.com/docs/git-bundle), which package git objects into a single file that can be transferred without a live remote. 283 284For each checkpoint we create two bundles: 2851. headCommit 286 1. this is a bundle containing the current head commit for the checkpoint 287 2. this will contain the majority of the repositoryâs commit history 2882. incremental checkpointRef bundle 289 1. This contains the incremental changes from headCommit 290 291Using two bundles, one being incremental helps us save a little bit on storage upload times and storage costs. Technically, the optimal solution would be hosting a git remote per user workspace to dedupe git objects, however, we just end up deduping the headCommit. It's content-addressed by the HEAD SHA, so if a bundle for that commit already exists we skip the upload. We store everything in object storage using presigned URLs (we use R2) which lets us upload from the user's own machine or our managed cloud sandboxes. Even though weâre inefficient with storage, object storage is cheap, so itâs not a big deal if weâre duplicating a lot of data. This significantly reduces complexity, since we donât need to expose full git remote functionality to the user. 292 293Then, once uploaded, we modify a pointer for latestSyncedCheckpoint, which is a parameter for each worktree. Our abstraction for a single copy of a workspace is based on worktrees, so you may move worktrees between remote and local (and have any number of chats grouped with a worktree) 294 295## Sandboxing (and why cold start doesn't matter that much) 296 297When a user resumes a session remotely, we start a session using a sandbox. We use Cloudflareâs Sandbox SDK, but you could use any other sandbox provider. It just needs a filesystem and coding agent harness. We initialize the repo with the bundles we created above, and then seed the .claude/ or .codex/ folder with our session file reconstructed from the messages in our database. 298 299One aside: we don't use much of the richer functionality of these sandbox SDKs (CF Sandbox SDK, E2B, Daytona). We mostly treat it as a dumb keyed sandbox, because all of our setup is upfront. Most of these sandbox libraries want you to manage lifecycle through the SDK. We already have a daemon process that handles our application lifecycle, so we don't end up using most of those features. Here's roughly what the setup process looks like: 300 301\`\`\`typescript 302// workers API 303app.post('/worktrees/:worktree_id', /* auth & validation middleware */ async (c) => { 304 const sandbox = getSandbox(env.Sandbox, worktreeId, { sleepAfter: "4h" });
305 await sandbox.start({ entrypoint: ["./worktree-entrypoint.ts"], envVars: buildEnvVars(), enableInternet: true }); 306 return c.ok() 307}) 308\`\`\` 309 310\`\`\`typescript 311// entrypoint inside container 312async function entrypoint() { 313 const config = validateConfig(process.env) 314 315 // initialize and create llm configs, like ~/.claude and ~/.codex folders 316 writeLLMCreds(config) 317 318 // run background daemon, this allows us to start coding agent sessions on our machine 319 const daemonPid = spawn("omnara daemon run-service"); 320 321 // setup github CLI creds and git push credentials 322 if (config.github) { 323 setupGithub(config.github) 324 } 325 326 if (config.checkpointId) { 327 // clone from workspace bundles (existing checkpoint id) 328 await exec(\`omnara workspace load --checkpoint-id \${config.checkpointId}\`) 329 } else { 330 // clone from scratch (not starting from a checkpoint) 331 await gitClone(config) 332 } 333 334 // write file that indicates to the daemon that the workspace is loaded, so 335 // we don't start sessions before the session has started 336 writeFile(\`/tmp/.omnara-workspace-loaded\`) 337} 338\`\`\` 339 340Many sandbox providers fixate on cold start time, but in our experience, it doesn't matter much. The marginal difference between 500ms and 2s is negligible if your sandbox is stateful. The cold start time is almost always going to be dominated by the time it takes to bootstrap code and configs. Currently, our TTI for our sandboxes is around 8-10s. Under 2s of that is the sandbox itself initializing; the remaining 6-8s is all of our application logic. This includes resolving the git checkpoint, loading session files, and starting the \`omnara\` background process. 341 342## Try it out 343 344The hard part of running a sandbox is the state. We've figured out the hard parts of state sync, so you don't have to figure it out yourself. Try it out by signing up at omnara.com! 345`,p=`--- 346title: "Serverless Agents" 347subtitle: "No machine owns the loop" 348seoTitle: "Serverless Agents: No Single Machine Owns the Loop | Omnara" 349seoDescription: "No single machine should own the agent loop. Put agent continuity in a persistent control plane, make the loop serverless, and expose machines as tools." 350date: "2026-07-23" 351author: "Ishaan Sehgal" 352thumbnail: "./assets/thumbnail.png" 353draft: false 354--- 355 356Start a coding agent on your laptop. Give it an hour-long task. Close the lid five minutes in. 357 358The agent dies. 359 360We spent two decades moving compute into the cloud, then built intelligence that can work around the clock, only to chain it to devices that sleep. 361 362Today this is normal. The agent loop and the developer's device share one lifecycle. It's why the quarter-open laptop meme exists: lids propped open overnight so an "asynchronous" agent doesn't die. 363 364 365 366It won't stay normal. Laptops will still matter, but as interfaces to agents, not where their loops run. In fact, no single machine should own the loop. 367 368## How Agents Inherited the Laptop 369 370When Claude Code launched in early 2025, local-first was the obvious choice. The model ran in the cloud, but the harness stayed beside the code: holding the conversation, deciding what happened next, invoking tools, waiting for results. The agent and its execution environment became one unit. 371 372 373 374Everything that followed copied the shape. Codex, Gemini, Cline, Grok, OpenCode â every coding agent shipped a local-first CLI. Agentic IDEs like Cursor and Zed told the same story. Frameworks made it easy to build your own local-first loops, and when people wanted those agents accessible to others, they did the natural thing: rented a machine in the cloud and ran the same loop there. The architecture didn't change. The laptop just moved. 375 376None of this was a mistake. The agent lived on the machine because that was where the developer already was, and there was no compelling reason yet to separate the two. A natural starting point hardened into the default. 377 378But that default carried an assumption. 379 380## Agents Break the Synchronous Assumption 381 382For most of programming history, the only thing that could write code was us. An assumption settled in so deeply that nobody thought to name it: when the programmer stops, the programming stops. Every tool we built respected it. Even cloud development environments â always-on compute, sitting in a datacenter â mostly just gave the programmer another place to type. The session still ended when the human left. 383 384Agents broke that assumption. 385 386An agent can investigate a failure, wait on CI, react to an external event, ask for approval, and keep going long after the interaction that started it has ended. Its useful lifetime is no longer bounded by a terminal session or a person at a keyboard. 387 388That's the step function: useful programming continuing after the programmer leaves. This renders the local loop a constraint rather than a convenience. There is no reason for the agent to inherit the lifecycle of the humanâs device. 389 390## Separating Continuity From Execution 391 392If the agent shouldn't inherit the device's lifecycle, its continuity has to live somewhere else. 393 394[*The Log Is the Agent*](/blog/the-log-is-the-agent) argued that an agent's continuity lives in its durable event history, not in any particular machine or process. Every message, tool call, and decision is appended to a log, and a fresh executor can reconstruct the agent from that log alone. 395 396That property demotes the machine. If reconstruction is always possible, no laptop â no continuously running process anyw
396here â needs to own the loop. 397 398Which suggests a cleaner boundary. 399 400- **The control plane** owns the durable agent: its event history, pending work, model calls, approvals, and lifecycle. 401- **The execution plane** holds the environments where actions land: a laptop with a working tree, a cloud machine running tests, a host inside a private network. 402 403 404 405Where the control plane runs is a deployment choice. It can be managed, self-hosted in a VPC, or operated on private infrastructure. What matters is that it persists independently of whichever device the user happens to be holding. 406 407The execution plane can span everything from your laptop to cloud sandboxes, containers, VMs, and GPUs. The key inversion is that machines are now exposed to the agent as tools. And it's up to the agent to decide where to run what, be it in the control plane itself when no dedicated machine is needed, or in whichever execution environment it finds best fits the work. (More on the execution plane in its own post.) 408 409 410 411Separate the lifecycles this way, and the loop itself can go serverless. 412 413## What a Serverless Agent Actually Is 414 415A message arrives. An ephemeral worker claims the agent, reconstructs its state from the log, asks the model for the next action, records it, and disappears. When a tool result, timer, or human reply lands later, a different worker picks up where the last one left off. 416 417Simplified example: 418 419\`\`\`python 420# Runs on any worker, whenever an event lands 421def advance(agent_id, event): 422 with temporary_lease(agent_id): 423 append_to_log(agent_id, event) 424 state = reconstruct_from_log(agent_id) 425 action = model.next(state) 426 append_to_log(agent_id, action) 427 dispatch(action) # fire-and-forget 428 # worker exits - the agent persists in the log 429\`\`\` 430 431"Serverless" doesn't mean no computer runs the loop. It means no particular computer owns it. Workers are temporary executors over durable state. An agent can therefore remain alive while zero workers are running. It may simply be waiting on CI, an approval, a scheduled time, or another external event. 432 433 434 435Local-first architecture also obscured how little agent work requires a dedicated machine. A chat turn is the clearest example: a message arrives, the model responds, and the agent waits. The same is true when an agent calls an API, browses the web, invokes an integration, or asks a human a question. None of those actions requires a Linux box assigned to the conversation. 436 437A machine enters only when the agent needs something the control plane can't provide: an operating system, a working tree, a private network, specialized hardware, or local data. Binding every agent to a machine mistakes an occasional execution requirement for a permanent dependency. 438 439## The New Role of the Device 440 441The most compelling part of this shift is that the user experience can remain exactly as it is today. Nobody has to abandon the terminal, replace their IDE, or move every repository into a cloud sandbox. The interface that made local agents useful stays. 442 443You open a terminal inside a repository, type a request, watch commands run against local files, and approve changes in the same place. The agent uses the same working tree, tools, and credentials because the laptop remains part of the execution plane. 444 445What changes is the role of the device. It is no longer the container for the agent; it is a client connected to a durable harness running elsewhere. When that harness needs to read a file or run a local command, it routes the action to the laptop and records the result back into the agent's history. From your perspective, the command ran locally. From the system's perspective, the local machine was just one execution environment utilized by the agent. 446 447The difference appears when the device disappears. Close the laptop and work that depends on its local files may pause, but the agent remains in the control plane. If the required state is available elsewhere, it can continue there or reproduce the environment on a new machine. And when the laptop returns, the same agent can resume using it again. The machine, it turns out, was never special: the agent can provision machines as the task demands, spread work across several at once, release them when it's done, and carry on as machines come and go. 448 449 450 451And because the agent is no longer contained by one interface, it can be reached through many. Start a task from a laptop, approve a question from a phone, follow its progress in Slack, and review the result from another machine. Several people can also steer the same durable session without sharing access to one developerâs terminal. 452 453In this setup, the laptopâs role resolves cleanly: an interface for the user and an execution environment for the agent. No longer the place the agent lives. 454 455## Properties That Fall Out 456 457Once continuity no longer depends on a particular device or process, several properties follow. 458 459**Availability.** Agents spend most of their lives waiting â on tests, approvals, timers, APIs, people. In a local architecture, every wait is an uptime requirement for some machine. In a persistent control plane, waiting is just durable state. When new work arrives, a worker reconstructs the agent and continues. The agent doesn't need to run continuously to be continuously available. 460 461**Resilience.** Because no worker owns the agent, workers are allowed to fail. Another reconstructs the same state from the log and picks up. A laptop can disconnect without erasing the agent's objective, history, or pending work. This doesn't magically migrate an uncommitted working tree or a running OS process, but one executor's failure no longer becomes the agent's failure. The process died; the agent didn't. 462 463**Scalability.** The platform no longer needs one continuously running process per agent. A shared worker pool advances whichever agents currently have work, and the two kinds of capacity scale on separate curves: 464 465\`\`\` 466worker capacity scales with concurrent agent advancement 467machine capacity scales with active operating-system work 468\`\`\` 469 470**Efficiency.** A persistent agent no longer implies a permanently allocated sandbox. Imagine 1,000 durable agents where only 5 percent need a shell at any given moment: the control plane holds 1,000 histories, but the execution plane only needs capacity for ~50 active workloads plus headroom. Thatâs the outcome of separating persistent identity from active execution. An idle agent consumes durable storage rather than
470idle machines. And specialized hardware can attach for one stage of a task instead of for the agentâs entire lifetime. 471 472Now some environments should remain warm. A large repository, a loaded model, an expensive-to-rebuild cache, or simply an actively used workspace can all justify keeping a machine alive. The difference is that persistence becomes an explicit choice rather than a side effect of the agent existing. 473 474And these are only a few examples. Treat agents as durable systems rather than device-bound processes, and they gain the properties we expect from serverless infrastructure. 475 476## Who Owns the Loop 477 478The industry is already moving in this direction. Anthropicâs [Managed Agents](https://www.anthropic.com/engineering/managed-agents) separates the harness advancing the agent from the sandbox where code executes. Inference can begin before a container is provisioned. Ramp, Stripe, Sentry, Coinbase, and others have built internal background agents around related separations. 479 480But notice what none of them offer: ownership. The internal agents are internal. The managed offerings run one provider's models on that provider's infrastructure: not model-agnostic, not open-source, not self-hostable. 481 482We think that has to change, because an agent is the most intimate software you'll ever run. To be useful, it needs your personal data, your company's data, your workflows, your decisions. [*The Log Is the Agent*](/blog/the-log-is-the-agent) made the argument for the record itself: if a provider holds the only durable copy of your agent's history, the provider owns your agent. The same argument now climbs a level. The control plane is where the log lives and the harness runs, so you should be able to own that too. 483 484## How We Handle This in Practice at Omnara 485 486At Omnara, the control plane owns each agentâs durable log and lifecycle. Temporary workers advance the loop when messages, tool results, or other events arrive. 487 488Machines join the execution plane through a small daemon that connects outbound to the control plane. The control plane records a command, the daemon claims and executes it, and the result is written back to the agentâs log. The worker that requested the action and the machine that performs it do not need to be alive at the same time. 489 490This makes machines tools. An agent can discover, acquire, target, and release them as needed. If a machine goes offline or fails to complete an action, the outcome is written back as a structured result, and the agent can decide what to do next. A machine provides compute, files, network access, and hardware. It never provides the agentâs identity. 491 492## Conclusion 493 494The point of this piece was twofold: to pull apart the agent from its execution environment, and make the resulting architecture serverless. Agents broke the status quo. An agent that can outlive your presence shouldn't inherit the lifecycle of your device. 495 496Put the loop in a persistent control plane. Make it serverless. Expose machines as tools. The rest falls into place: availability, resilience, scaling, efficiency. 497 498That's the system we're building at Omnara. Weâre preparing to open-source our control plane for agents soon. You can [join the waitlist here](https://omnara.com). 499 500> **Update:** Omnara has launched. You can use Omnara Cloud or self-host. 501`,y=`--- 502title: "The Harness Doesn't Matter" 503subtitle: "Just use Pi, bro" 504seoTitle: "The Harness Doesn't Matter | Omnara" 505seoDescription: "What an AI agent harness really is, why most harnesses are equivalent, and where they can still meaningfully differ." 506date: "2026-09-01" 507author: "Kartik Sarangmath" 508thumbnail: "./assets/titleimg-thdm.jpeg" 509draft: false 510--- 511 512Models are out. Harnesses are in. Cheap open source models have taken the wind out of the big AI labs, and model gateways like OpenRouter have made the cost of switching models basically zero. The value is moving up the stack into the layer that wields those models: the harness. 513 514If you already know what a harness is, you can skip to the âWhat is NOT a Harness?â section. 515 516## **What Is a Harness?** 517 518A raw LLM is a stateless function. It takes some input text like âwhat color is an orangeâ and returns some output text, usually something like âYouâre absolutely right!â 519 520A harness is just a loop around the LLM, which allows it to be called multiple times. 521 522 523 524There, thatâs a harness! With it, we can talk to the LLM forever. The only problem is that the LLM wonât remember what you said one message ago, since itâs stateless. 525 526To solve this really challenging problem, our brightest minds came together and arrived at a brilliant solution: why not pass the entire conversation to the LLM on every call? 527 528 529 530Now, every time you talk to the LLM, it remembers what you said before. 531 532One more issue though. It can only respond with text. How do we get it to actually do things? We give it tools: 533 534 535 536Thatâs pretty much it. Thatâs AGI. It remembers everything you said, it can continue conversations, it can solve math problems that havenât been solved in decades, it can create trillions of dollars in the stock market, it can reply to Dax tweets a second after theyâre posted. 537 538From here, you can add MCPs, skills, memory, subagents, bash, and everything else youâve ever seen an agent do. Every modern harness is some version of this same loop. This loop is the harness. 539 540## **What Is NOT a Harness?** 541 542An interface or UI is NOT the harness. There is no such thing as an âiMessage harnessâ or a âSlack harness.â The interface is whatever sends messages to the harness and displays what comes back. 543 544Harnesses like OpenCode and Codex make this distinction pretty clear because they implement a client-server architecture. [OpenCodeâs server](https://
544opencode.ai/docs/server/) runs the harness loop, while its TUI connects as a client. [Codexâs app-server](https://learn.chatgpt.com/docs/app-server) serves the same role for Codex CLI, their desktop app, and interfaces such as its VS Code extension. A Slack bot interface could talk to the OpenCode server just like its TUI does, and now youâre using OpenCode through Slack. You could even use the Codex CLI as the frontend for an OpenCode server (idk why youâd want to do that, but Iâm not judging). 545 546The system prompt, tools, memory system, subagents, plan mode, and pretty much every other agent âprimitiveâ you care about are also NOT the harness. They all reduce to the same two variables the loop already takes in: the system prompt and the tool set. MCP just adds more tools, a subagent is just a tool that launches another loop, and skills, memory, and plan mode change the system prompt and add new tools. Take the toy harness in the above example, drop in Claude Codeâs system prompt, reproduce its tool definitions and implementations, and you basically have the Claude Code harness (probably a bit better, actually). 547 548 549 550Being able to edit the system prompt and tools is table stakes for a harness. If you can customize those two things, you should be able to reproduce pretty much the exact behavior of another harness without changing the harness code itself. For example, give Pi the same tools and system prompt as OpenCode, and it should behave like vanilla OpenCode without changing any of Piâs harness code. Hereâs a repo that I (i.e. Codex (i.e. gpt-5.6-sol)) made that actually does that, and you can see the results of the two harnesses side by side: [harness-equivalence](https://github.com/omnara-ai/harness-equivalence). 551 552If a harness can be used to represent any other harness, what does that mean? 553 554## **The Harness Doesnât Matter** 555 556All that matters is the system prompt and tools you give the harness, as well as the interface to interact with that harness. Thatâs where all the alpha is. Thatâs where all the value will flow. Youâre welcome, go use this information to make you millions in the stock market. 557 558Of course, this argument relies on some pretty big assumptions that Iâve conveniently glossed over. What if, instead of using our brilliant append-the-entire-conversation algorithm, the harness rebuilt the conversation state at every turn? It could use another LLM to decide what gets pruned or emphasized, or route hard tasks to a super smart LLM and easier tasks to a workhorse. You couldnât easily reproduce a harness like that by handing Pi a system prompt and some tools, because the difference would live in the harness algorithm itself. 559 560It seems like this is where harnesses could truly differentiate themselves and create the most leverage. There are so many different algorithms that could be used! 561 562But for some reason, every popular harness manages conversation state in basically the same way. They also donât do model routing. They all behave like the simple while loop above. The existing conversation stays as is, anything new gets appended, and the same LLM gets called again. 563 564And that wonât change any time soon, because of the prompt cache. 565 566Itâs much cheaper to call an LLM with text that is prefixed with the EXACT same text as the previous call because of something called the prompt cache ([hereâs why itâs cheaper](https://huggingface.co/blog/not-lain/kv-caching)). The LLM provider has already done the work for that part of the conversation, so it only has to process whatever comes after it. Change one letter and everything after it gets processed from scratch and billed at full price. On Claude, uncached input costs 10x as much as reading those tokens from the cache ([Claude pricing](https://platform.claude.com/docs/en/build-with-claude/prompt-caching#pricing)). 567 568Since everyone is scared of paying 10x more on their already-egregious model bills, pretty much every harness goes out of its w
568ay to avoid missing the cache. The safest way to do that is to leave the existing conversation untouched and only add to the end. Thatâs why they all end up as the same rudimentary loop. 569 570There is, however, one point where the cache is going to break no matter what, and the harness can rebuild the conversation however it wants. 571 572## **Compaction** 573 574Compaction is arguably the biggest way that harnesses differ today, at least when it comes to performance-related features. LLMs have a limit on how much conversation you can pass into them, so when a conversation gets close to that limit, compaction summarizes or removes old parts so the LLM can keep going. The full conversation can still exist in logs, but the model only sees the compacted version. 575 576Compaction can be implemented however you want, because the prompt cache is going to break anyway. A harness can prune old tool results, or use another LLM to summarize the older conversation, or keep only the last few messages, or do something completely different. The possibilities are endless. Compaction is especially important for long-running tasks because it decides what the LLM remembers over time. Codex is commonly praised for its compaction, which is implemented via [server-side compaction](https://developers.openai.com/cookbook/examples/gpt-5/codex_prompting_guide#compaction). This returns opaque encrypted content, so you canât inspect the compaction content, and that compaction content only works with OpenAIâs API (Iâm not a fan of this lock-in, but thatâs besides the point). Whatever algorithm theyâre using is good, and itâs a big reason long-horizon tasks feel great on Codex. 577 578In practice, most harnesses land on the same basic algorithm. They summarize older history with an LLM, keep the recent messages, and sometimes prune tool outputs. The summary prompts and cut points differ, but thatâs about it. So even compaction is not that different between harnesses. And in the worst case, you can just give the harness a tool that searches through its conversation history, which can make up for a lot of bad compaction. 579 580## **RLâed Harnesses** 581 582Another argument from the labs is that Claude Code and Codex have an advantage because their models were trained inside those exact harnesses. But since Codex and Claude Code are both open source ([iykyk](https://x.com/trq212/status/2092305080158748741)), you can copy their system prompts and tool implementations into Pi, and the model wouldnât know the difference. Also, if AGI gets confused because an \`edit\` tool takes \`path\` instead of \`file_path\`, we should probably sell our Nvidia stock. 583 584Public benchmarks also show that itâs a toss-up. On [Terminal-Bench 2.0](https://www.tbench.ai/leaderboard/terminal-bench/2.0), GPT-5.5 scored 84.7% with NexAU-AHE and 83.1% with Capy, both ranking above its 82.2% with Codex. The current [Terminal-Bench 3.0](https://www.frontierbench.ai/) leaderboard is topped by Opus 5 running in [mini-SWE-agent](https://github.com/swe-agent/mini-swe-agent) at 42.7%, ahead of every native model-harness pairing on the board. [Terminal-Bench 2.1](https://www.tbench.ai/leaderboard/terminal-bench/2.1) goes the other way, with the native harnesses coming out on top. 585 586The native harness wins some and loses some, and itâs pretty arbitrary when or why that happens. Training the model inside a particular harness might make the model more comfortable with those tools, but whatever advantage that creates should only shrink as models get better, if it even mattered in the first place. 587 588## **Conclusion** 589 590You donât need to build your own harness, and you donât need a harness for all your harnesses. I made this post because I kept seeing people on X treat the harness itself like some deep optimization problem, and I think most people would save a lot of time by just using a good one and moving on (just use Pi, bro). Worry about the system prompt and tools you give it, and how you interface with it! 591 592 593 594_this comes from a place of love_ 595 596## **One Last Thing** 597 598Iâm building my own harness. 599 600 601 602_you right now_ 603 604### **Why?** 605 606Because the harness matters for reasons that arenât directly tied to task performance. I just havenât covered those in this post. 607 608Next week Iâll tell you why the harness actually matters :) 609`,f=`--- 610title: "The Log Is the Agent" 611subtitle: "" 612seoTitle: "The Log Is the Agent | Omnara" 613seoDescription: "An agent is its durable event history: the log that lets it resume, fork, migrate, and survive failures across models, runtimes, and machines." 614date: "2026-06-11" 615author: "Ishaan Sehgal" 616thumbnail: "./assets/thumbnail.png" 617--- 618 619Think about a character you have spent 100 hours playing in Skyrim or Elden Ring. 620 621What exactly is your character? 622 623- Is it the game engine? No. 624- Is it the PlayStation? No. 625- Is it the controller? No. 626 627Your character is the save file. 628 629If your PlayStation bursts into flames, your character is not dead. You buy another PlayStation, download your save file from the cloud, and your character is exactly where they were, mid-swing. 630 631 632 633AI agents are hitting the same inflection point. 634 635Most people think an agent is the model, the runtime, or the loop currently executing the task. Those things matter. But they aren't the agent. 636 637In this piece I'll argue that **an agent is its data**: specifically its history of events, which we'll call the log. When the log is constructed correctly, an agent can be resumed from it alone. And that single property unlocks a whole set of capabilities that make even advanced agent use cases easier to reason about and build into everyday applications. 638 639## Defining the Agent 640 641So what is the log? Defining the agent means defining the log. At its core, the log is the event history: every user input, model output, tool call, and tool result that accumulates as the agent works: an append-only record of everything that happened.
642 643The log also carries a reference to the session definition: the system prompt, tool descriptions, and skills the agent is running under. This doesn't change from turn to turn, so it's more a versioned constant than an active part of the stream. 644 645Together they form the agent's full state. Nothing the agent is lives in the runtime, the model, or the tools; they're just interpreters and appenders. They read the durable state, act on it, and write the next event back. So you can hand a fresh executor the same log and it will reconstruct exactly where the agent was and continue from there. The log is enough, on its own, to resume the agent. 646 647## The Log in Practice 648 649Once you define the agent as the log, the rest of the system gets easier to reason about. Every operation on the agent either **reads the log, appends to it, or renders a view of it**. The model reads a view and produces the next action. The tool runner executes a tool call and appends the result. The UI reads the log and renders a timeline; the tracing system reads it and renders traces;
649 an auditor reads it to reconstruct what happened. It's the same pattern databases settled on years ago: the tables, indexes, and caches are all projections over an underlying log of changes. Diagram below adapted from [@dexhorthy](https://x.com/dexhorthy)'s excellent [12-factor agents](https://github.com/humanlayer/12-factor-agents); worth a read if you haven't. 650 651 652 653_A high-level agent control loop, running on the log._ 654 655In practice, a simplified loop can look like this: 656 657\`\`\`python 658while session_has_work: 659 take_temporary_lease(session_id) 660 state = reconstruct_from_log(session_id) 661 response = model.next(state) 662 append(response, to=session_log) 663 664 if response.requests_tool: 665 append(tool_call_started, to=session_log) 666 result = run_tool(response.tool_call) 667 append(result, to=session_log) 668 continue 669 670 finish_turn(session_id) 671\`\`\` 672 673It looks simple, but the insight is that each pass claims a temporary lease, reads the log, advances one step, and writes the result back. The loop is idempotent and fault-tolerant: as long as every meaningful state transition is durably written, any executor can pick up the session and carry on. 674 675## Compaction Is Not the Log 676 677While the log can grow indefinitely, a model's view of it can't: context windows are finite. You can't hand the model the entire raw history on every call. This is where compaction comes in. And since compaction replaces everything before it with a summary, doesn't that destroy the claim that the log is the agent? 678 679No, it doesn't. Remember, compaction is lossy. A compacted summary doesn't reproduce the agent's state in a smaller form; it throws information away. 680 681That actually reinforces the claim. The full log is the record; a compaction is just one projection of it, the way a materialized view isn't the database and a summary isn't the conversation. Keep the raw log and you can always generate new projections from it. Throw the raw log away and keep only the compaction, and you've lost part of the agent. So it's cleanest to treat compaction as a best-effort, lossy fork, one you resume as a new log. 682 683 684 685## The Log Isn't the Whole World 686 687There's an obvious objection, worth taking seriously: what about tools that change state outside the log? An agent edits a file, opens a GitHub issue, sends an email. Now there's state living somewhere other than the log. Doesn't that sink the claim? 688 689No, it doesn't. You re-derive the agent's state from the log, not the world: if it already sent the email, forking back won't un-send it, and a file it edited may have changed underneath it. The log doesn't make the world deterministic or reversible. It keeps a faithful, resumable record of what the agent did and saw, which is exactly the thing you can't afford to lose. The save file makes the same move: it doesn't contain the Skyrim engine or the map, just the player-specific state needed to drop you back in. And if the world has changed since the agent last ran, the agent, much like the character, updates its worldview as it re-engages with what's around it. 690 691## Properties That Fall Out 692 693Reasoning about agents this way gives you a set of nice system properties. They aren't independent; they all fall out of the same assumption that the log is the agent. 694 695- **Reliability.** Consider what happens today with Claude Code: if the agent reaches a permission prompt and the process dies, and you resume it, the permission prompt is gone and the agent has paused. That's unacceptable in production. When the log is the agent, the executor is allowed to be fallible: a new worker picks up the session, reconstructs the state, and the permission prompt is right where it was. The process died; the agent didn't. 696- **Scalability.** Most harnesses run one process per agent, which means the agent is tied to the machine running it. When the log is the state, you flip that model: one process can advance thousands of agents, each reconstructing its state from the log on each turn. The agent isn't tied to any single machine or worker, making failover trivial. And scaling out is just adding more workers: no sticky sessions, no state migration, no coordination overhead. 697- **Forking.** Instead of one linear path, you can branch the log. One branch runs on Claude, another on GPT, another on a local Qwe
697n, each exploring a different strategy, in a different sandbox, with different tools. Exploring different approaches becomes a lot simpler to architect. 698- **Multiplayer.** Sharing an agent shouldn't mean copying a transcript into Slack. That's like sharing a screenshot of a database and calling it replication. If the log is the agent, sharing means granting access to a durable history someone else can inspect, resume, or extend. 699- **Migration.** If the agent's identity is trapped inside provider-specific assumptions, moving providers is painful. If the log is the agent, migration becomes an adapter problem. Different models may want different projections, but those are engineering problems, not identity problems. The log is the continuity, and the agent should be able to pick up and resume interchangeably with any model provider. 700 701These are only a few examples. Once you start thinking of agents this way, they become pieces of data, and many of the things you can do with data become possible with agents too. 702 703## The Log as a Second-Class Citizen 704 705Most agent harnesses today treat the log as an afterthought: 706 707- **Claude Code and Codex** write transcripts as messy JSONL files to local disk. In Claude SDK mode, those writes are fire-and-forget, meaning if anything goes wrong before the write completes, that data is gone. 708- **OpenCode** stores state in a local SQLite file; GitHub issues report corruption and data loss. 709- **Durable objects** often end up holding different shards, making reconstructing history difficult. 710 711The log is a side effect, not the system. 712 713When you treat the log as a first-class citizen, durable, structured, replayable, and independent of the machine running the agent, all of these properties become structural. You don't bolt them on. They fall out. 714 715## Owning the Log 716 717One last point I'd want you to leave with: owning the log matters enormously. If the log is the agent, then whoever owns the log owns the agent. 718 719Long-term, the strongest form of lock-in isn't model lock-in: models can be swapped. It isn't API or tool lock-in either; those can be wrapped and adapted. The deepest lock-in is log lock-in. If a provider owns the only durable record of your agent, then that provider owns your agent. You can export a projection, a transcript, say, and still lose the agent, because the agent isn't its final output; it's the path-dependent history that produced it. 720 721This is worth taking seriously right now. Anthropic has Claude Managed Agents. Google has Gemini managed agents. Every major provider is moving to own more of the stack: hosted agent loop, managed memory, sandboxes, compaction, background execution. They want to own your agents, and agents are arguably the most intimate piece of technology you'll ever run. For an agent to be useful, it needs access to your personal information, your company's data, your workflows, your decisions. The log is a record of all of that. If it lives on someone else's infrastructure, under their retention policies, queryable by their systems, then they don't just host your agent. They own it. 722 723 724 725That's not an argument against managed infrastructure; it's useful and probably inevitable for most teams. But you should know where your log lives, who can inspect it, and whether it can be replayed, forked, migrated, or exported. Once the session log is the primitive, log ownership is agent ownership. 726 727## How We Handle This in Practice at Omnara 728 729At Omnara we think about agent execution as a set of components coordinated around a durable session log. A worker advances the loop, but the worker isn't the agent; it's just the current executor. 730 731When an agent calls a tool, the worker doesn't have to sit there holding all the state in memory. It writes to the log that a tool call started, dispatches the tool to whatever execution environment it belongs in, and lets it finish elsewhere. When the tool completes, its result gets appended back to the log, and a worker, maybe a different one, reconstructs the state and continues. 732 733This matters because agent systems have to survive real-world failure: workers crash, machines restart, sandboxes vanish, tool calls run long, providers fail, users disconnect. If the agent is the running process, all of that is terrifying. If the agent is the log, it's just execution detail. The session keeps going because the agent's state was never trapped inside the thing executing it. Treating the log as the system, durable, structured, and independent of any single machine, is the core of how we've built Omnara. 734 735## Conclusion 736 737The point of this piece was to get you reasoning about agents from first principles. An agent is the durable history of the work being done, and that history is the log. 738 739Once you see it this way, a lot falls into place: reliability, scalability, compaction, forking, migration, multiplayer, ownership. It also changes how you build. You stop treating the log as exhaust the system gives off and start treating it as the system itself. The loop becomes an executor over the log. It's the same inversion databases went through years ago: the durable history is primary, and everything else is a projection. 740 741If this was useful, stay tuned to what we're building at Omnara. We're getting ready to open-source our managed agent platform, and you can [join the waitlist here](/). "The log is the agent" is just one of several pieces we think will make agents far more powerful in the future. 742 743> **Update:** Omnara has launched. You can use Omnara Cloud or self-host. 744`,w=`--- 745title: "Beyond the Desk" 746subtitle: "How programming is changing, and why we built Omnara" 747seoTitle: "Beyond the Desk: Why Mobile AI Coding Agents Matter in 2026" 748seoDescription: "Learn how AI coding agents are changing software development from desk-bound workflows to mobile-first, always-on execution, and why Omnara built for that shift." 749date: "2026-01-28" 750author: "Kartik Sarangmath" 751thumbnail: "./assets/thumbnail.png" 752archiveNote: "This post covers Omnara's previous remote coding product and is retained for historical reference. Its features and usage figures refer to that product. Omnara is now an open-source managed-agent platform." 753--- 754 755*The moment you step away from your desk, progress stops.* 756 757Writing software has always been a synchronous act. You sat down at a computer and translated your thoughts into code line by line, remaining fully responsible for every change as it happened. Progress depended on your presence. 758 759When AI entered programming, it didnât immediately change this. Cursor sped up typing and answered simple questions, but the workflow itself stayed the same. Even with better autocomplete, developers were still the bottleneck, watching code change in real time and staying fully engaged throughout. 760 761The real shift came with coding agents. 762
763Claude Code made it possible to describe what you wanted to build rather than how to build it, and to let code be written in the background. By abstracting away the code view and much of the machinery of an IDE, agents encouraged a different relationship with programming, one centered on intent and direction instead of constant execution. 764 765Once code can be written without your continuous attention, the old assumptions break down. Programming no longer needs to block you, and there is no inherent reason to remain at your computer while work progresses. 766 767In practice, todayâs tools still fall short. Some agents run locally and stay close to real code, but only work while you are at your computer. Others run in hosted environments, detached from the familiar codebases and setups that developers are used to working in. 768 769We built Omnara to close that gap. 770 771Omnara lets you run Claude Code on your own computer while allowing you to stay connected to it from anywhere. You can step away and continue steering from your phone without breaking the flow of work. If your machine does go offline, you can continue the session in the cloud and sync back when it returns. When typing isnât convenient, you can speak with your agent instead. 772 773Whatâs stood out most to us is how naturally this fits into peopleâs lives. Over six thousand people have sent more than two million messages through Omnara, often away from their desks. A few of the ways weâve heard people use it include walking the dog while building a travel app, driving to work while keeping a machine learning training job on track, or being at the gym while pushing a startup forward. The work keeps moving, even as life goes on around it. 774 775For a long time, building software meant being chained to your desk. Inspiration that struck elsewhere had no way to move forward. Thatâs no longer the case. We built Omnara to let you keep building when ideas show up, wherever you are. 776 777--- 778 779## Try Omnara 780 781If this way of building resonates with you, try out Omnara for free. 782 783Install Omnara in your terminal: 784 785\`\`\`bash 786curl -fsSL https://omnara.com/install.sh | bash 787\`\`\` 788 789Then run Omnara in the directory you want to work from: 790 791\`\`\`bash 792omnara 793\`\`\` 794 795Join the [Discord](https://discord.gg/Dc46sYk6e3) to ask questions, share feedback, and discuss ideas with the community. 796 797â Ishaan, Kartik, and Christian 798`,b=`--- 799title: "What Is an Async Agent, Really?" 800subtitle: "Spoiler: you may or may not find out" 801date: "2026-02-09" 802author: "Kartik Sarangmath" 803thumbnail: "./assets/conductor.png" 804--- 805 806Look up the term "async agents" online. You'll find dozens of posts using the phrase, and the ones that bother to define the term all seem to be talking about different things. It shows up in product announcements, HN threads, and architecture blog posts, always casually, as if the meaning were obvious. So I wanted to figure out which definition was actually correct. 807 808The most common definition I saw was that an async agent is simply an agent that runs for a while. A long-running task feels async. If it keeps working while you go to the bathroom or refill your water bottle, that feels asynchronous. And it's true that a task running long enough gives you the opportunity to go do something else. But then how long does the task need to run before it counts? What about an agent that finishes in a second versus one that takes an hour? Is the fast one synchronous and the slow one async? Can I create an async agent by adding a \`sleep\` statement before running the agent? That doesn't feel like a satisfying definition. 809 810Another definition I kept running into was that async agents are the ones running in the cloud. Devin runs remotely, so it's async. Claude Code runs locally, so it's not. But if I spin up an EC2 instance, SSH in, install Claude Code, and run it there, did I just convert it into an async agent? The tool didn't change. Only the machine running it did. That can't be it. 811 812The third definition was that async agents are event-driven. The ones that get triggered without you. A PR lands and an agent spins up. A cron job fires and the agent messages you on Slack. That feels asynchronous because you aren't the one typing the command at that moment. But a cron job can kick off any program. The trigger is asynchronous, but that doesn't make the program it runs async. That's scheduling, not a property of the agent itself. 813 814None of these are wrong exactly, but none of them feel like definitions either. They're all describing properties that happen to correlate with the thing people are trying to point at. So let's go back to basics. 815 816## What's an Agent? What's Async? 817 818As Simon Willison put it, an agent is just [an LLM that runs tools in a loop](https://simonwillison.net/2025/Sep/18/agents/). I'd go a
818step further and say an agent also needs continuity of context. If I start up two different sessions of Claude Code, those are two different agents. If I type \`/clear\` in an instance of Claude Code, I've killed one agent and spawned a new one. The context is what makes it *that* agent. 819 820Now, asynchrony.[^1] The [technical definition](https://en.wikipedia.org/wiki/Asynchrony_(computer_programming)) says it's when events happen independently of the main program flow. The key insight is that an async function isn't magically async by itself. It's async *relative to its caller*. If the caller doesn't wait, the function runs independently. If the caller waits, it's effectively synchronous. The async part isn't the function. It's the caller's decision to not block on it. 821 822[^1]: This [FastAPI post](https://fastapi.tiangolo.com/async/) is how I first really understood async programming. Still one of the best explainers out there. 823 824Think about what coding looked like before agents. You typed; work happened. You stopped typing; work stopped. You could only progress one task at a time, all of it synchronous. 825 826When coding agents arrived, they unlocked something new. They made asynchronous work possible. You could delegate work and not wait for it to finish. You could give an agent a task, go make lunch, and come back to a finished PR. For the first time, your work could keep progressing while you did something else. 827 828But that didn't make the agent inherently async. You could turn around and ask the same agent a quick question and wait for the answer. In that moment, you used it synchronously. The agent didn't change. Your behavior did. 829 830So what is this "async agent" that everyone keeps referring to? It's in the eye of the beholder. The real async agents were the friends we made along the way. 831 832But seriously, no agent is inherently async. **It just depends on whether you wait for it to finish or not.** 833 834## Using Agents Asynchronously 835 836If you *do* choose to use agents asynchronously, you unlock something powerful: concurrency. You can delegate multiple tasks to multiple agents and let them all make progress at the same time. But once you do that, you hit a practical problem: they're all working on the same codebase on your machine. That's not how real engineering teams work. Every engineer has their own computer, their own copy of the code, their own branch. 837 838Why not just have everyone edit the same codebase in real time, like Google Docs? Seems like it would eliminate an entire class of problems: broken merges, conflicting edits, diverging branches⦠basically all the stuff Git makes you deal with. Collaborative coding has been tried, and it hasn't caught on for good reason (this is what [Replit](https://replit.com/collaboration) did early on). The problem is that without isolation, one person's work-in-progress can break another person's working code. You need each task to live in its own environment where it can be built, tested, and validated independently. 839 840Agents run into the same problem. They need their own copy of the codebase to make progress without stepping on each other. That's why tools like [Conductor](https://www.conductor.build/) and [Omnara](https://omnara.dev) rely on git worktrees, why people like [Boris (creator of Claude Code) literally clone whole directories](https://x.com/bcherny/status/2017742743125299476), and why apps like [Codex Web](https://developers.openai.com/codex/cloud/) or [Sculptor](https://imbue.com/sculptor/) use isolated VMs or local containers. Each agent gets its own workspace so one agent's progress doesn't break another's. 841
842With isolated workspaces, you're the manager. You're the one spawning agents, watching agents, coordinating agents. Delegating work to agents is a huge force multiplier. It dramatically increases output, but it also increases the amount of context you have to manage and switch between. There is a ceiling. 843 844Which begs the question: can an agent manage the agents? 845 846## So What Should "Async Agent" Actually Mean? 847 848Honestly, we probably shouldn't use the term at all. But if you're going to anyway, it should mean something that isn't already true of every agent. And there's a natural parallel from programming that gives us exactly the right distinction. 849 850In software, there's a difference between an async *function* and the *runtime* that manages it. An async function can run without blocking its caller. The async runtime is the thing that manages the event loop: it spawns functions, schedules them, and coordinates their results. The function is just along for the ride. The runtime is doing the orchestration. 851 852Agents map onto this perfectly. Every agent today is an async function. You call it, it runs, you go do something else. But an async *agent*, in the meaningful sense, is the runtime. It's an agent that manages its own event loop of other agents. 853 854You give it a task; it spins up a subagent in a background workspace and keeps interacting with you. You ask it to build a login page. "Got it." It delegates that to another agent running in the background. You ask it for a billing page. "Sure, and by the way, the login agent wants to know if you prefer GitHub or Google OAuth." You're not switching tabs or managing ten sessions. The agent is managing the team. You're talking to one entity, and that entity orchestrates all the others. 855 856You stopped being the developer. You stopped being the manager. You're just the person with the intent, and the agent figures out the rest. 857 858Early attempts at this model exist. [Claude's Agent Teams](https://code.claude.com/docs/en/agent-teams) and [Gastown](https://github.com/steveyegge/gastown) are early examples. And Cognition's ["Don't Build Multi-Agents"](https://cognition.ai/blog/dont-build-multi-agents) post explains why it's hard today: context sharing, token costs, unreliable inter-agent reasoning. But these are engineering constraints, not architectural ones. As models get cheaper, context windows expand, and agent-to-agent communication improves, this architecture will stop being experimental and start becoming the default. 859 860In programming, we distinguish an async runtime from a regular program because it manages concurrent execution. It spawns functions, schedules them, coordinates their results, and handles the plumbing that makes this possible: event loops, callbacks, shared state. A sequential program does not. 861 862The same distinction applies to agents. An agent that spawns subagents, manages their execution, shares context between them, and coordinates their results is architecturally different from an agent that just grinds through a task on its own. 863 864So if you're going to call something an "async agent," call it *that*. Not an agent that runs for a while. Not an agent that runs in the cloud. Not an agent triggered by a cron job. An agent that manages other agents concurrently. Everything else is just an agent you happened to not wait for. 865 866> **Editor's note:** The Omnara worktree example refers to our previous remote coding product and is retained for historical reference. Omnara is now an open-source managed-agent platform. 867`,v="/assets/immutable/thumbnail-BHxkU85_.png",k="/assets/immutable/diagram1-DAeUdDW9.png",I="/assets/immutable/diagram2-Bu8y-FMN.png",T="/assets/immutable/hero-Cg_SSu7G.png",x="/assets/immutable/alive-not-running-timeline-D_YQrGtD.png",C="/assets/immutable/control-execution-planes-C6LsvYcc.png",_="/assets/immutable/machine-lifecycles-as-tools-D1kyltac.png",A="/assets/immutable/machines-are-tools-BtjheLIS.png",S="/assets/immutable/one-machine-one-lifecycle-CC9n5Zsv.png",M="/assets/immutable/quarter-open-laptop-meme-EaOVAta7.png",j="/assets/immutable/thumbnail-DupNLuTB.png",W="/assets/immutable/img1-thdm-CyqFIbHa.png",D="/assets/immutable/img2-thdm-BkWtJh7e.png",P="/assets/immutable/img3-thdm-CGCC9iaE.png",L="/assets/immutable/img4-thdm-E_l6TVyW.jpeg",O="/assets/immutable/img5-thdm-DoR0PtQB.jpeg",H="/assets/immutable/img6-thdm-CgD5cynh.jpeg",B="/assets/immutable/titleimg-thdm-DAYWxpOq.jpeg",N="/assets/immutable/compaction-bgCnVYzw.png",Y="/assets/immutable/control-loop-D23esN3u.png",Z="/assets/immutable/owning-the-log-BU5Q0-GY.png",E="/assets/immutable/save-file-metaphor-MmA_uCQk.png",G="/assets/immutable/thumbn
867ail-C2C6DJ8V.png",z="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjY0MCIgdmlld0JveD0iMCAwIDEyMDAgNjQwIiBmaWxsPSJub25lIj4KICA8cmVjdCB3aWR0aD0iMTIwMCIgaGVpZ2h0PSI2NDAiIHJ4PSIzMiIgZmlsbD0iIzBCMEIwQiIgLz4KICA8cmVjdCB4PSI4MCIgeT0iMTIwIiB3aWR0aD0iMzIwIiBoZWlnaHQ9IjE2MCIgcng9IjIwIiBmaWxsPSIjMTExODI3IiBzdHJva2U9IiMxRjI5MzciIC8+CiAgPHJlY3QgeD0iNDQwIiB5PSIxMjAiIHdpZHRoPSIzMjAiIGhlaWdodD0iMTYwIiByeD0iMjAiIGZpbGw9IiMxMTE4MjciIHN0cm9rZT0iIzFGMjkzNyIgLz4KICA8cmVjdCB4PSI4MDAiIHk9IjEyMCIgd2lkdGg9IjMyMCIgaGVpZ2h0PSIxNjAiIHJ4PSIyMCIgZmlsbD0iIzExMTgyNyIgc3Ryb2tlPSIjMUYyOTM3IiAvPgogIDxyZWN0IHg9IjI2MCIgeT0iMzYwIiB3aWR0aD0iNjgwIiBoZWlnaHQ9IjE4MCIgcng9IjI0IiBmaWxsPSIjMTExODI3IiBzdHJva2U9IiMxRjI5MzciIC8+CgogIDx0ZXh0IHg9IjE3MCIgeT0iMjEwIiBmaWxsPSIjRTJFOEYwIiBmb250LWZhbWlseT0iSW50ZXIsIHNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMjQiPkNsaWVudDwvdGV4dD4KICA8dGV4dCB4PSI1MTUiIHk9IjIxMCIgZmlsbD0iI0UyRThGMCIgZm9udC1mYW1pbHk9IkludGVyLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjI0Ij5BUEk8L3RleHQ+CiAgPHRleHQgeD0iODgwIiB5PSIyMTAiIGZpbGw9IiNFMkU4RjAiIGZvbnQtZmFtaWx5PSJJbnRlciwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSIyNCI+QWdlbnRzPC90ZXh0PgogIDx0ZXh0IHg9IjUwMCIgeT0iNDUwIiBmaWxsPSIjRTJFOEYwIiBmb250LWZhbWlseT0iSW50ZXIsIHNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMjQiPk9tbmFyYSBQbGF0Zm9ybTwvdGV4dD4KCiAgPHBhdGggZD0iTTQwMCAyMDBINDQwIiBzdHJva2U9IiMzOEJERjgiIHN0cm9rZS13aWR0aD0iNCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiAvPgogIDxwYXRoIGQ9Ik03NjAgMjAwSDgwMCIgc3Ryb2tlPSIjMzhCREY4IiBzdHJva2Utd2lkdGg9IjQiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgLz4KICA8cGF0aCBkPSJNNjAwIDI4MFYzNjAiIHN0cm9rZT0iI0Y1OUUwQiIgc3Ryb2tlLXdpZHRoPSI0IiBzdHJva2UtbGluZWNhcD0icm91bmQiIC8+Cjwvc3ZnPgo=",R="/assets/immutable/thumbnail-B4mCIFCl.png",U="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjY3NSIgdmlld0JveD0iMCAwIDEyMDAgNjc1IiBmaWxsPSJub25lIj4KICA8ZGVmcz4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0iYmciIHgxPSIwIiB5MT0iMCIgeDI9IjEiIHkyPSIxIj4KICAgICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzBCMEIwQiIgLz4KICAgICAgPHN0b3Agb2Zmc2V0PSI1MCUiIHN0b3AtY29sb3I9IiMxMTE4MjciIC8+CiAgICAgIDxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzBGMTcyQSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgPC9kZWZzPgogIDxyZWN0IHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjY3NSIgcng9IjQ4IiBmaWxsPSJ1cmwoI2JnKSIgLz4KICA8cmVjdCB4PSI4MCIgeT0iODAiIHdpZHRoPSIxMDQwIiBoZWlnaHQ9IjUxNSIgcng9IjMyIiBmaWxsPSIjMTExMTExIiBzdHJva2U9IiNGRkZGRkYiIHN0cm9rZS1vcGFjaXR5PSIwLjA4IiAvPgogIDxjaXJjbGUgY3g9IjE4MCIgY3k9IjE4MCIgcj0iNDgiIGZpbGw9IiNGNTlFMEIiIGZpbGwtb3BhY2l0eT0iMC4yIiAvPgogIDxjaXJjbGUgY3g9IjEwMDAiIGN5PSI1MjAiIHI9IjY0IiBmaWxsPSIjMzhCREY4IiBmaWxsLW9wYWNpdHk9IjAuMTgiIC8+CiAgPHRleHQgeD0iMTQwIiB5PSIyNjAiIGZpbGw9IiNGOEZBRkMiIGZvbnQtZmFtaWx5PSJJbnRlciwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSI1NCIgZm9udC13ZWlnaHQ9IjYwMCI+T21uYXJhIEJsb2c8L3RleHQ+CiAgPHRleHQgeD0iMTQwIiB5PSIzMzAiIGZpbGw9IiM5NEEzQjgiIGZvbnQtZmFtaWx5PSJJbnRlciwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSIyNCI+VXBkYXRlcywgZ3VpZGVzLCBhbmQgcHJvZHVjdCBzdG9yaWVzPC90ZXh0Pgo8L3N2Zz4K",F="/assets/immutable/conductor-84y5f0Fy.png",q=Object.assign({"../content/blog/mobile-coding-landscape/index.md":g,"../content/blog/sandbox-sync/index.md":m,"../content/blog/serverless-agents/index.md":p,"../content/blog/the-harness-doesnt-matter/index.md":y,"../content/blog/the-log-is-the-agent/index.md":f,"../content/blog/welcome-to-omnara/index.md":w,"../content/blog/what-is-an-async-agent-really/index.md":b}),J=Object.assign({"../content/blog/mobile-coding-landscape/assets/thumbnail.png":v,"../content/blog/sandbox-sync/assets/diagram1.png":k,"../content/blog/sandbox-sync/assets/diagram2.png":I,"../content/blog/sandbox-sync/assets/hero.png":T,"../content/blog/serverless-agents/assets/alive-not-running-timeline.png":x,"../content/blog/serverless-agents/assets/control-execution-planes.png":C,"../content/blog/serverless-agents/assets/machine-lifecycles-as-tools.png":_,"../content/blog/serverless-agents/assets/machines-are-tools.png":A,"../content/blog/serverless-agents/assets/one-machine-one-lifecycle.png":S,"../content/blog/serverless-agents/assets/quarter-open-laptop-meme.png":M,"../content/blog/serverless-agents/assets/thumbnail.png":j,"../content/blog/the-harness-doesnt-matter/assets/img1-thdm.png":W,"../content/blog/the-harness-doesnt-matter/assets/img2-thdm.png":D,"../content/blog/the-harness-doesnt-matter/assets/img3-thdm.png":P,"../content/blog/the-harness-doesnt-matter/assets/img4-thdm.jpeg":L,"../content/blog/the-harness-doesnt-matter/assets/img5-thdm.jpeg":O,"../content/blog/the-harness-doesnt-matter/assets/img6-thdm.jpeg":H,"../content/blog/the-harness-doesnt-matter/assets/titleimg-thdm.jpeg":B,"../content/blog/the-log-is-the-agent/assets/compaction.png":N,"../content/blog/the-log-is-the-agent/assets/control-loop.png":Y,"../content/blog/the-log-is-the-agent/assets/owning-the-log.png":Z,"../content/blog/the-log-is-the-agent/assets/save-file-metaphor.png":E,"../content/blog/the-log-is-the-agent/assets/thumbnail.png":G,"../content/blog/welcome-to-omnara/assets/architecture.svg":z,"../content/blog/welcome-to-omnara/assets/thumbnail.png":R,"../content/blog/welcome-to-omnara/assets/thumbnail.svg":U,"../content/blog/what-is-an-async-agent-really/assets/conductor.png":F}),Q=n=>{const t=/^---\s*\n([\s\S]*?)\n---\s*\n?/.exec(n);if(!t)return{data:{},content:n};const a=t[1]??"",i=n.slice(t[0].length),e={};return a.split(` 868`).map(r=>
868r.trim()).filter(Boolean).forEach(r=>{const l=r.indexOf(":");if(l===-1)return;const o=r.slice(0,l).trim(),s=r.slice(l+1).trim().replace(/^['"]|['"]$/g,"");if(o==="draft"){e.draft=s.toLowerCase()==="true";return}s&&(o==="title"&&(e.title=s),o==="subtitle"&&(e.subtitle=s),o==="seoTitle"&&(e.seoTitle=s),o==="seoDescription"&&(e.seoDescription=s),o==="archiveNote"&&(e.archiveNote=s),o==="date"&&(e.date=s),o==="author"&&(e.author=s),o==="thumbnail"&&(e.thumbnail=s))}),{data:e,content:i.trim()}},V=n=>{if(!n)return null;const t=/^(\d{4})-(\d{2})-(\d{2})/.exec(n);if(!t)return null;const a=new Date(Date.UTC(Number(t[1]),Number(t[2])-1,Number(t[3])));return Number.isNaN(a.getTime())?null:a},$=n=>n.date?n.date.toLocaleDateString("en-US",{month:"short",day:"numeric",year:"numeric",timeZone:"UTC"}):n.dateLabel||"Undated",c=(n,t)=>{if(!t)return;if(/^(https?:|data:|#|\/)/.test(t))return t;const a=t.replace(/^\.\//,""),i=`${n}/${a}`;return J[i]},X=(n,t)=>{const a=/!\[([^\]]*)\]\(([^)]+)\)/g;return n.replace(a,(i,e,r)=>{const l=r.trim(),o=/^(\S+)(\s+"[\s\S]*")$/.exec(l),h=o?o[1]:l,s=o?o[2]:"",u=c(t,h)??h;return``})},K=()=>Object.entries(q).flatMap(([n,t])=>{const a=n.replace(/[\\/]+index\.md$/,""),i=a.split("/").at(-1)??a,{data:e,content:r}=Q(t),l={slug:i,title:e.title??i.replace(/-/g," "),subtitle:e.subtitle??"",seoTitle:e.seoTitle,seoDescription:e.seoDescription,archiveNote:e.archiveNote,date:V(e.date),dateLabel:e.date??"",author:e.author,thumbnailUrl:c(a,e.thumbnail),content:X(r,a)};return e.draft?[]:[l]}).sort((n,t)=>{var a,i;return(((a=t.date)==null?void 0:a.getTime())??0)-(((i=n.date)==null?void 0:i.getTime())??0)}),d=K(),ee=()=>d,te=n=>d.find(t=>t.slug===n);export{$ as formatPostDate,te as getBlogPostBySlug,ee as getBlogPosts};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.