|
| 1 | +## Self-Hosted Metal Runner Setup |
| 2 | + |
| 3 | +Register a Mac with Apple Silicon as a GitHub Actions self-hosted runner |
| 4 | +so it can pick up Metal/MLX workflow jobs. |
| 5 | + |
| 6 | +### Prerequisites |
| 7 | + |
| 8 | +- macOS with Apple Silicon (M-series chip) |
| 9 | +- gh CLI installed and authenticated: `gh auth login` |
| 10 | +- workflow scope on your token: `gh auth refresh -s workflow` |
| 11 | + |
| 12 | +### Setup |
| 13 | + |
| 14 | +# 1. Create runner directory (outside the repo) |
| 15 | +mkdir -p ~/actions-runner && cd ~/actions-runner |
| 16 | + |
| 17 | +# 2. Download the runner agent (macOS ARM64) |
| 18 | +curl -o actions-runner.tar.gz -L https://github.com/actions/runner/releases/download/v2.323.0/actions-runner-osx-arm64-2.323.0.tar.gz |
| 19 | + |
| 20 | +# 3. Extract |
| 21 | +tar xzf actions-runner.tar.gz |
| 22 | + |
| 23 | +# 4. Get a registration token (expires in 1 hour) |
| 24 | +TOKEN=$(gh api -X POST repos/<OWNER>/<REPO>/actions/runners/registration-token --jq '.token') |
| 25 | + |
| 26 | +# 5. Configure the runner |
| 27 | +./config.sh --url https://github.com/<OWNER>/<REPO> \ |
| 28 | + --token $TOKEN \ |
| 29 | + --name metal-runner \ |
| 30 | + --labels arc-metal-runner-set \ |
| 31 | + --work _work |
| 32 | + |
| 33 | +# Accept defaults when prompted (runner group: Default, etc.) |
| 34 | + |
| 35 | +# 6. Start the runner (foreground) |
| 36 | +./run.sh |
| 37 | + |
| 38 | +# Or install as a background service: |
| 39 | +# ./svc.sh install && ./svc.sh start |
| 40 | + |
| 41 | +### Verify the runner is registered |
| 42 | + |
| 43 | +Go to your repo -> Settings -> Actions -> Runners. |
| 44 | +You should see "metal-runner" listed with status "Idle". |
| 45 | + |
| 46 | +--- |
| 47 | + |
| 48 | +## Push the Workflow |
| 49 | + |
| 50 | +The metal_workflow.yml must exist on the branch that gets dispatched to. |
| 51 | + |
| 52 | +# Push your branch to the repo |
| 53 | +# (gh token needs workflow scope or this will be rejected) |
| 54 | +git push origin <branch> |
| 55 | + |
| 56 | +--- |
| 57 | + |
| 58 | +## Test the Workflow |
| 59 | + |
| 60 | +### Option A: Smoke test via gh CLI |
| 61 | + |
| 62 | +Triggers the workflow with a dummy payload. The runner step will fail |
| 63 | +(bad payload), but confirms the job is picked up by your runner. |
| 64 | + |
| 65 | +gh workflow run metal_workflow.yml \ |
| 66 | + --repo <OWNER>/<REPO> \ |
| 67 | + --ref <branch> \ |
| 68 | + --field run_id=test-123 \ |
| 69 | + --field payload=dGVzdA== |
| 70 | + |
| 71 | +# Watch it |
| 72 | +gh run list --repo <OWNER>/<REPO> --workflow=metal_workflow.yml |
| 73 | +gh run watch --repo <OWNER>/<REPO> |
| 74 | + |
| 75 | +### Option B: Full end-to-end test via the API |
| 76 | + |
| 77 | +Start the API server with METAL_LAUNCHER=arc so submissions dispatch |
| 78 | +through GitHub Actions instead of running locally. |
| 79 | + |
| 80 | +# 1. Start Postgres |
| 81 | +brew services start postgresql@14 |
| 82 | + |
| 83 | +# 2. Create DB and run migrations |
| 84 | +export DATABASE_URL="postgresql://$(whoami)@localhost:5432/kernelbot" |
| 85 | +createdb kernelbot # skip if already exists |
| 86 | +cd /path/to/kernelbot |
| 87 | +uv run yoyo apply --database "$DATABASE_URL" src/migrations/ |
| 88 | + |
| 89 | +# 3. Create test user |
| 90 | +psql "$DATABASE_URL" -c "INSERT INTO leaderboard.user_info (id, user_name, cli_id, cli_valid) |
| 91 | +VALUES ('999999', 'testuser', 'test-cli-id-123', true) |
| 92 | +ON CONFLICT (id) DO UPDATE SET cli_id = 'test-cli-id-123', cli_valid = true;" |
| 93 | + |
| 94 | +# 4. Install mlx |
| 95 | +uv pip install mlx |
| 96 | + |
| 97 | +# 5. Start the API server with ARC mode |
| 98 | +cd src/kernelbot |
| 99 | +export DATABASE_URL="postgresql://$(whoami)@localhost:5432/kernelbot" |
| 100 | +export ADMIN_TOKEN="your-admin-token" |
| 101 | +export PROBLEM_DEV_DIR="/path/to/kernelbot/examples" |
| 102 | +export GITHUB_TOKEN="<your-github-token>" |
| 103 | +export GITHUB_REPO="<OWNER>/<REPO>" |
| 104 | +export GITHUB_WORKFLOW_BRANCH="<branch>" |
| 105 | +export METAL_LAUNCHER=arc |
| 106 | +export DISABLE_SSL=1 |
| 107 | +uv run python main.py --api-only |
| 108 | + |
| 109 | +# 6. (In another terminal) Create the dev leaderboard |
| 110 | +curl -X POST "http://localhost:8000/admin/leaderboards" \ |
| 111 | + -H "Authorization: Bearer your-admin-token" \ |
| 112 | + -H "Content-Type: application/json" \ |
| 113 | + -d '{"directory": "mlx/example"}' |
| 114 | + |
| 115 | +# 7. Submit a test (dispatches to your self-hosted runner via GitHub Actions) |
| 116 | +curl -X POST "http://localhost:8000/mlx_example-dev/M4_Max/test" \ |
| 117 | + -H "X-Popcorn-Cli-Id: test-cli-id-123" \ |
| 118 | + -F "file=@examples/mlx/example/submission.py" |
| 119 | + |
| 120 | +# 8. Submit a benchmark |
| 121 | +curl -X POST "http://localhost:8000/mlx_example-dev/M4_Max/benchmark" \ |
| 122 | + -H "X-Popcorn-Cli-Id: test-cli-id-123" \ |
| 123 | + -F "file=@examples/mlx/example/submission.py" |
| 124 | + |
| 125 | +--- |
| 126 | + |
| 127 | +## Scaling to Multiple Machines |
| 128 | + |
| 129 | +Register additional Macs with the same label (arc-metal-runner-set). |
| 130 | +GitHub Actions automatically queues and distributes jobs across all |
| 131 | +runners sharing that label. |
| 132 | + |
| 133 | +# On each additional Mac, repeat the setup steps above with a unique --name: |
| 134 | +./config.sh --url https://github.com/<OWNER>/<REPO> \ |
| 135 | + --token $TOKEN \ |
| 136 | + --name metal-runner-2 \ |
| 137 | + --labels arc-metal-runner-set \ |
| 138 | + --work _work |
0 commit comments