Skip to main content

Global Flags

-v, --verbose
boolean
Enable verbose logging output

Top-Level Commands

Authentication

m87 login

Authenticate with make87 via browser-based OAuth flow.
m87 login

m87 logout

Logout and clear local credentials.
m87 logout

Device Management

m87 devices list

List all accessible devices.
m87 devices list

m87 devices approve <device>

Approve a pending device registration.
device
string
required
Device name or ID to approve
m87 devices approve my-device

m87 devices reject <device>

Reject a pending device registration.
device
string
required
Device name or ID to reject
m87 devices reject my-device

m87 devices show <device>

Show detailed information about a specific device.
device
string
required
Device name or ID
m87 devices show my-device
This command is not yet fully implemented.

File Operations

m87 cp <source> <dest>

Copy files between local and remote devices (SCP-style).
source
string
required
Source path. Use <device>:<path> for remote, <path> for local.
dest
string
required
Destination path. Use <device>:<path> for remote, <path> for local.
# Copy from device to local
m87 cp my-device:/var/log/app.log ./app.log

# Copy from local to device
m87 cp ./config.yml my-device:/etc/app/config.yml

m87 sync <source> <dest>

Sync files between local and remote devices (rsync-style).
source
string
required
Source path. Use <device>:<path> for remote, <path> for local.
dest
string
required
Destination path. Use <device>:<path> for remote, <path> for local.
--delete
boolean
default:"false"
Delete files from destination that are not present in source
--watch
boolean
default:"false"
Watch for changes and sync automatically
-n, --dry-run
boolean
default:"false"
Show what would be done without making changes
-e, --exclude
string[]
Exclude files matching pattern (can be used multiple times)
# Sync directory to device
m87 sync ./src my-device:/app/src

# Sync with delete flag
m87 sync --delete ./src my-device:/app/src

# Watch mode with exclusions
m87 sync --watch --exclude "*.log" --exclude "node_modules" ./src my-device:/app/src

m87 ls <path>

List files on a device.
path
string
required
Remote path in format <device>:<path>
m87 ls my-device:/var/log

Utility Commands

m87 version

Show CLI version information including build details and platform.
m87 version

m87 update

Update the CLI to the latest version.
m87 update

Configuration

m87 config set

Set configuration values.
--runtime-server-url
string
Override API URL (e.g., https://eu.public.make87.dev)
--owner-reference
string
Set owner reference (email or org ID)
--make87-api-url
string
Set make87 API URL
--make87-app-url
string
Set make87 app URL
--trust-invalid-server-cert
boolean
Trust invalid server certificates (use with caution)
m87 config set --runtime-server-url https://eu.public.make87.dev
m87 config set --owner-reference myorg

m87 config show

Display current configuration.
m87 config show

m87 config file

Show path to configuration file.
m87 config file

SSH Commands

m87 ssh enable

Enable SSH host resolution for .m87 domains.
m87 ssh enable
After enabling, you can use standard SSH:
ssh my-device.m87

m87 ssh disable

Disable SSH host resolution.
m87 ssh disable

MCP Server

m87 mcp

Start MCP server (Model Context Protocol) for AI agent integration. The server runs on stdin/stdout and exposes m87 platform commands as MCP tools.
m87 mcp
See MCP Overview for configuration details.

Device Commands

Device commands follow the pattern m87 <device> <command>. These commands operate on a specific device.

m87 <device> shell

Open an interactive shell on the device.
m87 my-device shell

m87 <device> exec

Execute a command on the device.
-i, --stdin
boolean
default:"false"
Keep stdin open (for responding to prompts)
-t, --tty
boolean
default:"false"
Allocate a pseudo-TTY (for TUI apps like vim, htop)
command
string[]
required
Command and arguments to execute (use -- before command)
# Simple command
m87 my-device exec -- ls -la

# Interactive command
m87 my-device exec -it -- vim config.yml

# Command with pipes
m87 my-device exec -- "ps aux | grep nginx"

m87 <device> forward

Forward remote port(s) to localhost.
targets
string[]
required
Port forwarding specifications. Supports:
  • Single port: 8080
  • Port mapping: 3000:8080 (local:remote)
  • Port range: 8080-8090
  • Range mapping: 8080-8090:9080-9090
  • With host: 8080:192.168.1.50:9080
  • With protocol: 8080/udp (default: tcp)
# Forward single port
m87 my-device forward 8080

# Forward to different local port
m87 my-device forward 3000:8080

# Forward multiple ports
m87 my-device forward 8080 9090 3000

# Forward port range
m87 my-device forward 8080-8090

# Forward to specific host on device network
m87 my-device forward 8080:192.168.1.50:9080

# UDP forwarding
m87 my-device forward 8080/udp

m87 <device> docker

Run docker commands on the device.
args
string[]
required
Docker CLI arguments (passed through to docker command)
# List containers
m87 my-device docker ps

# List all containers
m87 my-device docker ps -a

# Run a container
m87 my-device docker run -d nginx

# Execute in container
m87 my-device docker exec -it my-container bash

# View logs
m87 my-device docker logs my-container

m87 <device> logs

Stream container logs from the device.
-f, --follow
boolean
default:"false"
Follow log output
--tail
number
default:"100"
Number of lines to show from end of logs
# View last 100 lines
m87 my-device logs

# Follow logs
m87 my-device logs -f

# Show last 50 lines
m87 my-device logs --tail 50

m87 <device> metrics

Show device system metrics (CPU, memory, disk, network).
m87 my-device metrics
Alias: m87 <device> stats

m87 <device> status

Show device status including health, crashes, and incidents.
m87 my-device status

m87 <device> audit

View audit logs showing who interacted with the device.
--until
string
End time in RFC 3339 format (e.g., 2026-01-31 or 2026-01-31T13:00:00)
--since
string
Start time in RFC 3339 format
--max
number
default:"100"
Maximum number of log entries
--details
boolean
default:"false"
Show detailed audit information
# Recent audit logs
m87 my-device audit

# Last 50 entries with details
m87 my-device audit --max 50 --details

# Time range query
m87 my-device audit --since 2026-01-01 --until 2026-01-31

m87 <device> serial

Connect to a serial device.
path
string
required
Path to serial device (e.g., /dev/ttyUSB0)
baud
number
default:"115200"
Baud rate for serial connection
# Connect with default baud rate
m87 my-device serial /dev/ttyUSB0

# Connect with custom baud rate
m87 my-device serial /dev/ttyUSB0 9600

Deployment Commands

Deployment commands manage asynchronous job execution on devices.

m87 <device> deploy

Add a run spec to a deployment.
file
string
required
Path to deployment file (docker-compose.yml or run spec YAML)
--type
enum
default:"auto"
Spec type: auto, compose, runspec, deployment
--name
string
Optional display name for the run spec
--deployment-id
string
Add to a specific deployment (otherwise uses active deployment)
# Deploy docker-compose file
m87 my-device deploy ./docker-compose.yml

# Deploy with custom name
m87 my-device deploy ./my-app.yml --name "production-app"

# Deploy to specific deployment
m87 my-device deploy ./app.yml --deployment-id dep-123

# Force spec type
m87 my-device deploy ./custom.yml --type runspec

m87 <device> undeploy

Remove a run spec from a deployment.
job_id
string
required
Job ID or name to remove
--deployment-id
string
Remove from specific deployment (otherwise uses active deployment)
m87 my-device undeploy my-app
m87 my-device undeploy my-app --deployment-id dep-123

m87 <device> deployment list

List all deployments for the device.
m87 my-device deployment list

m87 <device> deployment new

Create a new deployment.
--active
boolean
default:"false"
Make this deployment active immediately
# Create inactive deployment
m87 my-device deployment new

# Create and activate
m87 my-device deployment new --active

m87 <device> deployment show

Show deployment details including run specs.
--deployment-id
string
Specific deployment to show (defaults to active deployment)
--yaml
boolean
default:"false"
Output as YAML instead of formatted display
# Show active deployment
m87 my-device deployment show

# Show specific deployment
m87 my-device deployment show --deployment-id dep-123

# Show as YAML
m87 my-device deployment show --yaml

m87 <device> deployment status

Get deployment execution status.
--deployment-id
string
Specific deployment (defaults to active deployment)
--logs
boolean
default:"false"
Show logs from deployment steps
# Status of active deployment
m87 my-device deployment status

# Status with logs
m87 my-device deployment status --logs

# Status of specific deployment
m87 my-device deployment status --deployment-id dep-123

m87 <device> deployment active

Print the currently active deployment ID.
m87 my-device deployment active

m87 <device> deployment activate

Set the active deployment.
deployment_id
string
required
Deployment ID to activate
m87 my-device deployment activate dep-123

m87 <device> deployment rm

Remove a deployment.
deployment_id
string
required
Deployment ID to remove
--force
boolean
default:"false"
Skip confirmation prompt
m87 my-device deployment rm dep-123
m87 my-device deployment rm dep-123 --force

m87 <device> deployment clone

Clone an existing deployment into a new one.
deployment_id
string
required
Source deployment ID to clone
--active
boolean
default:"false"
Make the cloned deployment active immediately
m87 my-device deployment clone dep-123
m87 my-device deployment clone dep-123 --active

m87 <device> deployment update

Update a deployment (remove/replace/rename specs).
--deployment-id
string
Deployment to update (defaults to active)
--rm
string[]
Remove job(s) by ID (can be used multiple times)
--replace
string[]
Replace job: <job_id>=<file> (can be used multiple times)
--rename
string[]
Rename job: <job_id>=<new_name> (can be used multiple times)
--enable
string[]
Enable job(s) by ID (can be used multiple times)
--disable
string[]
Disable job(s) by ID (can be used multiple times)
--type
enum
default:"auto"
Spec type for replacements: auto, compose, runspec
# Remove a job
m87 my-device deployment update --rm old-app

# Replace a job
m87 my-device deployment update --replace my-app=./new-version.yml

# Rename a job
m87 my-device deployment update --rename my-app=production-app

# Enable/disable jobs
m87 my-device deployment update --enable app1 --disable app2

# Combine operations
m87 my-device deployment update --rm old-app --replace app=./new.yml --enable new-app

Device Access Control

m87 <device> access list

List users with access to the device.
m87 my-device access list

m87 <device> access add

Grant access to a user or organization.
email_or_org_id
string
required
Email address or organization ID
role
enum
required
Role: admin, editor, or viewer
m87 my-device access add user@example.com editor
m87 my-device access add my-org admin

m87 <device> access remove

Revoke access from a user or organization.
email_or_org_id
string
required
Email address or organization ID
m87 my-device access remove user@example.com

m87 <device> access update

Update user or organization role.
email_or_org_id
string
required
Email address or organization ID
role
enum
required
New role: admin, editor, or viewer
m87 my-device access update user@example.com admin

Organization Commands

m87 org list

List all organizations.
m87 org list

m87 org create

Create a new organization.
id
string
required
Organization ID
owner_email
string
required
Email of organization owner
m87 org create my-org owner@example.com

m87 org delete

Delete an organization.
id
string
required
Organization ID to delete
m87 org delete my-org

m87 org update

Update organization ID.
id
string
required
Current organization ID
new_id
string
required
New organization ID
m87 org update my-org new-org-name

Organization Members

m87 org members list

List organization members.
--org-id
string
Organization ID (auto-resolved if omitted)
m87 org members list
m87 org members list --org-id my-org

m87 org members add

Add a member to the organization.
email
string
required
Member email address
role
enum
required
Role: admin, editor, or viewer
--org-id
string
Organization ID (auto-resolved if omitted)
m87 org members add user@example.com editor
m87 org members add admin@example.com admin --org-id my-org

m87 org members update

Update a member’s role.
email
string
required
Member email address
role
enum
required
New role: admin, editor, or viewer
--org-id
string
Organization ID (auto-resolved if omitted)
m87 org members update user@example.com admin

m87 org members remove

Remove a member from the organization.
email
string
required
Member email address
--org-id
string
Organization ID (auto-resolved if omitted)
m87 org members remove user@example.com

Organization Devices

m87 org devices list

List devices owned by the organization.
--org-id
string
Organization ID (auto-resolved if omitted)
m87 org devices list
m87 org devices list --org-id my-org

m87 org devices add

Add a device to the organization.
device_name
string
required
Device name or ID
--org-id
string
Organization ID (auto-resolved if omitted)
m87 org devices add my-device
m87 org devices add my-device --org-id my-org

m87 org devices remove

Remove a device from the organization.
device_name
string
required
Device name or ID
--org-id
string
Organization ID (auto-resolved if omitted)
m87 org devices remove my-device
m87 org devices remove my-device --org-id my-org

Runtime Commands (Linux Only)

These commands manage the m87 runtime service on Linux devices. Most require root privileges and automatically invoke sudo.

m87 runtime login

Register this device as a runtime (headless flow, requires approval).
--org-id
string
Organization ID to register runtime under (mutually exclusive with —email)
--email
string
Email address to register runtime under (mutually exclusive with —org-id)
m87 runtime login --email you@example.com
m87 runtime login --org-id my-org
After registration, approve from your workstation with m87 devices approve <device>.

m87 runtime logout

Logout and deauthenticate the runtime.
m87 runtime logout

m87 runtime run

Run the runtime daemon (blocking, used by systemd service).
--org-id
string
Organization ID to register runtime under
--email
string
Email address to register runtime under
m87 runtime run --email you@example.com

m87 runtime start

Start the runtime service now.
--org-id
string
Organization ID to register runtime under
--email
string
Email address to register runtime under
sudo m87 runtime start

m87 runtime stop

Stop the runtime service now.
sudo m87 runtime stop

m87 runtime restart

Restart the runtime service.
--org-id
string
Organization ID to register runtime under
--email
string
Email address to register runtime under
sudo m87 runtime restart

m87 runtime enable

Configure service to auto-start on boot.
--now
boolean
default:"false"
Enable AND start service immediately
--org-id
string
Organization ID to register runtime under
--email
string
Email address to register runtime under
sudo m87 runtime enable
sudo m87 runtime enable --now

m87 runtime disable

Remove auto-start on boot.
--now
boolean
default:"false"
Disable AND stop service immediately
sudo m87 runtime disable
sudo m87 runtime disable --now

m87 runtime status

Show local runtime service status.
m87 runtime status