Files

Omnigent on Islo

Islo sandboxes give you disposable cloud machines for running Omnigent hosts, two ways:

  • CLI-launched: omnigent sandbox create / connect provisions a sandbox from your terminal, ships your local checkout into it, and registers it as a host with your server.
  • Server-managed: the server provisions a sandbox automatically when a session is created with "host_type": "managed" and terminates it when the session is deleted.

Sandboxes boot from the official prebaked host image, so startup is seconds. Unlike Modal and Daytona, the Islo launcher talks to the Islo HTTP API directly through httpx (already an Omnigent dependency), so there is no provider SDK extra to install — just an API key.

What makes Islo different from the other providers, and shapes the rest of this guide:

  • A credential gateway. Islo can inject LLM/API keys into a sandbox's outbound traffic at the network layer, so the raw key never reaches the sandbox process. This is a first-class, recommended path for model credentials (see Model credentials) and has no equivalent on Modal or Daytona.
  • No local port forward. Islo can't forward a sandbox→laptop callback port, so the interactive in-sandbox omnigent login / App OAuth step is skipped automatically (as on Modal and Daytona).
  • No lifetime cap. Islo sandboxes run until deleted (like Daytona, unlike Modal's 24 h).

Prerequisites

Install the Islo CLI and create an API key, then make it available where the launcher runs — your shell for the CLI flow, the server process for managed sandboxes:

curl -fsSL https://islo.dev/install.sh | sh   # install the islo CLI
islo login                                     # browser OAuth (one-time)
islo api-key create omnigent --show            # prints an islo_key_… value
export ISLO_API_KEY=islo_key_…
# Optional: a non-default API endpoint
# export ISLO_BASE_URL=https://api.islo.dev

ISLO_API_KEY is exchanged for a short-lived session token at POST /auth/token; the token is cached until shortly before expiry. The key is the only required credential — no SDK, no ~/.config file.

Note

Islo cannot forward a local callback port into the sandbox. The interactive omnigent login browser flow (and the in-sandbox App OAuth callback) needs a sandbox→laptop port forward, which Islo doesn't provide — so the CLI skips that step automatically, exactly as it does for Modal and Daytona. For a server that requires authentication, inject the credentials instead (see Connecting to an authenticated server).

The host image

Sandboxes boot from ghcr.io/omnigent-ai/omnigent-host:latest, published by CI from the host target of deploy/docker/Dockerfile with Omnigent and its dependencies preinstalled — including the coding-harness CLIs (claude, codex, pi, kiro-cli), so agents on any harness run without an in-sandbox install.

To use a different image (a fork, or extra tooling baked in), build the same target and push it anywhere Islo can pull from:

docker build -f deploy/docker/Dockerfile --target host \
  --platform linux/amd64 \
  -t docker.io/<you>/omnigent-host:latest .
docker push docker.io/<you>/omnigent-host:latest

Then point Omnigent at it — OMNIGENT_ISLO_HOST_IMAGE for the CLI flow, or sandbox.islo.image in the server config for the managed flow. For a private registry, configure the pull credentials on the Islo side (Islo pulls the image, not Omnigent).

Important

Native terminals need bubblewrap. The claude-native / codex-native / kiro-native / pi harnesses wrap each agent terminal in a bubblewrap (bwrap) OS-sandbox, and on Linux that isolation is mandatory and fail-loud — a host image without the bwrap binary makes those terminals fail to start (linux_bwrap sandbox requires the 'bwrap' binary on PATH). The host Dockerfile target installs bubblewrap; if you bring your own image, install it there too. See Troubleshooting.

CLI-launched sandboxes

Provision a sandbox and ship your local checkout into it:

omnigent sandbox create --provider islo

This pulls the host image, builds wheels from your local checkout, and overlays them on top — so the sandbox runs your code, not whatever the image was built from. Then register it as a host with your server:

omnigent sandbox connect --provider islo \
  --sandbox-id <id-printed-by-create> \
  --server https://your-host

connect runs omnigent host inside the sandbox and holds the connection open in your terminal — Ctrl-C tears it down. New sessions targeting that host now run in the sandbox.

Running multiple sandboxes against one server? Pass a unique --host-name <label> to each connect — the server keys hosts on (owner, name), and sandboxes that share a hostname collide.

Sandboxes are disposable. When your code changes, create a new one — and delete the old one (Islo sandboxes have no lifetime cap, so an abandoned sandbox keeps billing until removed via islo rm <id> or the dashboard).

To inject LLM/git credentials into a CLI-launched sandbox, set OMNIGENT_ISLO_SANDBOX_ENV in your shell to a comma-separated list of variable names (e.g. ANTHROPIC_API_KEY,GIT_TOKEN) before running create — the named variables are copied from your environment into the sandbox at provision time. A listed name that is not set fails the launch loudly (it would otherwise surface much later as an opaque harness auth failure inside the sandbox).

Connecting to an authenticated server

connect runs omnigent host inside the sandbox, and that host must present credentials when it dials back to a server that requires authentication. The interactive omnigent login browser flow can't run inside an Islo sandbox (no callback port forward), so inject the keys for the relevant server instead — name them in OMNIGENT_ISLO_SANDBOX_ENV before create:

export OMNIGENT_ISLO_SANDBOX_ENV=DATABRICKS_HOST,DATABRICKS_TOKEN
omnigent sandbox create --provider islo

The in-sandbox host mints a fresh bearer token from those credentials on every connect and reconnect. For a Databricks-fronted server, inject DATABRICKS_HOST plus either DATABRICKS_TOKEN (a PAT) or DATABRICKS_CLIENT_ID / DATABRICKS_CLIENT_SECRET (an OAuth service principal — re-minting keeps a long-lived sandbox connected past any single token's expiry).

A server with no authentication on the host tunnel needs none of this, and neither do server-managed sandboxes — those authenticate with a server-minted per-launch token automatically.

Server-managed sandboxes

Add a sandbox: section to the server config (omnigent server -c config.yaml, or <data_dir>/config.yaml):

sandbox:
  provider: islo
  server_url: https://your-host    # public URL sandboxes dial back to

server_url must be reachable from Islo's cloud — a public HTTPS URL, not localhost. The server itself needs ISLO_API_KEY (and optional ISLO_BASE_URL) in its environment. Sessions created with host_type: "managed" (the API call or the Web UI's New Sandbox option) then run on a fresh Islo sandbox; the create returns immediately and provisioning happens in the background, exactly like the Modal managed flow — including repository workspaces, the first-message rendezvous, and dead-sandbox relaunch.

curl -X POST https://your-host/v1/sessions \
  -H "Content-Type: application/json" \
  -d '{"agent_id": "agent_...", "host_type": "managed"}'

Each managed sandbox authenticates back with a server-minted, per-launch token (7-day TTL — see Lifecycle); no user credentials enter the sandbox for the server connection.

Managed hosts and server auth

How the dial-back authenticates depends on how the server does auth, and there is one interaction worth knowing before you deploy. A managed sandbox opens two kinds of connections back to the server:

  • the host tunnel (/v1/hosts/<id>/tunnel), which the per-launch token authenticates directly — the server mints it, scopes it to one host, and resolves the owner from it. This always works.
  • one runner tunnel per session (/v1/runners/<token>/tunnel), opened by the runner subprocess the host spawns. The runner authenticates with whatever server credential it can resolve — a proxy-injected identity (header / OIDC), or a stored omnigent login token (local hosts only; a fresh managed sandbox has none) — not the per-launch host token.

The consequence:

  • Header / OIDC-proxy auth, or single-user (no-auth) servers — the runner tunnel needs no extra identity, so managed hosts work out of the box. Verified end-to-end on a single-user server: a session created with host_type: "managed" provisioned an Islo sandbox from the bwrap image, the launcher cleared the seeded apiKeyHelper, the host and runner tunnels connected, and a native Claude terminal ran on the injected CLAUDE_CODE_OAUTH_TOKEN subscription.
  • The built-in accounts provider (OMNIGENT_AUTH_ENABLED=1) — the runner tunnel additionally requires a user identity, which the per-launch host token does not carry, so the runner dial-back is refused (403) even though the host tunnel connects. This is a framework-level managed-host interaction shared by all sandbox providers (Modal / Daytona / Islo), not specific to Islo.

So for a managed Islo deployment, front the server with header or OIDC auth (a reverse proxy / IdP injects the user identity on every request, including the runner WebSocket — see deploy/README.md#auth), or run it single-user. The accounts provider is fine for CLI-launched hosts (you omnigent login, and that token is what the in-sandbox host forwards), but not yet for the managed runner dial-back.

Optional islo: settings:

sandbox:
  provider: islo
  server_url: https://your-host
  islo:
    image: docker.io/<you>/omnigent-host:latest   # default: official image
    env: [OPENAI_API_KEY, GIT_TOKEN]               # copy from server env
    base_url: https://api.islo.dev                 # non-default API endpoint
    gateway_profile: default                       # Islo gateway for egress + credential injection
    snapshot_name: warm-host                       # boot from a prebaked snapshot
    workdir: /root/workspace                       # sandbox working directory
    vcpus: 2
    memory_mb: 4096
    disk_gb: 20

Model credentials (LLM keys)

A fresh sandbox has no model credentials of your own. Islo offers two distinct ways to give the agent a model — and they interact, so pick one deliberately per harness.

This is the Islo-native path with no Modal/Daytona equivalent. Islo gateways "automatically attach API keys, tokens, and secrets to outbound requests" at the network layer"credentials never reach the sandbox process." You connect a provider once, server-side, and every sandbox picks it up:

islo login --tool claude     # OAuth-connect Anthropic (alias: --tool anthropic)
islo login --tool openai     # …and/or OpenAI
islo status                  # shows connected integrations

This is not Claude-specific — it's how Islo supplies model credentials to every harness. Islo pre-seeds each sandbox with a phantom placeholder key (islo_phantom_…) in whatever location the harness reads, per provider:

Harness Phantom key location Provider endpoint
Claude Code (claude-native, claude-sdk, pi) apiKeyHelper in ~/.claude/settings.json api.anthropic.com
Codex / OpenAI agents OPENAI_API_KEY env var api.openai.com

The harness sends that placeholder to its provider endpoint; the gateway intercepts the request and swaps it for your connected credential before forwarding. The raw key never lands in the sandbox, and the connection is team-wide — other members don't need their own. (We observed both phantom keys pre-seeded in a single sandbox.)

These integrations connect provider API keys (per-token billing), not plan/subscription auth — --tool claude gives an Anthropic API key, not a Claude Pro/Max subscription; --tool openai gives an OpenAI API key, not a ChatGPT plan. To use a subscription or plan token on any harness (a Claude Pro/Max token, a Codex access token), use Option B.

Important

If islo status shows "No integrations connected" for a provider, its phantom key resolves to nothing — the harness falls back to a failing request (Claude reports "API Usage Billing" and retries). Connect the integration for each provider whose harness you use.

Path A under managed hosts

This is where the gateway shines: when the server launches sandboxes, you configure no model credential on the Omnigent side at all. The flow:

admin (once):  islo login --tool claude   → connects Anthropic to the Islo ACCOUNT
                                                              │
server ──ISLO_API_KEY──▶ Islo API "create sandbox" ──▶ sandbox under that account
                                                              │ Islo pre-seeds the
                                                              │ phantom apiKeyHelper
                                                              ▼
   agent's claude → api.anthropic.com (phantom key) ──▶ Islo gateway swaps in the real key

The Omnigent server only ever holds ISLO_API_KEY — the credential it uses to create sandboxes. Because every managed sandbox is created under that Islo account, and integrations are connected at the account/team level, each one inherits the connected Claude credential through the gateway automatically. The only Omnigent-side knob is which gateway a managed sandbox uses:

sandbox:
  provider: islo
  server_url: https://your-host
  islo:
    gateway_profile: default     # the Islo gateway carrying the connected integration

Two consequences worth internalizing:

  • No model secret lives in the Omnigent server's config or environment — nothing to leak there. Contrast Option B under managed hosts, where the key sits in sandbox.islo.env (copied from the server's env into each sandbox).
  • The integration must be connected on the same Islo account the server's ISLO_API_KEY belongs to. If your server runs under a dedicated service/CI Islo account, run islo login --tool claude while authenticated as that account — not a personal laptop login.

Option B — Omnigent env injection (your own key or a subscription)

Bring your own credential by naming it in OMNIGENT_ISLO_SANDBOX_ENV (CLI) or sandbox.islo.env (managed); the launcher copies the value from the launching environment into the sandbox, and the in-sandbox host forwards the standard harness credential vars to its runners:

Variable Enables
ANTHROPIC_API_KEY Claude models on the Anthropic API
ANTHROPIC_AUTH_TOKEN, ANTHROPIC_BASE_URL Anthropic-compatible gateways (LiteLLM, Bedrock/Vertex bridges, corporate proxies)
CLAUDE_CODE_OAUTH_TOKEN claude-code with a Claude subscription (no API key)
OPENAI_API_KEY / OPENAI_BASE_URL OpenAI or any OpenAI-compatible endpoint (OpenRouter, vLLM, Ollama, …)
CODEX_ACCESS_TOKEN codex with a ChatGPT Business/Enterprise workspace
GEMINI_API_KEY Gemini on the Google AI API

The full per-plan recipes (subscriptions, gateways, open-source models) are identical to Modal — see the variable table and recipes. For a Claude subscription specifically, run claude setup-token on your own machine (one-time browser auth) and inject the resulting long-lived token as CLAUDE_CODE_OAUTH_TOKEN. For env vars beyond the standard set, inject OMNIGENT_RUNNER_ENV_PASSTHROUGH=NAME1,NAME2.

Note

Your injected Claude credential automatically wins over Islo's phantom helper. Islo seeds an apiKeyHelper into every sandbox, and Claude Code would normally prefer it over a CLAUDE_CODE_OAUTH_TOKEN/ANTHROPIC_API_KEY in the environment. So when you inject one of those, the Islo launcher strips the seeded apiKeyHelper at provision time — for both CLI-launched and server-managed sandboxes — leaving your credential as the sole auth path. No manual step, nothing to run inside the sandbox.

Codex/OpenAI needs nothing special either — its phantom is the OPENAI_API_KEY env var, which your injected OPENAI_API_KEY simply overrides.

Choosing between A and B

Option A — gateway Option B — env injection
Credential provider API key (Anthropic, OpenAI, …) your API key or subscription/plan token
Billing per-token API API key, or your subscription/plan
Key in sandbox? No (gateway injects out-of-band) Yes (in the sandbox env)
Scope account/team-wide, all sandboxes per-sandbox
Managed-host config just gateway_profile; no secret on server key in sandbox.islo.env
Best for managed / production, API-key billing your own subscription or key; CLI or managed
Catch needs a connected integration the injected var must be set where the launcher runs

Pick one per harness — connect Islo's integration or inject your own credential, never both. Both work in either launch flow: the launcher strips Islo's seeded apiKeyHelper automatically when you inject a Claude credential. The same two patterns apply to Codex/OpenAI (islo login --tool openai, or inject OPENAI_API_KEY / CODEX_ACCESS_TOKEN).

Git credentials (private repositories)

Inject an HTTPS token as GIT_TOKEN (GitLab: add GIT_USERNAME=oauth2) via OMNIGENT_ISLO_SANDBOX_ENV / sandbox.islo.env. The host image's git credential helper answers HTTPS auth from it for both the launch-time clone and the agent's later fetch / push, writing nothing to disk. Use HTTPS repository URLs. Details by provider match the Modal git guide.

Security considerations

  • Path A keeps the model key out of the sandbox — a real advantage. With the gateway, the agent process only ever sees the phantom placeholder; the real key is injected at Islo's network edge. A prompt-injected or compromised agent can't exfiltrate a key it never holds. This is the strongest credential posture of the three providers for model keys, and the reason to prefer Option A where API-key billing is acceptable.
  • The gateway terminates TLS to inject. Credential injection means Islo's gateway sits in the path of the agent's outbound LLM traffic and re-originates it — so that traffic (prompts, completions, tool output sent to the model) is visible at Islo's edge. Acceptable for most teams, but weigh it for highly sensitive workloads, and scope the gateway_profile to exactly the egress you intend.
  • Option B puts the key in the sandbox. A subscription token or API key named in sandbox.islo.env is copied into the sandbox environment at provision time and lives there for the sandbox's life. Prefer scoped, short-lived credentials, and rely on the per-terminal bwrap sandbox (below) to keep the agent away from it.
  • The agent terminal is sandboxed away from those secrets. Native harness terminals run under a bubblewrap OS-sandbox that masks dotfiles (~/.ssh, ~/.aws, the injected ~/.omnigent server token) and pins the agent to its workspace — defense-in-depth inside the Islo sandbox, independent of Islo's own isolation. This is why the image must ship bwrap (see the host image).
  • All managed sandboxes share one Islo org + ISLO_API_KEY. Cross-user isolation rides on Islo's sandbox boundaries, and the shared org key can enumerate and delete any sandbox — the same single-tenant-org shape as the Modal and Daytona providers. Scope the org to this workload.
  • The launch token's lifetime is 7 days. Islo sandboxes have no platform lifetime cap, so the per-launch host token must outlive a long-running sandbox across reconnects (a longer replay window than Modal's ~24 h; same as Daytona). A relaunch mints a fresh one.

Lifecycle notes

  • No platform lifetime cap. Unlike Modal's 24-hour limit, Islo sandboxes run until deleted. The managed flow deletes a sandbox when its session is deleted, and the dead-sandbox relaunch path replaces one that crashed or was removed out-of-band. CLI-launched sandboxes you delete yourself (islo rm <id>).
  • Resources. Sandboxes default to 2 vCPUs and 4 GiB of memory; override per managed launch with vcpus / memory_mb / disk_gb.
  • Warm starts. Set sandbox.islo.snapshot_name to boot from a prebaked Islo snapshot instead of a cold image pull.
  • Provider-side lifecycle (list / status / delete / stop) — use the islo CLI (islo ls, islo rm <id>) or the dashboard directly.

Cost

Islo bills usage with no seat licenses or idle fees: ~$0.07/CPU-hour, ~$0.04/GB-hour of memory, ~$0.0007/GB-hour of disk — about $0.25/hour for the default 2 vCPU / 4 GiB sandbox while it runs. New accounts get $50 of free credits. Rates: islo.dev.

Troubleshooting

  • Native Claude/Codex terminal fails with linux_bwrap sandbox requires the 'bwrap' binary on PATH. The native harnesses wrap each agent terminal in a bubblewrap OS-sandbox; the host image must ship bubblewrap. The host Dockerfile target installs it — rebuild from a current image, or for a one-off on a CLI-launched sandbox run apt-get install -y bubblewrap inside it.
  • Claude shows "API Usage Billing" / "both CLAUDE_CODE_OAUTH_TOKEN and apiKeyHelper set." You injected your own Claude credential (Option B) but Islo's phantom apiKeyHelper is still present — the launcher strips it automatically at provision, so this means the strip didn't run: confirm the credential is named in OMNIGENT_ISLO_SANDBOX_ENV / sandbox.islo.env (the signal the launcher keys on), and check the provision log for the "clearing Islo's seeded apiKeyHelper" line.
  • Requests retry then fail with no obvious error. islo status shows no connected integration, so the phantom apiKeyHelper resolves to nothing. Connect one (Option A) or switch to Option B.
  • "managed host did not come online within 120s." Check that server_url is publicly reachable from Islo's cloud, then inspect the in-sandbox host log: ~/.omnigent/logs/host-runner/*.log.
  • Agent has no credentials. Verify the injected var names match the forwarded set above (or are named in OMNIGENT_RUNNER_ENV_PASSTHROUGH), and that each name was actually set in the launching environment.

Environment variable reference

Variable Where it's read Purpose
ISLO_API_KEY CLI machine / server Islo API credentials (required)
ISLO_BASE_URL CLI machine / server Non-default Islo API endpoint (default https://api.islo.dev)
OMNIGENT_ISLO_HOST_IMAGE CLI machine / server Override the host image ref (sandbox.islo.image takes precedence for managed)
OMNIGENT_ISLO_SANDBOX_ENV CLI machine / server Comma-separated launcher-side env var names to inject (sandbox.islo.env takes precedence for managed)
OMNIGENT_RUNNER_ENV_PASSTHROUGH inside the sandbox (injected) Extra env var names the host forwards to runners
GIT_TOKEN / GIT_USERNAME inside the sandbox (injected) HTTPS credentials for private repository clone / fetch / push