The Filesystem API gives you full programmatic access to files and directories inside a running computer. All operations are proxied through the in-VM envd daemon and restricted to allowed paths.
Base path: /api/v1/computers/{id}/files
Allowed paths: /home/user, /home/ubuntu, /tmp
Quick Start
import { Miosa } from '@miosa/sdk';
const client = new Miosa();
// Write a file
await client.files.write(computerId, {
path: '/home/user/hello.py',
content: 'print("Hello from MIOSA")',
});
// List the directory
const { files } = await client.files.list(computerId, '/home/user');
// Download it back
const content = await client.files.download(computerId, '/home/user/hello.py'); Endpoints
| Method | Path | Description |
|---|---|---|
POST | /files/upload | Upload a file (multipart) |
POST | /files/write | Write text/binary content directly |
GET | /files | List directory (readdir) |
GET | /files/download | Download a file |
POST | /files/export | Download with metadata (base64) |
DELETE | /files | Delete a file |
GET | /files/stat | Stat a file or directory |
POST | /files/mkdir | Create a directory |
POST | /files/rename | Rename or move a file/directory |
POST | /files/copy | Copy a file |
POST | /files/chmod | Change file permissions |
Upload a File
POST /api/v1/computers/{id}/files/upload
Multipart upload — use this for binary files or large payloads.
Request — multipart/form-data
| Field | Type | Required | Description |
|---|---|---|---|
file | file | Yes | File to upload |
path | string | No | Remote path. If ends with /, filename is appended. Default: /home/user/ |
Response — 201 Created
{
"success": true,
"file": {
"path": "/home/user/script.py",
"filename": "script.py",
"size_bytes": 1234
}
} Errors
| Status | Code | Description |
|---|---|---|
| 400 | MISSING_FILE | No file field in request |
| 403 | FORBIDDEN_PATH | Path outside allowed directories |
| 413 | FILE_TOO_LARGE | File exceeds 10 MB limit |
| 502 | AGENT_UNAVAILABLE | In-VM agent unreachable |
curl -X POST https://api.miosa.ai/api/v1/computers/{id}/files/upload
-H "Authorization: Bearer $MIOSA_API_KEY"
-F "file=@./script.py"
-F "path=/home/user/scripts/" Write a File
POST /api/v1/computers/{id}/files/write
Write text or base64-encoded binary content. Faster than multipart for programmatic use.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
path | string | Yes | Full destination path |
content | string | Yes | File content (UTF-8 text or base64 when encoding="base64") |
encoding | string | No | "utf8" (default) or "base64" |
Response — 201 Created
{
"success": true,
"file": {
"path": "/home/user/config.json",
"size_bytes": 256
}
} curl -X POST https://api.miosa.ai/api/v1/computers/{id}/files/write
-H "Authorization: Bearer $MIOSA_API_KEY"
-H "Content-Type: application/json"
-d '{"path": "/home/user/config.json", "content": "{"key": "value"}"}' List Directory (readdir)
GET /api/v1/computers/{id}/files
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
path | string | No | Directory to list. Default: /home/user |
Response — 200 OK
{
"files": [
{
"name": "Documents",
"type": "directory",
"size_bytes": 4096,
"permissions": "drwxr-xr-x",
"modified_at": "2026-04-11T10:30:00Z"
},
{
"name": "script.py",
"type": "file",
"size_bytes": 1234,
"permissions": "-rw-r--r--",
"modified_at": "2026-04-11T10:25:00Z"
}
],
"path": "/home/user"
} curl "https://api.miosa.ai/api/v1/computers/{id}/files?path=/home/user"
-H "Authorization: Bearer $MIOSA_API_KEY" Download a File
GET /api/v1/computers/{id}/files/download
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
path | string | Yes | Full path to the file |
Response — 200 OK
Binary file content. Content-Disposition is set for browser download.
Errors
| Status | Code | Description |
|---|---|---|
| 400 | MISSING_PATH | No path parameter |
| 403 | FORBIDDEN_PATH | Path outside allowed directories |
| 404 | FILE_NOT_FOUND | File does not exist |
| 502 | AGENT_UNAVAILABLE | In-VM agent unreachable |
curl "https://api.miosa.ai/api/v1/computers/{id}/files/download?path=/home/user/output.txt"
-H "Authorization: Bearer $MIOSA_API_KEY"
--output output.txt Export a File
POST /api/v1/computers/{id}/files/export
Returns metadata and base64-encoded content in a single JSON response. Useful when you need the file and its metadata together without handling binary responses.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
path | string | Yes | Full path to the file |
Response — 200 OK
{
"success": true,
"file": {
"path": "/home/user/data.json",
"filename": "data.json",
"size_bytes": 5678,
"content_type": "application/json",
"modified_at": "2026-04-11T10:30:00Z"
},
"content_base64": "eyJrZXkiOiAidmFsdWUifQ=="
} curl -X POST https://api.miosa.ai/api/v1/computers/{id}/files/export
-H "Authorization: Bearer $MIOSA_API_KEY"
-H "Content-Type: application/json"
-d '{"path": "/home/user/data.json"}' Delete a File
DELETE /api/v1/computers/{id}/files
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
path | string | Yes | Full path to delete |
Response — 200 OK
{ "success": true, "path": "/home/user/old-file.txt" } curl -X DELETE https://api.miosa.ai/api/v1/computers/{id}/files
-H "Authorization: Bearer $MIOSA_API_KEY"
-H "Content-Type: application/json"
-d '{"path": "/home/user/old-file.txt"}' Stat a File or Directory
GET /api/v1/computers/{id}/files/stat
Returns metadata without downloading file content.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
path | string | Yes | Full path |
Response — 200 OK
{
"path": "/home/user/script.py",
"type": "file",
"size_bytes": 1234,
"permissions": "-rw-r--r--",
"owner": "user",
"group": "user",
"modified_at": "2026-04-11T10:25:00Z",
"created_at": "2026-04-11T09:00:00Z"
} Errors
| Status | Code | Description |
|---|---|---|
| 404 | FILE_NOT_FOUND | Path does not exist |
curl "https://api.miosa.ai/api/v1/computers/{id}/files/stat?path=/home/user/script.py"
-H "Authorization: Bearer $MIOSA_API_KEY" Create a Directory
POST /api/v1/computers/{id}/files/mkdir
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
path | string | Yes | Directory path to create |
recursive | boolean | No | Create parent directories if missing (default: false) |
Response — 201 Created
{ "success": true, "path": "/home/user/project/src" } curl -X POST https://api.miosa.ai/api/v1/computers/{id}/files/mkdir
-H "Authorization: Bearer $MIOSA_API_KEY"
-H "Content-Type: application/json"
-d '{"path": "/home/user/project/src", "recursive": true}' Rename or Move
POST /api/v1/computers/{id}/files/rename
Renames a file or directory, or moves it to a different path. Both source and destination must be within allowed paths.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
source | string | Yes | Current path |
destination | string | Yes | Target path |
Response — 200 OK
{ "success": true, "source": "/home/user/old.txt", "destination": "/home/user/new.txt" } Errors
| Status | Code | Description |
|---|---|---|
| 404 | FILE_NOT_FOUND | Source path does not exist |
| 409 | DESTINATION_EXISTS | Destination already exists |
curl -X POST https://api.miosa.ai/api/v1/computers/{id}/files/rename
-H "Authorization: Bearer $MIOSA_API_KEY"
-H "Content-Type: application/json"
-d '{"source": "/home/user/app.py", "destination": "/home/user/app_v2.py"}' Copy a File
POST /api/v1/computers/{id}/files/copy
Copies a file to a new path. Directory copy is not supported — copy individual files.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
source | string | Yes | Source file path |
destination | string | Yes | Destination file path |
Response — 201 Created
{ "success": true, "source": "/home/user/template.py", "destination": "/home/user/project/main.py" } curl -X POST https://api.miosa.ai/api/v1/computers/{id}/files/copy
-H "Authorization: Bearer $MIOSA_API_KEY"
-H "Content-Type: application/json"
-d '{"source": "/home/user/template.py", "destination": "/home/user/project/main.py"}' Change Permissions
POST /api/v1/computers/{id}/files/chmod
Sets UNIX file permissions.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
path | string | Yes | File path |
mode | string | Yes | Octal permission string, e.g. "755" or "644" |
Response — 200 OK
{ "success": true, "path": "/home/user/script.sh", "mode": "755" } curl -X POST https://api.miosa.ai/api/v1/computers/{id}/files/chmod
-H "Authorization: Bearer $MIOSA_API_KEY"
-H "Content-Type: application/json"
-d '{"path": "/home/user/script.sh", "mode": "755"}' Path Security
All paths are validated before execution:
- Expansion —
Path.expandresolves..,~, and symlinks - Prefix check — Must start with
/home/user,/home/ubuntu, or/tmp - Rejection — Paths outside these prefixes return
403 FORBIDDEN_PATH
/home/user/../../etc/passwd expands to /etc/passwd and is rejected.
Common Recipes
Scaffold a project directory
// Create structure
await client.files.mkdir(computerId, { path: '/home/user/app/src', recursive: true });
await client.files.mkdir(computerId, { path: '/home/user/app/tests', recursive: true });
// Write files
await client.files.write(computerId, { path: '/home/user/app/src/main.py', content: mainPy });
await client.files.write(computerId, { path: '/home/user/app/requirements.txt', content: reqs });
// Make entrypoint executable
await client.files.chmod(computerId, { path: '/home/user/app/src/main.py', mode: '755' }); Retrieve build artifacts
# List the build output directory
files = client.files.list(computer_id, path="/home/user/app/dist")
for f in files["files"]:
if f["type"] == "file":
content = client.files.export(computer_id, path=f"/home/user/app/dist/{f['name']}")
save_artifact(f["name"], content["content_base64"])