Skip to main content

Official Python SDK and CLI for InstaVM APIs

Project description

InstaVM Python SDK + CLI

Official Python SDK and installed CLI for InstaVM. Use it to manage VMs, snapshots, shares, volumes, desktops, account settings, and code execution from Python or your shell.

Installation

pip install instavm

Requirements: Python 3.10+

Table of Contents


CLI

pip install instavm installs the instavm command in the active Python environment.

instavm --help
python -m instavm.cli --help

The CLI stores defaults in ~/.instavm/config.json, checks INSTAVM_API_KEY when no key is stored, and also respects INSTAVM_BASE_URL and INSTAVM_SSH_HOST. instavm login is the easiest way to populate the config — see Auth & Config below.

Auth & Config

The fastest way to authenticate is the browser-based login (recommended for laptops/workstations):

instavm login

This opens your browser, asks you to confirm the pairing on the dashboard, and writes a labelled API key (CLI – <hostname>) back to your local config. The key never touches the URL bar — it's exchanged server-to-server over a local loopback callback using PKCE. To switch accounts, run instavm auth logout then instavm login again.

For headless environments (CI, servers without a browser) paste an existing key:

instavm auth set-key                          # prompts for the key (stdin / hidden)
printf '%s' "$INSTAVM_API_KEY" | instavm auth set-key
instavm auth status

Pointing the CLI at a non-production environment

The CLI honors INSTAVM_BASE_URL (and the --base-url flag). To run the same flow against staging — useful for verifying a release before it reaches production:

export INSTAVM_BASE_URL=https://api.staging.instavm.io
instavm login          # browser will open the staging dashboard

The login flow always opens the dashboard URL returned by the API for the configured base URL, so a single INSTAVM_BASE_URL switches both the API and the browser side of the handshake.

If your dashboard's API key gets revoked from the web UI, the next CLI call will print a hint to re-run instavm login.

Common Commands

instavm whoami
instavm ls
instavm ls -a
instavm ls --watch
instavm create --type computer-use --memory 4096
instavm connect vm_123
instavm pty vm_123                           # interactive PTY (like docker exec -it)
instavm pty vm_123 /bin/zsh                  # custom shell program
instavm deploy
instavm deploy --plan
instavm egress get --vm vm_123
instavm exec --cmd "print('hello from CLI')" --language python
instavm exec ./script.py
instavm browser read https://example.com
instavm browser screenshot https://example.com --out page.png
instavm browser session create
instavm browser navigate https://example.com --session $SID
instavm browser click "button#submit" --session $SID
instavm browser type "input[name=q]" "hello world" --session $SID
instavm browser fill "input[name=email]" "user@example.com" --session $SID
instavm browser scroll --session $SID --y 500
instavm browser extract --session $SID --selector "a"
instavm browser session close $SID
instavm snapshot ls
instavm snapshot get <snapshot_id> --watch
instavm volume ls
instavm volume files upload <volume_id> ./README.md --path docs/README.md
instavm share create vm_123 3000 --public
instavm share set-private <share_id>
instavm ssh-key list
instavm desktop viewer <session_id>
instavm doc
instavm billing

instavm ls shows active VMs only. Use -a or --all to include terminated VM records. On ANSI terminals the human-readable list uses colored status badges, and both instavm ls and instavm snapshot get support --watch for periodic refreshes.

Cookbooks

instavm cookbook pulls curated starter apps from the public instavm/cookbooks catalog, creates a VM, starts the service, creates the share, and returns the public URL.

instavm cookbook list
instavm cookbook info neon-city-webgl
instavm cookbook deploy neon-city-webgl
instavm cookbook deploy hello-fastapi

The CLI syncs the cookbook repo into ~/.instavm/cookbooks/, checks for git, ssh, scp, and tar, prompts for any required secrets, and auto-registers a local public SSH key if your account does not already have one.

Deploy

instavm deploy tries to deploy the app in the current directory without asking you to create an instavm.yaml first. It detects a simple Node.js or Python web app, creates a VM, uploads the project, starts the service, and gives you a share URL.

instavm deploy
instavm deploy --plan
instavm deploy ./path/to/app

--plan shows the detected runtime, install command, start command, port, and secrets without creating a VM.

instavm deploy is experimental right now. The zero-config path is working best for straightforward Node.js and Python apps. Some runtimes and projects still need follow-up fixes or backend support.

Command Reference

  • auth: set-key, status, logout
  • whoami: show account details and SSH keys
  • ls/list: show active VMs by default; use -a or --all for all VM records
  • cookbook: list, info, deploy for curated starter apps from instavm/cookbooks
  • deploy: experimental zero-config deploy for the current app directory
  • egress: get, set for session and VM network egress policy
  • exec: run inline code or a local file, plus result for async task lookup
  • pty: open an interactive PTY inside a VM (like docker exec -it)
  • browser: read, screenshot, navigate, click, type, fill, scroll, wait, extract, session
  • create/new, rm/delete, clone, connect: core VM workflows
  • snapshot: ls, create, build, get, rm
  • desktop: status, start, stop, viewer
  • volume: ls, get, create, update, rm, checkpoint, files
  • share: create, set-public, set-private, revoke
  • ssh-key: list, add, remove
  • doc/docs, billing: docs and billing links

All leaf commands support --json. Share visibility updates use share_id, which matches the public API.

Library Quick Start

import os
from instavm import InstaVM

client = InstaVM(
    api_key=os.environ.get("INSTAVM_API_KEY"),
    auto_start_session=False,
)

me = client.get_current_user()
vms = client.vms.list()

print(me["email"])
print(len(vms))

Code Execution

Sessions & Configuration

from instavm import InstaVM

client = InstaVM(
    api_key="your_api_key",
    cpu_count=2,
    memory_mb=1024,
    env={"APP_ENV": "dev"},
    metadata={"team": "platform"},
)

result = client.execute("print('session id:', 'ok')")
print(result)
print(client.session_id)

File Operations

client = InstaVM(api_key="your_api_key")

client.upload_file("local_script.py", "/app/local_script.py")
client.execute("python /app/local_script.py", language="bash")
client.download_file("output.json", local_path="./output.json")

Async Execution

client = InstaVM(api_key="your_api_key")

task = client.execute_async("sleep 5 && echo 'done'", language="bash")
result = client.get_task_result(task["task_id"], poll_interval=2, timeout=60)
print(result)

Sessions & Sandboxes

client = InstaVM(api_key="your_api_key")

# Get the publicly-reachable app URL (optionally for a specific port)
app_url = client.get_session_app_url(port=8080)
print(app_url.get("app_url"))

# List sandbox records with optional metadata filter and limit
sandboxes = client.list_sandboxes(metadata={"env": "production"}, limit=50)
print(len(sandboxes))

VMs & Snapshots

client = InstaVM(api_key="your_api_key")

# Create a basic VM
vm = client.vms.create(wait=True, metadata={"purpose": "dev"})

# Create a VM with pre-attached volumes
vm_with_vols = client.vms.create(
    wait=True,
    volumes=[{"volume_id": "vol_abc", "mount_path": "/data", "mode": "rw"}],
)

# List VMs
vms = client.vms.list()                 # GET /v1/vms  (running)
all_records = client.vms.list_all_records()  # GET /v1/vms/ (all records)

# Snapshot a running VM
snap_from_vm = client.vms.snapshot(vm_id=vm["vm_id"], wait=True, name="dev-base")

# Build a snapshot from an OCI image
snap_from_oci = client.snapshots.create(
    oci_image="docker.io/library/python:3.11-slim",
    name="python-3-11-dev",
    vcpu_count=2,
    memory_mb=1024,
    snapshot_type="user",
    build_args={
        "git_clone_url": "https://github.com/example/repo.git",
        "git_clone_branch": "main",
        "envs": {"PIP_INDEX_URL": "https://pypi.org/simple"},
    },
)

user_snaps = client.snapshots.list(snapshot_type="user")

Volumes

Volume CRUD & Files

client = InstaVM(api_key="your_api_key")

# Create
volume = client.volumes.create(name="project-data", quota_bytes=10 * 1024 * 1024 * 1024)
volume_id = volume["id"]

# Read / Update
client.volumes.list(refresh_usage=True)
client.volumes.get(volume_id, refresh_usage=True)
client.volumes.update(volume_id, name="project-data-v2", quota_bytes=20 * 1024 * 1024 * 1024)

# File operations
client.volumes.upload_file(volume_id, file_path="./README.md", path="docs/README.md", overwrite=True)
files = client.volumes.list_files(volume_id, prefix="docs/", recursive=True, limit=1000)
download = client.volumes.download_file(volume_id, path="docs/README.md")
client.volumes.delete_file(volume_id, path="docs/README.md")

# Checkpoints
checkpoint = client.volumes.create_checkpoint(volume_id, name="pre-release")
client.volumes.list_checkpoints(volume_id)
client.volumes.delete_checkpoint(volume_id, checkpoint["id"])

# Cleanup
client.volumes.delete(volume_id)

VM Volume Attachments

vm = client.vms.create(wait=True)
vm_id = vm["vm_id"]

client.vms.mount_volume(vm_id, volume_id, mount_path="/data", mode="rw", wait=True)
client.vms.list_volumes(vm_id)
client.vms.unmount_volume(vm_id, volume_id, mount_path="/data", wait=True)

Networking

Egress, Shares, SSH

client = InstaVM(api_key="your_api_key")

# Egress policy
policy = client.set_session_egress(
    allow_package_managers=True,
    allow_http=False,
    allow_https=True,
    allowed_domains=["pypi.org", "files.pythonhosted.org"],
)

# Public/private share links
share = client.shares.create(port=3000, is_public=False)
client.shares.update(share_id=share["share_id"], is_public=True)

# SSH key registration
key = client.add_ssh_key("ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... user@host")

Browser Automation

Basic Browser Flow

client = InstaVM(api_key="your_api_key")

session = client.browser.create_session(viewport_width=1366, viewport_height=768)
session.navigate("https://example.com")
links = session.extract_elements("a", ["text", "href"])
shot_b64 = session.screenshot(full_page=True)
session.close()

Interactions: Click, Type, Fill, Scroll

All interaction methods use CSS selectors to target elements (not pixel coordinates):

client = InstaVM(api_key="your_api_key")

with client.browser.create_session() as session:
    session.navigate("https://www.google.com")

    # Type into an input field (keystroke-by-keystroke with configurable delay)
    session.type("textarea[name=q]", "InstaVM cloud VMs", delay=50)

    # Fill a form field (clears existing value first, sets value instantly)
    session.fill("input[name=email]", "user@example.com")

    # Click an element (supports force-click for obscured elements)
    session.click("button[type=submit]", force=False)

    # Scroll the page or a specific element
    session.scroll(y=500)
    session.scroll(selector="#results")

    # Wait for a condition before continuing
    session.wait_for("visible", selector="#results", timeout=5000)

    # Extract DOM elements with specific attributes
    elements = session.extract_elements("a.result-link", ["href", "text"])
    for el in elements:
        print(el["href"], el["text"])

    # Take a screenshot
    session.screenshot(full_page=True)

Content Extraction

LLM-friendly extraction with optional interactive-element and anchor discovery:

client = InstaVM(api_key="your_api_key")

content = client.browser.extract_content(
    url="https://example.com/docs",
    include_interactive=True,
    include_anchors=True,
    max_anchors=30,
)

print(content["readable_content"].get("title"))
for anchor in (content.get("content_anchors") or [])[:5]:
    print(anchor.get("text"), anchor.get("selector"))

Computer Use

Control a full desktop environment inside a VM session:

client = InstaVM(api_key="your_api_key")

session_id = client.session_id

# Viewer URL and state
viewer = client.computer_use.viewer_url(session_id)
state = client.computer_use.get(session_id, "/state")

# Proxy methods (GET, POST, HEAD)
head_resp = client.computer_use.head(session_id, "/state")

# VNC websockify URL for remote desktop streaming
vnc = client.computer_use.vnc_websockify(session_id)

PTY (Interactive Terminals)

Create and manage interactive pseudo-terminal sessions inside VMs. Used by the OpenAI Agents SDK's Shell capability for write_stdin support.

pip install instavm[pty]  # adds websockets dependency
import asyncio
from instavm import InstaVM

client = InstaVM(api_key="your_api_key")
session_id = client.session_id

# Create a PTY session
pty_info = client.pty.create(session_id, cols=120, rows=40)
pty_id = pty_info["session_id"]

# List / get / resize / kill PTY sessions
sessions = client.pty.list(session_id)
info = client.pty.get(session_id, pty_id)
client.pty.resize(session_id, pty_id, cols=200, rows=50)
client.pty.kill(session_id, pty_id)

# WebSocket URL for interactive I/O (use with websockets library)
ws_url = client.pty.ws_url(session_id, pty_id)

WebSocket Protocol

Connect to ws_url for bidirectional PTY I/O:

  • Client → Server: Binary frames = stdin, Text frames = JSON control ({"type": "resize", "cols": N, "rows": N})
  • Server → Client: Binary frames = stdout/stderr, Text frame = exit notification ({"type": "exit", "exit_code": N})

OpenAI Agents SDK Integration

With PTY support enabled, the Shell capability's write_stdin tool works automatically:

from agents.sandbox import SandboxAgent

agent = SandboxAgent(
    name="Developer",
    model="gpt-5.4",
    instructions="Run interactive commands and inspect output.",
)
# Shell tool's write_stdin is available when supports_pty() returns True

OpenAI Agents SDK: Sandbox Provider

To use InstaVM as a sandbox backend for the OpenAI Agents SDK, install the agents extra:

pip install instavm[agents]

This pulls in openai-agents>=0.14.1,<0.15 and registers InstaVM as a sandbox provider automatically. Each agent runs in its own cloud VM with filesystem, shell, networking, and snapshot support.

import asyncio, os
from agents import Runner, RunConfig
from agents.sandbox import SandboxAgent, SandboxRunConfig
from instavm.integrations.openai_agents import (
    InstaVMSandboxClient,
    InstaVMSandboxClientOptions,
)

agent = SandboxAgent(
    name="Analyst",
    model="gpt-5.4",
    instructions="Analyze workspace files and answer concisely.",
)

async def main():
    client = InstaVMSandboxClient(api_key=os.environ["INSTAVM_API_KEY"])
    result = await Runner.run(
        agent,
        "What OS is this sandbox running?",
        run_config=RunConfig(
            sandbox=SandboxRunConfig(
                client=client,
                options=InstaVMSandboxClientOptions(memory_mb=1024),
            ),
        ),
    )
    print(result.final_output)

asyncio.run(main())

Features: streaming, resume & snapshots, persistent volumes, egress control, cloud bucket mounts, exposed ports, and more.

📖 Full documentation · 📂 Examples


Platform APIs

API keys, audit logs, and webhooks:

client = InstaVM(api_key="your_api_key")

# API Keys
api_key = client.api_keys.create(description="ci key")

# Audit log
audit_page = client.audit.events(limit=25, status="success")

# Webhooks
endpoint = client.webhooks.create_endpoint(
    url="https://example.com/instavm/webhook",
    event_patterns=["vm.*", "snapshot.*"],
)

deliveries = client.webhooks.list_deliveries(limit=10)

Error Handling

All SDK errors extend a typed hierarchy for precise except handling:

from instavm import (
    InstaVM,
    AuthenticationError,
    ExecutionError,
    NetworkError,
    RateLimitError,
    SessionError,
)

client = InstaVM(api_key="your_api_key")

try:
    client.execute("raise Exception('boom')")
except AuthenticationError:
    print("Invalid API key")
except RateLimitError:
    print("Rate limited")
except SessionError as exc:
    print(f"Session issue: {exc}")
except ExecutionError as exc:
    print(f"Execution failed: {exc}")
except NetworkError as exc:
    print(f"Network issue: {exc}")

Development & Testing

pip install -e .                              # Install for development
python3 -m pytest tests/test_api_client.py -v # Unit tests

Further Reading


Changelog

Current package version: 0.19.1

0.19.1

  • Fix: browser navigate now shows page title. The CLI was reading title from the wrong level of the API response, always showing -. Now correctly extracts title from the nested data field.
  • Fix: egress set now shows the new policy state. Previously displayed the old state (all allowed) because the backend only returns {"status": "ok"}. The CLI now fetches the updated state after applying.

0.19.0

  • Full browser interaction CLI. instavm browser now exposes navigate, click, type, fill, scroll, wait, and extract subcommands — all backed by Playwright via CSS selectors. Previously these were SDK-only; now they're available from the terminal.
  • Browser session management CLI. instavm browser session create|close|ls for managing persistent browser sessions across multiple interactions.
  • PTY CLI. instavm pty <vm_id> opens an interactive terminal inside a VM, like docker exec -it. Supports custom shell programs and automatic window resize.
  • ForbiddenError handling. The SDK now catches 403 responses as ForbiddenError instead of retrying indefinitely, with proper error messages for tier limit violations.

0.18.0

  • OpenAI Agents SDK sandbox provider. pip install instavm[agents] adds InstaVM as a backend for Sandbox Agents with auto-registration, no SDK patches needed.
  • PTY (interactive terminal) support. pip install instavm[pty] enables PtyManager for creating, resizing, and killing interactive terminal sessions over WebSocket. The OpenAI Agents SDK's Shell capability (write_stdin) works automatically when PTY is available.
  • InstaVMSandboxClient / InstaVMSandboxSession implementing the full sandbox session contract (exec, read, write, persist, hydrate, resume, exposed ports).
  • InstaVMSandboxClientOptions with VM sizing, snapshots, egress control, exposed ports, environment variables, and metadata.
  • InstaVMCloudBucketMountStrategy for S3/R2/GCS/Azure Blob mounts via rclone+FUSE.
  • Persistent JuiceFS volume helpers (mount, unmount, list).
  • Workspace snapshots with mount-safe tar archiving (unmount, tar, remount).
  • Exit-code auto-detection: uses native API exit_code when available, falls back to sentinel wrapping on older backends.
  • Egress policy management (allow/block HTTP/HTTPS, package managers, domain/CIDR allowlists).
  • 125 unit tests, 21 e2e integration tests, full Runner.run agent smoke test verified.
  • CI matrix: Python 3.10–3.13, Ubuntu/macOS/Windows, plus early-warning job tracking openai-agents @ git+main.

0.17.0

  • Added CLI parity for egress, exec, and terminal-first browser workflows
  • Added colored VM status badges, --watch refreshes for ls and snapshot get, and snapshot-build spinner coverage

0.16.1

  • Fixed deploy and cookbook uploads through the SSH gateway by forcing legacy SCP mode

0.16.0

  • Expanded CLI docs for instavm cookbook
  • Added experimental instavm deploy for zero-config app deploys from the current directory

0.15.1

  • ls now matches the SSH gateway: active VMs by default, -a or --all for all VM records
  • whoami now uses the live /v1/users/me endpoint

0.15.0

  • Installed instavm CLI for pip install instavm, including python -m instavm.cli
  • Stored CLI auth/config in ~/.instavm/config.json with INSTAVM_API_KEY fallback
  • Added get_current_user() and get_session_status(session_id=None) helpers for account and desktop workflows

0.13.0

0.12.0

  • Manager-based APIs across VMs, volumes, snapshots, shares, custom domains, computer use, API keys, audit, and webhooks
  • Snapshot build args support for env vars and Git clone inputs
  • Distinct VM list helpers for /v1/vms and /v1/vms/

For detailed history, see repository tags and PR history.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

instavm-0.21.0.tar.gz (146.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

instavm-0.21.0-py3-none-any.whl (103.7 kB view details)

Uploaded Python 3

File details

Details for the file instavm-0.21.0.tar.gz.

File metadata

  • Download URL: instavm-0.21.0.tar.gz
  • Upload date:
  • Size: 146.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.5

File hashes

Hashes for instavm-0.21.0.tar.gz
Algorithm Hash digest
SHA256 02e081d770c0755ccdb50d252462289612da1e36b4a3e911e28aa542da42b143
MD5 0dda67d179b8e001991d1cb92a499417
BLAKE2b-256 9c11e2a584de66605961a2b0a3e11bbab6599a06efd161c36e0a1dff17936025

See more details on using hashes here.

File details

Details for the file instavm-0.21.0-py3-none-any.whl.

File metadata

  • Download URL: instavm-0.21.0-py3-none-any.whl
  • Upload date:
  • Size: 103.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.5

File hashes

Hashes for instavm-0.21.0-py3-none-any.whl
Algorithm Hash digest
SHA256 60bcacd5b7f1a1399333a092689dff3a44eb06b538a20d2f103bf646dc8c38af
MD5 c23d73640dee40a854f1b032cdff13ca
BLAKE2b-256 e34e89dfd96c99eafff3f093f7d9f6486d2e22f281f1c42a1a5f8ff605c7f53f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page