Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.remotemux.com/llms.txt

Use this file to discover all available pages before exploring further.

RemoteMux environments are durable cloud VMs. CI runners can create ephemeral workspaces inside them to run tests, then clean up. The environment stays warm between runs, so Docker images, build caches, and databases are already there.
CI never creates or destroys environments. A developer provisions the environment once. CI only creates and removes workspaces.

Why Use RemoteMux for CI

RemoteMux workspaces skip the setup tax that ephemeral CI runners pay on every run:
StepGitHub runnerRemoteMux workspace
Checkout repo~15s~5s (git worktree)
Install dependencies60-120s (cold)10-20s (warm cache)
Start services (Docker Compose)120-300s (pull images)0s (already running)
DB migrations / seed30-60s0s (already done)
Total setup3-8 min~15-30s
This adds up. For a team running 50 PRs/day with a heavy environment, RemoteMux saves 200+ runner minutes per day. The compute cost is sunk since the environment is already running for development. RemoteMux CI is most useful when:
  • Your project has a complex dev environment (Docker Compose stacks, databases, GPUs)
  • Environment setup time dominates test execution time
  • You need VPC access or internal services that runners can’t reach
  • You want dev/CI parity (tests run in the same environment developers use)

Setup

1

Create a CI token

Create a service token for the CI runner. This only needs to happen once.
rmux token create --label "github-actions" --project-id <project-id>
Prefer a project-scoped token for CI so the runner can only access the one hosted project it needs. Use --org-id <organization-id> if you need to target an organization other than your active default.Copy the token value for the next step.
2

Add GitHub secrets

In your repo settings, add two secrets:
SecretValue
RMUX_CI_TOKENThe token from step 1
RMUX_ENVIRONMENTEnvironment name (e.g. my-project) or ID (e.g. env_abc123)
The environment must already be provisioned and in ready state.
3

Make config available to the runner

The runner still needs RemoteMux config so the CLI can resolve the backend and control plane URL.Choose one:
  • Commit a minimal ./.rmux.toml to the repository:
    backend = "managed"
    apiBaseUrl = "https://api.remotemux.com"
    
  • Or set these workflow environment variables:
    RMUX_BACKEND: managed
    RMUX_API_BASE_URL: https://api.remotemux.com
    
RMUX_ENVIRONMENT tells the runner which environment to target, but it does not replace backend or API base URL config.
4

Add the workflow

Create .github/workflows/test.yml in your repository.

Example Workflow

.github/workflows/test.yml
name: Test
on:
  pull_request:
    types: [opened, synchronize, reopened]

concurrency:
  group: rmux-${{ github.event.pull_request.number }}
  cancel-in-progress: true

env:
  RMUX_BACKEND: managed
  RMUX_API_BASE_URL: https://api.remotemux.com
  RMUX_API_KEY: ${{ secrets.RMUX_CI_TOKEN }}
  RMUX_ENVIRONMENT: ${{ secrets.RMUX_ENVIRONMENT }}

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install RemoteMux
        run: curl -fsSL https://remotemux.com/releases/install.sh | bash

      - name: Create workspace
        run: rmux workspace new "ci-pr-${{ github.event.pull_request.number }}"

      - name: Run tests
        run: |
          rmux workspace run -w "ci-pr-${{ github.event.pull_request.number }}" \
            "cd /workspace && npm ci && npm test"

      - name: Cleanup
        if: always()
        run: rmux workspace rm "ci-pr-${{ github.event.pull_request.number }}" --force
Each workspace new creates a git worktree on the remote environment. Multiple PRs can run concurrently since each workspace is isolated at the filesystem level. If your repository already includes a minimal .rmux.toml with backend and apiBaseUrl, you can omit RMUX_BACKEND and RMUX_API_BASE_URL from the workflow env block.

Config Resolution In CI

RemoteMux resolves config separately from environment targeting:
  • RMUX_BACKEND or ./.rmux.toml selects the backend
  • RMUX_API_BASE_URL or ./.rmux.toml selects the control plane URL
  • RMUX_API_KEY authenticates the runner
  • RMUX_ENVIRONMENT selects the target environment
On a fresh GitHub runner with no checked-in .rmux.toml, set all four in the job environment.

Environment Resolution

Workspace commands resolve the target environment in this order:
  1. --env flag (explicit override)
  2. RMUX_ENVIRONMENT env var
  3. .rmux/state.json directory binding (local dev)
In CI, there is no directory binding. Set RMUX_ENVIRONMENT once in the workflow env block and all workspace commands pick it up. You can also override per-command:
rmux workspace ls --env staging
rmux workspace new ci-run --env my-other-project
Both environment names and IDs (env_*) are accepted.

Token Scope

Service tokens are scoped to the hosted organization and, optionally, a hosted project.
  • Project-scoped tokens are the safest default for CI.
  • Organization-scoped tokens are useful when one workflow needs to operate across multiple hosted projects in the same organization.
  • CI workspace commands still target a concrete environment through RMUX_ENVIRONMENT; token scope controls what the runner is allowed to see.

Cleaning Up Stale Workspaces

If a CI runner is killed or GitHub has an outage, the cleanup step may not run. Use workspace prune to remove orphaned workspaces.

Manual prune

# See what would be removed
rmux workspace prune --prefix "ci-" --stale 2h --dry-run

# Remove them
rmux workspace prune --prefix "ci-" --stale 2h --force

Scheduled prune

Add a cron workflow to your repository:
.github/workflows/prune.yml
name: Prune stale CI workspaces
on:
  schedule:
    - cron: '0 */6 * * *'

env:
  RMUX_BACKEND: managed
  RMUX_API_BASE_URL: https://api.remotemux.com
  RMUX_API_KEY: ${{ secrets.RMUX_CI_TOKEN }}
  RMUX_ENVIRONMENT: ${{ secrets.RMUX_ENVIRONMENT }}

jobs:
  prune:
    runs-on: ubuntu-latest
    steps:
      - name: Install RemoteMux
        run: curl -fsSL https://remotemux.com/releases/install.sh | bash

      - name: Prune stale workspaces
        run: rmux workspace prune --prefix "ci-" --stale 2h --force

Prune options

OptionDescription
--prefix <prefix>Only prune workspaces whose name starts with this prefix
--stale <duration>Only prune workspaces idle longer than this duration (30s, 5m, 2h, 1d)
--dry-runList candidates without deleting
-f, --forceSkip the confirmation prompt (required in non-TTY / CI)
Root workspaces are never pruned regardless of filters.

Concurrency

Multiple CI workspaces share a single VM. They are isolated at the filesystem level (separate git worktrees) but share CPU, memory, disk, and the Docker daemon. Shared resources can be an advantage: Docker layer caches, node_modules caches, and pre-started services are available to all workspaces without redundant setup. If concurrent CI runs overwhelm the VM, size the environment appropriately or use GitHub Actions concurrency groups to limit parallel runs.
Last modified on April 9, 2026