OMA: An Open-Source Managed Agent Platform That Decouples Brain, Sandbox, and State
Title: Open-source a Managed Agents cloud-hosted intelligent agent platform
This article introduces our open-source cloud-hosted intelligent agent platform OMA https://github.com/superduck-ai/open-managed-agents, as well as the overall architecture and design trade-offs behind it.
In the process of integrating Agent into actual business, we found that after connecting models and tools, there are still many operational issues to solve: how to recover after long tasks are interrupted, how credentials are used safely, how files are persistently stored, how internal tools are accessed, and whether execution processes and costs can be traced. These issues recur across different businesses, and are suitable to be centrally handled by a shared runtime platform.
OMA aims to take on this part of the work. We reference Anthropic's managed agent design, and implement session management, decoupling of reasoning and execution, credential hosting, and file systems on our own infrastructure, allowing business teams to define and use Agents via API. Below, we start with this division of labor, then expand on the implementation of each module, and our considerations in selection and practice.
From model API to managed agents
When building Agents directly using model APIs, the model provider runs the model, while the application side handles the agent loop: sending context, parsing tool calls, executing tools, returning results, and then deciding whether to continue or end the task.
In the diagram, the blue parts need to be built and operated by the application team, including context management, tool execution, session persistence, credential management, sandbox isolation, and observability. Ready-made agent frameworks can reduce the development work of the loop itself, but these capabilities needed for production still need someone to integrate them.
A managed agent platform centralizes these common responsibilities, and business systems submit tasks, receive events, and obtain results through interfaces.
Business developers define the Agent's role, instructions, Skills, and tools, decide which operations require approval, and connect the results back into business processes. The platform is responsible for the behind-the-scenes operation, state preservation, and security control.
For a self-hosted platform like OMA, enterprises still need to deploy and operate, but it can be centrally undertaken by the platform team, allowing different businesses to reuse the same set of capabilities. Model services are run by the configured model provider, and data flow depends on the specific deployment and model configuration.
Starting from Anthropic's design
OMA mainly references Anthropic's Claude Managed Agents for its construction. It provides the agent loop together with production infrastructure as a service, clearly dividing business definition and runtime mechanisms. We borrowed its resource model, API design, and architecture ideas such as session persistence, hand-brain separation, and credential hosting.
Other vendors are also advancing similar products. OpenAI Agents API provides Codex runtime framework as a managed service, managing session, context compression and recovery; Alibaba Cloud's Qoder Cloud Agents also provide interfaces for Agent definition, environment configuration, session management, and event streams.
Each implementation differs, but they all solve the same problem: how to organize model calls, tool execution, and state management into tasks that can run continuously. As tasks become longer, the object developers need to manage expands from a single request to the entire session.
OMA aims to provide these capabilities on enterprise's own infrastructure. We provide an interface compatible with the Anthropic SDK, connect to existing model services, storage, private network tools, and security systems, while retaining the ability to replace underlying components.
Abstraction, or abstraction
Anthropic abstracts the external interface of managed agents into Agent, Environment, Session, and Events, which respectively describe capability definition, execution environment, running instances, and interaction processes. OMA follows this abstraction.
Taking an analysis report as an example, the developer configures the model, report requirements, analysis Skill, and data query tools in Agent, and prepares Python dependencies and restricts network access in Environment. When a user submits data, the business system creates a Session and sends a task, then subscribes to Events to show progress, handle approvals, and obtain the report when complete.
When the user continues to follow up with questions, the original Session can be reused; another task creates a new Session, reusing the same Agent definition. Thus, capability configuration and running state are managed separately, and business code does not need to directly handle processes, sandboxes, and storage.
Analogy with Kubernetes to understand this abstraction
If you are familiar with Kubernetes, you can think of Agent as a reusable runtime definition, Environment as execution conditions, Session as a stateful task instance, and Events as connecting state observation with business interaction.
This is an analogy of responsibilities: Session can extend beyond execution instances, and Events also carry inputs and approvals. They do not correspond one-to-one with Kubernetes resources, nor do they require Kubernetes at the underlying level. You can refer to the official workloads and API concepts for understanding.
Overall architecture
In implementation, OMA's core is divided into three parts: Platform is responsible for control and governance, Brain is responsible for reasoning and tool orchestration, and Sandbox is responsible for command execution and file operations.
The OMA platform is the entry point for business access and runtime management, managing sessions, permissions, and resources, providing model proxy and sandbox orchestration, and passing messages, approval requests, and status changes to business systems.
Brain runs the agent loop outside the sandbox, exchanging inputs, outputs, and runtime events with the platform via CCRv2. We use DeepSeek Harness to implement this part. When a command needs to be executed, Brain initiates a tool call, the platform handles permissions and resources, and the Rust MCP Server inside the sandbox completes the execution and returns the result.
The underlying layers use PostgreSQL, NATS, and S3 for state storage, message delivery, and object storage; Vault, KMS, and outbound policies protect credentials and network access; FUSE, Filestore, and Memory provide persistent files, Skills, and memory.
The overall task flow is: business submits input, Brain calls the model and orchestrates tools, Sandbox executes operations, and the platform saves states and returns events and outputs to the business. The most critical boundary here is to give the reasoning process, execution environment, and session state their own lifecycles.
Decoupling the "brain" and "hands"
A common deployment approach is to put the runtime framework and command execution environment together into a sandbox. This is easy to get started, but after a user initiates a task, the sandbox needs to start first, then the Agent process starts, and finally model calls begin. When the sandbox fails, the reasoning process and session state may also be affected.
We refer to Anthropic's design and move the Brain outside the sandbox. The sandbox only handles tool execution, while session state is saved independently by the platform.
First response does not need to wait for the sandbox
Brain can start reasoning after receiving input, while the sandbox prepares in parallel, or is created only when a tool actually needs to be executed. For tasks that do not require command execution, environment preparation can also be omitted.
In Anthropic's related architecture report, the result is that p50 TTFT decreases by about 60%, and p95 by more than 90%. TTFT refers to the wait time for the first response token.
Running processes can be replaced, state needs to be preserved
After a sandbox fails, it can be recreated; after Brain restarts, it can read history based on session ID. The basis for recovery is that conversations, events, and files are independently saved in the platform. As for whether already-issued tool calls can be retried, this requires combining execution state and business idempotency, which we will expand on later when introducing CCRv2.
Brain can be replaced, the protocol needs to be stable
After separating brain and hands, a runtime protocol is needed between the platform and the Brain. We refer to CCRv2, used by Claude Code for remote running scenarios. It is Claude's non-public protocol, which specifies how the running side and the server exchange inputs, outputs, approvals, and session state.
From OMA's adaptation practice, it is not deeply bound to Claude models or a specific runtime framework. It mainly solves communication and lifecycle issues in remote execution, including reconnection redelivery, process recovery, instance takeover, and approval interaction during task execution. Other Brains implementing this contract can also connect to the same backend.
In OMA, after the Brain registers, it maintains a lease through heartbeats. When takeover occurs, the platform promotes worker_epoch, refusing old instances to continue writing or confirming messages. User input, approval results, and control instructions are delivered via SSE, while outputs, states, and persisted data are returned via HTTP. received, processing, and processed distinguish receiving, processing, and completion, avoiding treating message delivery as task completion; control responses are handled separately and are not blocked by tasks waiting for approval.
Runtime logs and checkpoints are saved by the platform for rebuilding sessions. But if a tool has already executed and the result has not been saved, upon recovery it will be marked as unknown result, blocked and waiting for verification, to avoid duplicate operations caused by automatic replay. MCP is responsible for tool access, model API is responsible for reasoning calls, and CCRv2 manages the collaboration between the execution process and the platform.
We tried the Rust implementation of grok build, and also the Go implementation of Crush, and finally chose DeepSeek Harness, mainly because of its plugin extension approach. Event reporting, platform data reading, and protocol adaptation can be done through plugins, reducing modifications to core code and lowering the cost of following upstream upgrades.
In this selection, language consistency, performance, and resource usage are all important, but how much code needs to be changed for long-term maintenance is also a practical consideration. Keeping the protocol boundary is to allow the business integration and session data to be reused when replacing the Brain later.
Sandbox solution
OMA's cloud deployment uses Tencent's open-source CubeSandbox. I started paying attention to it when it was first open-sourced and studied its underlying implementation. Compared to the E2B solution tried earlier, some of its designs better meet our needs: it supports running on adapted cloud servers via PVM, reducing reliance on bare metal; uses eBPF to manage network, and the overall implementation is more lightweight.
However, the stability of the early version was still insufficient, and we encountered some problems in use. Therefore, OMA retains an independent sandbox adaptation layer, continuously evaluating other options, and choosing the underlying implementation based on maturity and deployment needs.
For local development, we use our own e2b-local, an E2B-compatible gateway written in Go. It accepts E2B SDK requests and runs sandboxes on Docker, OrbStack CLI-managed Linux VMs, or Apple Containers. The cloud and local use the same set of interfaces, reusing calling logic as much as possible to reduce adaptation work when switching environments.
Credential security
After splitting runtime boundaries, another key issue is credentials. We previously introduced the design where credentials do not enter the Agent and Sandbox; here we will discuss it in conjunction with the calling chain.
Agent may come into contact with user input, web pages, repository files, and tool results, which may contain malicious instructions. If generated code can read long-term credentials, there is a risk of copying or leaking them. Therefore, OMA keeps long-term credentials in the platform control plane. The sandbox only holds the session identity needed to access the platform; real credentials are injected by the proxy when requesting upstream.
Model and MCP addresses are managed by the platform, and requests go through the model proxy and MCP gateway respectively. Other network access initiated by scripts, command-line tools, and generated code goes through the outbound gateway, where the platform checks the target and authorization configuration.
For example, when a command-line tool calls a business API that requires authentication, there is no need to write the API Key into the sandbox in advance. The gateway matches the target service with the credential binding relationship, then adds the authentication information and requests upstream.
In the HTTPS link, the client initiates a CONNECT request through the proxy, and the Local relay forwards the encrypted bytes to the server. The outbound gateway handles two separate TLS connections: client-to-gateway and gateway-to-upstream, performing policy checks and credential injection. The client needs to configure the appropriate certificate trust.
This link also has clear protocol boundaries, such as HTTPS CONNECT 443, Git uniformly using HTTPS; the actual effect depends on outbound constraints, proxy configuration, and client compatibility.
Separately managing ciphertext and decryption capability
Credential storage uses Vault and KMS-related mechanisms for protection. The database stores ciphertext, and the runtime service calls the key service to decrypt under authorized conditions, then injects into the matched upstream. Having the database ciphertext does not mean having usable credentials. The platform also needs to manage decryption permissions, usage scope, and call auditing.
FUSE-based userspace file system
When Agents execute tasks in the Sandbox, they still heavily rely on native CLIs such as git, find, grep. These tools require a stable POSIX file interface: input files, Skills, and task outputs need to land in predictable logical paths, and the access method should not change with the underlying storage format. The file system also provides an intuitive permission boundary, such as mounting /skills as read-only and /outputs as writable.
The problem is that traditional distributed file systems (such as NFS and NAS) are designed for long-lifecycle, shared workloads, and do not fit Sandboxes that are dynamically created per-Session, short-lived, and highly concurrent. Taking Alibaba Cloud NAS as an example, the official usage limits include:
- A single file system can be mounted by at most 1000 compute nodes at the same time;
- A single account in a single region can create at most 20 general-purpose NAS file systems, or 200 performance NAS file systems.
If each Sandbox is mounted as an independent compute node, or a separate file system is applied for each Session, the above quotas quickly become a bottleneck for concurrent scaling and resource orchestration.
Another common path is to use tools like ossfs to directly mount a subpath under an object storage bucket into the Sandbox. This bypasses the NAS instance and mount node quotas, and continues to access files with absolute paths; but object storage is essentially a flat Key-Value space, and ossfs merely derives virtual directories based on the / separator in the object Key. It solves "how to read remote objects with file paths", but does not answer "which files should the current task see".
Therefore, the Agent-side file mounting cannot directly expose the physical bucket or host directory, but needs a programmable abstraction layer: dynamically build a virtual view based on the task, and control permissions and lifecycles on the server side. FUSE (Filesystem in Userspace) is exactly suitable for this layer - continuing to provide a standard POSIX interface upward, and delegating namespace, authentication, and lifecycle to the platform downward.
FUSE provides a programmable abstraction layer between the standard POSIX file interface and platform services. The Agent transparently accesses mounted directories through system calls like open, read, write, readdir, without needing to know whether the underlying data source is a database, object storage, or a remote API.
FUSE only hands Linux file operations to a userspace process. To make this mechanism suitable for cloud Agents, additional work is needed beyond FUSE: Session orchestration, virtual namespace, remote file protocol, and credential boundaries.
I think the biggest benefit of implementing a file system based on FUSE is that it can provide each Session with a virtual view organized by task. The paths the Agent sees do not have to correspond to the actual locations in object storage. The platform can combine files scattered in different locations into a directory tree according to the current task's needs, while deciding what content is visible, read-only, and writable.
For example, after a user uploads a CSV, they can specify the mount location via mount_path when associating the file to a Session. Setting it to /reports/input.csv, the platform will normalize it to /uploads/reports/input.csv, and the Agent reads it in the sandbox via /mnt/session/uploads/reports/input.csv. This path is determined by task needs, independent of the actual Key in object storage, and does not require the user to manually copy the file into the sandbox.
Similarly, multiple Skills can be combined into a unified directory, and the same content can be referenced by different Sessions, choosing versions and mount paths as needed. The platform organizes the view, and the Agent uses files according to the agreed paths.
This is especially convenient for Skill management. Multiple versions of Skills can be resolved separately when preparing a session, then combined into a unified directory; even if the content is stored as ZIP packages, the backend can parse the directories inside the package and read files on demand, reducing the work of downloading in advance, fully extracting, and repackaging directories.
Therefore, this design separates "where files are stored" from "what the task sees". FUSE handles file operations, Filestore processes requests based on the session's directory mapping and permissions, and then accesses the actual content. Uploaded files and Skills can be set to read-only, while output directories allow writes; when the underlying storage layout changes, the mapping can be adjusted to keep the paths used by the Agent stable.
File operations passing through the platform also provide a unified entry point for permission checks and change logs. After the sandbox is replaced, the session's file view can be remounted, persistent content is still saved by the backend, and long-term keys for object storage do not need to be distributed to the execution environment.
MCP Tunnel, letting cloud Agents call private network tools
Cloud Agents have powerful reasoning capabilities, but when their execution tasks need to reach private network core assets (such as enterprise internal knowledge bases, internal OA systems), they are often blocked by corporate firewalls.
Three common solutions exist:
- Open a public entry for the MCP Server: Requires minimal changes, but private services are directly exposed to the public internet, expanding the attack surface.
- Use VPN or dedicated line to connect networks: Has broad connectivity, suitable for overall network interconnection. If only a few tools need to be exposed, the network and operational costs are high.
- Reverse connection: Run a client in the private network, which actively connects to the cloud, and receives tool calls through this connection.
We chose the third option. The enterprise only needs to allow this client's outbound connection to the cloud, and the MCP Server remains in the private network. Reverse connection is not authorization: it only changes "who initiates the connection"; after the channel is established, calls still enter the private network, and results also return to the cloud. Authorization scope and data flow still need to be designed separately.
To allow existing clients and management tools to be used directly, we acted as a "Frankenstein" (缝合怪):
- The management API fully aligns with the Tunnels interface protocol of Claude Managed Agents;
- For the private network client, we did not develop it ourselves, but directly used OpenAI's open-source tunnel-client, hereafter referred to as Connector.
The protocol is ready-made; what we really need to design is the scheduling layer in between.
tunnel-client's data plane is based on HTTPS long polling: the Connector establishes a long connection to the cloud to request "whether there are new tasks", and after receiving a task, it calls MCP locally, then submits the result through another Response request. The whole process is just ordinary outbound HTTPS, which is most friendly to corporate firewalls.
For the Agent, it is still an ordinary MCP call. This channel only carries tool requests and results, without needing to turn internal services into a public internet entry point, nor to open up the entire private network.
Observability
After tasks can run, we also need to know how well they run.
If a report is not generated, it could be the model misunderstanding, or tool failure, missing dependencies, or permission denial. Looking only at the final reply makes it hard to locate the cause; looking only at total Token count also does not explain why a task suddenly became more expensive.
OMA uses a timeline to show model and tool calls, helping developers inspect execution steps, time consumption, and failure locations. When a task repeatedly calls the same tool, developers can inspect tool descriptions, parameter design, and Skill instructions along the records.
The global view aggregates requests, tokens, costs, and failures, supporting analysis by team and scenario.
Currently, these records are mainly used for manual troubleshooting. In the future, we plan to provide diagnostic suggestions based on Trace, to help adjust prompts, tool configurations, and execution processes.
Other features and plans
In addition to the designs expanded above, OMA also supports long-term memory, Dream, scheduled runs, session budgets, and mounting GitLab, GitHub repositories. Scheduled tasks can generate daily summaries, or organize the day's accumulated memories at night; repo mounting prepares code and files for development tasks.
Next, we will focus on Agent evaluation. After adjusting Skills, adding tools, or switching models, it is hard to judge whether real tasks have improved with just a few chat experiences. We hope to compare versions based on actual outputs: whether the report is generated, whether the content meets standards, where the process fails, and how costs change.
Final thoughts
This project is essentially a heavy-backend infrastructure project, and we will continue to share more implementation details from this project in the future.
Top 1 from juejin.cn, machine-translated. The original thread is authoritative.
Regarding recovery from long-task interruptions, we added an extra rule in our local execution scenario: for short interruptions, just resume from the original session; for interruptions exceeding one hour, first ask the person who assigned the task whether to continue. The reason is that after long interruptions, the main code and requirements themselves may have changed, so directly continuing would be editing on outdated context. Would like to ask whether OMA's Session recovery has considered this 'confirm before resume' step?