@magpiecloud/mags 1.5.0 → 1.6.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.
Files changed (42) hide show
  1. package/API.md +381 -0
  2. package/Mags-API.postman_collection.json +374 -0
  3. package/QUICKSTART.md +283 -0
  4. package/README.md +287 -79
  5. package/bin/mags.js +161 -27
  6. package/deploy-page.sh +171 -0
  7. package/index.js +1 -163
  8. package/mags +0 -0
  9. package/mags.sh +270 -0
  10. package/nodejs/README.md +191 -0
  11. package/nodejs/bin/mags.js +1146 -0
  12. package/nodejs/index.js +326 -0
  13. package/nodejs/package.json +42 -0
  14. package/package.json +4 -15
  15. package/python/INTEGRATION.md +747 -0
  16. package/python/README.md +139 -0
  17. package/python/dist/magpie_mags-1.0.0-py3-none-any.whl +0 -0
  18. package/python/dist/magpie_mags-1.0.0.tar.gz +0 -0
  19. package/python/examples/demo.py +181 -0
  20. package/python/pyproject.toml +39 -0
  21. package/python/src/magpie_mags.egg-info/PKG-INFO +164 -0
  22. package/python/src/magpie_mags.egg-info/SOURCES.txt +9 -0
  23. package/python/src/magpie_mags.egg-info/dependency_links.txt +1 -0
  24. package/python/src/magpie_mags.egg-info/requires.txt +1 -0
  25. package/python/src/magpie_mags.egg-info/top_level.txt +1 -0
  26. package/python/src/mags/__init__.py +6 -0
  27. package/python/src/mags/client.py +283 -0
  28. package/skill.md +153 -0
  29. package/website/api.html +927 -0
  30. package/website/claude-skill.html +483 -0
  31. package/website/cookbook/hn-marketing.html +410 -0
  32. package/website/cookbook/hn-marketing.sh +50 -0
  33. package/website/cookbook.html +278 -0
  34. package/website/env.js +4 -0
  35. package/website/index.html +718 -0
  36. package/website/llms.txt +242 -0
  37. package/website/login.html +88 -0
  38. package/website/mags.md +171 -0
  39. package/website/script.js +425 -0
  40. package/website/styles.css +845 -0
  41. package/website/tokens.html +171 -0
  42. package/website/usage.html +187 -0
@@ -0,0 +1,139 @@
1
+ # Mags Python SDK
2
+
3
+ Execute scripts on [Magpie's](https://mags.run) instant VM infrastructure from Python.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pip install magpie-mags
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```python
14
+ from mags import Mags
15
+
16
+ m = Mags(api_token="your-token")
17
+
18
+ # Run a script and wait for the result
19
+ result = m.run_and_wait("echo 'Hello from a VM!'")
20
+ print(result["status"]) # "completed"
21
+ print(result["exit_code"]) # 0
22
+ for log in result["logs"]:
23
+ print(log["message"])
24
+ ```
25
+
26
+ ## Authentication
27
+
28
+ Pass `api_token` directly, or set one of these environment variables:
29
+
30
+ ```bash
31
+ export MAGS_API_TOKEN="your-token"
32
+ # or
33
+ export MAGS_TOKEN="your-token"
34
+ ```
35
+
36
+ ## Usage
37
+
38
+ ### Run a Script
39
+
40
+ ```python
41
+ # Fire-and-forget
42
+ job = m.run("apt install -y ffmpeg && ffmpeg -version")
43
+ print(job["request_id"])
44
+
45
+ # Run and wait for completion
46
+ result = m.run_and_wait(
47
+ "python3 -c 'print(sum(range(100)))'",
48
+ timeout=30,
49
+ )
50
+ ```
51
+
52
+ ### Persistent Workspaces
53
+
54
+ ```python
55
+ # First run: creates the workspace
56
+ m.run_and_wait(
57
+ "pip install pandas && echo 'setup done'",
58
+ workspace_id="my-project",
59
+ persistent=True,
60
+ )
61
+
62
+ # Second run: reuses the workspace (pandas is already installed)
63
+ m.run_and_wait(
64
+ "python3 -c 'import pandas; print(pandas.__version__)'",
65
+ workspace_id="my-project",
66
+ )
67
+ ```
68
+
69
+ ### Enable URL / SSH Access
70
+
71
+ ```python
72
+ job = m.run("python3 -m http.server 8080", persistent=True)
73
+
74
+ # HTTP access
75
+ access = m.enable_access(job["request_id"], port=8080)
76
+ print(access["url"])
77
+
78
+ # SSH access
79
+ ssh = m.enable_access(job["request_id"], port=22)
80
+ print(f"ssh root@{ssh['ssh_host']} -p {ssh['ssh_port']}")
81
+ ```
82
+
83
+ ### Upload Files
84
+
85
+ ```python
86
+ file_ids = m.upload_files(["data.csv", "config.json"])
87
+ result = m.run_and_wait(
88
+ "ls /uploads && wc -l /uploads/data.csv",
89
+ file_ids=file_ids,
90
+ )
91
+ ```
92
+
93
+ ### Cron Jobs
94
+
95
+ ```python
96
+ cron = m.cron_create(
97
+ name="nightly-backup",
98
+ cron_expression="0 0 * * *",
99
+ script="tar czf /workspace/backup.tar.gz /data",
100
+ workspace_id="backups",
101
+ )
102
+
103
+ jobs = m.cron_list()
104
+ m.cron_update(cron["id"], enabled=False)
105
+ m.cron_delete(cron["id"])
106
+ ```
107
+
108
+ ### Check Usage
109
+
110
+ ```python
111
+ usage = m.usage(window_days=7)
112
+ print(f"Jobs: {usage['total_jobs']}, VM seconds: {usage['vm_seconds']:.0f}")
113
+ ```
114
+
115
+ ## API Reference
116
+
117
+ | Method | Description |
118
+ |--------|-------------|
119
+ | `run(script, **opts)` | Submit a job (returns immediately) |
120
+ | `run_and_wait(script, **opts)` | Submit and block until done |
121
+ | `status(request_id)` | Get job status |
122
+ | `logs(request_id)` | Get job logs |
123
+ | `list_jobs(page, page_size)` | List recent jobs |
124
+ | `update_job(request_id, startup_command)` | Update job config |
125
+ | `enable_access(request_id, port)` | Enable URL or SSH access |
126
+ | `usage(window_days)` | Get usage summary |
127
+ | `upload_file(path)` | Upload a file, returns file ID |
128
+ | `upload_files(paths)` | Upload multiple files |
129
+ | `cron_create(**opts)` | Create a cron job |
130
+ | `cron_list()` | List cron jobs |
131
+ | `cron_get(id)` | Get a cron job |
132
+ | `cron_update(id, **updates)` | Update a cron job |
133
+ | `cron_delete(id)` | Delete a cron job |
134
+
135
+ ## Links
136
+
137
+ - Website: [mags.run](https://mags.run)
138
+ - Node.js SDK: `npm install @magpiecloud/mags`
139
+ - CLI: `go install` or download from releases
@@ -0,0 +1,181 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Mags Python SDK - Usage Examples
4
+
5
+ Set your API token before running:
6
+ export MAGS_API_TOKEN="your-token-here"
7
+
8
+ Then:
9
+ pip install -e ../ # install the SDK locally
10
+ python demo.py # run all examples
11
+ python demo.py quick # run just the quick example
12
+ python demo.py workspace # run the workspace example
13
+ python demo.py url # run the URL access example
14
+ python demo.py cron # run the cron example
15
+ python demo.py usage # check usage stats
16
+ """
17
+
18
+ import sys
19
+ import time
20
+
21
+ from mags import Mags
22
+
23
+
24
+ def quick_run(m: Mags):
25
+ """Run a simple script and get the output."""
26
+ print("=== Quick Run ===")
27
+ result = m.run_and_wait(
28
+ "echo 'Hello from Mags!' && uname -a && python3 --version",
29
+ timeout=30,
30
+ )
31
+ print(f"Status: {result['status']}")
32
+ print(f"Exit code: {result['exit_code']}")
33
+ print(f"Duration: {result['duration_ms']}ms")
34
+ print("Logs:")
35
+ for log in result["logs"]:
36
+ print(f" [{log['source']}] {log['message']}")
37
+ print()
38
+
39
+
40
+ def workspace_example(m: Mags):
41
+ """Demonstrate persistent workspaces."""
42
+ print("=== Persistent Workspace ===")
43
+ ws = "python-sdk-demo"
44
+
45
+ # First run: install something
46
+ print(f"1. Setting up workspace '{ws}'...")
47
+ result = m.run_and_wait(
48
+ "pip install cowsay && echo 'setup done'",
49
+ workspace_id=ws,
50
+ persistent=True,
51
+ timeout=60,
52
+ )
53
+ print(f" Setup: {result['status']} (exit={result['exit_code']})")
54
+
55
+ # Second run: use what we installed (it persists!)
56
+ print(f"2. Running in existing workspace '{ws}'...")
57
+ result = m.run_and_wait(
58
+ "python3 -c \"import cowsay; cowsay.cow('Mags Python SDK!')\"",
59
+ workspace_id=ws,
60
+ timeout=30,
61
+ )
62
+ print(f" Result: {result['status']} (exit={result['exit_code']})")
63
+ for log in result["logs"]:
64
+ if log["source"] == "stdout":
65
+ print(f" {log['message']}")
66
+ print()
67
+
68
+
69
+ def url_access_example(m: Mags):
70
+ """Start a web server and get its public URL."""
71
+ print("=== URL Access ===")
72
+
73
+ # Start a persistent job with a web server
74
+ job = m.run(
75
+ "echo '<h1>Hello from Mags!</h1>' > /tmp/index.html && "
76
+ "cd /tmp && python3 -m http.server 8080",
77
+ persistent=True,
78
+ name="python-sdk-webserver",
79
+ )
80
+ request_id = job["request_id"]
81
+ print(f"Job submitted: {request_id}")
82
+
83
+ # Wait for it to start running
84
+ print("Waiting for VM to start...")
85
+ for _ in range(20):
86
+ s = m.status(request_id)
87
+ if s["status"] == "running":
88
+ break
89
+ time.sleep(1)
90
+
91
+ # Enable URL access
92
+ access = m.enable_access(request_id, port=8080)
93
+ print(f"URL: {access.get('url', 'N/A')}")
94
+ print(f"Access type: {access['access_type']}")
95
+
96
+ # Enable SSH access
97
+ ssh = m.enable_access(request_id, port=22)
98
+ print(f"SSH: ssh root@{ssh['ssh_host']} -p {ssh['ssh_port']}")
99
+ print()
100
+
101
+
102
+ def cron_example(m: Mags):
103
+ """Create, list, and clean up a cron job."""
104
+ print("=== Cron Jobs ===")
105
+
106
+ # Create a cron job
107
+ cron = m.cron_create(
108
+ name="sdk-test-cron",
109
+ cron_expression="0 * * * *", # every hour
110
+ script="echo 'cron tick' && date",
111
+ )
112
+ print(f"Created cron job: {cron['id']} ({cron['name']})")
113
+
114
+ # List cron jobs
115
+ all_crons = m.cron_list()
116
+ print(f"Total cron jobs: {all_crons.get('total', len(all_crons.get('cron_jobs', [])))}")
117
+
118
+ # Disable it
119
+ m.cron_update(cron["id"], enabled=False)
120
+ print(f"Disabled cron job: {cron['id']}")
121
+
122
+ # Delete it
123
+ m.cron_delete(cron["id"])
124
+ print(f"Deleted cron job: {cron['id']}")
125
+ print()
126
+
127
+
128
+ def usage_example(m: Mags):
129
+ """Show account usage stats."""
130
+ print("=== Usage Stats ===")
131
+ u = m.usage(window_days=30)
132
+ print(f"Window: {u['window_days']} days")
133
+ print(f"Total jobs: {u['total_jobs']}")
134
+ print(f"VM seconds: {u['vm_seconds']:.1f}")
135
+ print(f"CPU seconds: {u['cpu_seconds']:.1f}")
136
+ print(f"Memory (GB-seconds): {u['memory_gb_seconds']:.1f}")
137
+ print(f"Storage (GB-seconds): {u['storage_gb_seconds']:.1f}")
138
+ print(f"VM config: {u['vcpus']} vCPU, {u['memory_mb']}MB RAM, {u['disk_gb']}GB disk")
139
+ print()
140
+
141
+
142
+ def list_jobs(m: Mags):
143
+ """List recent jobs."""
144
+ print("=== Recent Jobs ===")
145
+ resp = m.list_jobs(page=1, page_size=5)
146
+ for job in resp["jobs"]:
147
+ print(
148
+ f" {job['request_id'][:8]}.. "
149
+ f"{job['status']:>10} "
150
+ f"{job.get('name', 'unnamed')}"
151
+ )
152
+ print(f"Total: {resp['total']}")
153
+ print()
154
+
155
+
156
+ EXAMPLES = {
157
+ "quick": quick_run,
158
+ "workspace": workspace_example,
159
+ "url": url_access_example,
160
+ "cron": cron_example,
161
+ "usage": usage_example,
162
+ "list": list_jobs,
163
+ }
164
+
165
+ if __name__ == "__main__":
166
+ m = Mags() # reads MAGS_API_TOKEN from env
167
+
168
+ which = sys.argv[1] if len(sys.argv) > 1 else None
169
+
170
+ if which and which in EXAMPLES:
171
+ EXAMPLES[which](m)
172
+ elif which:
173
+ print(f"Unknown example: {which}")
174
+ print(f"Available: {', '.join(EXAMPLES)}")
175
+ sys.exit(1)
176
+ else:
177
+ # Run all examples
178
+ quick_run(m)
179
+ list_jobs(m)
180
+ usage_example(m)
181
+ print("(Run with 'workspace', 'url', or 'cron' arg for more examples)")
@@ -0,0 +1,39 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "magpie-mags"
7
+ version = "1.0.0"
8
+ description = "Mags SDK - Execute scripts on Magpie's instant VM infrastructure"
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ requires-python = ">=3.8"
12
+ authors = [
13
+ {name = "Magpie Cloud"}
14
+ ]
15
+ keywords = ["magpie", "mags", "vm", "microvm", "cloud", "serverless", "sandbox"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Intended Audience :: Developers",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.8",
22
+ "Programming Language :: Python :: 3.9",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Programming Language :: Python :: 3.13",
27
+ "Topic :: Software Development :: Libraries",
28
+ ]
29
+ dependencies = [
30
+ "requests>=2.25.0",
31
+ ]
32
+
33
+ [project.urls]
34
+ Homepage = "https://mags.run"
35
+ Repository = "https://github.com/magpiecloud/mags"
36
+ Issues = "https://github.com/magpiecloud/mags/issues"
37
+
38
+ [tool.setuptools.packages.find]
39
+ where = ["src"]
@@ -0,0 +1,164 @@
1
+ Metadata-Version: 2.4
2
+ Name: magpie-mags
3
+ Version: 1.0.0
4
+ Summary: Mags SDK - Execute scripts on Magpie's instant VM infrastructure
5
+ Author: Magpie Cloud
6
+ License: MIT
7
+ Project-URL: Homepage, https://mags.run
8
+ Project-URL: Repository, https://github.com/magpiecloud/mags
9
+ Project-URL: Issues, https://github.com/magpiecloud/mags/issues
10
+ Keywords: magpie,mags,vm,microvm,cloud,serverless,sandbox
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.8
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Software Development :: Libraries
22
+ Requires-Python: >=3.8
23
+ Description-Content-Type: text/markdown
24
+ Requires-Dist: requests>=2.25.0
25
+
26
+ # Mags Python SDK
27
+
28
+ Execute scripts on [Magpie's](https://mags.run) instant VM infrastructure from Python.
29
+
30
+ ## Install
31
+
32
+ ```bash
33
+ pip install magpie-mags
34
+ ```
35
+
36
+ ## Quick Start
37
+
38
+ ```python
39
+ from mags import Mags
40
+
41
+ m = Mags(api_token="your-token")
42
+
43
+ # Run a script and wait for the result
44
+ result = m.run_and_wait("echo 'Hello from a VM!'")
45
+ print(result["status"]) # "completed"
46
+ print(result["exit_code"]) # 0
47
+ for log in result["logs"]:
48
+ print(log["message"])
49
+ ```
50
+
51
+ ## Authentication
52
+
53
+ Pass `api_token` directly, or set one of these environment variables:
54
+
55
+ ```bash
56
+ export MAGS_API_TOKEN="your-token"
57
+ # or
58
+ export MAGS_TOKEN="your-token"
59
+ ```
60
+
61
+ ## Usage
62
+
63
+ ### Run a Script
64
+
65
+ ```python
66
+ # Fire-and-forget
67
+ job = m.run("apt install -y ffmpeg && ffmpeg -version")
68
+ print(job["request_id"])
69
+
70
+ # Run and wait for completion
71
+ result = m.run_and_wait(
72
+ "python3 -c 'print(sum(range(100)))'",
73
+ timeout=30,
74
+ )
75
+ ```
76
+
77
+ ### Persistent Workspaces
78
+
79
+ ```python
80
+ # First run: creates the workspace
81
+ m.run_and_wait(
82
+ "pip install pandas && echo 'setup done'",
83
+ workspace_id="my-project",
84
+ persistent=True,
85
+ )
86
+
87
+ # Second run: reuses the workspace (pandas is already installed)
88
+ m.run_and_wait(
89
+ "python3 -c 'import pandas; print(pandas.__version__)'",
90
+ workspace_id="my-project",
91
+ )
92
+ ```
93
+
94
+ ### Enable URL / SSH Access
95
+
96
+ ```python
97
+ job = m.run("python3 -m http.server 8080", persistent=True)
98
+
99
+ # HTTP access
100
+ access = m.enable_access(job["request_id"], port=8080)
101
+ print(access["url"])
102
+
103
+ # SSH access
104
+ ssh = m.enable_access(job["request_id"], port=22)
105
+ print(f"ssh root@{ssh['ssh_host']} -p {ssh['ssh_port']}")
106
+ ```
107
+
108
+ ### Upload Files
109
+
110
+ ```python
111
+ file_ids = m.upload_files(["data.csv", "config.json"])
112
+ result = m.run_and_wait(
113
+ "ls /uploads && wc -l /uploads/data.csv",
114
+ file_ids=file_ids,
115
+ )
116
+ ```
117
+
118
+ ### Cron Jobs
119
+
120
+ ```python
121
+ cron = m.cron_create(
122
+ name="nightly-backup",
123
+ cron_expression="0 0 * * *",
124
+ script="tar czf /workspace/backup.tar.gz /data",
125
+ workspace_id="backups",
126
+ )
127
+
128
+ jobs = m.cron_list()
129
+ m.cron_update(cron["id"], enabled=False)
130
+ m.cron_delete(cron["id"])
131
+ ```
132
+
133
+ ### Check Usage
134
+
135
+ ```python
136
+ usage = m.usage(window_days=7)
137
+ print(f"Jobs: {usage['total_jobs']}, VM seconds: {usage['vm_seconds']:.0f}")
138
+ ```
139
+
140
+ ## API Reference
141
+
142
+ | Method | Description |
143
+ |--------|-------------|
144
+ | `run(script, **opts)` | Submit a job (returns immediately) |
145
+ | `run_and_wait(script, **opts)` | Submit and block until done |
146
+ | `status(request_id)` | Get job status |
147
+ | `logs(request_id)` | Get job logs |
148
+ | `list_jobs(page, page_size)` | List recent jobs |
149
+ | `update_job(request_id, startup_command)` | Update job config |
150
+ | `enable_access(request_id, port)` | Enable URL or SSH access |
151
+ | `usage(window_days)` | Get usage summary |
152
+ | `upload_file(path)` | Upload a file, returns file ID |
153
+ | `upload_files(paths)` | Upload multiple files |
154
+ | `cron_create(**opts)` | Create a cron job |
155
+ | `cron_list()` | List cron jobs |
156
+ | `cron_get(id)` | Get a cron job |
157
+ | `cron_update(id, **updates)` | Update a cron job |
158
+ | `cron_delete(id)` | Delete a cron job |
159
+
160
+ ## Links
161
+
162
+ - Website: [mags.run](https://mags.run)
163
+ - Node.js SDK: `npm install @magpiecloud/mags`
164
+ - CLI: `go install` or download from releases
@@ -0,0 +1,9 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/magpie_mags.egg-info/PKG-INFO
4
+ src/magpie_mags.egg-info/SOURCES.txt
5
+ src/magpie_mags.egg-info/dependency_links.txt
6
+ src/magpie_mags.egg-info/requires.txt
7
+ src/magpie_mags.egg-info/top_level.txt
8
+ src/mags/__init__.py
9
+ src/mags/client.py
@@ -0,0 +1 @@
1
+ requests>=2.25.0
@@ -0,0 +1,6 @@
1
+ """Mags SDK - Execute scripts on Magpie's instant VM infrastructure."""
2
+
3
+ from .client import Mags
4
+
5
+ __all__ = ["Mags"]
6
+ __version__ = "1.0.0"