Skip to content

Runtime telemetry API

Core reports what hosted Runtimes and sandbox nodes consume through read-only administrator routes under /core/v1: current Runtime observations, the stored Runtime history of one Session, and the host observations and history of a sandbox node. Reads never create, wake, renew or change compute and never add samples to history. Runtime observability defines how Core collects and keeps these values; Console API usage lists the Web pages that read them.

Every route requires the Core key as the bearer credential; a missing or invalid key returns 401 invalid_admin_key. A Project ID in a path selects the target Project and does not authenticate. Responses carry Cache-Control: no-store, use the Core error envelope and never contain provider responses, native identifiers, paths or credentials.

Current Runtime observations ​

List observations of every Project ​

http
GET /core/v1/sandbox/runtime-observations?after={session_id}&limit=20&order=desc
Authorization: Bearer <Core key>
ParameterRules
afterObservation ID (a Session ID) that ended the previous page.
limit1 to 100, default 20.
orderasc or desc by Session creation time, default desc.

The list has one row for every Session of every Project that is not deleted, including none, self_hosted and released managed Sessions. Each row carries the owning project_id and an observation: the RuntimeObservation plus disk. Pages use the Session list's creation-time and ID keyset. The observation ID is the Session ID, so page boundaries do not move when the Runtime behind a Session changes. A page is not an atomic snapshot: each row has its own resolved_at and, when sampled, observed_at. Unknown query keys are ignored.

json
{
  "object": "list",
  "data": [
    {
      "project_id": "3f0c2a9e-2b7d-4d0f-9a51-1c8e4b6d7a20",
      "observation": {
        "id": "6c77d3a2-71d6-4ed5-884f-687aecda02a3",
        "object": "agent.runtime_observation",
        "session_id": "6c77d3a2-71d6-4ed5-884f-687aecda02a3",
        "environment_id": "6c02fb71-5fa8-4298-93e8-57c6625a3fc2",
        "mode": "openai_hosted",
        "provider_type": "docker",
        "instance": {
          "kind": "managed_allocation",
          "allocation_id": "d23ab94e-e40b-45bd-93a2-444f1f74642b",
          "device_id": "2e434f4f-76aa-4e54-a707-4757036d90ef",
          "connection_generation": null
        },
        "lifecycle_state": "active",
        "status": "observed",
        "reason": null,
        "allocation_created_at": 1789951200,
        "resolved_at": 1789953021,
        "observed_at": 1789953020,
        "started_at": 1789951220,
        "cpu": {
          "usage_seconds_total": 482.75,
          "capacity_cores": 2.0,
          "usage_cores": null,
          "utilization_ratio": null
        },
        "memory": {
          "usage_bytes": 805306368,
          "limit_bytes": 2147483648
        },
        "disk": null
      }
    }
  ],
  "has_more": false,
  "first_id": "6c77d3a2-71d6-4ed5-884f-687aecda02a3",
  "last_id": "6c77d3a2-71d6-4ed5-884f-687aecda02a3"
}

Retrieve one Session's observation ​

http
GET /core/v1/projects/{project_id}/sessions/{session_id}/runtime-observation
Authorization: Bearer <Core key>

This returns one RuntimeObservation, without disk. It accepts no query parameters. An environment:none Session returns 200 with status unsupported.

RuntimeObservation ​

FieldTypeMeaning
idstringThe Session ID; the stable identity of this resource and its list cursor.
objectstringagent.runtime_observation.
session_idstringThe Session.
environment_idstring or nullNull only for mode none.
modeenumnone, self_hosted or openai_hosted.
provider_typestring or nullSource kind, such as docker, microsandbox or e2b; null when no provider was read. Treat an unknown value as a new kind, not an error.
instanceobjectThe current compute identity; see RuntimeInstance.
lifecycle_stateenum or nullCore's own lifecycle view of a managed allocation; null for none and self_hosted. See below.
statusenumobserved, unsupported or unavailable.
reasonenum or nullWhy the row has no sample; see Status and reason.
allocation_created_atinteger or nullUnix seconds when the managed allocation was created.
resolved_atintegerUnix seconds when Core resolved this row.
observed_atinteger or nullUnix seconds of the provider sample; null without a sample.
started_atinteger or nullUnix seconds when the current compute incarnation started.
cpuobject or nullNull when no CPU value was observed.
memoryobject or nullNull when no memory value was observed.

lifecycle_state comes from Core's allocation records, never from the sample:

ValueAllocation
pendingNot created yet, or being created
activeRunning
sleepingSuspended
transitioningQuiescing, suspending, restoring or waking
stoppedCleanup pending, or released

RuntimeInstance ​

FieldMeaning
kindmanaged_allocation, self_hosted_connection or none.
allocation_idThe managed allocation, which identifies the compute of a managed Session; null otherwise.
device_idThe Runtime device bound to the managed allocation, when there is one; null otherwise.
connection_generationAlways null: Core does not observe self-hosted connections.

cpu ​

All fields are finite nonnegative numbers or null. Zero is an observed zero; null is unavailable.

FieldMeaning
usage_seconds_totalCumulative CPU seconds of the current compute incarnation (Docker, microsandbox).
capacity_coresConfigured CPU capacity, greater than zero.
usage_coresAlways null.
utilization_ratioProvider-reported share of capacity_cores (E2B), not clamped; null for providers that report cumulative CPU time.

memory ​

usage_bytes and limit_bytes are safe JSON integers or null. Zero usage is observed zero; limit_bytes is at least 1, and an unknown or unlimited limit is null.

disk ​

Only list rows carry disk: null, or {usage_bytes, limit_bytes} with the rules of memory. E2B fills it when the sandbox reports both its disk usage and a nonzero capacity. Docker and microsandbox return null. A non-null disk appears only on an observed row.

Status and reason ​

StatusReasonWhen
observednullThe provider returned a sample.
unsupportedruntime_mode_not_observablenone and self_hosted Sessions.
unavailableallocation_pendingThe managed allocation does not exist yet or is being created.
unavailableruntime_not_runningThe allocation is being cleaned up or is released, or the provider reports the Runtime absent, stopped or suspended.
unavailablesource_not_configuredNo observation source serves the allocation's provider.
unavailablesample_timeoutThe provider read exceeded its deadline.
unavailablesample_unavailableThe provider could not produce a current sample.

An ownership mismatch, malformed durable identity or invalid provider evidence fails the request instead of becoming an unavailable row. The generated core.openapi.yaml records each field's type, nullability and enum but cannot express which combinations of status, mode and fields are valid; this table and the field rules above are normative.

Errors ​

HTTPCodeWhen
400invalid_request_errorList: a repeated after, limit or order, or an invalid limit or order.
400unsupported_parameterSingle read: any query parameter.
404not_found_errorA missing Project; a missing, malformed or foreign Session or list cursor.
500internal_errorInconsistent identity or invalid provider evidence.
503execution_unavailableThe list exceeded its collection budget.

Client ​

packages/agents-client exposes AdminClient.listRuntimeObservations({after, limit, order}) and AdminClient.retrieveRuntimeObservation(projectId, sessionId, options). RuntimeObservation in src/types.ts is a union discriminated by status and mode; AdminRuntimeObservation adds disk. The client checks every field, enum, nullability rule, timestamp and number and rejects unknown fields. A malformed observation rejects with a 502 invalid_runtime_observation error and a malformed page with invalid_admin_response; one bad row rejects the whole page.

Session Runtime history ​

http
GET /core/v1/projects/{project_id}/sessions/{session_id}/runtime-history?start=1789951200&end=1789954800&max_points=120
Authorization: Bearer <Core key>
ParameterRules
startRequired. Inclusive Unix second, 0 or more.
endRequired. Exclusive Unix second, after start, at most 24 hours after it and at most one second in the future.
max_pointsOptional. Buckets per array, 2 to 1000; default 120.

Each parameter may appear once. Core chooses the bucket width: the range divided by max_points, rounded up to whole seconds, and at least 30 seconds or the sampling interval, whichever is longer. Buckets start at start; the last one ends at end.

Core resolves the Project, then the Session and its Environment, before it reads storage; allocation and provider identities are results, never query inputs. History exists only for openai_hosted Sessions.

json
{
  "object": "agent.runtime_history",
  "source": "durable",
  "session_id": "6c77d3a2-71d6-4ed5-884f-687aecda02a3",
  "requested_range": { "start": 1789951200, "end": 1789954800 },
  "resolution_seconds": 60,
  "generated_at": 1789954801,
  "coverage": {
    "retained_start": 1789951200,
    "first_sample_at": 1789951210,
    "last_sample_at": 1789954750,
    "sample_count": 118,
    "expected_sample_count": 120,
    "buckets": []
  },
  "series": [],
  "token_usage": []
}

source is always durable. resolution_seconds is the bucket width and generated_at the read time. Only buckets that hold at least one sample appear in coverage.buckets, series[].points and token_usage; a gap stays a gap, never a zero.

Coverage ​

coverage counts every stored sample of the Session in the range, including unavailable ones that belong to no allocation. retained_start is the later of start and seven days before generated_at. expected_sample_count is the number of sampling intervals between retained_start and end, rounded up. Each bucket has start, end, first_observed_at, last_observed_at, observation_count, observed_count and unavailable_count.

Series ​

There is one series per managed allocation, keyed by allocation_id, so a provider that pauses, restores or replaces compute under the same allocation keeps one series. environment_id and provider_type identify its source. started_at is the earliest retained start of the allocation's compute, as JSON-safe {seconds, nanoseconds} with nanoseconds 0 to 999,999,999; it is not a per-bucket start, and compute uptime comes only from current observations.

Each point has the bucket bounds, the coverage counts of the allocation's samples, and nullable cpu and memory objects with a contributor_count of at least 1:

  • cpu.utilization_ratio comes from consecutive cumulative CPU counters of one compute incarnation: the CPU seconds consumed divided by the elapsed time multiplied by the capacity, over the intervals that end in the bucket. The baseline resets when the incarnation changes or a counter decreases. E2B reports no cumulative CPU time; its bucket value is the mean of the ratios sampled in it. cpu.capacity_cores is the last capacity in the bucket.
  • memory.usage_bytes and memory.limit_bytes are the last values observed in the bucket.

Disk is not kept in history.

Token usage ​

token_usage belongs to the Session, not to an allocation. Each point holds the last cumulative measured Session usage sampled in its bucket: start, end, sampled_at, input_tokens and output_tokens. Measured Session usage is a Core extension that sums every recorded root Turn snapshot, active Turns included. It differs from public Session usage, which is null while a root Turn runs or after one ends unmeasured. These counters are measured model tokens, not prices or billing records.

Errors and bounds ​

HTTPCodeWhen
400unsupported_parameterA parameter other than start, end and max_points, or one supplied twice.
400invalid_requestAn invalid range or max_points.
404not_found_errorA missing Project, or a Session missing from it.
409runtime_history_unsupportedThe Session is not openai_hosted.
500internal_errorInconsistent stored identity.
503runtime_history_unavailableCore collects no periodic history (it runs without the execution worker), or the read failed, timed out or produced a result outside the bounds.

A response holds at most max_points buckets per array, 64 series and 10,000 coverage and series points in total. Storage error text is neither returned nor logged.

Client ​

AdminClient.retrieveRuntimeHistory(projectId, sessionId, {start, end, maxPoints, signal}) validates the query before sending it. It then checks the exact fields, the echoed range and Session, bucket order within the range, coverage totals, allocation identity, contributor counts, token usage order, nullability, numbers and response size. Any violation rejects the whole response with a 502 invalid_admin_response error.

Node host observations and history ​

http
GET /core/v1/sandbox/nodes/{node_id}?range=1h
Authorization: Bearer <Core key>

range is 1h (the default), 6h or 24h. Another parameter, a repeated or invalid range, or a malformed node ID returns 400 invalid_request; a missing or removed node returns 404 not_found_error. The response is the node object of the node list plus host and history:

json
{
  "host": {
    "effective_cpu_cores": 4,
    "cpu_utilization": 0.35,
    "total_memory_bytes": 17179869184,
    "available_memory_bytes": 8589934592,
    "available_disk_bytes": 107374182400,
    "observed_at": "2026-09-25T09:00:00Z"
  },
  "history": {
    "resolution_seconds": 60,
    "points": [{
      "start": "2026-09-25T08:59:00Z",
      "cpu_utilization_max": 0.4,
      "memory_used_bytes_max": 8589934592,
      "available_disk_bytes_min": 107374182400
    }]
  }
}

host is the node's last received heartbeat observation; every unavailable value, including an unobserved observed_at, is null. An offline node keeps its last values and their original time, so judge freshness by the node's online and host.observed_at.

  • cpu_utilization is the share of busy ticks in the host's aggregate /proc/stat counters between two heartbeats, 0 to 1. Idle and I/O-wait ticks are not busy, and guest time is not counted twice. The first heartbeat of a connection, a counter reset and an unreadable baseline give null. It measures the whole visible host, not the node process or its sandboxes.
  • effective_cpu_cores accounts for the node process's CPU affinity and cgroup limits; null when those cannot be established.
  • total_memory_bytes and available_memory_bytes are MemTotal and MemAvailable.
  • available_disk_bytes is the free space of the node's state filesystem, not a sandbox quota.

The node measures what its namespaces can see, so run it on the host it reports on.

history covers the range in complete UTC buckets: 60 seconds for 1h, 300 for 6h and 900 for 24h. Every bucket of the range is present, and the bucket in progress is left out. cpu_utilization_max and memory_used_bytes_max are the maxima of the recorded observations, where used memory is total minus available memory of the same observation; available_disk_bytes_min is the minimum. Each metric is null for a bucket without a recorded value, including offline periods. Core never interpolates or backfills.

SandboxAdminClient.retrieveNode(nodeId, range, options) in packages/agents-client reads this route and validates the response.

Released under the MIT License.