miosa (Elixir)

Official Elixir SDK for MIOSA — the AI cloud platform for sandboxes, computers, deployments, and managed data.

Hex versionHex downloadsLicense: MITDocs

Elixir 1.15+. HTTP transport via Req, JSON via Jason.

Install

def deps do
  [
    {:miosa, "~> 0.3"}
  ]
end

Then run mix deps.get.

Quickstart

client = Miosa.client("msk_live_...")

{:ok, computer} = Miosa.Computers.create(client, %{
  name: "my-build",
  template_type: "miosa-sandbox",
  size: "small"
})

{:ok, result} = Miosa.Exec.bash(client, computer.id, "echo 'hello from miosa'")
IO.puts(result.output)  # hello from miosa

{:ok, _} = Miosa.Files.write_file(client, computer.id, "/workspace/app.exs", ~s(IO.puts("hi")))
{:ok, text} = Miosa.Files.read_file(client, computer.id, "/workspace/app.exs")

:ok = Miosa.Computers.delete(client, computer.id)

What's included

Module Description
Miosa.Computers Create, list, get, delete computers
Miosa.Computer Bound handle — start, stop, restart, wait
Miosa.Execbash/4 and python/4 execution inside VMs
Miosa.Files Upload, download, write, read, list, stat, mkdir
Miosa.Services Background process management (start/stop/restart/logs)
Miosa.Desktop Screenshot, click, type, key, scroll
Miosa.Events SSE event streaming per computer
Miosa.Checkpoints Snapshot and restore computer state
Miosa.Credits Credit balance and transaction history
Miosa.OpenComputers BYOC host management
Miosa.Workspaces Workspace CRUD
Miosa.Admin Admin-scoped operations

Exec

{:ok, result} = Miosa.Exec.bash(client, computer.id, "ls -la /workspace",
  timeout: 10_000,
  working_dir: "/workspace",
  env: %{"DEBUG" => "1"}
)
IO.puts(result.stdout)
IO.puts("exit: #{result.exit_code}")

{:ok, py} = Miosa.Exec.python(client, computer.id, """
  import json
  print(json.dumps({"status": "ok"}))
""")
IO.puts(py.output)

File operations

# Write / read
{:ok, _} = Miosa.Files.write_file(client, id, "/workspace/app.py", "print('hi')")
{:ok, text} = Miosa.Files.read_file(client, id, "/workspace/app.py")

# Upload binary
{:ok, _} = Miosa.Files.upload(client, id, "./local.txt", "/workspace/remote.txt")

# List / stat / mkdir / rename / delete
{:ok, entries} = Miosa.Files.list(client, id, "/workspace")
{:ok, stat}    = Miosa.Files.stat(client, id, "/workspace/app.py")
{:ok, _}       = Miosa.Files.mkdir(client, id, "/workspace/output")
{:ok, _}       = Miosa.Files.rename(client, id, "/workspace/old.py", "/workspace/new.py")
:ok            = Miosa.Files.delete(client, id, "/workspace/old.py")

Desktop control

{:ok, png} = Miosa.Desktop.screenshot(client, computer.id)
File.write!("screen.png", png)

:ok = Miosa.Desktop.click(client, computer.id, 640, 400)
:ok = Miosa.Desktop.double_click(client, computer.id, 640, 400)
:ok = Miosa.Desktop.right_click(client, computer.id, 640, 400)
:ok = Miosa.Desktop.type(client, computer.id, "hello world")
:ok = Miosa.Desktop.key(client, computer.id, "Return")
:ok = Miosa.Desktop.key(client, computer.id, "ctrl+c")
:ok = Miosa.Desktop.scroll(client, computer.id, 640, 400, "down", 3)
:ok = Miosa.Desktop.drag(client, computer.id, 100, 100, 400, 400)

{:ok, windows} = Miosa.Desktop.windows(client, computer.id)
{:ok, cursor}  = Miosa.Desktop.cursor(client, computer.id)
:ok            = Miosa.Desktop.launch(client, computer.id, "firefox")

SSE event streaming

:ok = Miosa.Events.stream(client, computer.id, fn event ->
  IO.inspect({event.type, event.data})
end)

OTP / Supervisor integration

children = [
  {Miosa.Client, api_key: System.fetch_env!("MIOSA_API_KEY")}
]

Supervisor.start_link(children, strategy: :one_for_one)

Phoenix / LiveView integration

defmodule MyAppWeb.SandboxLive do
  use Phoenix.LiveView

  def mount(_params, _session, socket) do
    client = Miosa.client(System.fetch_env!("MIOSA_API_KEY"))
    {:ok, assign(socket, client: client, output: nil)}
  end

  def handle_event("run", %{"cmd" => cmd}, socket) do
    {:ok, result} = Miosa.Exec.bash(
      socket.assigns.client,
      socket.assigns.computer_id,
      cmd
    )
    {:noreply, assign(socket, output: result.output)}
  end
end

White-label / multi-tenant

{:ok, computer} = Miosa.Computers.create(client, %{
  name: "customer-build",
  template_type: "miosa-sandbox",
  metadata: %{
    "external_workspace_id" => "acme-corp",
    "external_user_id"      => "user-99"
  }
})

Error handling

All functions return {:ok, result} or {:error, %Miosa.Error{}}:

case Miosa.Computers.get(client, "cmp_doesnt_exist") do
  {:ok, computer} ->
    computer

  {:error, %Miosa.Error{status: 404}} ->
    IO.puts("not found")

  {:error, %Miosa.Error{status: 429, message: msg}} ->
    IO.puts("rate limited: #{msg}")

  {:error, %Miosa.Error{message: msg}} ->
    IO.puts("error: #{msg}")
end

Miosa.Error fields: :message, :status, :code, :body.

Configuration

client = Miosa.client("msk_live_...",
  base_url:        "https://api.miosa.ai/api/v1",
  timeout:         30_000,
  receive_timeout: 60_000,
  retry:           false
)
Option Default
:api_key required — pass explicitly; env var not auto-read
:base_urlhttps://api.miosa.ai/api/v1
:timeout30_000 ms
:receive_timeout60_000 ms
:retryfalse

Links

License

MIT