# Mags - Instant VM Execution

Execute scripts instantly on Magpie's microVM infrastructure. VMs boot in <100ms from a warm pool, giving you instant access to isolated compute environments.

## What is Mags?

Mags is a CLI and SDK for running scripts on ephemeral microVMs. Each execution gets its own isolated VM that:

- Boots in <100ms (from warm pool)
- Has persistent workspaces synced to S3
- Syncs /root directory automatically every 30 seconds
- Can expose public URLs for web services
- Provides SSH access through secure proxy
- Auto-sleeps when idle and wakes on request

## Installation

### npm (recommended)

```bash
npm install -g @magpiecloud/mags
```

### Go CLI

```bash
go install github.com/magpiecloud/mags/cmd/mags@latest
```

## Authentication

### Interactive Login (Recommended)

```bash
mags login
```

This opens your browser to the Magpie dashboard where you can create an API token. Paste the token when prompted, and it will be saved to `~/.mags/config.json` for all future commands.

### Auth Commands

```bash
mags login     # Authenticate with Magpie
mags whoami    # Check current authentication status
mags logout    # Remove saved credentials
```

### Environment Variable (Alternative)

```bash
export MAGS_API_TOKEN="your-token-here"
```

## Quick Start

### Run a simple command

```bash
mags run 'echo Hello World'
```

### Create a persistent VM

```bash
# Create a new VM with workspace "myproject"
mags new myproject

# SSH into it
mags ssh myproject

# Your /root directory persists to S3 automatically
```

### Run with a persistent workspace

Workspaces persist data between runs using S3 sync:

```bash
# First run - install dependencies
mags run -w myproject 'apk add python3 py3-pip && pip install requests'

# Second run - dependencies are still there
mags run -w myproject 'python3 -c "import requests; print(requests.__version__)"'
```

### Deploy a web service with public URL

```bash
mags run -p --url 'python3 -m http.server 8080'
# Returns: https://abc123.apps.magpiecloud.com
```

## CLI Reference

### Commands

| Command | Description |
|---------|-------------|
| `mags login` | Authenticate with Magpie (saves token locally) |
| `mags logout` | Remove saved credentials |
| `mags whoami` | Show current authentication status |
| `mags new <workspace>` | Create a persistent VM with workspace |
| `mags run [options] <script>` | Execute a script on a microVM |
| `mags ssh <workspace>` | Open interactive SSH session to a VM |
| `mags status <job-id>` | Get job status |
| `mags logs <job-id>` | Get job logs |
| `mags list` | List recent jobs |
| `mags url <job-id> [port]` | Enable URL access for a job |
| `mags stop <job-id>` | Stop a running job |

### Run Options

| Flag | Description | Default |
|------|-------------|---------|
| `-w, --workspace <id>` | Use persistent workspace (S3 sync) | auto-generated |
| `-p, --persistent` | Keep VM alive after script completes | false |
| `--url` | Enable public URL access (requires -p) | false |
| `--port <port>` | Port to expose for URL access | 8080 |
| `--startup-command <cmd>` | Command to run when VM wakes from sleep | none |

## SSH Access

Connect to any running VM via SSH:

```bash
mags ssh myproject
```

### SSH Features

- **Secure proxy**: Connect via `api.magpiecloud.com:PORT` (agent IPs are hidden)
- **PTY support**: Full interactive terminal with colors and editors
- **Key-based auth**: Automatic SSH key management
- **Hostname**: VMs use `mags-vm` as hostname

### SSH Session Example

```bash
$ mags ssh myproject
Connecting to api.magpiecloud.com:40006...
(Use Ctrl+D or 'exit' to disconnect)

mags-vm:~# ls
index.html  test.txt

mags-vm:~# python3 --version
Python 3.11.6

mags-vm:~# exit
```

## Workspaces & Persistence

### How It Works

When you use a workspace, Mags:

1. Mounts a JuiceFS filesystem backed by S3
2. Creates an OverlayFS to capture all filesystem changes
3. Syncs your `/root` directory to S3 every 30 seconds
4. Restores your files when you reconnect

### What Gets Persisted

- `/root` - Your home directory (synced every 30 seconds)
- `/jfs` - Direct JuiceFS mount (instant S3 sync)
- Installed packages and dependencies
- Configuration files and dotfiles

### Sync Behavior

| Event | Behavior |
|-------|----------|
| While running | Auto-sync every 30 seconds |
| On stop | Full sync before VM terminates |
| On wake | Previous state restored instantly |

## Usage Examples

### Basic Execution

```bash
# Simple command
mags run 'echo Hello World'

# Multi-line script
mags run 'apk add curl && curl -s https://api.github.com/users/octocat | head -5'

# With environment info
mags run 'uname -a && cat /etc/os-release'
```

### Persistent Workspaces

```bash
# Create a workspace with dependencies
mags run -w ml-project 'apk add python3 py3-pip && pip install numpy pandas scikit-learn'

# Run scripts using the workspace
mags run -w ml-project 'python3 train.py'

# All files in /root are persisted
mags run -w ml-project 'ls -la /root'
```

### Web Services

```bash
# Simple static server
mags run -p --url 'python3 -m http.server 8080'

# Node.js app
mags run -w myapp -p --url --port 3000 'npm install && npm start'

# Flask app
mags run -w flask-app -p --url 'pip install flask && python app.py'

# Custom startup command for auto-wake
mags run -w api -p --url --startup-command 'python server.py' 'pip install -r requirements.txt && python server.py'
```

### Interactive Development

```bash
# Create a persistent dev environment
mags new dev-env

# SSH in and work
mags ssh dev-env

# Inside the VM:
mags-vm:~# apk add git nodejs npm
mags-vm:~# git clone https://github.com/user/repo
mags-vm:~# cd repo && npm install
mags-vm:~# npm run dev
```

## Node.js SDK

For programmatic access, use the SDK:

```javascript
const Mags = require('@magpiecloud/mags');

const mags = new Mags({
  apiToken: process.env.MAGS_API_TOKEN
});

// Run and wait for completion
const result = await mags.runAndWait('echo Hello World');
console.log(result.logs);

// Run with workspace
const { requestId } = await mags.run('python script.py', {
  workspaceId: 'myproject',
  persistent: true,
  startupCommand: 'python server.py'
});

// Get status
const status = await mags.status(requestId);
console.log(status);

// Get logs
const logs = await mags.logs(requestId);
logs.logs.forEach(l => console.log(l.message));

// Enable URL access
await mags.enableUrl(requestId, 8080);

// List jobs
const jobs = await mags.list({ page: 1, pageSize: 10 });

// Stop a job
await mags.stop(requestId);
```

## API Endpoints

For direct API access:

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/v1/mags-jobs` | POST | Submit a new job |
| `/api/v1/mags-jobs` | GET | List jobs (paginated) |
| `/api/v1/mags-jobs/{id}/status` | GET | Get job status |
| `/api/v1/mags-jobs/{id}/logs` | GET | Get job logs |
| `/api/v1/mags-jobs/{id}/access` | POST | Enable SSH/URL access |
| `/api/v1/mags-jobs/{id}` | PATCH | Update job settings |

### Example API Request

```bash
curl -X POST https://api.magpiecloud.com/api/v1/mags-jobs \
  -H "Authorization: Bearer $MAGS_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "script": "echo Hello World",
    "type": "inline",
    "workspace_id": "myproject",
    "persistent": true
  }'
```

## Job Status Values

| Status | Description |
|--------|-------------|
| `pending` | Job queued, waiting for VM |
| `running` | Script executing |
| `sleeping` | Persistent VM idle (wakes on request) |
| `completed` | Script finished successfully |
| `error` | Script failed |

## VM Environment

Each VM runs Alpine Linux with hostname `mags-vm` and includes:

- `/root` - Persistent home directory (synced to S3)
- `/jfs` - Direct JuiceFS mount
- Common tools: curl, wget, git, python3, nodejs
- Package manager: `apk add <package>`

### Installing Packages

```bash
# Python packages
mags run 'apk add python3 py3-pip && pip install requests flask pandas'

# Node.js packages
mags run 'apk add nodejs npm && npm install -g express'

# System packages
mags run 'apk add ffmpeg imagemagick'
```

## Performance

| Metric | Value |
|--------|-------|
| Warm start | <100ms |
| Cold start | ~4 seconds |
| Script overhead | ~50ms |
| Workspace sync | Every 30 seconds |

## Environment Variables

| Variable | Description | Default |
|----------|-------------|---------|
| `MAGS_API_TOKEN` | Your API token (required) | - |
| `MAGS_API_URL` | API endpoint | https://api.magpiecloud.com |

## Troubleshooting

### "API token required"

Set your API token:
```bash
mags login
# or
export MAGS_API_TOKEN="your-token-here"
```

### "Job timed out"

Increase the timeout or check if your script is hanging:
```bash
mags run --timeout 600 'long-running-script.sh'
```

### "Workspace not found"

Workspace IDs are case-sensitive. Check with:
```bash
mags list
```

### URL not accessible

Make sure you're using both `-p` (persistent) and `--url` flags, and your app is listening on the correct port:
```bash
mags run -p --url --port 3000 'node server.js'
```

### SSH connection issues

SSH connects through our proxy. If you have issues:
1. Ensure the job is running: `mags status <id>`
2. Try reconnecting: `mags ssh <workspace>`

## Support

- Documentation: https://magpiecloud.com/docs/mags
- Issues: https://github.com/magpiecloud/mags/issues
- Dashboard: https://magpiecloud.com/mags

## License

MIT
