Editors
Remote workspaces
Open the machine in any editor that speaks SSH and work against the real filesystem, with the language server running next to the code instead of across the network.
MANSSINO / Developers
The CLI is for your hands, the HTTP API is for your agent loop, and SSH is for the tools you already own. They operate on one fleet with one set of semantics, so a machine created from a script is the same object you can open a shell on a minute later.
Conventions
Base URL
https://api.manssino.co/v1
Auth
Authorization: Bearer MANSSINO_API_KEY
Format
JSON request and response bodies, UTF-8, no envelope
Machine ids
Stable strings such as m-7f3a, usable everywhere
01 Quickstart
Four commands. The only thing you need in advance is an API key, which arrives with your access invitation.
# 1. install the cli npm install -g manssino # 2. authenticate, once per profile manssino auth login # 3. ask for a machine manssino create --vcpu 4 --memory 8 --disk 50 --name builder m-7f3a live in 0.24s # 4. use it manssino exec m-7f3a "uname -a" manssino ssh m-7f3a
What just happened
A virtual machine was allocated with its own kernel and a fifty gigabyte disk, and it is now yours until you delete it. Sleep it when you are done and the next resume lands in under 250 milliseconds with everything still in place.
02 CLI reference
Every command accepts --json for machine-readable output, which is what makes the CLI safe to drive from a script when you do not want to reach for the API yet.
| Command | What it does | Common flags |
|---|---|---|
create |
Allocates a machine, attaches a disk, and returns once it is running. | --vcpu --memory --disk --gpu --name --region |
ls |
Lists machines with state, shape, labels, and active time. | --state --label --json |
exec |
Runs a command on a machine and streams stdout and stderr back. | --cwd --env --timeout |
ssh |
Opens an interactive session, or forwards a port with the standard flags. | -L -R -t |
cp |
Copies files between your workstation and a machine. | --recursive |
sleep |
Snapshots memory and disk, freezes the machine, and stops the meter. | --all --label |
resume |
Restores a sleeping machine, typically in under a quarter second. | --wait |
rm |
Deletes a machine along with its disk and snapshots. Not reversible. | --force |
# sleep everything tagged crawler manssino ls --label crawler --json \ | jq -r '.[].id' \ | xargs -n1 manssino sleep
# create, run, delete ID=$(manssino create --vcpu 2 --memory 4 --json | jq -r '.id') manssino exec $ID "./build.sh" manssino rm $ID --force
03 API reference
A small surface on purpose. Machines are created, inspected, commanded, slept, resumed, and deleted. Everything else happens inside the machine, where your code already knows what to do.
| Method and path | Purpose | Body |
|---|---|---|
POST /machines |
Create a machine and wait for it to reach running. | vcpu, memory, disk, gpu, name, labels |
GET /machines |
List machines, filtered by state or label. | Query parameters only |
GET /machines/{id} |
Fetch one machine with its state, shape, and active seconds. | None |
POST /machines/{id}/exec |
Run a command and return exit code, stdout, and stderr. | command, cwd, env, timeout |
POST /machines/{id}/sleep |
Snapshot and freeze the machine, stopping the meter. | None |
POST /machines/{id}/resume |
Restore the machine from its snapshot. | None |
DELETE /machines/{id} |
Destroy the machine, its disk, and its snapshots. | None |
curl -X POST https://api.manssino.co/v1/machines \ -H "Authorization: Bearer $MANSSINO_API_KEY" \ -H "Content-Type: application/json" \ -d '{"vcpu":4,"memory":8,"disk":50,"labels":{"role":"builder"}}' # {"id":"m-7f3a","state":"running","boot_ms":241} curl -X POST https://api.manssino.co/v1/machines/m-7f3a/exec \ -H "Authorization: Bearer $MANSSINO_API_KEY" \ -d '{"command":"pip install -r requirements.txt"}'
import { Manssino } from "manssino"; const mn = new Manssino({ apiKey: process.env.MANSSINO_API_KEY }); const machine = await mn.machines.create({ vcpu: 4, memory: 8, disk: 50, labels: { role: "builder" } }); const run = await mn.machines.exec(machine.id, { command: "pytest -q", timeout: 600 }); console.log(run.exitCode, run.stdout); await mn.machines.sleep(machine.id);
from manssino import Manssino mn = Manssino(api_key=os.environ["MANSSINO_API_KEY"]) machine = mn.machines.create( vcpu=4, memory=8, disk=50, labels={"role": "trainer"} ) run = mn.machines.exec(machine.id, command="python train.py", timeout=3600) print(run.exit_code, run.stdout) mn.machines.sleep(machine.id)
04 Wiring it into an agent loop
The lifecycle maps onto a turn so directly that most integrations are a dozen lines. Store the machine id next to the session, resume it when a turn begins, hand the agent an exec tool, and sleep when the turn ends. The environment becomes part of the conversation state instead of something you reconstruct from it.
async function runTurn(session, toolCall) { await mn.machines.resume(session.machineId); const result = await mn.machines.exec(session.machineId, { command: toolCall.command, cwd: "/workspace", timeout: 120 }); await mn.machines.sleep(session.machineId); return { exitCode: result.exitCode, output: result.stdout || result.stderr }; }
05 SSH and local tooling
A machine is an ordinary SSH host. That one fact is what lets every tool you already use work without a plugin, an adapter, or a vendor extension.
Editors
Open the machine in any editor that speaks SSH and work against the real filesystem, with the language server running next to the code instead of across the network.
Ports
Bring a service running on the machine to your laptop with standard port forwarding, so a dev server or a debugger is reachable without exposing it publicly.
Files
Move data the way you always have. The disk is persistent, so a large upload is something you do once rather than at the start of every run.
# forward a dev server to localhost:3000 manssino ssh m-7f3a -L 3000:localhost:3000 # keep a long job alive across disconnects manssino ssh m-7f3a -t "tmux new -A -s build" # sync a dataset once, keep it forever manssino cp ./corpus m-7f3a:/data/corpus --recursive
06 Errors and behaviour under load
| Status | Meaning | What to do |
|---|---|---|
400 |
A shape or parameter is outside the supported range. | Read error.field, correct the request. Retrying will not help. |
401 |
Missing or revoked API key. | Reissue a key and update the profile or environment variable. |
404 |
No machine with that id, or it was deleted. | Create a new machine. Deleted machines never return. |
409 |
The machine is mid-transition, for example resuming. | Wait a few hundred milliseconds and retry the same call. |
429 |
Too many concurrent creates for the account. | Back off, or ask us to raise the concurrency ceiling for your fleet. |
503 |
Capacity is temporarily unavailable in the region. | Retry with backoff. Resumes are prioritised over new creates. |
Idempotency
Send an Idempotency-Key header on creates and a retried request returns the original machine instead of a second one. Sleep, resume, and delete are naturally idempotent.
Timeouts
An exec call takes a timeout in seconds and kills the process group when it expires. For work that outlives a request, start it in the background and poll, the way you would on any other host.
Waitlist open
Access comes with an API key, a CLI profile, and a machine already provisioned in the shape you asked for, so the first command you run is your own.