Skip to content

Feature: Add an Exec channel to run commands inside a running actor (E2B-style sandbox exec) #185

Description

Summary

Add a first-class streaming Exec RPC that lets a client run an arbitrary command inside a running actor's gVisor sandbox, with bidirectional stdin / stdout / stderr, exit code, optional TTY, and window resize — analogous to
kubectl exec for Pods, or to E2B's Sandbox.commands.run / Sandbox.pty.create APIs for sandboxed code-execution platforms.

This is a management-plane channel, separate from the L7 actor traffic that atenet routes. It does not change the Actor lifecycle and is purely additive.

Motivation

Substrate is positioned as the runtime for agentic / sandboxed code-execution workloads (see README.md:199 "Sandbox Demo" and docs/api-guide.md:168 LangChain section). For that class of workload, "run a command in the
sandbox and stream the result back" is the single most fundamental primitive — it's what platforms like E2B, Modal sandboxes, and Daytona expose to end users. Today Substrate has no equivalent:

  • pkg/proto/ateapipb/ateapi.proto — Control service exposes Create / Suspend / Resume / Delete / Get / List only.
  • internal/proto/ateletpb/atelet.proto — AteomHerder exposes Run / Checkpoint / Restore only, all unary, Streams: [] confirmed in the generated atelet_grpc.pb.go:221.
  • internal/proto/ateompb/ateom.proto — Ateom mirrors the same three unary RPCs.
  • cmd/ateom-gvisor/runsc.go wraps runsc create / start / wait / kill / checkpoint / restore — runsc exec is not wrapped, even though it exists upstream.
  • cmd/kubectl-ate/internal/cmd/ has create / get / delete / suspend / resume / logs / admin — no exec. logs_actors.go:73 falls back to kubelet Pods().GetLogs(...), i.e. log streaming is delegated to Kubernetes today.

Concretely this blocks the following use cases:

  1. Agent tool calls that exec untrusted code (the canonical E2B use case). Today an agent has to embed an HTTP/RPC server in its image and let atenet route to it — every template author re-implements the same exec-server
    boilerplate.
  2. Interactive debugging of a stuck actor. SREs currently have to kubectl exec into the privileged atelet DaemonSet pod (which mounts the host's /run/ateom-gvisor) and hand-craft a runsc -root
    /run/ateom-gvisor/actors/::/runsc-state exec ... invocation. This works but bypasses the control plane entirely (no audit, no lock against concurrent suspend/checkpoint, RBAC granularity = "all actors on the
    cluster").
  3. One-shot setup commands for templates (npm install, db migrate, …) without baking them into the container image or the workload entrypoint.

Activity

  1. rogeroger-yu commented on Jun 16, 2026

    @rogeroger-yu
    Author

    One related requirement from our side is an E2B-compatible SDK/API layer on top of this lower-level Exec primitive.
    Many early sandbox/code-execution workloads are already driven through the E2B SDK, and a number of open-source sandbox runtimes have chosen to expose E2B-compatible interfaces for that reason. For our planned usage, we expect hundreds of thousands of sandbox instances/workloads over time. Substrate's Kubernetes-native architecture is one of the core reasons we are evaluating it, because it fits much better with our existing infrastructure and operations model.
    However, without an E2B-compatible SDK or API surface, migration becomes significantly harder. It would require multiple business teams to modify application code and replace existing E2B SDK integrations, which is a much larger organizational cost than changing the underlying sandbox runtime.
    So I think this issue is important not only as "kubectl exec for actors", but also as the foundation for an E2B-style compatibility layer. For example, Sandbox.commands.run and Sandbox.pty.create could be mapped onto Substrate's Exec channel. Even if the SDK itself is tracked as a separate issue, it would be valuable to keep this migration path in mind when designing the Exec API.
    Julian Gutierrez Oschmann (@juli4n) I would like to know what suggestions or opinions the community has about the needs of this scene? We can pitch in and build together

  2. juli4n commented on Jun 23, 2026

    @juli4n
    Collaborator

    I personally think that substrate should be "batteries included" and have built-in support for something like this. Requiring every user to assemble their own solution will hurt UX and adoption.

  3. thockin commented on Jul 20, 2026

    @thockin
    Collaborator

    Having exec-into-actor seems important in order to debug the actor itself, but I don't think that should be the API by which we offer "execution environments". I do think it makes sense to have a substrate-native execution environment thing in the project (but a new repo?)

    The way I mapped that mentally is a "simple" process which serves an API (REST or RPC) which is more or less rsh++ or ssh++, with OCI images built around the 1-3 most useful base-images that can be used to install tools and things that such environments might need (debian, ubuntu, ...)

    I see a distinction between what ate offers for ALL actors and what an actor-template which is specifically supposed to be an execution environment for higher-order harnesses offers.

    Specifically, exec-into-actor should get all the same env vars, CWD, and other settings as the actor's "main" process, while exec-environ's API almost certainly wants to offer more control - env vars, CWD, possibly even a notion of sub-container (chroot, cgroup, ...).

  4. eliranw commented on Jul 21, 2026

    @eliranw
    Collaborator

    We have 2 types of use cases where we would need some type of exec into actors:

    1. Actor Lifecycle hooks - as part of an actorTemplate, add pre-suspend/post-resume hooks to run things like cuda-checkpoint. Actor lifecycle hooks #450
    2. API for platforms using Agent Substrate that run a command inside a sandbox - similarly to E2B exec.
  5. thockin commented on Jul 21, 2026

    @thockin
    Collaborator

    Lifecycle hooks is a good use-case (I'd call it #3) but is probably simpler than either debugging or execution environments. Why?

    Debugging needs to route an interactive session from a user's desktop to the actor, transiting all the things between. In K8s that includes the primary API server, and I expect that to be true here too (for authz if nothing else).

    Intentional execution environment actors will want to keep the API server out of the data path, relying on the general actor authz, and almost certainly want more robust features than are needed for debug.

    Lifecycle hooks are simpler - only between the atelet and actor or maybe even just ateom and actor - no real authz needed. They will be short-lived and not need TTY support.

    But I agree it's a use-case.

  6. ptone commented on Oct 1, 2026

    @ptone

    Here is additional feedback and concrete integration findings from multi-tenant testing on Substrate d277088b regarding exec, attach, and TTY APIs:

    Summary

    Substrate has no exec, attach or TTY RPC, and kubectl-ate has no exec command. kubectl exec on the worker pod lands in the distroless ateom container, not in the actor. Integrators that need to run commands in an actor, deliver input to an interactive process, or debug a broken actor have to build their own server inside the actor. That server typically has to stay privileged, and it is unavailable exactly when the actor is broken.

    Impact

    • Who hits it: integrators that drive interactive workloads (sending keystrokes or commands to a running agent), that offer terminal access, or that need to debug actors.
    • What breaks:
      • A broken actor cannot be diagnosed unless the integrator's own in-actor server happens to be running.
      • Interactive attach cannot be offered on Substrate.
    • Cost:
      • Each integrator has to build its own in-actor server to provide exec and a pty over the router.
      • Such a server typically has to run privileged for the actor's lifetime alongside the workload and hold a control credential, which makes it a security-sensitive component.
    • Severity: High / Proposed priority: P1. Exec is table stakes for operating containers. Its absence pushes a large, security-sensitive component into every integrator.

    Environment

    • Substrate d277088b (v1alpha), ateapi proto, kubectl-ate.
    • GKE 1.36 with gVisor workers.

    Steps to reproduce / evidence

    1. No exec or attach in the API (code-read at d277088b). The ateapi Control service (pkg/proto/ateapipb/ateapi.proto:25-146) has no exec or attach RPC. kubectl-ate's verbs are get, create, update, delete, pause, resume, suspend, logs and top (cmd/kubectl-ate/internal/cmd/verbs.go:24-32), plus admin, revert and tag; there is no exec or attach command.
    2. kubectl exec reaches the wrong container (code-read). kubectl exec into the worker pod reaches the ateom container, which is distroless, and not the gVisor sandbox where the actor runs.

    Proposed behaviour / API sketch

    • An ExecActor streaming RPC:
      • request fields: atespace, actor name, container, argv, env overrides, working directory, user, and a tty flag;
      • bidirectional stdin/stdout/stderr frames, with a resize message when tty is set;
      • the exit status returned at the end.
    • An AttachActor streaming RPC that attaches to the main process's stdio or pty.
    • kubectl ate exec and kubectl ate attach.
    • Authorization scoped per atespace.

    Workaround

    An integrator can:

    • run its own control server inside the actor, reachable through the router, that provides exec and a pty (for example on top of tmux);
    • give that server a per-actor credential delivered after resume.

    The server has to be designed to survive workload failures, and it becomes a privileged, security-sensitive component. Interactive attach can be left unsupported.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions