> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hiloop.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Capture agent telemetry

> Wrap any agent command with hiloop run to capture its model, tool, MCP, and stdio telemetry.

hiloop captures an agent's telemetry from the **outside** — you don't add an SDK to your harness or
change its code. You wrap the command with `hiloop run`, and hiloop records what crosses the
process and network boundaries, tagging every event with
[run identity](/concepts/run-scoped-observability).

## Wrap a command

Everything after `--` is the command to run:

```sh theme={null}
export HILOOP_API_KEY="hil_…"

hiloop run --label baseline -- claude -p "fix the failing test"
```

Each wrapped command is registered as a **run**: it appears in `hiloop runs list`, marked `running`
while the command executes and `succeeded` or `failed` from its exit code when it finishes.
`--label` names the run in that listing; without it a name is assigned.

Because the run's lifecycle belongs to the wrapped command, a run whose process vanished without
reporting stays `running` — the platform never invents an ending it didn't observe. Instead, run
reads derive a liveness signal: each run carries `last_activity_at` (its most recent telemetry
event, falling back to its start) and a `stale` flag once it has been quiet past a 15-minute
window, which `runs list` renders as `running (stale)`. Staleness is
derived at read time — never stored, and never a terminal state: the run flips back on new
telemetry, and if the liveness source can't be reached the fields are simply absent (an unknown
run is never rendered stale).

`hiloop run` is transparent: the child's stdout, stderr, and exit code pass straight through, so it's
safe to drop into a script. When the run registers, its **run id** is announced on stderr
(`hiloop: recorded run …`, with the `hiloop runs show` command to view it) so you can query the
capture later — stdout stays clean for pipelines. If the control plane cannot be reached when the run starts, the
command still executes and telemetry still ships, but the run won't appear in `hiloop runs list` —
a warning on stderr tells you when that happens.

## Use it in CI

Wrap the command you already run and keep the original exit behavior:

```sh theme={null}
export HILOOP_API_KEY="${HILOOP_API_KEY}"
export HILOOP_PROJECT="default"

hiloop run --project "$HILOOP_PROJECT" -- ./scripts/agent-eval.sh
```

If the wrapped command fails, `hiloop run` exits with the same code. The stderr announcement
includes the run id for follow-up query steps.

## Inside a sandbox

Every sandbox has one ambient run and a platform-managed capture session. Create reports that run
id; the workload receives no Hiloop API key and needs no harness-specific configuration:

```sh theme={null}
created="$(hiloop sandbox create my-sandbox --output json -- sleep infinity)"
run_id="$(printf '%s' "$created" | jq -r '.run_id')"

hiloop sandbox exec my-sandbox -- python /workspace/agent.py
hiloop query --run-id "$run_id" --limit 50
```

The explicit create command and every buffered `sandbox exec` receive process, exit, stdout, and
stderr capture as distinct executions. A non-interactive SSH command gets the same capture; a PTY
session records its start, end, and terminal output, but deliberately not keystrokes/input. The
sandbox also exposes a shared OTLP/HTTP receiver and sets standard OpenTelemetry exporter variables
for software that already emits spans or logs.

HTTP capture uses a sandbox-scoped cooperative proxy. Common clients honor the injected proxy and
CA-bundle variables with no agent configuration, but a client that ignores them or opens raw
sockets can bypass capture. An image's implicit default entrypoint receives proxy and OTLP capture,
but Kubernetes cannot prepend a supervisor while preserving an unknown image command; pass an
explicit create command when you need entrypoint process and stdio capture.

If the hiloop CLI happens to run inside a sandbox, `hiloop run -- <command>` joins this same ambient
run. It does not register a child run or start another proxy, and it does not need a Hiloop
credential. Run-selecting flags and per-command egress policy are refused because those belong to
the ambient sandbox boundary.

### Model access

Sandbox model traffic must use the proof-bound model gateway. Do not copy a raw provider API key or
platform-managed credential into the sandbox through SSH, exec, environment variables, an image, or
the workspace. A compatible provider subscription may keep its own login state in the tool, but its
traffic is supported only through the proof-bound provider-native gateway route, never by direct
provider egress.

The hosted service supports proof-bound bearer secrets for exact public HTTPS destinations. That
generic delivery path does not replace the provider-native model gateway, so supported model access
remains unavailable until the gateway route is active. See
[managing secrets](/guides/managing-secrets) for the destination-bound contract.

## What gets captured

Three capture paths run in parallel, all on by default:

| Path                   | Captures                                                               | Disable with        |
| ---------------------- | ---------------------------------------------------------------------- | ------------------- |
| Network capture        | Model (LLM) calls, tool calls, MCP traffic, and other network activity | `--net-capture=off` |
| Embedded OTLP receiver | The agent's own OpenTelemetry spans and logs, if it emits them         | `--no-otlp`         |
| stdio capture          | The wrapped command's stdout and stderr                                | always on           |

Each event is stamped with the run's `run_id` and its `lineage_path` before it's
streamed to the telemetry gateway. Large bodies (full prompts, completions, HTTP responses) are
stored by content-addressed reference, not inline — see [the event model](/concepts/event-model).

### How network capture stays scoped

On supported Linux hosts, the default `--net-capture=auto` mode places the wrapped process in a
private network namespace after a preflight succeeds. It does not set proxy variables in the child.
On macOS or an incompatible Linux host, an observation-only run warns once and uses a cooperative
proxy instead. Both active modes scope their per-run certificate authority to the wrapped process;
they never modify your machine's system trust store.

Use `--net-capture=proxy` to request the cooperative proxy explicitly, or
`--net-capture=off` when you only want spans and stdio. Restrictive egress policies require
transparent netns capture and fail before the child starts if it is unavailable.

## Configuration

`hiloop run` reads these (flags override environment):

| Setting                   | Env var                     | Flag            | Notes                                                                                                                                                              |
| ------------------------- | --------------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| API key                   | `HILOOP_API_KEY`            | `--api-key`     | The gateway derives your organization from it.                                                                                                                     |
| API context               | `HILOOP_CONTEXT`            | `--context`     | Selects the API edge whose discovery document supplies sibling service URLs.                                                                                       |
| Gateway endpoint override | `HILOOP_TELEMETRY_ENDPOINT` | `--endpoint`    | Optional. Use only when your deployment cannot advertise the gateway through service discovery.                                                                    |
| Project                   | `HILOOP_PROJECT`            | `--project`     | The project (slug or id) the run and its captured events are recorded under. Selection precedence: `--project` > `HILOOP_PROJECT` > the context's project > error. |
| Label                     | —                           | `--label`       | A human-readable name for the run, shown by `hiloop runs list`.                                                                                                    |
| Network capture           | —                           | `--net-capture` | `auto` (default), `netns`, `proxy`, or `off`.                                                                                                                      |

For a local or self-hosted gateway speaking cleartext h2c, add `--insecure`. See
[Configure CLI contexts](/guides/configure-cli-contexts) and the
[CLI reference](/reference/cli/hiloop) for every flag.

## Then query it

Captured events are queryable within moments. Take the announced run id from stderr and head to
[querying telemetry](/guides/querying-telemetry). To watch a run unfold in real time instead,
[live-tail it](/observability/live-tail).
