Base URL https://app.mandala.computer/api/v1. Every request carries an API key, and failures take the shape under Errors.
PUT/computers/{id}/files
Upload a filemember+
Writes a file inside the guest. The request body is the file itself, raw — not multipart, not JSON — and the destination is the path query parameter.
One upload is at most 64 MiB. A larger one is a 413 — refused on its Content-Length before any bytes move when the length is declared, and stopped at the limit otherwise. There is no ranged or append upload on this endpoint. Use PUT /computers/{id}/files/uploads for resumable files up to 2 GiB on Linux.
By default an existing file at path is replaced. Send overwrite=false to create the file only if nothing is there: a path that is taken answers 409 with reason: "exists" and nothing is written. The body is written beside the destination first and published only once it is complete, so incomplete contents are never published at path. A failure while publishing, or while answering, can still leave the complete file there: after an error, inspect path before retrying or overwriting, since what is there may be your own upload. Linux computers only: overwrite=false on Windows is a 400. A computer whose host is too old to do a create-only upload answers 409 with reason: "unsupported" and nothing is sent; one whose host could not be asked answers 503, and the same request can be sent again, since nothing was sent. Neither of those means the path is free.
A computer suspended for being idle just as the upload arrived answers 409 with resume_required and reason: "contention": send the entire upload again, and it resumes the computer first.
Set MANDALA_API_KEY to your bearer key. MANDALA_BASE_URL, when set, is the full API base including /api/v1. Replace the illustrative resource IDs with yours. These pinned 0.16.0 SDK and direct HTTP examples do not read saved device-login credentials. Supply notes.txt locally; its raw bytes are uploaded to the path query value. SDK setup first GETs the computer. Python start/stop/suspend/restart also refresh it with another GET; TypeScript refreshes only if the action returns an acknowledgement.
curl
base_url="${MANDALA_BASE_URL:-}"
if [ -z "$base_url" ]; then base_url='https://app.mandala.computer/api/v1'; fi
curl --fail-with-body -X PUT "${base_url%/}"'/computers/vm-a1b2c3d4e5f6/files?path=%2Fhome%2Fuser%2Fnotes.txt' \
-H "Authorization: Bearer $MANDALA_API_KEY" \
-H "Content-Type: application/octet-stream" \
--data-binary @notes.txt
Python — Mandala SDK 0.16.0
# Python 3.10+: pip install mandala-computer==0.16.0
import os
from pathlib import Path
from mandala_computer import Client
with Client(api_key=os.environ["MANDALA_API_KEY"], base_url=os.environ.get("MANDALA_BASE_URL") or "https://app.mandala.computer/api/v1") as client:
id = "vm-a1b2c3d4e5f6"
query = {"path":"/home/user/notes.txt"}
data = Path("notes.txt").read_bytes()
c = client.computers.get(id)
result = c.write_file(query["path"], data)
print(result)
TypeScript — Mandala SDK 0.16.0
// Node.js 22+: npm install mandala-computer@0.16.0
import { Client } from "mandala-computer";
import { readFile } from "node:fs/promises";
const apiKey = process.env.MANDALA_API_KEY;
if (!apiKey) throw new Error("Set MANDALA_API_KEY");
const client = new Client({apiKey, baseUrl: process.env.MANDALA_BASE_URL || "https://app.mandala.computer/api/v1"});
const id = "vm-a1b2c3d4e5f6";
const query = {"path":"/home/user/notes.txt"};
const bytes = await readFile("notes.txt");
const c = await client.computers.get(id);
const result = await c.writeFile(query.path, bytes);
console.log(JSON.stringify(result, null, 2));
false creates the file only if nothing is at path, and refuses with 409 (reason: "exists") otherwise. The dashboard sends false and asks before replacing. Not supported on Windows.
no_wake
string
Set to 1 to require a running computer without automatic resume: a computer that is not running answers 409 with reason: unavailable rather than being resumed. Any other value is a 400. The dashboard always sends this.
Response
Where it landed and how much of it did.
Response fields
path
string
Where it landed inside the guest.
bytes
integer
What the guest agent acknowledged writing, not the length of what you sent. The daemon refuses a short write, so a 200 with a smaller number than you sent has told you something about your own request body.
Failures
503
Also, on a suspended computer this request would resume, a sealed session the platform could not open or carry just then — the service that holds its key did not answer, or the host failed moving the saved session. Nothing ran in the guest. Read the computer’s status, then send it again; it usually clears in a moment.
GET/computers/{id}/files
Download a filemember+
Reads a file out of the guest. The response body is the file’s bytes.
Needs the member role despite being a read. path is an arbitrary read of the guest’s filesystem rather than a read of anything this platform models — /home/user/.ssh/id_rsa is one call — which is strictly more than a viewer is given anywhere else.
A whole file is capped at 64 MiB, and a Range is how you get past that. Without one this endpoint refuses anything larger with a 413, because the bytes cross the guest agent in chunks and one request holds that channel for as long as it takes. With one, the cap applies to the WINDOW you asked for rather than to the file, so a 2 GB build output is something you page through rather than something you cannot fetch.
A satisfied range answers 206 with a Content-Range giving the bytes you got and the file’s total length. You may get fewer bytes than you asked for — a window past 64 MiB is trimmed to it rather than refused, since you cannot know the limit before you ask — so read the Content-Range and ask again from where it ended. That is the paging loop, and it needs nothing else:
Which end is trimmed follows the end you anchored: bytes=N- keeps its start and loses its far end, while bytes=-N keeps its END — an over-long tail is still the tail of the file, never the middle of it.
A range that names no byte the file has is a 416 whose Content-Range carries the real length. A file whose length the guest cannot report — a /proc entry, say — answers Accept-Ranges: none and ignores your Range, sending the whole thing with a 200; the status is how you tell. And the 413 you get for asking for a whole file that is too big names this header in its message, since that refusal is exactly when you need to know the option exists.
Set MANDALA_API_KEY to your bearer key. MANDALA_BASE_URL, when set, is the full API base including /api/v1. Replace the illustrative resource IDs with yours. These pinned 0.16.0 SDK and direct HTTP examples do not read saved device-login credentials. SDK setup first GETs the computer. Python start/stop/suspend/restart also refresh it with another GET; TypeScript refreshes only if the action returns an acknowledgement.
curl
base_url="${MANDALA_BASE_URL:-}"
if [ -z "$base_url" ]; then base_url='https://app.mandala.computer/api/v1'; fi
curl --fail-with-body "${base_url%/}"'/computers/vm-a1b2c3d4e5f6/files?path=%2Fhome%2Fuser%2Fnotes.txt' \
-H "Authorization: Bearer $MANDALA_API_KEY" \
-o download.bin
Python — Mandala SDK 0.16.0
# Python 3.10+: pip install mandala-computer==0.16.0
import os
from pathlib import Path
from mandala_computer import Client
with Client(api_key=os.environ["MANDALA_API_KEY"], base_url=os.environ.get("MANDALA_BASE_URL") or "https://app.mandala.computer/api/v1") as client:
id = "vm-a1b2c3d4e5f6"
query = {"path":"/home/user/notes.txt"}
c = client.computers.get(id)
result = c.read_file(query["path"])
Path("download.bin").write_bytes(result)
TypeScript — Mandala SDK 0.16.0
// Node.js 22+: npm install mandala-computer@0.16.0
import { Client } from "mandala-computer";
import { writeFile } from "node:fs/promises";
const apiKey = process.env.MANDALA_API_KEY;
if (!apiKey) throw new Error("Set MANDALA_API_KEY");
const client = new Client({apiKey, baseUrl: process.env.MANDALA_BASE_URL || "https://app.mandala.computer/api/v1"});
const id = "vm-a1b2c3d4e5f6";
const query = {"path":"/home/user/notes.txt"};
const c = await client.computers.get(id);
const result = await c.readFile(query.path);
await writeFile("download.bin", result);
200 Raw UTF-8 file bytes, including the final LF.
HTTP 200
Content-Type: application/octet-stream
X-Request-ID: 3f2c9a1e-7b4d-4e8a-9c61-0d5f2b8e4a17
Content-Length: 20
Accept-Ranges: bytes
Raw bytes (UTF-8 shown literally; includes any final newline):
Hello from Mandala.
206 Raw bytes for request Range: bytes=0-4.
HTTP 206
Content-Type: application/octet-stream
X-Request-ID: 3f2c9a1e-7b4d-4e8a-9c61-0d5f2b8e4a17
Content-Range: bytes 0-4/20
Content-Length: 5
Accept-Ranges: bytes
Raw bytes (UTF-8 shown literally; includes any final newline):
Hello
A single byte range — bytes=0-1048575, bytes=1048576- or bytes=-4096 for the tail. Only the first range of a multi-range request is served. A bytes= spec that cannot be read is a 400; a unit that is not bytes is ignored and you get the whole file.
Query parameters
pathrequired
string
Absolute path inside the guest.
no_wake
string
Set to 1 to require a running computer without automatic resume: a computer that is not running answers 409 with reason: unavailable rather than being resumed. Any other value is a 400. The dashboard always sends this.
Response
The file, or the window you asked for.
Failures
503
Also, on a suspended computer this request would resume, a sealed session the platform could not open or carry just then — the service that holds its key did not answer, or the host failed moving the saved session. Nothing ran in the guest. Read the computer’s status, then send it again; it usually clears in a moment.
GET/computers/{id}/files/list
List a guest directorymember+
Reads directory entry names, types and regular-file sizes through the guest agent. Requires member access, like file downloads. The computer must already be running; listing never resumes it or extends its idle timer. The dashboard Files panel opens the guest user’s Desktop directory by default.
Supported on Linux images with /usr/bin/python3. The fixed helper examines at most 512 entries and returns at most 128 KiB of JSON. A large directory returns truncated: true; the response is an unordered subset, not a page with a continuation token. Open a more specific directory by path to narrow the result.
Entries are inspected without following symbolic links. A directory path whose final component is a symlink is refused. Control characters and non-UTF-8 filenames are omitted and counted in skipped. Metadata can change before a subsequent transfer; the existing file transfer path and size rules still apply. Clicking a name in the dashboard never executes a file.
Set MANDALA_API_KEY to your bearer key. MANDALA_BASE_URL, when set, is the full API base including /api/v1. Replace the illustrative resource IDs with yours. These pinned 0.16.0 SDK and direct HTTP examples do not read saved device-login credentials. SDK setup first GETs the computer. Python start/stop/suspend/restart also refresh it with another GET; TypeScript refreshes only if the action returns an acknowledgement.
curl
base_url="${MANDALA_BASE_URL:-}"
if [ -z "$base_url" ]; then base_url='https://app.mandala.computer/api/v1'; fi
curl --fail-with-body "${base_url%/}"'/computers/vm-a1b2c3d4e5f6/files/list?path=%2Fhome%2Fuser' \
-H "Authorization: Bearer $MANDALA_API_KEY"
Python — Mandala SDK 0.16.0
# Python 3.10+: pip install mandala-computer==0.16.0
import os
from mandala_computer import Client
with Client(api_key=os.environ["MANDALA_API_KEY"], base_url=os.environ.get("MANDALA_BASE_URL") or "https://app.mandala.computer/api/v1") as client:
id = "vm-a1b2c3d4e5f6"
query = {"path":"/home/user"}
c = client.computers.get(id)
result = c.list_directory(query["path"])
print(result)
TypeScript — Mandala SDK 0.16.0
// Node.js 22+: npm install mandala-computer@0.16.0
import { Client } from "mandala-computer";
const apiKey = process.env.MANDALA_API_KEY;
if (!apiKey) throw new Error("Set MANDALA_API_KEY");
const client = new Client({apiKey, baseUrl: process.env.MANDALA_BASE_URL || "https://app.mandala.computer/api/v1"});
const id = "vm-a1b2c3d4e5f6";
const query = {"path":"/home/user"};
const c = await client.computers.get(id);
const result = await c.listDirectory(query.path);
console.log(JSON.stringify(result, null, 2));
True when the directory exceeded the bounded listing. Entries are a partial, unordered sample, not a complete listing.
skippedalways
integer
Number of inspected names omitted because their encoding or control characters cannot be used by this file API.
Failures
400
Also a path the guest cannot list: a directory that does not exist (that directory no longer exists), a path naming a regular file or a symbolic link (that path is not an accessible directory), or one the guest user may not read. Unlike the general rule above, these are not final: the same request succeeds once the directory exists or becomes readable. A download of a file that does not exist answers 404 instead.
PUT/computers/{id}/files/uploads
Upload a resumable file chunkmember+
Linux with /usr/bin/python3 only. Send raw chunks of at most 8 MiB in order. Each request body must arrive within two minutes, with no 60-second idle gap; use smaller chunks on slow links. Use the same path, upload_id, size and overwrite on each request. Total size is at most 2 GiB. The first chunk at offset 0 creates a private sibling staging directory. The final chunk publishes the complete file atomically; partial uploads never replace the destination. An empty chunk at offset=size retries publication. With overwrite=false an occupied destination returns 409 reason: exists. Offset or metadata conflicts return 409: read status before retrying. After a lost reply or partial write, GET status and resume from the returned offset. Never reuse an ID for different contents. Keep the source unchanged throughout. DELETE removes staging and the completion receipt without deleting the destination. Staging consumes guest disk until deleted; there is no automatic expiry. Completed data is retained as a hardlink, not a second copy, until the destination is replaced or deleted: from then on the receipt alone holds the old bytes, so DELETE it to free that space. Older hosts return 404; never fall back to ordinary PUT for a chunk.
A chunk whose length differs from its Content-Length, or that runs past size from its offset, is a 400, and so is an empty chunk at any offset other than size. A Windows computer is a 400. A guest-side failure to write the chunk, such as a full guest disk or a directory the upload cannot write to, is a 400 naming the likely causes: fix it, then read status before retrying.
A 503 can mean the host’s upload buffers are all in use by other uploads just then: nothing was staged, so read status and resend from its offset after a short pause. A computer suspended as the chunk arrived answers 409 with resume_required and reason: contention: read status, then resend from the returned offset.
Set MANDALA_API_KEY to your bearer key. MANDALA_BASE_URL, when set, is the full API base including /api/v1. Replace the illustrative resource IDs with yours. These pinned 0.16.0 SDK and direct HTTP examples do not read saved device-login credentials. Supply notes.txt locally; its raw bytes are uploaded to the path query value. Linux with python3 only. The example uses a 20-byte file (Hello from Mandala. followed by LF). Use a fresh random upload_id for a new upload, retain it for status/cancel, and keep the source unchanged. See the operation description for chunking and cleanup. SDK setup first GETs the computer. Python start/stop/suspend/restart also refresh it with another GET; TypeScript refreshes only if the action returns an acknowledgement.
curl
base_url="${MANDALA_BASE_URL:-}"
if [ -z "$base_url" ]; then base_url='https://app.mandala.computer/api/v1'; fi
curl --fail-with-body -X PUT "${base_url%/}"'/computers/vm-a1b2c3d4e5f6/files/uploads?path=%2Fhome%2Fuser%2Fnotes.txt&upload_id=0123456789abcdef0123456789abcdef&offset=0&size=20&overwrite=true' \
-H "Authorization: Bearer $MANDALA_API_KEY" \
-H "Content-Type: application/octet-stream" \
--data-binary @notes.txt
Python — Mandala SDK 0.16.0
# Python 3.10+: pip install mandala-computer==0.16.0
import os
from pathlib import Path
from mandala_computer import Client
with Client(api_key=os.environ["MANDALA_API_KEY"], base_url=os.environ.get("MANDALA_BASE_URL") or "https://app.mandala.computer/api/v1") as client:
id = "vm-a1b2c3d4e5f6"
query = {"path":"/home/user/notes.txt","upload_id":"0123456789abcdef0123456789abcdef","offset":"0","size":"20","overwrite":"true"}
data = Path("notes.txt").read_bytes()
c = client.computers.get(id)
result = c.write_file_chunk(query["path"], data, upload_id=query["upload_id"], offset=int(query["offset"]), size=int(query["size"]))
print(result)
TypeScript — Mandala SDK 0.16.0
// Node.js 22+: npm install mandala-computer@0.16.0
import { Client } from "mandala-computer";
import { readFile } from "node:fs/promises";
const apiKey = process.env.MANDALA_API_KEY;
if (!apiKey) throw new Error("Set MANDALA_API_KEY");
const client = new Client({apiKey, baseUrl: process.env.MANDALA_BASE_URL || "https://app.mandala.computer/api/v1"});
const id = "vm-a1b2c3d4e5f6";
const query = {"path":"/home/user/notes.txt","upload_id":"0123456789abcdef0123456789abcdef","offset":"0","size":"20","overwrite":"true"};
const bytes = await readFile("notes.txt");
const c = await client.computers.get(id);
const result = await c.writeFileChunk(query.path, bytes, {uploadId: query.upload_id, offset: Number(query.offset), size: Number(query.size)});
console.log(JSON.stringify(result, null, 2));
Normalized absolute destination file path, at most 4096 bytes, with no control characters and no empty, . or .. segment; the parent directory must exist. Anything else is a 400.
upload_idrequired
string
A fresh random 32-character lowercase hex ID. Save it with path and the source file to resume.
no_wake
string
Set to 1 to require a running computer without automatic resume: a computer that is not running answers 409 with reason: unavailable rather than being resumed. Any other value is a 400.
offsetrequired
integer
The last confirmed byte offset, initially 0. At most size: a larger one is a 400.
sizerequired
integer
Total file size in bytes.
overwrite
string
Replace the destination atomically when complete, or refuse if it exists.
Response
Confirmed progress and publication state.
Response fields
pathalways
string
Destination inside the guest.
upload_idalways
string
Client-generated 32 lowercase hex characters identifying this upload.
offsetalways
integer
Bytes staged. Resume from this offset; do not guess after a lost response.
sizealways
integer
Declared total file size, at most 2147483648 bytes (2 GiB).
completealways
boolean
The complete file has been published at path.
Failures
503
Also, on a suspended computer this request would resume, a sealed session the platform could not open or carry just then — the service that holds its key did not answer, or the host failed moving the saved session. Nothing ran in the guest. Read the computer’s status, then send it again; it usually clears in a moment.
GET/computers/{id}/files/uploads
Read resumable upload statusmember+
Read staged bytes and completion state before retrying an interrupted upload. Uses the guest agent and may resume the computer unless no_wake=1. A missing upload returns 404. This reads metadata; it does not publish a staged file.
Set MANDALA_API_KEY to your bearer key. MANDALA_BASE_URL, when set, is the full API base including /api/v1. Replace the illustrative resource IDs with yours. These pinned 0.16.0 SDK and direct HTTP examples do not read saved device-login credentials. Linux with python3 only. The example uses a 20-byte file (Hello from Mandala. followed by LF). Use a fresh random upload_id for a new upload, retain it for status/cancel, and keep the source unchanged. See the operation description for chunking and cleanup. SDK setup first GETs the computer. Python start/stop/suspend/restart also refresh it with another GET; TypeScript refreshes only if the action returns an acknowledgement.
curl
base_url="${MANDALA_BASE_URL:-}"
if [ -z "$base_url" ]; then base_url='https://app.mandala.computer/api/v1'; fi
curl --fail-with-body "${base_url%/}"'/computers/vm-a1b2c3d4e5f6/files/uploads?path=%2Fhome%2Fuser%2Fnotes.txt&upload_id=0123456789abcdef0123456789abcdef' \
-H "Authorization: Bearer $MANDALA_API_KEY"
Python — Mandala SDK 0.16.0
# Python 3.10+: pip install mandala-computer==0.16.0
import os
from mandala_computer import Client
with Client(api_key=os.environ["MANDALA_API_KEY"], base_url=os.environ.get("MANDALA_BASE_URL") or "https://app.mandala.computer/api/v1") as client:
id = "vm-a1b2c3d4e5f6"
query = {"path":"/home/user/notes.txt","upload_id":"0123456789abcdef0123456789abcdef"}
c = client.computers.get(id)
result = c.file_upload(query["path"], query["upload_id"])
print(result)
TypeScript — Mandala SDK 0.16.0
// Node.js 22+: npm install mandala-computer@0.16.0
import { Client } from "mandala-computer";
const apiKey = process.env.MANDALA_API_KEY;
if (!apiKey) throw new Error("Set MANDALA_API_KEY");
const client = new Client({apiKey, baseUrl: process.env.MANDALA_BASE_URL || "https://app.mandala.computer/api/v1"});
const id = "vm-a1b2c3d4e5f6";
const query = {"path":"/home/user/notes.txt","upload_id":"0123456789abcdef0123456789abcdef"};
const c = await client.computers.get(id);
const result = await c.fileUpload(query.path, query.upload_id);
console.log(JSON.stringify(result, null, 2));
Normalized absolute destination file path, at most 4096 bytes, with no control characters and no empty, . or .. segment; the parent directory must exist. Anything else is a 400.
upload_idrequired
string
A fresh random 32-character lowercase hex ID. Save it with path and the source file to resume.
no_wake
string
Set to 1 to require a running computer without automatic resume: a computer that is not running answers 409 with reason: unavailable rather than being resumed. Any other value is a 400.
Response
Current progress, including a receipt for a completed upload until DELETE.
Response fields
pathalways
string
Destination inside the guest.
upload_idalways
string
Client-generated 32 lowercase hex characters identifying this upload.
offsetalways
integer
Bytes staged. Resume from this offset; do not guess after a lost response.
sizealways
integer
Declared total file size, at most 2147483648 bytes (2 GiB).
completealways
boolean
The complete file has been published at path.
Failures
503
Also, on a suspended computer this request would resume, a sealed session the platform could not open or carry just then — the service that holds its key did not answer, or the host failed moving the saved session. Nothing ran in the guest. Read the computer’s status, then send it again; it usually clears in a moment.
DELETE/computers/{id}/files/uploads
Remove resumable upload stagingmember+
Cancel an interrupted upload or clean up its completion receipt. Idempotent when the staging directory is absent. Never deletes the published destination. May resume the computer unless no_wake=1.
Set MANDALA_API_KEY to your bearer key. MANDALA_BASE_URL, when set, is the full API base including /api/v1. Replace the illustrative resource IDs with yours. These pinned 0.16.0 SDK and direct HTTP examples do not read saved device-login credentials. Linux with python3 only. The example uses a 20-byte file (Hello from Mandala. followed by LF). Use a fresh random upload_id for a new upload, retain it for status/cancel, and keep the source unchanged. See the operation description for chunking and cleanup. SDK setup first GETs the computer. Python start/stop/suspend/restart also refresh it with another GET; TypeScript refreshes only if the action returns an acknowledgement.
curl
base_url="${MANDALA_BASE_URL:-}"
if [ -z "$base_url" ]; then base_url='https://app.mandala.computer/api/v1'; fi
curl --fail-with-body -X DELETE "${base_url%/}"'/computers/vm-a1b2c3d4e5f6/files/uploads?path=%2Fhome%2Fuser%2Fnotes.txt&upload_id=0123456789abcdef0123456789abcdef' \
-H "Authorization: Bearer $MANDALA_API_KEY"
Python — Mandala SDK 0.16.0
# Python 3.10+: pip install mandala-computer==0.16.0
import os
from mandala_computer import Client
with Client(api_key=os.environ["MANDALA_API_KEY"], base_url=os.environ.get("MANDALA_BASE_URL") or "https://app.mandala.computer/api/v1") as client:
id = "vm-a1b2c3d4e5f6"
query = {"path":"/home/user/notes.txt","upload_id":"0123456789abcdef0123456789abcdef"}
c = client.computers.get(id)
result = c.cancel_file_upload(query["path"], query["upload_id"])
print(result)
TypeScript — Mandala SDK 0.16.0
// Node.js 22+: npm install mandala-computer@0.16.0
import { Client } from "mandala-computer";
const apiKey = process.env.MANDALA_API_KEY;
if (!apiKey) throw new Error("Set MANDALA_API_KEY");
const client = new Client({apiKey, baseUrl: process.env.MANDALA_BASE_URL || "https://app.mandala.computer/api/v1"});
const id = "vm-a1b2c3d4e5f6";
const query = {"path":"/home/user/notes.txt","upload_id":"0123456789abcdef0123456789abcdef"};
const c = await client.computers.get(id);
const result = await c.cancelFileUpload(query.path, query.upload_id);
console.log(JSON.stringify(result, null, 2));
Normalized absolute destination file path, at most 4096 bytes, with no control characters and no empty, . or .. segment; the parent directory must exist. Anything else is a 400.
upload_idrequired
string
A fresh random 32-character lowercase hex ID. Save it with path and the source file to resume.
no_wake
string
Set to 1 to require a running computer without automatic resume: a computer that is not running answers 409 with reason: unavailable rather than being resumed. Any other value is a 400.
Response
Staging removed.
Response fields
ok
boolean
Always true. A failure is a status code, not ok: false.
Failures
503
Also, on a suspended computer this request would resume, a sealed session the platform could not open or carry just then — the service that holds its key did not answer, or the host failed moving the saved session. Nothing ran in the guest. Read the computer’s status, then send it again; it usually clears in a moment.