> ## 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.

# Run an agent harness in a sandbox

> Install a coding-agent harness on a durable sandbox and reach its web interface over managed SSH.

A coding-agent harness is the thing you actually sit in front of: it drives agents, keeps session
history, and gives you a web interface to watch and steer them. Running one inside a sandbox puts
the agent and its work on the same isolated machine, so the harness reaches your code and your
tools without either leaving the sandbox.

This guide uses [Omnigent](https://github.com/omnigent-ai/omnigent), an open-source harness that
drives several coding agents behind one interface. Nothing here is specific to it. Any harness that
speaks HTTP on a local port installs and is reached the same way, and the two things that need care
are the same in every case: install it where a stop cannot delete it, and reach its interface over
a port forward.

<Note>
  The shell and the port forward in this guide need the sandbox SSH endpoint, which an operator
  enables per deployment and which is off by default. On the hosted service it is currently enabled
  only in pre-release environments. Where it is off, a connect is refused with
  `unsupported_capability`. The authoritative status list is
  [what's live today](/sandboxes/overview#whats-live-today).
</Note>

## Create a durable sandbox

```sh theme={null}
hiloop sandbox create harness --storage-class durable --workspace-gib 500 --cpus 4 --memory-mb 8192
```

`--storage-class durable` is what makes this worth doing. It gives `/workspace` its own lifetime,
so everything you install there survives a stop. Everything outside `/workspace` comes back from
the image on every start, which is the single fact that shapes the rest of this guide.

`--workspace-gib` sets the durable workspace capacity in whole GiB. Omit it to use the
deployment default. You can grow it later without cluster access:

```sh theme={null}
hiloop sandbox grow harness --workspace-gib 750
```

Workspace growth is one-way; choose a larger value than the capacity shown by
`hiloop sandbox get harness`.

Some deployments use a fixed-geometry durable filesystem. Those deployments require you to omit
`--workspace-gib` and return `unsupported_capability` from `sandbox grow`; the capacity shown by
`sandbox get` is the immutable filesystem size.

If growth returns `snapshot_in_progress`, a snapshot seal has not reached a durable outcome yet.
Repeat that snapshot request exactly, including its idempotency key if you supplied one. Once it
returns a durable receipt, growth and snapshot deletion are available again.

## Install the harness where it survives a stop

The default image carries Python 3.12, Node, `git`, a build toolchain, and
[uv](https://docs.astral.sh/uv/). That is enough to install the harness with no image of your own
and no system packages.

Install into a virtual environment under `/workspace`, not into the system Python and not into
`$HOME`:

```sh theme={null}
hiloop sandbox exec harness --timeout 600 -- bash -lc '
  export UV_CACHE_DIR=/workspace/omnigent/.uv-cache
  uv venv --clear --python 3.12 /workspace/omnigent/venv
  uv pip install --python /workspace/omnigent/venv/bin/python omnigent
'
```

`--clear` makes the step safe to run again. If the command reports a transient failure, run it
again rather than trying to work out how far it got.

The harness also keeps state: its configuration and a database of your sessions. By default that
goes to `~/.omnigent`, which a stop deletes. Point it at `/workspace` instead.

Write a launcher next to the install so every setting lives with it and a restart is one command:

```sh theme={null}
hiloop sandbox exec harness -- bash -lc 'cat > /workspace/omnigent/start.sh <<"EOF"
#!/bin/sh
set -e
export OMNIGENT_CONFIG_HOME=/workspace/omnigent/state
export OMNIGENT_DATA_DIR=/workspace/omnigent/state
export OMNIGENT_DISABLE_KEYRING=1
mkdir -p "$OMNIGENT_DATA_DIR"
[ -L "$HOME/.omnigent" ] || rm -rf "$HOME/.omnigent"
ln -sfn "$OMNIGENT_DATA_DIR" "$HOME/.omnigent"
exec /workspace/omnigent/venv/bin/omnigent server --host 127.0.0.1 --port 6767 --no-open
EOF
chmod +x /workspace/omnigent/start.sh'
```

Three of those lines are doing real work:

* The two directory variables move the configuration and the session database onto durable storage,
  and the harness passes them down to the agent processes it starts.
* A few of the harness's paths resolve against `$HOME` whatever those variables say. `$HOME` is
  rebuilt from the image on every start, so the symlink is re-made at each launch rather than once
  at install time.
* `OMNIGENT_DISABLE_KEYRING=1` stops the harness reaching for a desktop keyring service that a
  container does not run, which otherwise makes its secret commands fail rather than fall back.

Both the install and the launcher now live on durable storage. A stop costs you a restart, never a
reinstall.

## Start the server

```sh theme={null}
hiloop sandbox exec harness -- bash -lc \
  'nohup /workspace/omnigent/start.sh >>/workspace/omnigent/server.log 2>&1 & echo started'
```

It listens on `127.0.0.1:6767` inside the sandbox and takes a few seconds to bind. Confirm it is up
before you go looking for it from outside:

```sh theme={null}
hiloop sandbox exec harness -- curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:6767/
```

```
200
```

Keep the bind on `127.0.0.1`. The port forward in the next step connects from inside the sandbox,
so a loopback bind is all you need, and it keeps the interface off the sandbox's network interface.

## Reach the web interface

There is no public URL for a port inside a sandbox. You reach it by forwarding the port over your
SSH session, which needs nothing installed and nothing exposed:

```sh theme={null}
hiloop sandbox ssh harness -- -L 6767:127.0.0.1:6767 -N
```

Leave that running and open `http://localhost:6767` in your browser. The interface is a
mobile-ready web app, so the same forward from a laptop tethered to a phone gives you a usable
interface on a small screen.

The `--` is required. Everything after it goes to `ssh`, and without it the CLI rejects the `ssh`
flags as its own:

```
error: unexpected argument '-L' found
```

A tool that expects to invoke a plain remote-shell program cannot pass `--` itself, so it needs the
`hiloop-ssh` shim from
[run a sandbox as a devbox](/guides/personal-devbox#get-code-and-files-in-and-out).

## Pick it up after a stop

```sh theme={null}
hiloop sandbox stop harness
hiloop sandbox start harness
```

Your install and your session history are still there. The server is not: a stop ends every process
in the sandbox. Start it again with the same launcher, and it picks up the same state:

```sh theme={null}
hiloop sandbox exec harness -- bash -lc \
  'nohup /workspace/omnigent/start.sh >>/workspace/omnigent/server.log 2>&1 & echo started'
```

A start can report `running` a little before the sandbox can serve. If that first `exec` is
refused, wait and retry.

## Configure model access

A harness with no model provider starts, serves its interface, and shows you its session history.
It cannot run an agent until its model traffic uses the proof-bound model gateway. Do not place a
raw provider API key or platform-managed credential in the sandbox environment, command line,
image, or workspace; those paths expose plaintext to the workload and may preserve it in snapshots
or forks. 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: supported model access
remains unavailable until the gateway route is active, rather than falling back to a raw provider
credential. See [managing secrets](/guides/managing-secrets) for write-only storage, grants, and
destination-bound delivery.

## Quieten it for a restricted network

Omnigent reports anonymous usage data by default and writes an installation identifier into its
state directory on first run. It also looks up a model catalogue and checks for its own updates. On
a restricted or disconnected network you want all three off. Add them to the launcher, before the
`exec` line:

```sh theme={null}
export DO_NOT_TRACK=1
export OMNIGENT_DISABLE_CATALOG_LOOKUP=1
export OMNIGENT_NO_UPDATE_CHECK=1
```

These values are matched literally, so `DO_NOT_TRACK=1` works and `DO_NOT_TRACK=true` does not.
With reporting off, the harness makes no call to its telemetry service at all. This is the
harness's own reporting, separate from anything the sandbox records.

## What does not work yet

**A stop ends every process.** Only files under `/workspace` survive. The harness server, any agent
it was running, and your shell are all gone on the next start. That is why the launcher script
matters: it makes recovery one command instead of a reconstruction.

**Nothing outside `/workspace` survives either.** Packages installed with a system package manager,
files in `$HOME`, and shell configuration all come back from the image on every start. If a setup
step of yours writes outside `/workspace`, fold it into the launcher.

**The interface is reachable only through a port forward.** There is no public URL and no shared
link, so the harness is reachable by people who can open an SSH session to that sandbox and no one
else. Convenient for a single user, not yet a way to share a session with a colleague.

**The port forward needs the `--` separator.** Any tool that shells out to a remote-shell program
needs the shim above, because it cannot pass `--` itself.

**One sandbox, one harness.** The harness can drive agents on remote hosts, but nothing here
registers your sandboxes as hosts it can schedule onto. What this guide gives you is the harness
and its agents together inside a single sandbox.
