Isolated Code Execution: Computation Inside, Authority Through Tools
In the reference split-Docker profile, generated code runs in a separate networkless executor while approved tools act through a trusted supervisor.
An agent can write useful code: inspect data, join records, transform files, build a chart, or assemble a report. That code needs CPU, libraries, and a workspace. In KDCube's reference split-Docker profile, network access, provider credentials, deployment secrets, and authority stay with a trusted supervisor while generated code runs in a separate executor.
This separation is the core of KDCube isolated execution. It gives generated Python enough room to solve open-ended problems while keeping external authority behind explicit, inspectable interfaces. A mail tool can send mail. A search tool can reach the web. A named service can update a task. The generated program receives their declared contracts and results; credentials, network clients, identity resolution, grants, budgets, and service connections remain on the trusted side.
KDCube also supports local subprocess and remote Fargate profiles, and still accepts a legacy configurable combined-Docker profile. They keep the same execution contract but do not provide identical physical isolation. Their differences are stated explicitly below.
The result is more useful than a sealed box and more controlled than an ordinary container. The code can think in files and Python. The platform decides how it may reach the world.
01 Four boundaries, four different guarantees
"Isolation" can describe several different subjects. KDCube keeps four boundaries separate because each one protects something different.
| Boundary | What shares infrastructure | What establishes the boundary |
|---|---|---|
| Tenant/project deployment | PostgreSQL, Redis, object storage, or filesystems may be shared across deployments | One running KDCube deployment is bound to one tenant/project; PostgreSQL schemas, Redis namespaces, and storage prefixes preserve that scope |
| Users inside the deployment | Users share proc workers, processor capacity, client pools, and filesystem infrastructure | Authenticated request context, user-scoped addresses, guarded surfaces, and per-object storage scope |
| Actor and authority | An external actor, platform subject, storage subject, and economics subject may differ | Connection Hub authenticators, explicit connection/delegation edges, server-side grants, and boundary-specific authority projection |
| Agent-generated code | ReAct, LangGraph, or another integrated agent can request data and computation | Runtime-bound user/authority, trusted input resolution, per-execution workspace, and the supervisor/executor boundary |
The first boundary is the deployment scope. One KDCube deployment runs for one tenant and one project. Its PostgreSQL schema, Redis keys/channels/streams, and object/file paths carry that tenant/project namespace. The backing PostgreSQL instance, Redis deployment, or bucket can be dedicated, or it can be shared with other tenant/project deployments through those namespaces.
Inside one deployment, users meet on shared machinery. Several user requests can execute concurrently in the same proc process and processor pool, and their workspaces can live under the same mounted filesystem root. KDCube binds each request to an authenticated actor and preserves that identity as work crosses supported runtime boundaries. Platform-owned stores and protected services use the carried scope instead of accepting a user identity chosen by model output.
Authority is another layer. A Telegram actor, delegated external client, or connected provider account reaches a platform-authority boundary through an explicitly consented edge or server-side grant. Connection Hub verifies the presented proof and projects the required authority at the boundary that asks for it. The actor remains visible for provenance even when product reads or economics use a consented platform or grantor projection.
This article then focuses on the fourth boundary: the narrower physical and capability view given to model-generated code. KDCube ReAct uses this boundary natively, and other agent frameworks can bind the same workspace and ISO execution primitives as tools.
The agent chooses what to request. It does not decide who it is allowed to read as. A ref supplied by the model is an untrusted locator; tenant, project, actor, user, and authority were already bound by authenticated runtime context.
For conversation history, the requested conversation and turn are queried
under RuntimeCtx.user_id. For git-backed project history,
lineage is rooted by tenant/project/user/conversation. For an external owner
ref, the registered owner resolver authorizes under the carried request
identity. A compromised agent can change the locator it requests; it cannot
change the bound user. An out-of-scope locator produces no workspace
bytes.
02 The boundary starts with one design decision
An ordinary Python process inherits its surroundings. Environment variables, mounted directories, network routes, SDK clients, and process credentials can all become ambient capabilities. A generated program may only need to calculate a result, yet the process around it may already know how to reach Redis, storage, mail, Slack, model providers, and platform configuration.
In the supervised profiles, KDCube makes capability explicit. The generated program receives a reduced execution environment. External actions are represented as tools. Tool calls cross an authenticated local bridge and run in a component that can apply the platform's normal rules. Split Docker adds the strongest built-in physical separation: a separate networkless executor with narrow mounts. That creates two clean questions:
Can the code compute this? → executor: Python, files, libraries, CPU May this action happen? → supervisor/tool: identity, policy, grants, budget
The first question is open-ended. The second is governed. Keeping them separate is what lets an agent write real code without giving every line of generated Python the runtime's full authority.
03 One request, end to end
The isolated path begins when an agent harness or app tool asks the
runtime to execute Python. The platform writes two source files: a stable
main.py loader owned by the runtime and the verbatim generated
program in user_code.py. It prepares a per-execution workspace,
selects a runtime profile, launches the selected environment, and later
collects artifacts, logs, accounting records, and the structured result.
04 Split Docker gives the supervisor and executor different views
In split-Docker execution, the two roles deliberately see different parts of the system.
| Surface | Trusted supervisor | Generated-code executor |
|---|---|---|
| Network | Deployment network and approved external services | Private network namespace; split mode uses --network none |
| Configuration | Descriptor-backed app and platform configuration | Small sanitized runtime values |
| Secrets | Normal secrets lifecycle and provider resolution | Secret material remains outside the executor environment |
| App code | Read-only app tool modules when required | Generated execution package only |
| App storage | Prepared read-only data when required by tools | Materialized current-execution files only |
| Writable files | Runtime output, diagnostics, and artifact workspace | Work directory, artifact directory, and executor logs |
| Tooling | Real tool implementations and service clients | Typed stubs that call the supervisor |
| Identity and policy | Restored request identity, grants, user selection, accounting | Business parameters only; authorization identity comes from bound request context |
The executor's split-Docker filesystem is intentionally short:
/workspace/work/ main.py, user_code.py, execution inputs /workspace/out/ generated artifacts /workspace/logs/executor/ user and executor diagnostics /supervisor-socket/ authenticated local tool bridge
The supervisor has the broader runtime tree: descriptor material, app tool modules, prepared app data, complete runtime metadata, supervisor diagnostics, and network clients. Those paths are absent from the split executor's mount list. Host-path translation used by Docker-in-Docker identifies the source of each narrow mount while preserving that same executor mount list.
05 Split isolation is a stack of controls
A container name alone says little about the effective boundary. KDCube's split-Docker path layers several controls so each one answers a different failure mode.
| Layer | Runtime behavior | Boundary it creates |
|---|---|---|
| Process | Generated code runs in its own child process | Crashes and exits stay outside the app server |
| Network | The generated-code child uses a private network namespace | Only supervisor tools make network calls |
| Filesystem | Read-only root plus narrow writable mounts | Writes stay in work, artifacts, and executor logs |
| Identity | Child drops to executor UID/GID and clears supplementary groups | Generated code runs outside the service/root identity |
| Linux capabilities | Split container starts from --cap-drop=ALL; child verifies zero effective capabilities | Kernel privileges stay with the lifecycle entrypoint |
| Privilege escalation | no-new-privileges, stripped setuid/setgid helpers, inherited seccomp deny for socket(AF_ALG, ...) | Helper binaries and alternate socket facilities stay outside the generated-code capability set |
| Tool bridge | Per-execution random token plus Linux SO_PEERCRED UID check | Only the intended executor can ask its supervisor to run tools |
| Tool policy | Tool id, parameter signature, allowlist, user selection, grants, and runtime policy are checked | A socket request becomes an authorized tool call only after validation |
| Resources | Timeout, file-size limit, workspace-growth monitor, and cancellation | One execution remains inside its configured time and storage envelope |
| Observability | Preserved source, component logs, tool-call records, and structured errors | Operators and agents can distinguish code, tool, and harness failures |
In the split strategy, the executor container starts read-only, with all
Linux capabilities dropped. A small root entrypoint prepares bind-source
ownership, starts the UID/GID-dropped child, and retains only the lifecycle
ability needed to stop that child on timeout, cancellation, or quota breach.
Generated Python then runs as UID 1001, GID 1000,
with zero effective capabilities. The entrypoint's narrow
CAP_KILL allowance exists for that child-lifecycle step; it is
gone from the generated-code process after the identity and capability
drop.
This is defense in depth with a practical purpose. The network rule protects service endpoints. The mount list protects runtime files. The identity and capability rules protect the container boundary. The tool policy protects side effects. Resource controls protect availability. Logs and structured results make every outcome visible.
06 Two Docker strategies, one trust model
KDCube supports two supervised Docker topologies. The
combined compatibility topology places the trusted
supervisor and the generated-code executor child in one
py-code-exec container. The container has the mounts and network
required by the supervisor. The child receives a private network namespace,
drops identity, and receives the sanitized environment.
The split strategy, the current platform default, places the same roles in sibling containers. The supervisor container receives network, descriptors, app modules, prepared app data, and runtime storage. The executor container receives only work, artifacts, executor logs, and the Unix socket volume.
Both strategies implement the same conceptual split. The split topology adds a container-level filesystem boundary between the two roles, making supervisor descriptors, app storage, platform storage, and diagnostic paths absent by construction from the executor container.
07 Tools are the authority gates
Generated code can call a configured tool through the executor stub. The stub serializes the tool id and parameters, adds the per-execution credential, and sends the request over the Unix socket. The supervisor authenticates the peer, validates the call, runs the approved implementation under restored request context, and returns a bounded result.
generated Python tool_call("named_services.object_action", {{"namespace": "mail", "action": "send", ...}}) → executor tool stub → authenticated Unix socket → trusted supervisor: authenticate peer + per-execution token resolve qualified tool id validate protocol + parameter signature apply configured and per-user allowances bind original request identity apply grants, claims, budgets, service policy execute approved implementation record usage, logs, and result → sanitized tool result returns to generated Python
This is the central security and productization seam. A tool is trusted code, yet each invocation still passes through policy. The supervisor derives the platform user id, provider credential, roles, and economics subject from the request context that entered the execution. Ordinary tool parameters carry the business request.
The code can compute. The platform decides how it may reach the world.
The model remains useful because the boundary controls authority rather than removing capabilities. Web search, model calls, storage access, mail, Slack, memory, and app-defined services can all remain available as narrow tools. Their network and credentials live with their implementations. The generated program sees the contract and the result.
The restored actor can differ from the authority required by a tool. At
that point the protected surface asks Connection Hub for the exact authority
and grants it requires. A same-authority request uses that authority's grant
resolver. A cross-authority request requires an explicit connection or
delegation edge. The resulting identity_authority projection and
edge provenance travel with the request; a missing edge or grant stops the
operation.
This is also how the two delegation directions stay distinct. A connected Gmail or Slack account lets a trusted KDCube tool use the current user's provider credential. A delegated KDCube credential lets an external operator call a bounded KDCube resource. Provider credentials remain in user-scoped secrets, while delegated bearer tokens are handles to server-side grant and session records. Neither credential becomes an ordinary generated-code value.
08 Context crosses the boundary as a portable room
Trusted tool code still needs to know which request it serves. KDCube carries a small, JSON-safe portable context room across runtime boundaries. It contains the situation required to reconstruct trusted SDK services:
PORTABLE_SPEC_JSON request context tenant / project user / roles / permissions / identity authority session / conversation / turn / app / agent app call context small request-scoped app metadata named-service discovery tenant/project-scoped provider lookup descriptor named-service client policy acting client id + configured consumer allowances accounting context user / app / conversation / turn / component / agent
Live Redis clients, database pools, callbacks, provider clients, large documents, and binary payloads remain in their owning runtime. A local child or trusted supervisor receives the portable model-service configuration needed to rebuild trusted SDK services; that configuration can include model-provider keys. A Docker/Fargate supervisor can also receive descriptor-backed settings and secrets for trusted tools. The split executor receives a separately stripped payload containing the reduced values required for its workspace and tool stubs. It receives neither the full portable spec nor descriptor or provider secret material.
The portable room preserves facts. Authorization remains local to the boundary that understands the resource. When Connection Hub has already resolved an edge, the room carries the actor, platform/economics projection, and edge provenance forward. When a later surface requires another authority, that surface invokes the relevant resolver and guard. Shared workers and subprocesses therefore preserve the original user while each protected surface enforces its own rule.
verified actor telegram user / platform user / delegated client → REQUEST_CONTEXT + UserSession actor + tenant/project + routing → Connection Hub boundary authenticate proof if needed resolve explicit edge or server-side grant project platform/storage/economics subject as allowed → BUNDLE_CALL_CONTEXT.identity_authority carried across trusted runtime transitions → tool / named service / economics / app operation enforces its own resource rule
This distinction matters beyond serialization. Discovery answers where a named service lives. Client policy answers which operations this agent may call. Per-user capability choices narrow that configured ceiling. Provider code then authorizes through the carried request identity. The model supplies the business parameters, while the platform supplies identity and authority.
09 The return path is a reduce boundary
Runtime context has an explicit outbound path as well. The host serializes
the portable room in PORTABLE_SPEC_JSON and the communicator
contract in COMM_SPEC, then starts the fenced runtime. The child
reconstructs its SDK surfaces, runs, and writes bounded output and side
files. The host reducer is the only component that merges those child records
back into the parent run.
This bootstrap/run/reduce shape works across a local child, Docker, and external execution. It avoids passing process-local clients into the child and avoids letting child memory become host state by accident. Communication records carry stable ids for idempotent merge. A hard kill may leave a side file absent; the reducer treats the missing file as an empty contribution and reports the execution failure through the normal result path.
For external execution, snapshots extend the same contract over distance. The host uploads the work and input runtime state, the task restores them, and the output snapshot returns artifacts and side files to the reducer.
10 Isolated code can still use named services
An in-process agent can call a named-service provider directly through the live app registry. An isolated supervisor lives in another process and often another container. It carries discovery, client policy, and identity; the live registry object remains in the host process. KDCube closes that transport gap with the named-service Data Bus relay.
The message actor is the restored request identity. A provider applies the same connected-account consent, claims, grants, and visibility rules it applies to a direct call. A missing approval returns the standard structured consent response and action link. Once the user approves, the same generated code can succeed.
The relay uses an at-least-once lane. Side-effecting calls use a required message id and a recorded response. A redelivery with the same id returns the recorded result instead of executing the provider action again. This makes a generated mail send or Slack post safe across worker retry while preserving the provider's normal authorization model. The executor still owns only computation. The supervisor owns the relay client, the Data Bus carries transport, and the provider app owns the domain action.
11 Files cross through workspaces and artifact contracts
Generated code works with real bytes without placing those bytes in model messages. The model proposes a ref; trusted runtime code resolves it under the bound user and authority. Successfully resolved inputs are materialized into the current execution workspace. Outputs are written to the artifact directory. The runtime preserves the exact executed source and collects declared files for delivery.
hosted input / conversation attachment
→ model proposes locator
→ trusted user-bound resolver
→ in scope: materialize bytes
→ /workspace/work or current-turn attachment path
→ generated Python reads/transforms
→ /workspace/out/turn_<id>/files/<deliverable>
→ validate declared file contract
→ conversation attachment storage + chat.files event
→ user’s Files surface
The output declaration and the hosted artifact together establish
delivery. A hosting failure places a
delivery_failed.file_hosting notice on the timeline, giving the
agent concrete evidence that delivery stopped at the hosting stage. The
executor's ability to create a local file and the platform's ability to host
that file are separate, observable stages.
The complete diagnostic tree remains available to the platform. It
includes the verbatim user_code.py, the stable loader, executor
and supervisor logs, Docker launcher logs, tool-call metadata, and the
artifact workspace. In split mode, generated code sees only its own work,
artifacts, and executor logs.
12 Every execution has a resource envelope
Isolation also protects availability. The runtime enforces limits at the
child process boundary, independently of whether the generated program
follows its file contract. Current controls include maximum execution time; a
maximum size for one generated file, enforced in the child through
RLIMIT_FSIZE and currently 100 MiB by default; maximum
net-new bytes across monitored writable roots, currently 250 MiB per
execution by default; an optional maximum for total workspace bytes; a live
workspace monitor, currently polling every 0.5 seconds; cancellation
propagation and child cleanup; and declared output validation before files
are reported as delivered.
The monitored roots include work, artifact output, and executor logs. A user attachment begins consuming the local envelope when the platform materializes it into the active workspace. Hosted metadata alone remains outside that byte count until the file is pulled. An app can override the runtime profile for its workload: a document-generation app may need larger artifacts; a small data-transform tool may choose a tighter envelope. The limit belongs to the execution boundary, close to the resource it controls.
13 Runtime mode is a policy choice
KDCube supports several execution modes because different code has different trust and operational needs.
| Mode | Placement | Primary use |
|---|---|---|
none | Main app process | Small platform-owned tools where direct execution is intended |
local | Separate host subprocess | Crash containment for native libraries and local development |
docker + combined (legacy, configurable) | Supervisor and executor child in one container | Supervised tool mediation without split Docker's separate-container boundary |
docker + split | Supervisor and executor in sibling containers | Strong filesystem, descriptor, and secret separation for generated code |
| external / Fargate | Trusted bootstrap and filtered child in one remote task/container | Remote snapshot execution; task IAM, network, filesystem, and child-process controls are profile-specific |
local provides process and crash containment but inherits the
host network and environment. The legacy combined option adds
supervised tool mediation and a filtered child inside one container, without
split Docker's separate mount namespace. split uses sibling containers and
gives generated code a networkless executor with narrow mounts. Fargate moves
execution through snapshots to one remote task/container; its filtered,
privilege-dropped child does not inherit split Docker's separate-container
boundary.
Runtime selection can be made for the app or tool profile, so one deployment can keep a deterministic trusted helper in-process and send generated Python through split isolation.
External execution moves the work through snapshots. The host packages the workdir and runtime state, the remote task restores them, executes under the supervised contract, uploads output deltas, and the host merges the result. Descriptor and launch payloads remain supervisor inputs. The generated-code child still receives the sanitized executor subset.
14 Large launch context stays on the trusted transport
Real apps can have large descriptor and runtime payloads. In split Docker,
large supervisor values such as RUNTIME_GLOBALS_JSON and
KDCUBE_RUNTIME_*_YAML_B64 move from command-line -e
arguments to a JSON environment map streamed over the supervisor container's
stdin. The switch is signaled by
KDCUBE_EXEC_PAYLOAD_STDIN=env_json;
KDCUBE_EXEC_RUNTIME_GLOBALS_INLINE_MAX_BYTES sets the inline
threshold, currently 96 KiB. The supervisor hydrates the map before
descriptor materialization.
This avoids the Linux per-argument MAX_ARG_STRLEN /
E2BIG failure while preserving the trust boundary: the transport
change applies to the supervisor, and the executor subset remains the same
size and shape. External Fargate execution uses its own launch transport
through AWS Secrets Manager and passes a payload identifier to the task. The
larger rule: configuration can cross a runtime boundary through a trusted
transport; generated code still receives only the fields assigned to the
executor contract.
15 Failures return evidence
An isolated runtime has more moving parts than an in-process function, so failure reporting is part of the architecture. KDCube separates three questions:
Did the runtime launch and complete? → harness / container / IPC Did user_code.py complete? → program exception / exit / timeout Did it produce the promised output? → declared file contract / hosting
| Evidence | Meaning |
|---|---|
user.log | Program-visible logging |
runtime.err.log | Executor capture and traceback context |
executor.log | Executor lifecycle diagnostics |
supervisor.log | Tool bridge and trusted runtime diagnostics |
docker.out.log, docker.err.log | Container launcher output |
infra.log | Derived cross-component infrastructure summary |
executed_programs/<execution_id>/user_code.py | Exact generated program that ran |
A harness failure that happens before the program starts is returned as an
ordinary react.tool.result block with
mime: application/json and a payload of this shape:
{{
"status": "error",
"error": {{
"code": "sandbox_execution_failed",
"message": "...",
"details": {{"where": "exec.tool.harness"}}
}}
}}
The message identifies the platform/harness boundary and states that execution stopped before the user program started. The agent therefore receives a terminal result for the tool call instead of an empty timeline gap that could be mistaken for success. Retry guidance is bounded: retry once, then run a minimal probe, then report the infrastructure failure or finish without exec. Re-sending the same oversized or structurally failing payload indefinitely only repeats the same boundary condition.
16 What a builder configures
Builders can preserve an existing agent and its Python tools. They connect those tools to the KDCube tool subsystem, then assign execution boundaries according to what each one does.
The boundary is already used outside KDCube ReAct. The
ported-langgraph-agents@2026-07-13 reference app binds a normal
LangChain run_python tool to the deployment-selected KDCube
execution runtime. For each turn it creates a fresh workspace, binds the
current request identity and trusted ToolSubsystem, executes
through run_exec_tool_side_effects(...), and hosts produced
files into conversation storage. The LangGraph graph, model loop, and
streaming adapter remain LangGraph code.
A typical adoption path: keep business actions in narrow Python tools with explicit parameters and results; register the tools in the app's per-agent inventory; route generated Python and higher-risk code through a supervised runtime; let generated code use tools for networked or credentialed actions; write user deliverables into the artifact directory and declare their file contract; configure timeout and workspace limits for the app's workload; and test the executor view, tool policy, cancellation, and failure result before release.
config: execution: runtime: mode: docker container_strategy: split max_file_bytes: 100m max_exec_workspace_delta_bytes: 250m workspace_monitor_interval_s: 0.5
The tool inventory can differ per agent. The app runtime profile supplies its execution defaults, and tool isolation policy can route individual tools. An app can host several agents, each with its own tools, skills, model choices, and execution policy. Builders can start with one isolated code path and adopt more of the framework as useful. The runtime boundary works alongside the agent logic, orchestration framework, and frontend that already work.
17 The trust model, stated plainly
The generated program is untrusted input. The trusted computing base includes the KDCube host process, the supervisor, approved tool implementations, the descriptor and secrets lifecycle, the container runtime, and provider services. That makes responsibilities explicit:
| Runtime behavior | Builder-owned responsibilities |
|---|---|
| The configured runtime profile selects the execution boundary | Select the profile appropriate to the workload |
| The split executor receives no platform credentials or network | Keep credentials inside SDK/config/secrets APIs |
| The split executor has narrow mounts and a reduced Linux identity | Do not add unnecessary mounts or privileges |
| Integrated tool calls are authenticated and policy-checked | Design narrow tools and validate business parameters |
| Supported transitions carry request identity and accounting context | Declare grants, provider claims, and app visibility accurately |
| Time and filesystem resource limits | Size limits for expected inputs and deliverables |
| Structured errors and preserved diagnostics on managed execution paths | Handle failures and avoid claiming undelivered output |
| Relay replay protection for named-service calls | Preserve external idempotency where provider APIs require it |
One running KDCube deployment is scoped to one tenant and one project. Inside that deployment, users share worker and processor infrastructure. Each request has a bound actor/user context, and the portable room preserves that context across supported transitions. Guarded services enforce authority and grants when the request reaches them. Each isolated execution then receives its own run workspace, supervisor bridge credential, and resource envelope. The agent may request any locator, while trusted resolution keeps the runtime-bound user and authority fixed.
18 The useful form of isolation
The goal is to make the power of generated code legible. Python gets a place to compute. Files get a defined path from input to artifact. Tools get explicit contracts. External actions run under the user's real identity and the app's configured policy. Credentials stay with the trusted implementations that need them. Paid or state-changing actions that cross integrated tools produce attributable runtime records. Managed execution paths return a structured result and preserve available diagnostics; declared artifacts add verified delivery.
Generated code may compute freely inside its envelope. External authority is exercised only through governed tools.
KDCube gives builders both halves: an open-ended Python workspace for the work that is hard to predict, and a production runtime for the actions that must be authenticated, bounded, observable, and accountable.