@magpiecloud/mags 1.7.4 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/mags.js +12 -2
- package/package.json +1 -1
- package/python/pyproject.toml +1 -1
- package/python/src/mags/__init__.py +1 -1
- package/python/src/mags/client.py +5 -0
- package/website/api.html +6 -0
- package/website/index.html +71 -53
package/bin/mags.js
CHANGED
|
@@ -217,6 +217,7 @@ ${colors.bold}Run Options:${colors.reset}
|
|
|
217
217
|
-w, --workspace <id> Use persistent workspace (S3 sync)
|
|
218
218
|
-n, --name <name> Set job name (for easier reference)
|
|
219
219
|
-p, --persistent Keep VM alive after script completes
|
|
220
|
+
--no-sleep Never auto-sleep this VM (requires -p)
|
|
220
221
|
--base <workspace> Mount workspace read-only as base image
|
|
221
222
|
-e, --ephemeral No workspace/S3 sync (fastest execution)
|
|
222
223
|
-f, --file <path> Upload file(s) to VM (repeatable)
|
|
@@ -457,6 +458,7 @@ async function runJob(args) {
|
|
|
457
458
|
let baseWorkspace = '';
|
|
458
459
|
let name = '';
|
|
459
460
|
let persistent = false;
|
|
461
|
+
let noSleep = false;
|
|
460
462
|
let ephemeral = false;
|
|
461
463
|
let enableUrl = false;
|
|
462
464
|
let port = 8080;
|
|
@@ -481,6 +483,9 @@ async function runJob(args) {
|
|
|
481
483
|
case '--persistent':
|
|
482
484
|
persistent = true;
|
|
483
485
|
break;
|
|
486
|
+
case '--no-sleep':
|
|
487
|
+
noSleep = true;
|
|
488
|
+
break;
|
|
484
489
|
case '-e':
|
|
485
490
|
case '--ephemeral':
|
|
486
491
|
ephemeral = true;
|
|
@@ -522,6 +527,10 @@ async function runJob(args) {
|
|
|
522
527
|
log('red', 'Error: Cannot use --ephemeral with --base; ephemeral VMs have no workspace support');
|
|
523
528
|
process.exit(1);
|
|
524
529
|
}
|
|
530
|
+
if (noSleep && !persistent) {
|
|
531
|
+
log('red', 'Error: --no-sleep requires --persistent (-p)');
|
|
532
|
+
process.exit(1);
|
|
533
|
+
}
|
|
525
534
|
|
|
526
535
|
// Upload files if any
|
|
527
536
|
let fileIds = [];
|
|
@@ -546,6 +555,7 @@ async function runJob(args) {
|
|
|
546
555
|
type: 'inline',
|
|
547
556
|
persistent
|
|
548
557
|
};
|
|
558
|
+
if (noSleep) payload.no_sleep = true;
|
|
549
559
|
// Only set workspace_id if not ephemeral
|
|
550
560
|
if (!ephemeral && workspace) payload.workspace_id = workspace;
|
|
551
561
|
if (name) payload.name = name;
|
|
@@ -1296,7 +1306,7 @@ async function execOnJob(nameOrId, command) {
|
|
|
1296
1306
|
|
|
1297
1307
|
// Wrap command to use chroot if overlay is mounted, with proper env
|
|
1298
1308
|
const escaped = command.replace(/'/g, "'\\''");
|
|
1299
|
-
const wrappedCmd = `if [ -d /overlay/bin ]; then chroot /overlay /bin/sh -
|
|
1309
|
+
const wrappedCmd = `if [ -d /overlay/bin ]; then chroot /overlay /bin/sh -l -c 'cd /root 2>/dev/null; ${escaped}'; else cd /root 2>/dev/null; ${escaped}; fi`;
|
|
1300
1310
|
// Allocate TTY so interactive CLIs (e.g. claude) work
|
|
1301
1311
|
if (process.stdin.isTTY) {
|
|
1302
1312
|
sshArgs.push('-t');
|
|
@@ -1338,7 +1348,7 @@ async function main() {
|
|
|
1338
1348
|
break;
|
|
1339
1349
|
case '--version':
|
|
1340
1350
|
case '-v':
|
|
1341
|
-
console.log('mags v1.
|
|
1351
|
+
console.log('mags v1.8.0');
|
|
1342
1352
|
process.exit(0);
|
|
1343
1353
|
break;
|
|
1344
1354
|
case 'new':
|
package/package.json
CHANGED
package/python/pyproject.toml
CHANGED
|
@@ -98,6 +98,7 @@ class Mags:
|
|
|
98
98
|
workspace_id: str | None = None,
|
|
99
99
|
base_workspace_id: str | None = None,
|
|
100
100
|
persistent: bool = False,
|
|
101
|
+
no_sleep: bool = False,
|
|
101
102
|
ephemeral: bool = False,
|
|
102
103
|
startup_command: str | None = None,
|
|
103
104
|
environment: Dict[str, str] | None = None,
|
|
@@ -111,12 +112,16 @@ class Mags:
|
|
|
111
112
|
raise MagsError("Cannot use ephemeral with workspace_id")
|
|
112
113
|
if ephemeral and persistent:
|
|
113
114
|
raise MagsError("Cannot use ephemeral with persistent")
|
|
115
|
+
if no_sleep and not persistent:
|
|
116
|
+
raise MagsError("no_sleep requires persistent=True")
|
|
114
117
|
|
|
115
118
|
payload = {
|
|
116
119
|
"script": script,
|
|
117
120
|
"type": "inline",
|
|
118
121
|
"persistent": persistent,
|
|
119
122
|
}
|
|
123
|
+
if no_sleep:
|
|
124
|
+
payload["no_sleep"] = True
|
|
120
125
|
if name:
|
|
121
126
|
payload["name"] = name
|
|
122
127
|
if not ephemeral and workspace_id:
|
package/website/api.html
CHANGED
|
@@ -336,6 +336,12 @@ m = Mags(api_token="your-token")
|
|
|
336
336
|
<td>no</td>
|
|
337
337
|
<td>If <code>true</code>, VM stays alive after script finishes.</td>
|
|
338
338
|
</tr>
|
|
339
|
+
<tr>
|
|
340
|
+
<td><code>no_sleep</code></td>
|
|
341
|
+
<td>bool</td>
|
|
342
|
+
<td>no</td>
|
|
343
|
+
<td>If <code>true</code>, VM will never be auto-slept by the idle timeout. Requires <code>persistent: true</code>.</td>
|
|
344
|
+
</tr>
|
|
339
345
|
<tr>
|
|
340
346
|
<td><code>startup_command</code></td>
|
|
341
347
|
<td>string</td>
|
package/website/index.html
CHANGED
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
-
<title>Mags -
|
|
6
|
+
<title>Mags - Secure Cloud Sandboxes for AI Agents and Developers</title>
|
|
7
7
|
<meta
|
|
8
8
|
name="description"
|
|
9
|
-
content="Mags
|
|
9
|
+
content="Mags gives AI agents and developers secure, isolated sandboxes that boot in milliseconds. Workspaces persist automatically to the cloud. Run code, schedule jobs, and let agents work safely."
|
|
10
10
|
/>
|
|
11
11
|
<meta name="api-base" content="https://api.magpiecloud.com" />
|
|
12
12
|
<meta name="auth-base" content="https://api.magpiecloud.com" />
|
|
13
|
-
<link rel="stylesheet" href="styles.css?v=
|
|
13
|
+
<link rel="stylesheet" href="styles.css?v=5" />
|
|
14
14
|
<script src="env.js"></script>
|
|
15
15
|
</head>
|
|
16
16
|
<body>
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
<div class="container nav">
|
|
21
21
|
<div class="brand">
|
|
22
22
|
<span class="logo">Mags</span>
|
|
23
|
-
<span class="tag">
|
|
23
|
+
<span class="tag">Secure cloud sandboxes for the AI age</span>
|
|
24
24
|
</div>
|
|
25
25
|
<nav class="nav-links">
|
|
26
26
|
<a href="#overview">Overview</a>
|
|
@@ -42,11 +42,12 @@
|
|
|
42
42
|
<div class="container hero-grid">
|
|
43
43
|
<div class="hero-copy">
|
|
44
44
|
<span class="pill">New: Python SDK</span>
|
|
45
|
-
<h1>
|
|
45
|
+
<h1>Secure sandboxes that boot in milliseconds. Your data stays.</h1>
|
|
46
46
|
<p class="lead">
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
Give your AI agents and scripts a safe place to run. Every sandbox is
|
|
48
|
+
completely isolated, boots instantly, and syncs your files to the cloud
|
|
49
|
+
automatically. Perfect for agents, scheduled jobs, and anything that
|
|
50
|
+
needs to run without risk.
|
|
50
51
|
</p>
|
|
51
52
|
<div class="hero-actions">
|
|
52
53
|
<a class="button" href="#quickstart">Quickstart</a>
|
|
@@ -54,7 +55,7 @@
|
|
|
54
55
|
</div>
|
|
55
56
|
<div class="hero-meta">
|
|
56
57
|
<span>CLI, Python, and Node.js — pick your tool.</span>
|
|
57
|
-
<span>
|
|
58
|
+
<span>Sandboxes in ~300ms. Files persist to the cloud between runs.</span>
|
|
58
59
|
</div>
|
|
59
60
|
</div>
|
|
60
61
|
<div class="hero-card tab-group" aria-label="Mags example">
|
|
@@ -68,7 +69,7 @@
|
|
|
68
69
|
|
|
69
70
|
mags run -w myproject 'pip install flask'
|
|
70
71
|
mags ssh myproject</code></pre>
|
|
71
|
-
<p class="card-note">Run a script,
|
|
72
|
+
<p class="card-note">Run a script, keep your files, then jump in with SSH.</p>
|
|
72
73
|
</div>
|
|
73
74
|
<div class="tab-content" data-tab="hero-python">
|
|
74
75
|
<pre><code>from mags import Mags
|
|
@@ -95,7 +96,7 @@ console.log(result.logs);</code></pre>
|
|
|
95
96
|
<div class="container">
|
|
96
97
|
<div class="section-title">
|
|
97
98
|
<p>Quickstart</p>
|
|
98
|
-
<h2>
|
|
99
|
+
<h2>Three steps. Your first sandbox in under a minute.</h2>
|
|
99
100
|
</div>
|
|
100
101
|
<div class="tab-group">
|
|
101
102
|
<div class="tab-bar">
|
|
@@ -118,7 +119,7 @@ console.log(result.logs);</code></pre>
|
|
|
118
119
|
<article class="card" data-reveal>
|
|
119
120
|
<h3>3. Run</h3>
|
|
120
121
|
<pre><code>mags run 'echo Hello World'</code></pre>
|
|
121
|
-
<p>Add <code>-w myproject</code> to
|
|
122
|
+
<p>Add <code>-w myproject</code> to keep files between runs, synced to the cloud.</p>
|
|
122
123
|
</article>
|
|
123
124
|
</div>
|
|
124
125
|
</div>
|
|
@@ -174,7 +175,7 @@ console.log(result.status); // "completed"</code></pre>
|
|
|
174
175
|
<div class="container">
|
|
175
176
|
<div class="section-title">
|
|
176
177
|
<p>Usage Patterns</p>
|
|
177
|
-
<h2>
|
|
178
|
+
<h2>Run agents. Schedule jobs. Deploy apps. All sandboxed.</h2>
|
|
178
179
|
</div>
|
|
179
180
|
<div class="tab-group">
|
|
180
181
|
<div class="tab-bar">
|
|
@@ -197,16 +198,16 @@ mags login</code></pre>
|
|
|
197
198
|
<table class="ref-table">
|
|
198
199
|
<thead><tr><th>Command</th><th>Description</th></tr></thead>
|
|
199
200
|
<tbody>
|
|
200
|
-
<tr><td><code>mags run <script></code></td><td>Execute a script in a fresh
|
|
201
|
-
<tr><td><code>mags ssh <workspace></code></td><td>SSH into a
|
|
201
|
+
<tr><td><code>mags run <script></code></td><td>Execute a script in a fresh sandbox</td></tr>
|
|
202
|
+
<tr><td><code>mags ssh <workspace></code></td><td>SSH into a sandbox (auto-starts if needed)</td></tr>
|
|
202
203
|
<tr><td><code>mags list</code></td><td>List recent jobs</td></tr>
|
|
203
204
|
<tr><td><code>mags status <id></code></td><td>Get job status</td></tr>
|
|
204
205
|
<tr><td><code>mags logs <id></code></td><td>Get job output</td></tr>
|
|
205
206
|
<tr><td><code>mags stop <id></code></td><td>Stop a running job</td></tr>
|
|
206
|
-
<tr><td><code>mags sync <workspace></code></td><td>Sync workspace to
|
|
207
|
+
<tr><td><code>mags sync <workspace></code></td><td>Sync workspace to the cloud now</td></tr>
|
|
207
208
|
<tr><td><code>mags url <id> [port]</code></td><td>Enable public URL access</td></tr>
|
|
208
209
|
<tr><td><code>mags workspace list</code></td><td>List persistent workspaces</td></tr>
|
|
209
|
-
<tr><td><code>mags workspace delete <id></code></td><td>Delete workspace +
|
|
210
|
+
<tr><td><code>mags workspace delete <id></code></td><td>Delete workspace + cloud data</td></tr>
|
|
210
211
|
<tr><td><code>mags cron add [opts] <script></code></td><td>Create a scheduled cron job</td></tr>
|
|
211
212
|
<tr><td><code>mags cron list</code></td><td>List cron jobs</td></tr>
|
|
212
213
|
<tr><td><code>mags cron remove <id></code></td><td>Delete a cron job</td></tr>
|
|
@@ -221,15 +222,16 @@ mags login</code></pre>
|
|
|
221
222
|
<table class="ref-table">
|
|
222
223
|
<thead><tr><th>Flag</th><th>Description</th></tr></thead>
|
|
223
224
|
<tbody>
|
|
224
|
-
<tr><td><code>-w, --workspace <id></code></td><td>
|
|
225
|
-
<tr><td><code>--base <workspace></code></td><td>
|
|
226
|
-
<tr><td><code>-p, --persistent</code></td><td>Keep
|
|
227
|
-
<tr><td><code
|
|
228
|
-
<tr><td><code>-
|
|
225
|
+
<tr><td><code>-w, --workspace <id></code></td><td>Keep files across runs (synced to the cloud)</td></tr>
|
|
226
|
+
<tr><td><code>--base <workspace></code></td><td>Clone a workspace as a starting point (read-only)</td></tr>
|
|
227
|
+
<tr><td><code>-p, --persistent</code></td><td>Keep sandbox alive after script (sleeps when idle)</td></tr>
|
|
228
|
+
<tr><td><code>--no-sleep</code></td><td>Never auto-sleep this VM (requires <code>-p</code>)</td></tr>
|
|
229
|
+
<tr><td><code>-e, --ephemeral</code></td><td>No cloud sync — fastest execution</td></tr>
|
|
230
|
+
<tr><td><code>-f, --file <path></code></td><td>Upload file(s) into the sandbox (repeatable)</td></tr>
|
|
229
231
|
<tr><td><code>-n, --name <name></code></td><td>Name the job for easy reference</td></tr>
|
|
230
232
|
<tr><td><code>--url</code></td><td>Enable public HTTPS URL (requires <code>-p</code>)</td></tr>
|
|
231
233
|
<tr><td><code>--port <port></code></td><td>Port to expose for URL (default: 8080)</td></tr>
|
|
232
|
-
<tr><td><code>--startup-command <cmd></code></td><td>Command to run when
|
|
234
|
+
<tr><td><code>--startup-command <cmd></code></td><td>Command to run when sandbox wakes from sleep</td></tr>
|
|
233
235
|
</tbody>
|
|
234
236
|
</table>
|
|
235
237
|
</div>
|
|
@@ -246,22 +248,25 @@ mags run -w myproject 'python3 app.py'
|
|
|
246
248
|
|
|
247
249
|
# Base image — create a golden image, sync it, then reuse
|
|
248
250
|
mags run -w golden -p 'apt install -y nodejs && npm install -g typescript'
|
|
249
|
-
mags sync golden # persist to
|
|
251
|
+
mags sync golden # persist to cloud
|
|
250
252
|
mags run --base golden 'npm test' # read-only, changes discarded
|
|
251
253
|
mags run --base golden -w fork-1 'npm test' # fork: load golden, save to fork-1
|
|
252
254
|
|
|
253
|
-
# SSH into a workspace (auto-starts
|
|
255
|
+
# SSH into a workspace (auto-starts sandbox if needed)
|
|
254
256
|
mags ssh myproject
|
|
255
257
|
|
|
256
|
-
# Persistent
|
|
258
|
+
# Persistent sandbox with public URL
|
|
257
259
|
mags run -w webapp -p --url --port 8080 \
|
|
258
260
|
--startup-command 'python3 -m http.server 8080' \
|
|
259
261
|
'python3 -m http.server 8080'
|
|
260
262
|
|
|
263
|
+
# Always-on sandbox (never auto-sleeps)
|
|
264
|
+
mags run -w worker -p --no-sleep 'python3 worker.py'
|
|
265
|
+
|
|
261
266
|
# Upload files and run
|
|
262
267
|
mags run -f script.py -f data.csv 'python3 script.py'
|
|
263
268
|
|
|
264
|
-
# Ephemeral (fastest — no
|
|
269
|
+
# Ephemeral (fastest — no cloud sync)
|
|
265
270
|
mags run -e 'uname -a && df -h'
|
|
266
271
|
|
|
267
272
|
# Cron job
|
|
@@ -292,7 +297,7 @@ export MAGS_API_TOKEN="your-token"</code></pre>
|
|
|
292
297
|
<tr><td><code>enable_access(id, port)</code></td><td>Enable URL or SSH access</td></tr>
|
|
293
298
|
<tr><td><code>upload_files(paths)</code></td><td>Upload files, returns file IDs</td></tr>
|
|
294
299
|
<tr><td><code>list_workspaces()</code></td><td>List persistent workspaces</td></tr>
|
|
295
|
-
<tr><td><code>delete_workspace(id)</code></td><td>Delete workspace +
|
|
300
|
+
<tr><td><code>delete_workspace(id)</code></td><td>Delete workspace + cloud data</td></tr>
|
|
296
301
|
<tr><td><code>cron_create(**opts)</code></td><td>Create a cron job</td></tr>
|
|
297
302
|
<tr><td><code>cron_list()</code></td><td>List cron jobs</td></tr>
|
|
298
303
|
<tr><td><code>cron_delete(id)</code></td><td>Delete a cron job</td></tr>
|
|
@@ -308,12 +313,13 @@ export MAGS_API_TOKEN="your-token"</code></pre>
|
|
|
308
313
|
<table class="ref-table">
|
|
309
314
|
<thead><tr><th>Parameter</th><th>Description</th></tr></thead>
|
|
310
315
|
<tbody>
|
|
311
|
-
<tr><td><code>workspace_id</code></td><td>
|
|
316
|
+
<tr><td><code>workspace_id</code></td><td>Keep files across runs (synced to the cloud)</td></tr>
|
|
312
317
|
<tr><td><code>base_workspace_id</code></td><td>Mount a workspace read-only as base image</td></tr>
|
|
313
|
-
<tr><td><code>persistent</code></td><td>Keep
|
|
314
|
-
<tr><td><code>
|
|
318
|
+
<tr><td><code>persistent</code></td><td>Keep sandbox alive after script completes</td></tr>
|
|
319
|
+
<tr><td><code>no_sleep</code></td><td>Never auto-sleep (requires <code>persistent=True</code>)</td></tr>
|
|
320
|
+
<tr><td><code>ephemeral</code></td><td>No cloud sync (fastest)</td></tr>
|
|
315
321
|
<tr><td><code>file_ids</code></td><td>List of uploaded file IDs to include</td></tr>
|
|
316
|
-
<tr><td><code>startup_command</code></td><td>Command to run when
|
|
322
|
+
<tr><td><code>startup_command</code></td><td>Command to run when sandbox wakes</td></tr>
|
|
317
323
|
</tbody>
|
|
318
324
|
</table>
|
|
319
325
|
</div>
|
|
@@ -347,6 +353,10 @@ job = m.run("python3 -m http.server 8080",
|
|
|
347
353
|
startup_command="python3 -m http.server 8080")
|
|
348
354
|
access = m.enable_access(job["request_id"], port=8080)
|
|
349
355
|
|
|
356
|
+
# Always-on sandbox (never auto-sleeps)
|
|
357
|
+
job = m.run("python3 worker.py",
|
|
358
|
+
workspace_id="worker", persistent=True, no_sleep=True)
|
|
359
|
+
|
|
350
360
|
# Upload files
|
|
351
361
|
file_ids = m.upload_files(["script.py", "data.csv"])
|
|
352
362
|
m.run_and_wait("python3 /uploads/script.py", file_ids=file_ids)
|
|
@@ -398,12 +408,13 @@ export MAGS_API_TOKEN="your-token"</code></pre>
|
|
|
398
408
|
<table class="ref-table">
|
|
399
409
|
<thead><tr><th>Parameter</th><th>Description</th></tr></thead>
|
|
400
410
|
<tbody>
|
|
401
|
-
<tr><td><code>workspaceId</code></td><td>
|
|
411
|
+
<tr><td><code>workspaceId</code></td><td>Keep files across runs (synced to the cloud)</td></tr>
|
|
402
412
|
<tr><td><code>baseWorkspaceId</code></td><td>Mount a workspace read-only as base image</td></tr>
|
|
403
|
-
<tr><td><code>persistent</code></td><td>Keep
|
|
404
|
-
<tr><td><code>
|
|
413
|
+
<tr><td><code>persistent</code></td><td>Keep sandbox alive after script completes</td></tr>
|
|
414
|
+
<tr><td><code>noSleep</code></td><td>Never auto-sleep (requires <code>persistent: true</code>)</td></tr>
|
|
415
|
+
<tr><td><code>ephemeral</code></td><td>No cloud sync (fastest)</td></tr>
|
|
405
416
|
<tr><td><code>fileIds</code></td><td>Array of uploaded file IDs to include</td></tr>
|
|
406
|
-
<tr><td><code>startupCommand</code></td><td>Command to run when
|
|
417
|
+
<tr><td><code>startupCommand</code></td><td>Command to run when sandbox wakes</td></tr>
|
|
407
418
|
</tbody>
|
|
408
419
|
</table>
|
|
409
420
|
</div>
|
|
@@ -439,6 +450,11 @@ const webJob = await mags.run('python3 -m http.server 8080', {
|
|
|
439
450
|
const access = await mags.enableAccess(webJob.requestId, { port: 8080 });
|
|
440
451
|
console.log(access.url);
|
|
441
452
|
|
|
453
|
+
// Always-on sandbox (never auto-sleeps)
|
|
454
|
+
await mags.run('python3 worker.py', {
|
|
455
|
+
workspaceId: 'worker', persistent: true, noSleep: true,
|
|
456
|
+
});
|
|
457
|
+
|
|
442
458
|
// Upload files
|
|
443
459
|
const fileId = await mags.uploadFile('script.py');
|
|
444
460
|
await mags.runAndWait('python3 /uploads/script.py', { fileIds: [fileId] });
|
|
@@ -459,24 +475,26 @@ await mags.cronCreate({
|
|
|
459
475
|
<section class="section" id="workspaces">
|
|
460
476
|
<div class="container">
|
|
461
477
|
<div class="section-title">
|
|
462
|
-
<p>Workspaces</p>
|
|
463
|
-
<h2>
|
|
478
|
+
<p>Persistent Workspaces</p>
|
|
479
|
+
<h2>Your files survive. Every sandbox starts clean.</h2>
|
|
464
480
|
</div>
|
|
465
481
|
<div class="grid split">
|
|
466
482
|
<article class="panel" data-reveal>
|
|
467
|
-
<h3>
|
|
483
|
+
<h3>Backed up to object storage</h3>
|
|
468
484
|
<ul class="list">
|
|
469
|
-
<li>Files and
|
|
470
|
-
<li>
|
|
471
|
-
<li>
|
|
485
|
+
<li>Files, packages, and configs persist automatically</li>
|
|
486
|
+
<li>Optional backup to S3-compatible object storage</li>
|
|
487
|
+
<li>Clone a workspace as a read-only base for new sandboxes</li>
|
|
488
|
+
<li>Survives reboots, sleep, and agent restarts</li>
|
|
472
489
|
</ul>
|
|
473
490
|
</article>
|
|
474
491
|
<article class="panel" data-reveal>
|
|
475
|
-
<h3>
|
|
492
|
+
<h3>Fully isolated</h3>
|
|
476
493
|
<ul class="list">
|
|
477
|
-
<li>
|
|
478
|
-
<li>
|
|
479
|
-
<li>
|
|
494
|
+
<li>Every sandbox runs in its own isolated environment</li>
|
|
495
|
+
<li>No cross-user access — workspaces are private</li>
|
|
496
|
+
<li>Processes, memory, and ports reset between runs</li>
|
|
497
|
+
<li>Agents can't escape or affect the host</li>
|
|
480
498
|
</ul>
|
|
481
499
|
</article>
|
|
482
500
|
</div>
|
|
@@ -488,7 +506,7 @@ await mags.cronCreate({
|
|
|
488
506
|
<div class="container">
|
|
489
507
|
<div class="section-title">
|
|
490
508
|
<p>SDKs + API</p>
|
|
491
|
-
<h2>
|
|
509
|
+
<h2>Let your agents spin up sandboxes programmatically.</h2>
|
|
492
510
|
</div>
|
|
493
511
|
<div class="tab-group">
|
|
494
512
|
<div class="tab-bar">
|
|
@@ -508,7 +526,7 @@ m = Mags() # reads MAGS_API_TOKEN from env
|
|
|
508
526
|
|
|
509
527
|
# Run and wait
|
|
510
528
|
result = m.run_and_wait(
|
|
511
|
-
"echo Hello from a
|
|
529
|
+
"echo Hello from a sandbox!",
|
|
512
530
|
workspace_id="demo",
|
|
513
531
|
)
|
|
514
532
|
print(result["status"])
|
|
@@ -611,7 +629,7 @@ console.log(result.logs);</code></pre>
|
|
|
611
629
|
<div class="container">
|
|
612
630
|
<div class="section-title">
|
|
613
631
|
<p>Resources</p>
|
|
614
|
-
<h2>
|
|
632
|
+
<h2>Everything you need to get started.</h2>
|
|
615
633
|
</div>
|
|
616
634
|
<div class="grid cards">
|
|
617
635
|
<article class="card" data-reveal>
|
|
@@ -631,7 +649,7 @@ console.log(result.logs);</code></pre>
|
|
|
631
649
|
</article>
|
|
632
650
|
<article class="card" data-reveal>
|
|
633
651
|
<h3>Claude skill</h3>
|
|
634
|
-
<p>Install the Claude Code skill
|
|
652
|
+
<p>Install the Claude Code skill to run sandboxes from Claude.</p>
|
|
635
653
|
<a class="text-link" href="claude-skill.html">Open Claude skill</a>
|
|
636
654
|
</article>
|
|
637
655
|
<article class="card" data-reveal>
|
|
@@ -649,9 +667,9 @@ console.log(result.logs);</code></pre>
|
|
|
649
667
|
<div>
|
|
650
668
|
<div class="brand">
|
|
651
669
|
<span class="logo">Mags</span>
|
|
652
|
-
<span class="tag">
|
|
670
|
+
<span class="tag">Secure cloud sandboxes for the AI age</span>
|
|
653
671
|
</div>
|
|
654
|
-
<p>
|
|
672
|
+
<p>Secure, instant sandboxes for AI agents, developers, and automation.</p>
|
|
655
673
|
</div>
|
|
656
674
|
<div class="footer-links">
|
|
657
675
|
<a href="login.html">Login</a>
|
|
@@ -667,7 +685,7 @@ console.log(result.logs);</code></pre>
|
|
|
667
685
|
</div>
|
|
668
686
|
</footer>
|
|
669
687
|
|
|
670
|
-
<script src="script.js?v=
|
|
688
|
+
<script src="script.js?v=5"></script>
|
|
671
689
|
<script>
|
|
672
690
|
(function() {
|
|
673
691
|
var token = localStorage.getItem('microvm-access-token');
|