max@blog:~$ cat taking-agents-to-the-cloud-building-immortus.md
home blog ● online

Taking agents to the cloud (Building Immortus)

2026-07-28 · 5 min read

Earlier this year, I built a project called Clanker. It was an experiment in using coding agents to respond to work automatically: a Jira webhook would trigger an agent running inside a local Docker container, giving it the context it needed to investigate or complete a task and raise or update a pull request on Bitbucket.

Clanker was a lot of fun to build as a weekend project, but I quickly ran into its limitations. I knew it had much more potential if I spent more time on it.

I shelved the project and returned to my regularly scheduled programming, but kept Clanker at the back of my mind, waiting for an opportune moment to pick it up again.

Clanker V1 dashboard

Then June 22nd hit.

What was so special about June 22nd? It was the day AWS announced Lambda MicroVMs: isolated environments that could run Docker images and be spun up, suspended or terminated through a set of endpoints.

With MicroVMs at my disposal, I wrote down two goals for Clanker V2 so I wouldn’t go completely off the rails.

Spoiler: I went off the rails.

The goals were:

  • Take the existing Clanker workflow online. I wanted to confirm that MicroVMs could power a web-based dashboard for coding agents, replacing the local Docker containers I had used previously.
  • Expand the automation layer. Instead of only responding to Jira webhooks, agents should be able to respond to events from GitHub and, eventually, other platforms.

Somewhere between writing down those goals and starting the build, Clanker V2 became Immortus.

Building the foundations

To build the first version quickly, I chose SST, having used it on previous projects. It allowed me to spin up Lambdas, a single-table DynamoDB database and SQS queues through infrastructure as code without spending too much time wiring everything together manually.

Combined with a Claude subscription, I had most of the basic CRUD functionality set up within a couple of hours.

That left me free to start working on the more exciting, read: difficult, parts: getting an OpenCode session running inside a MicroVM to communicate with the dashboard.

For this, I created a small bridge.ts process that ran alongside OpenCode inside the MicroVM. The bridge listened to OpenCode’s SSE stream, stored the events locally and forwarded them to an endpoint on the Immortus platform, where they could be saved to DynamoDB and displayed in the dashboard through long-polling.

On the platform, conversations were represented by four main entities:

  • Threads, representing the conversation itself.
  • ThreadMessages, representing messages sent by either a human or the agent.
  • ThreadEvents, representing things that happened during the conversation, such as the session suspending or an Artifact being created.
  • AgentSteps, representing every reasoning step or tool call produced by the agent.

Creating a Thread also meant preparing the environment in which the agent would work. Immortus passed the MicroVM the repository and branch to check out, metadata about any related GitHub issue or pull request, and the URLs it needed to communicate with the platform.

It also received an OpenCode configuration for that session. This was effectively a generated opencode.jsonc file defining which provider and models the agent should use, which tools it had access to, and what permissions it had inside the environment. This meant different Threads could run with different models, capabilities and restrictions without requiring the MicroVM image itself to change.

Each Thread received its own Git identity too. The Thread ID was added to the email address used for commits, allowing Immortus to associate later GitHub push events with the correct Thread without requiring the agent to include any special metadata.

Finally, the environment received credentials that allowed it to communicate securely with Immortus and use the platform’s own MCP server, which I’ll come back to later.

Once the environment started, the bridge already knew which Thread it belonged to, which repository and branch it was working on, how OpenCode should behave, and where it needed to send updates.

To display those updates as a single conversation, I built a timeline endpoint that fetched the ThreadMessages, ThreadEvents and their associated Artifacts, and AgentSteps for a Thread, then sorted everything by timestamp.

This recreated much of the visibility provided by the OpenCode TUI. I could see not only the messages between myself and the agent, but every reasoning step, tool call, screenshot and session event in the order they happened.

Turning the prototype into a platform

At this point, I had proven the first of my two goals: I could start an agent inside a MicroVM, communicate with it through a web dashboard and preserve a complete timeline of what it said and did.

Before moving on to automation, I spent some time turning that proof of concept into something I would actually want to use.

The interface went through three substantial rewrites, all built with help from Codex. Each iteration moved it further away from the original Clanker issue list and closer to a dedicated workspace for agents, Threads and the context surrounding them.

I redesigned the Thread view, added Artifacts, got agent-browser working inside the MicroVM, and created tools that allowed agents to take screenshots and upload them directly into the conversation.

The dashboard also gained a context sidebar showing the repository, branch, GitHub issue or pull request, MicroVM state and other information passed into the environment when it started. Later, I added an Active Subagents section so a Thread could expose the work being delegated to other agents.

The Immortus dashboard showing a Thread, context sidebar and Active Subagents

Threads began updating their titles automatically based on the conversation, while pull requests opened by agents were linked back to their original Threads and appeared directly in the timeline as ThreadEvents.

A pull request linked back to its Thread as a ThreadEvent

I also experimented with taking the conversation outside the dashboard. Immortus could connect to GitHub, Jira and Slack, allowing an agent to receive work and communicate through the places where that work was already happening.

Immortus connected to Slack

I then built an MCP server specifically for Immortus. Through it, agents could interact with the platform itself, including finding other Threads and ending their own sessions when they had finished working.

Two additional sections started to push Immortus beyond being purely a chat interface:

  • Ideas gave me somewhere to record possible features or tasks and then create a new Thread directly from an idea.
  • Context became a graph where agents could build a connected understanding of the projects, concepts and systems they were working with over time.

None of these features were part of my original test, but together they turned Immortus from a dashboard attached to a MicroVM into the beginnings of an agent workspace.

More importantly, the first goal was complete.

MicroVMs could power a web-based environment for coding agents, and the local Docker workflow from Clanker had successfully moved into the cloud.

The second goal was expanding Clanker’s Jira automation into a wider event-driven system. That had become large enough to deserve an article of its own.

A full demo video: https://www.linkedin.com/feed/update/urn:li:activity:7483288383147028480/

15 articles · 7.8KB | rss.xml
max@blog:~$ _