# Manage Runners documentation > Run your own GitLab CI/CD runners on Hetzner Cloud, managed from a dashboard or the manage-runners CLI. Source: https://managerunners.com/docs/ Manage Runners creates GitLab runners as virtual machines in your own [Hetzner Cloud](https://www.hetzner.com/cloud) project. You choose the server type and location. Manage Runners provisions the server, installs and registers GitLab Runner, keeps its packages updated, and lets you pause, resume and schedule the runner, so you only pay Hetzner for servers while you need them. ## How it works 1. You give Manage Runners a Hetzner Cloud API token and a GitLab runner authentication token. 2. Manage Runners creates a server in your Hetzner project and installs Docker and GitLab Runner on it. 3. The server registers itself with your GitLab instance, GitLab.com or self-managed, using the runner authentication token. 4. The runner picks up CI/CD jobs directly from GitLab. Job traffic never passes through Manage Runners. The servers belong to your Hetzner project, and Hetzner bills you for them directly. Your Manage Runners plan covers the management. See [Costs](https://managerunners.com/docs/manual/concepts/#costs). ## Where to start - **New here?** Follow the [quick start](https://managerunners.com/docs/quickstart/) to run your first job on your own runner. - **Using the dashboard?** The [manual](https://managerunners.com/docs/manual/) explains every feature: [runners](https://managerunners.com/docs/manual/runners/), [schedules](https://managerunners.com/docs/manual/schedules/), [monitoring](https://managerunners.com/docs/manual/monitoring/), [organizations](https://managerunners.com/docs/manual/organizations/), [billing](https://managerunners.com/docs/manual/billing/) and more. - **Prefer the terminal?** The [manage-runners CLI](https://managerunners.com/docs/cli/) does the same from your shell and from scripts. - **Automating with an AI agent?** Read the [agent guide](https://managerunners.com/docs/cli/agents/). Every page is also available as Markdown (add `index.md` to its URL), and [/llms.txt](https://managerunners.com/llms.txt) lists them all. ## Components | Component | Address | | --- | --- | | Dashboard | | | API, used by the CLI | `https://api.managerunners.com` | | CLI | `manage-runners`, see [Install](https://managerunners.com/docs/cli/install/) | --- # Quick start > Create an account, connect Hetzner and GitLab, start your first runner and run a job on it. Source: https://managerunners.com/docs/quickstart/ This guide takes you from a new account to a CI/CD job running on your own runner. It takes about 15 minutes, most of it waiting for the server to start. You need: - A [Hetzner Cloud](https://console.hetzner.cloud) account. - A GitLab project on GitLab.com or on your own GitLab instance, where you have the Maintainer or Owner role. - An authenticator app for two-factor authentication. ## 1. Create your account 1. Open . 2. Enter your email address, given name, family name and a password. The password needs at least 8 characters with an uppercase letter, a lowercase letter, a number and a symbol. 3. Select **Create account**. 4. Scan the QR code with your authenticator app, enter the 6-digit code and select **Verify & Continue**. Two-factor authentication is always on. You enter a code from your authenticator app every time you sign in. ## 2. Choose a plan The dashboard opens **Billing** until your organization has an active plan. Choose a plan and complete the checkout. Every plan includes unlimited runners; [schedules](https://managerunners.com/docs/manual/schedules/) need Pro or Enterprise. See [Billing and plans](https://managerunners.com/docs/manual/billing/) and [pricing](https://managerunners.com/pricing/). ## 3. Create a Hetzner API token Manage Runners creates and deletes servers in your Hetzner project, so it needs a token with read and write access. 1. In the [Hetzner Cloud Console](https://console.hetzner.cloud), create a project for your runners, for example `gitlab-runners`. A separate project keeps runner servers apart from your other infrastructure. 2. Open the project, go to **Security** > **API tokens** and generate a token with **Read & Write** permission. 3. Copy the token. Hetzner shows it only once. Optional: to log in to the runner servers over SSH, add your public key under **Security** > **SSH keys** in the same project. You can select it when you create the runner. See [Hetzner setup](https://managerunners.com/docs/manual/hetzner/) for details. ## 4. Create a GitLab runner and copy its token GitLab issues a *runner authentication token* (it starts with `glrt-`) when you create a runner in the GitLab UI. Manage Runners uses this token. The older registration tokens are not used. 1. In your GitLab project, go to **Settings** > **CI/CD** and expand **Runners**. 2. Select **New project runner**. 3. Add the tags your jobs will use, for example `hetzner`, or select **Run untagged jobs**. 4. Select **Create runner** and copy the runner authentication token. You can also create group or instance runners. See [GitLab setup](https://managerunners.com/docs/manual/gitlab/). ## 5. Create the runner In the dashboard, select **Create Runner** and fill in the form: | Field | What to enter | | --- | --- | | Name | A name with letters, numbers, spaces and dashes, for example `build-01`. | | Product | The Hetzner server type. Each option shows the CPU architecture, vCPUs, RAM and disk. | | Location | The Hetzner location. Each option shows Hetzner's monthly net list price. | | Executor | `docker` for most projects. See [executors](https://managerunners.com/docs/manual/concepts/#executors). | | Concurrency | How many jobs run at once. Selecting a product sets it to twice the vCPU count. | | GitLab Host | `https://gitlab.com/`, or the base URL of your self-managed GitLab instance. | | GitLab Runner Token | The `glrt-` token from step 4. | | Hetzner Auth Token | The token from step 3. The form checks it and loads the project's SSH keys. | | Hetzner SSH Keys | Optional keys for root access to the server. | | Labels | Optional labels that are attached to the Hetzner server. | | Resource monitoring | Optional CPU, RAM and disk charts. Requires an active plan. | ![The Create Runner form filled in with a Docker runner on a CPX31 server in Falkenstein](https://managerunners.com/docs/screenshots/create-runner-light.webp) Select **Create**. The dashboard shows the runner as **Creating** while Hetzner starts the server, then **Configuring** while it installs GitLab Runner. After a few minutes it changes to **Active**. ![The dashboard with an active and a paused runner](https://managerunners.com/docs/screenshots/dashboard-light.webp) If the runner shows **Invalid Gitlab Token** instead, GitLab rejected the token. Select **Fix** on the runner and paste a new one. ## 6. Run a job In GitLab, the runner now appears under **Settings** > **CI/CD** > **Runners** as online. Add a job to `.gitlab-ci.yml` that uses its tag: ```yaml hello: image: alpine:latest tags: - hetzner script: - echo "Running on my own Hetzner runner" ``` Commit the file. GitLab assigns the job to your runner. If you selected **Run untagged jobs**, the `tags` section is not needed. ## 7. Pause it when you don't need it A runner costs Hetzner server time while it is active. Select **Pause** on the runner card to delete the server. The runner keeps its configuration and its IP addresses, so firewall rules and allow lists that mention them keep working. Select **Resume** to create a fresh server with the same settings. To pause and resume automatically, for example outside working hours, set up a [schedule](https://managerunners.com/docs/manual/schedules/). Schedules need a Pro or Enterprise plan. ## Prefer the command line? The same steps with the [manage-runners CLI](https://managerunners.com/docs/cli/), after the account and plan exist: ```sh manage-runners auth login --scope runners:write manage-runners product list manage-runners product locations --id hz-cpx31 export HCLOUD_TOKEN GLRT_TOKEN # set them from your secret manager manage-runners runner create --name build-01 --product-id hz-cpx31 --location fsn1 \ --executor docker --concurrency 8 --gitlab-host https://gitlab.com/ \ --runner-token-env GLRT_TOKEN --hetzner-token-env HCLOUD_TOKEN --wait ``` See [Manage runners with the CLI](https://managerunners.com/docs/cli/runners/) for every option. ## Next steps - Learn the [runner states](https://managerunners.com/docs/manual/concepts/#runner-states) and [which changes recreate the server](https://managerunners.com/docs/manual/concepts/#changes-that-recreate-the-server). - Invite your team to an [organization](https://managerunners.com/docs/manual/organizations/). - Create a [personal access token](https://managerunners.com/docs/manual/access-tokens/) for scripts and CI jobs. --- # Manual > Everything you can do with Manage Runners and what you need to know to do it safely. Source: https://managerunners.com/docs/manual/ The manual describes the dashboard at and the behaviour behind it. The [CLI documentation](https://managerunners.com/docs/cli/) covers the same features from the terminal. | Page | What it covers | | --- | --- | | [Concepts](https://managerunners.com/docs/manual/concepts/) | Runner states, products and locations, executors, changes that recreate the server, costs | | [Hetzner setup](https://managerunners.com/docs/manual/hetzner/) | The API token, what Manage Runners creates in your project, SSH keys, labels and firewalls | | [GitLab setup](https://managerunners.com/docs/manual/gitlab/) | Runner authentication tokens, tags, GitLab.com and self-managed GitLab | | [Runners](https://managerunners.com/docs/manual/runners/) | Create, edit, duplicate, pause, resume, delete and remove runners | | [Schedules](https://managerunners.com/docs/manual/schedules/) | Pause and resume runners automatically | | [Monitoring](https://managerunners.com/docs/manual/monitoring/) | CPU, RAM and disk usage of your runners | | [Organizations](https://managerunners.com/docs/manual/organizations/) | Share runners with your team, roles and invitations | | [Personal access tokens](https://managerunners.com/docs/manual/access-tokens/) | Scoped, expiring tokens for the CLI, scripts, CI jobs and agents | | [Account security](https://managerunners.com/docs/manual/account-security/) | Two-factor authentication, passwords and password reset | | [Billing and plans](https://managerunners.com/docs/manual/billing/) | Plans, checkout, upgrades, downgrades and payment | | [Troubleshooting](https://managerunners.com/docs/manual/troubleshooting/) | What to do when something does not work | --- # Concepts > Runner states, products and locations, executors, which changes recreate the server, and what you pay for. Source: https://managerunners.com/docs/manual/concepts/ ## Runners and servers A *runner* in Manage Runners is a configuration: name, server type, location, executor, concurrency, GitLab host and token, Hetzner token, SSH keys, labels and the monitoring setting. While the runner is active, a Hetzner server with that configuration exists in your Hetzner project and runs GitLab Runner. Every server is created fresh from a Debian 13 image. On first boot it: - installs Docker and GitLab Runner from their official package repositories, - registers with your GitLab instance using the runner authentication token, - sets GitLab Runner's global job concurrency, - turns on automatic package updates, including Docker and GitLab Runner, and reboots automatically when an update requires it, - allows SSH only for `root` with a key, never with a password, and enables fail2ban, - removes Docker volumes that GitLab Runner created and that are older than 7 days, once a day, - installs the monitoring collector, if [monitoring](https://managerunners.com/docs/manual/monitoring/) is on. Because a paused runner has no server, pausing and resuming always gives you a clean, freshly installed machine. Anything stored on the server's disk is lost when the server is deleted. ## Runner states | State | Meaning | | --- | --- | | **Creating** | Hetzner is creating the server. | | **Configuring** | The server is installing Docker and GitLab Runner. | | **Active** | GitLab Runner registered successfully. The runner takes jobs. The API and CLI call this state `READY`. | | **Invalid Gitlab Token** | GitLab rejected the runner token during registration. The server keeps running. Use **Fix** to enter a new token. | | **Paused** | The server is deleted. The configuration and the IP addresses are kept. | | **Unknown** | Manage Runners lost track of the server, for example because the Hetzner token stopped working. See [Troubleshooting](https://managerunners.com/docs/manual/troubleshooting/#a-runner-is-unknown). | A new runner normally goes from **Creating** through **Configuring** to **Active** within a few minutes. Resuming a paused runner takes the same path. ## IP addresses Each server gets a public IPv4 and IPv6 address, as Hetzner primary IPs. When you pause a runner, Manage Runners deletes the server but keeps both addresses, and attaches them to the new server when you resume. Firewall rules and allow lists that mention a runner's addresses keep working across pause and resume. The addresses are released only when you delete the runner. A runner's location cannot be changed, because a different location would change its addresses. ## Products and locations A *product* is a Hetzner Cloud server type. Manage Runners offers every server type that Hetzner has not deprecated and that is available in at least one location. Product IDs are the Hetzner server type name with a `hz-` prefix, for example `hz-cpx31`. Each product shows: - **Architecture:** x86 (Intel or AMD, best compatibility) or ARM. Your CI images must support the architecture you choose. - **vCPUs, RAM and disk.** - **Locations** where Hetzner currently offers it, with Hetzner's monthly net list price in EUR. Hetzner's locations are Falkenstein and Nuremberg (Germany), Helsinki (Finland), Singapore, and Ashburn and Hillsboro (USA). Not every server type is offered in every location, and availability changes over time. If Hetzner stops offering a server type in a location, a paused runner using it cannot be resumed until it is available again, and it cannot be duplicated. ## Executors | Executor | Dashboard label | What jobs get | | --- | --- | --- | | `docker` | docker | Each job runs in a container. The default image is `alpine:latest`; jobs choose their own with `image:`. | | `dind` | docker-in-docker | Like `docker`, with the default image `docker:28-cli`, privileged containers and the server's Docker socket mounted, so jobs can build and run images. | | `shell` | shell | Jobs run directly on the server as the `gitlab-runner` user. | With `dind`, jobs control the server's Docker daemon. Use it only for projects you trust. ## Concurrency Concurrency is the number of jobs the runner runs at the same time (GitLab Runner's global `concurrent` setting). When you select a product in the dashboard, it is set to twice the server's vCPU count. Lower it for memory-hungry jobs. ## Changes that recreate the server Some settings are applied when the server is created. Changing them on an active runner makes Manage Runners delete the server and create a new one with the same IP addresses. Jobs running at that moment are interrupted. | Change | Recreates an active runner's server | | --- | --- | | Product | yes | | GitLab host | yes | | GitLab runner token | yes | | Concurrency | yes | | Executor | yes | | SSH keys | yes | | Monitoring on or off | yes | | Name | no | | Labels | no, they are updated on the Hetzner server directly | | Hetzner token | no | | Location | cannot be changed | Editing a paused runner never creates a server; the new settings apply when you resume it. ## Costs You pay two parties: - **Hetzner** bills your Hetzner account for the servers in your project, at Hetzner's prices. The prices in the dashboard are Hetzner's monthly net list prices, without VAT. While a runner is paused, it has no server. Hetzner may still charge for the IP addresses that are kept; see Hetzner's pricing. - **Manage Runners** bills your plan. See [Billing and plans](https://managerunners.com/docs/manual/billing/) and [pricing](https://managerunners.com/pricing/). Pausing runners when nobody needs them, by hand or with a [schedule](https://managerunners.com/docs/manual/schedules/), is the main way to save server costs. --- # Hetzner setup > Create the Hetzner Cloud API token, and learn what Manage Runners creates in your project and how to use SSH keys, labels and firewalls. Source: https://managerunners.com/docs/manual/hetzner/ Your runners are servers in your own Hetzner Cloud project. Manage Runners manages them through the Hetzner Cloud API with a token you provide. ## Create a project and an API token 1. In the [Hetzner Cloud Console](https://console.hetzner.cloud), create a project for your runners. The dashboard recommends a separate project that only contains your runners, so the token cannot affect other servers. 2. In the project, go to **Security** > **API tokens** and generate a token with **Read & Write** permission. Manage Runners creates and deletes servers and changes IP addresses, which a read-only token cannot do. 3. Copy the token and paste it into the **Hetzner Auth Token** field when you create a runner. When you leave the token field, the dashboard checks the token by listing the project's SSH keys. That check only reads, so it also accepts a read-only token. A read-only token fails later, when the server is created, and the runner becomes **Unknown**. Manage Runners stores the token encrypted and uses it only for the runner you entered it for. Each runner has its own token, so different runners can use different Hetzner projects. ## What Manage Runners creates In your project, Manage Runners creates: - **one server per active runner**, named after the runner and its ID, for example `build-01-812999368881481087`; - **a primary IPv4 and a primary IPv6 address** for each server. They stay in your project while the runner is paused and are deleted with the runner. It does not create firewalls, networks, volumes or SSH keys. Do not delete or change runner servers in the Hetzner Console. Manage Runners does not watch the project for such changes, and the runner can end up in a state that does not match reality. Pause, resume and delete runners from the dashboard or the CLI instead. ## SSH keys Manage Runners does not create SSH keys. To log in to a runner's server: 1. Add your public key to the project under **Security** > **SSH keys** in the Hetzner Console. 2. When you create or edit the runner, select the key under **Hetzner SSH Keys**. The list shows the keys of the project that the Hetzner token belongs to. Selected keys are added to the server's `root` account. Password login is disabled. Changing the selected keys of an active runner [recreates its server](https://managerunners.com/docs/manual/concepts/#changes-that-recreate-the-server). ## Labels and firewalls Labels you add to a runner become Hetzner server labels. A label written as `key=value` becomes the Hetzner label `key` with the value `value`. A label without `=` becomes a label with an empty value. Hetzner firewalls can apply to all servers with a given label. To protect your runners with a firewall: 1. Create a firewall in the Hetzner Console with the rules you want. 2. Under **Apply to**, choose **Label selector** and enter a label, for example `role=ci-runner`. 3. Add the same label to your runners. GitLab Runner only makes outgoing connections to your GitLab instance, so a runner needs no incoming rules for GitLab. Keep SSH open only if you log in to the servers. Changing labels never recreates a server. ## Changing the token To use a new Hetzner token, for example after revoking the old one, edit the runner and enter the new token. Changing only the token does not recreate the server. If the runner was **Unknown** because the old token stopped working, saving the new token makes Manage Runners check the project again. See [Troubleshooting](https://managerunners.com/docs/manual/troubleshooting/#a-runner-is-unknown). --- # GitLab setup > Create a runner authentication token, choose tags, and connect runners to GitLab.com or a self-managed GitLab instance. Source: https://managerunners.com/docs/manual/gitlab/ Manage Runners registers each server with GitLab using a *runner authentication token*. You create that token in GitLab, so you decide in GitLab which projects or groups can use the runner and which jobs it picks up. ## Create a runner authentication token Create the runner in GitLab first: - **Project runner:** in the project, go to **Settings** > **CI/CD**, expand **Runners** and select **New project runner**. - **Group runner:** in the group, go to **Build** > **Runners** and select **New group runner**. - **Instance runner** (self-managed GitLab, administrators only): in the Admin area, go to **CI/CD** > **Runners** and select **New instance runner**. In the form, set the tags and options described below and select **Create runner**. GitLab shows the token, which starts with `glrt-`. Paste it into the **GitLab Runner Token** field in Manage Runners. GitLab's documentation describes the steps in detail: [Manage runners](https://docs.gitlab.com/ci/runners/runners_scope/). Manage Runners registers with the `--token` option of `gitlab-runner register`, which is the runner authentication token workflow. Registration tokens from GitLab's deprecated registration workflow do not work. ## Tags and untagged jobs Manage Runners does not set tags. GitLab stores them with the runner you created: - To send specific jobs to the runner, give it tags in GitLab, for example `hetzner`, and add the same tags to those jobs in `.gitlab-ci.yml`. - To let it pick up jobs without tags, select **Run untagged jobs** in GitLab. You can change tags and this option in GitLab at any time without touching the runner in Manage Runners. ## GitLab.com and self-managed GitLab Manage Runners works with GitLab.com and with self-managed GitLab instances. Enter the instance's base URL in **GitLab Host**: | GitLab | GitLab Host | | --- | --- | | GitLab.com | `https://gitlab.com/` (the default) | | Self-managed | Your instance's URL, for example `https://gitlab.example.com` | The server connects to this URL from the Hetzner location you chose, so a self-managed instance must be reachable from the internet, or at least from your runner's IP addresses. Because the addresses stay the same while a runner is paused, you can allow them in your instance's firewall. See [IP addresses](https://managerunners.com/docs/manual/concepts/#ip-addresses). Manage Runners does not check the URL or the token when you save the runner. If either is wrong, registration fails on the server and the runner shows **Invalid Gitlab Token**. Select **Fix** to correct the token and the host. ## When GitLab rejects the token A runner shows **Invalid Gitlab Token** when `gitlab-runner register` did not succeed, for example because the token was mistyped, revoked, or belongs to another GitLab instance than the host you entered. The server keeps running in this state. 1. If needed, create a new runner in GitLab to get a new token. 2. In the dashboard, select **Fix** on the runner, paste the token and, if needed, correct the GitLab host. 3. Select **Save**. Manage Runners recreates the server, which registers again. ## Removing a runner from GitLab Deleting a runner in Manage Runners deletes its server, but it does not remove the runner from GitLab. GitLab shows it as offline. Delete it in GitLab under **Settings** > **CI/CD** > **Runners** when you no longer need it. --- # Runners > Create, edit, duplicate, pause, resume, delete and remove runners in the dashboard. Source: https://managerunners.com/docs/manual/runners/ The **Dashboard** lists the runners of the selected [organization](https://managerunners.com/docs/manual/organizations/) as cards. Each card shows the runner's state, chip, vCPUs, RAM, disk, concurrency, executor, IPv4 and IPv6 addresses (select one to copy it), location and Hetzner's monthly price. Use the filters above the list to narrow it down by status, executor or location, or search by name. ![The dashboard with an active and a paused runner](https://managerunners.com/docs/screenshots/dashboard-light.webp) Owners and editors can change runners. Viewers see the list without actions and a **View only** badge. The dashboard needs an active plan; without one it opens **Billing**. ## Create a runner Select **Create Runner**, fill in the form and select **Create**. The [quick start](https://managerunners.com/docs/quickstart/#5-create-the-runner) explains every field. Some rules: - **Name:** letters, numbers, spaces and dashes only. Other characters are removed as you type. - **Product and location:** choose the product first; the location list then shows where Hetzner offers it and at what price. Locations where it is unavailable are disabled. - **Concurrency:** at least 1. Selecting a product sets it to twice the vCPU count. - **Tokens:** the [GitLab runner authentication token](https://managerunners.com/docs/manual/gitlab/) and a [Hetzner API token](https://managerunners.com/docs/manual/hetzner/) with read and write access. - **Resource monitoring:** on by default when your organization's plan is active. See [Monitoring](https://managerunners.com/docs/manual/monitoring/). The runner appears as **Creating**, then **Configuring**, then **Active**. The dashboard refreshes the list while any runner is changing state. ## Edit a runner Select **Edit** on the card, change the settings and select **Save changes**. - **Location** cannot be changed, because that would change the runner's IP addresses. To move a runner, create a new one in the other location. - **Product** offers only server types that are available in the runner's location. - **Tokens** show as `********`. Leave a token field empty to keep the stored token. > Changing the product, GitLab host, GitLab token, concurrency, executor, SSH keys or monitoring of an active runner deletes its server and creates a new one. Running jobs are interrupted. Changing the name, labels or Hetzner token does not. See [Changes that recreate the server](https://managerunners.com/docs/manual/concepts/#changes-that-recreate-the-server). ## Duplicate a runner Select **Duplicate** to create a copy with the same product, location, executor, concurrency, GitLab host and token, Hetzner token, SSH keys, labels and monitoring setting. The copy's name gets a number, for example `build-01 2`. It starts as a new runner and creates its own server and IP addresses. You can duplicate active and paused runners. **Duplicate** is disabled when Hetzner no longer offers the runner's server type in its location. ## Pause and resume **Pause** deletes the runner's server. The runner keeps its configuration and its IPv4 and IPv6 addresses, and Hetzner stops billing for the server. Jobs running at that moment are interrupted. **Resume** creates a new server with the same configuration and addresses. The runner goes through **Creating** and **Configuring** again before it is **Active**. Because the server is new, nothing from its previous disk remains. If Hetzner no longer offers the server type in the runner's location, **Resume** is disabled, and the card warns you before you pause a runner that could not be resumed. If Hetzner cannot create the server when you resume, for example because of capacity problems, the runner stays paused and the card shows the error. Try again later, or [edit](#edit-a-runner) the runner to use another server type. To pause and resume on a timetable, use a [schedule](https://managerunners.com/docs/manual/schedules/). ## Delete a runner Select **Delete**, then select it again to confirm. Manage Runners deletes the server, the runner's IP addresses and its schedule. If Hetzner does not confirm that the server was deleted, the runner is kept and the card shows an error, so you can try again. A server that no longer exists at Hetzner counts as deleted. Deleting a runner does not remove it from GitLab. [Delete it in GitLab](https://managerunners.com/docs/manual/gitlab/#removing-a-runner-from-gitlab) when you no longer need it. ## Remove an Unknown runner A runner in the **Unknown** state cannot be deleted normally, because Manage Runners does not know whether its server still exists. Selecting **Delete** on it opens **Delete Unknown Runner**, which only removes the runner from the dashboard: > If you delete an unknown runner, the ip and hetzner server will not be deleted. After you confirm, check the Hetzner Console and delete the server and its primary IPs there if they still exist. Before you remove an Unknown runner, see whether [editing it can recover it](https://managerunners.com/docs/manual/troubleshooting/#a-runner-is-unknown). ## When actions are unavailable | Action | Unavailable while the runner is | | --- | --- | | Duplicate, Pause, Resume | Creating, Unknown, or while a pause is in progress | | Delete | Creating, or while a pause is in progress | | Edit | Invalid Gitlab Token (use **Fix** instead) | Only one lifecycle action runs on a runner at a time. If you start another one, it fails with a message that the runner is locked. Wait until the first action has finished. --- # Schedules > Pause and resume runners automatically on a weekly timetable to save server costs. Source: https://managerunners.com/docs/manual/schedules/ A schedule resumes a runner at a start time and pauses it at a stop time, on the days of the week you choose. A runner that only runs during working hours, for example, costs Hetzner server time only then. Pausing runners outside working hours can save up to 50% of server costs. Schedules need a **Pro** or **Enterprise** plan for the runner's organization. See [Billing and plans](https://managerunners.com/docs/manual/billing/). > Schedules are managed with the [manage-runners CLI](https://managerunners.com/docs/cli/schedules/) or the API. The dashboard does not show them yet. ## How a schedule works A schedule has: | Setting | Description | | --- | --- | | Time zone | An IANA time zone, for example `Europe/Berlin`. Start and stop times are in this zone, including daylight saving time. | | Start time | When the runner is resumed, as `HH:MM`. | | Stop time or duration | When the runner is paused: a time later on the same day, or a duration of 1 to 1440 minutes. | | Days | One or more of `Mon`, `Tue`, `Wed`, `Thu`, `Fri`, `Sat`, `Sun`. | | Enabled | Whether the schedule is applied. A disabled schedule is kept but does nothing. | Each runner has at most one schedule. Manage Runners checks schedules every minute: - During the window, from the start time until the stop time, a paused runner is resumed. - At the stop time, an active runner is paused. Manage Runners records each start and stop it has applied and never applies a recorded one again. A start is recorded when the runner is resumed, or is found already active, during the window. A stop is recorded only when Manage Runners pauses an active runner. In practice: - If you pause a runner by hand during its window after the start was applied, it stays paused until the next start. - If a runner is already paused at the stop time, that stop is not recorded. If you then resume it by hand before the next start, it is paused again within a minute. - If you pause a runner during its window before the start was applied, it is resumed within a minute. To override a schedule reliably, for example to keep a runner running one evening, [disable the schedule](https://managerunners.com/docs/cli/schedules/#read-enable-and-disable) first and enable it again afterwards. A stop time must be later than the start time on the same day, so a window given by start and stop times cannot cross midnight. ## Example Run on weekdays from 07:00 to 19:00 Berlin time: ```sh manage-runners schedule set --runner-id 812999368881481087 \ --zone-id Europe/Berlin --start 07:00 --stop 19:00 \ --day Mon --day Tue --day Wed --day Thu --day Fri --enabled ``` Use `--duration-minutes 720` instead of `--stop 19:00` to give the window a length. See [Schedules with the CLI](https://managerunners.com/docs/cli/schedules/) for reading, disabling and deleting schedules. ## What happens to a schedule - Deleting a runner deletes its schedule. - Resuming by schedule creates a new server, like resuming by hand. See [Pause and resume](https://managerunners.com/docs/manual/runners/#pause-and-resume). - Disabling keeps the settings, so you can enable the schedule again later. --- # Monitoring > See CPU, RAM and disk usage of your runners in the dashboard, and what monitoring installs on the server. Source: https://managerunners.com/docs/manual/monitoring/ Resource monitoring shows the CPU, RAM and disk usage of each active runner on its dashboard card. It helps you choose the right server type and concurrency. Monitoring needs an active plan for the runner's organization. Any plan qualifies. See [Billing and plans](https://managerunners.com/docs/manual/billing/). ## Turn monitoring on or off Use the **Resource monitoring** switch when you [create](https://managerunners.com/docs/manual/runners/#create-a-runner) or [edit](https://managerunners.com/docs/manual/runners/#edit-a-runner) a runner. It is on by default for new runners when your plan is active. > Turning monitoring on or off for an active runner recreates its server, because the collector is installed when the server is created. Running jobs are interrupted. The edit form warns you before you save. ## What you see ![A runner card with CPU, RAM and disk charts for the last 24 hours](https://managerunners.com/docs/screenshots/monitoring-light.webp) Under **Resource usage**, each monitored active runner shows: - **CPU** usage in percent, - **RAM** used of the total, in GB, - **Disk** usage for each disk of the server. Each value comes with a chart. Choose the time range with the **Metrics** selector: last hour, 24 hours, 7 days, 30 days or 90 days. Only ranges for which data exists are offered. Manage Runners keeps samples for 90 days. The first values appear a few minutes after the runner starts. If the newest sample is older than three minutes, the card says how long no data has arrived. ## How it works When monitoring is on, the server runs a small collector as a systemd service under its own user, limited to 64 MB of memory and 5% of one CPU. About once a minute it sends CPU, memory and disk usage to Manage Runners over HTTPS. It collects only these system values. Each server gets its own credential for sending samples. The credential is revoked when the runner is deleted or becomes **Unknown**, and when the organization no longer has an active plan. ## When the plan ends If the organization's plan is no longer active, the dashboard shows **Monitoring paused**. The owner sees a link to **Billing**; other members are asked to contact the owner. The servers' monitoring credentials are revoked, so their collectors stop sending data. After the plan is active again, pause and resume a runner to give its new server a new credential. With the CLI, read the same data with [`manage-runners runner metrics`](https://managerunners.com/docs/cli/reference/runner-metrics/). --- # Organizations > Share runners with your team, assign roles, invite members and switch between organizations. Source: https://managerunners.com/docs/manual/organizations/ Runners, schedules, monitoring data and the plan belong to an *organization*. Everyone in an organization sees the same runners, and the organization's plan applies to all of them. ## Your default organization When you register, Manage Runners creates an organization for you and makes you its owner. It is your *default organization*: the dashboard selects it after you sign in, and the CLI and API use it when no other organization is selected. ## Switch and create organizations The organization menu at the top of the dashboard lists your organizations with your role in each. Select one to switch; the dashboard then shows that organization's runners. To create one, select **Create organization** in the menu and enter a name of up to 100 characters. You become its owner. A new organization starts without a plan, so its owner has to choose one under **Billing** before its runners can be used. ## Roles | Role | Can | | --- | --- | | Owner | Everything, including billing, members and invitations. | | Editor | Create, change, pause and delete runners and schedules. | | Viewer | See runners, their status and metrics. No changes. | Each organization has exactly one owner: the person who created it. The owner role cannot be given to someone else, and the owner cannot leave the organization. Editors can also see the SSH keys available to a runner's Hetzner token, because they edit runners. Viewers see the dashboard without any runner actions. ## Organization settings Select **Organization** in the sidebar. ![Organization settings with members and a pending invitation](https://managerunners.com/docs/screenshots/organization-light.webp) - **Name:** the owner can rename the organization. - **Your role** and **Plan** show your access and the organization's plan. - **Members:** the owner can change members between Editor and Viewer, and remove them. A removed member loses access immediately. ## Invite members Only the owner can invite people. 1. Under **Invitations**, select **Invite member**. 2. Enter the email address and choose **Editor** or **Viewer**. 3. Select **Send invitation**. The person receives an email with a link. They sign in, or register with that email address, and select **Accept invitation**. The link works once and expires after a week. An invitation can only be accepted by an account with the invited email address. Pending invitations stay in the list until they are accepted. The owner can **Resend** an invitation, which sends a new link and stops the old one from working, or **Revoke** it. ## Leave an organization Members other than the owner can leave under **Leave organization**. They lose access immediately; the owner has to invite them again for them to return. ## Organizations in the CLI and API The CLI and personal access tokens work with your default organization unless you select another one. See [Profiles and organizations](https://managerunners.com/docs/cli/profiles-and-organizations/). A personal access token can never do more than your role in the organization allows. Creating organizations, renaming them, and managing members and invitations are only available in the dashboard. --- # Personal access tokens > Create scoped, expiring tokens for the CLI, scripts, CI jobs and AI agents, and revoke them. Source: https://managerunners.com/docs/manual/access-tokens/ A personal access token (PAT) gives a script, a CI job, an agent or the [CLI](https://managerunners.com/docs/cli/) access to your account, limited to the scopes you choose and until it expires. It acts as you: in each organization it can do at most what both its scopes and your role allow. ## Create a token 1. Open **Settings** (your profile) and go to **Personal access tokens**. 2. Select **Create token**. 3. Enter a name of up to 96 characters, for example `CI deploy agent`. 4. Select the scopes the token needs. **Select read-only** selects all scopes that only read. 5. Choose the expiry: 7 days, 30 days, 90 days or 1 year. 6. Select **Create token**. ![The Create personal access token dialog with read-only scopes selected](https://managerunners.com/docs/screenshots/access-tokens-light.webp) The dashboard shows the token once. Copy it into a secret manager immediately; you cannot see it again. Tokens start with `mr_pat_`. They cannot be extended: create a new one before the old one expires. ## Scopes | Scope | Dashboard label | Allows | | --- | --- | --- | | `profile:read` | Read profile | Read your profile and list your organizations | | `runners:read` | Read runners | List and read runners and their monitoring data | | `runners:write` | Manage runners | Create, edit, pause, resume and duplicate runners. This can create paid Hetzner resources. Updating a runner with the CLI, and waiting for a change with the CLI, also need `runners:read`. | | `runners:delete` | Delete runners | Delete runners | | `runners:forget` | Remove unknown runners | Remove **Unknown** runners from the dashboard | | `schedules:read` | Read schedules | Read schedules (Pro or Enterprise plan) | | `schedules:write` | Manage schedules | Create, change, enable, disable and delete schedules (Pro or Enterprise plan) | | `products:read` | Read products | List server types, locations and prices | | `providers:ssh-keys:read` | Read SSH keys | List the SSH keys of a Hetzner project | | `subscriptions:read` | Read subscription | Read the organization's plan and the available plans | Grant only what the token needs. A token for a monitoring script, for example, needs `runners:read` only. Some things are never possible with a token, whatever its scopes: managing billing, creating or changing organizations, members and invitations, and creating or listing tokens. They need a signed-in dashboard session. ## Tokens created by the CLI When you log in with `manage-runners auth login` or `manage-runners setup`, the CLI creates a token for itself, named `manage-runners-cli`, that expires after 30 days and has the read scopes `profile:read`, `runners:read`, `schedules:read`, `products:read`, `providers:ssh-keys:read` and `subscriptions:read`. Add write scopes only when you need them, with `--scope`. See [Authentication](https://managerunners.com/docs/cli/authentication/). These tokens appear in the same list as the ones you create in the dashboard. ## Use a token - **CLI:** set `MANAGE_RUNNERS_TOKEN` for one-off use, for example in CI, or store the token with `manage-runners auth login --token-stdin`. See [Authentication](https://managerunners.com/docs/cli/authentication/). - **API:** send it as `Authorization: Bearer ` to `https://api.managerunners.com`. Treat tokens like passwords. Never put them in a repository, a command line or a log. ## Review and revoke tokens The list shows each token's name, status (**Active**, **Expired** or **Revoked**), scopes, and when it was created, expires and was last used. Scopes that change data are highlighted. Select **Revoke** to disable an active token. Scripts, CI jobs and CLI profiles that use it stop working immediately. This cannot be undone. The CLI can also revoke its own token with `manage-runners auth logout --revoke`. --- # Account security > Two-factor authentication, password rules, sign-in lockout, changing and resetting your password. Source: https://managerunners.com/docs/manual/account-security/ ## Two-factor authentication Every account uses two-factor authentication (2FA) with an authenticator app (TOTP). You set it up during registration by scanning a QR code, and you enter a 6-digit code from the app every time you sign in to the dashboard. There are no recovery codes, and 2FA cannot be turned off. Keep your authenticator app backed up. If you lose access to it, contact [support@managerunners.com](mailto:support@managerunners.com). The CLI asks for a 2FA code when it logs in with your password. Personal access tokens do not need 2FA, which is why they are limited by [scopes and an expiry](https://managerunners.com/docs/manual/access-tokens/). ## Passwords A password needs at least 8 characters, including an uppercase letter, a lowercase letter, a number and a symbol. ### Change your password 1. Open **Settings** and go to **Security Settings**. 2. Enter your current password and the new password twice, then select **Continue**. 3. Enter a 6-digit code from your authenticator app and select **Verify & Change**. ### Reset a forgotten password 1. On the sign-in page, select **Forgot password?**. 2. Enter your email address and select **Send reset link**. For privacy, the page shows the same message whether or not an account exists for that address. 3. Open the link in the email within 15 minutes, choose a new password and select **Update password**. Only the most recent reset link works. Resetting your password does not change your 2FA setup: you still sign in with your authenticator app. ## Sign-in lockout After a failed sign-in, the account is locked for a short time, and each further failure makes the lock longer. The sign-in page shows how long to wait. A successful sign-in or a password reset clears the lock. ## Sessions A dashboard session lasts up to 8 hours. Signing out ends it. Your name and email address cannot be changed in the dashboard. --- # Billing and plans > Plans and what they include, checkout, upgrades and downgrades, payment methods, and what the owner manages. Source: https://managerunners.com/docs/manual/billing/ Each [organization](https://managerunners.com/docs/manual/organizations/) has its own plan. The plan covers Manage Runners; the servers themselves are billed by Hetzner to your Hetzner account. See [Costs](https://managerunners.com/docs/manual/concepts/#costs). ## Plans | Plan | Includes | | --- | --- | | Basic | Unlimited runners, the predefined executors, [monitoring](https://managerunners.com/docs/manual/monitoring/), basic email support | | Pro | Everything in Basic, [schedules](https://managerunners.com/docs/manual/schedules/), priority email support | | Enterprise | Everything in Pro, custom SLA and uptime, priority onboarding | Current prices are on the [pricing page](https://managerunners.com/pricing/) and under **Billing** in the dashboard. An organization needs an active plan before its runners can be used in the dashboard. Until then, the dashboard opens **Billing**. ## Who manages billing Only the organization's owner can choose, change or cancel the plan and manage payment details. Other members see which plan the organization has and that the owner manages it. ## Choose a plan 1. Open **Billing**. 2. Select **Choose Basic** or **Choose Pro**. For Enterprise, select **Contact Sales**. 3. Complete the checkout with the payment provider, Dodo Payments. After the payment you return to the dashboard, which waits until the payment is confirmed. If the checkout was not completed, **Billing** lets you start a new one. ## Upgrade On **Billing**, select **Upgrade to** on the higher plan, for example **Upgrade to Pro**, and confirm. The upgrade takes effect immediately, and you are charged a prorated amount for the difference in cost right away. ## Downgrade Under **Settings** > **Billing**, select **Downgrade to Basic** and confirm. The downgrade takes effect at the end of the current billing period; until then you keep the features of your current plan. Afterwards, you can no longer read, create or change [schedules](https://managerunners.com/docs/manual/schedules/). ## Payment details Under **Settings** > **Billing**, the owner can: - select **Manage Subscription** to open the payment provider's customer portal, - select **Update Payment Method** to change the card or payment method. If a payment fails, the plan goes **on hold**. Update the payment method to continue. If the subscription is set to cancel, you keep access until the end of the current billing period. --- # Troubleshooting > What to do when a runner is stuck, unknown or rejected, jobs don't start, or the dashboard refuses an action. Source: https://managerunners.com/docs/manual/troubleshooting/ ## Jobs stay pending The runner is **Active** but GitLab does not give it jobs. - **Tags:** a job only runs on a runner that has all of the job's tags. Compare the job's `tags:` with the runner's tags in GitLab under **Settings** > **CI/CD** > **Runners**. Jobs without tags need **Run untagged jobs** on the runner. - **Scope:** a project runner only takes jobs of its project. Use a group runner to serve several projects. - **Architecture:** on an ARM server, images must support `arm64`. - **Paused in GitLab:** a runner paused in GitLab takes no jobs. That is separate from pausing it in Manage Runners. ## The runner shows Invalid Gitlab Token GitLab rejected the token when the server registered. The server keeps running and costs money while the runner is in this state. Select **Fix**, paste a valid runner authentication token, check the GitLab host, and select **Save**. See [When GitLab rejects the token](https://managerunners.com/docs/manual/gitlab/#when-gitlab-rejects-the-token). ## A runner is Unknown A runner becomes **Unknown** when Manage Runners can no longer tell what happened to its server. Common causes: - Hetzner could not create the server for a new runner, for example because the token is read-only or Hetzner had no capacity. - The Hetzner token was revoked or deleted while the runner existed, and a pause, resume or SSH key lookup failed. To recover: 1. Make sure you have a working **Read & Write** token for the runner's Hetzner project. 2. **Edit** the runner, enter the token in **Hetzner Auth Token**, and save. Manage Runners then checks the project. If the server exists, the runner becomes **Active** again, with monitoring turned off. If it does not, the runner becomes **Paused**, and you can resume it. If you no longer need the runner, [remove it](https://managerunners.com/docs/manual/runners/#remove-an-unknown-runner) and clean up the server and IP addresses in the Hetzner Console yourself. ## Hetzner could not create the server Resuming a runner can fail with an error saying that Hetzner responded with HTTP 412. This usually means Hetzner has no capacity for that server type in that location at the moment. The runner stays **Paused**. Try again later, or edit the runner to use another server type. A new runner in another location is the other option, since a runner's location cannot change. ## The Hetzner token is rejected When you leave the **Hetzner Auth Token** field, the dashboard checks the token by listing the project's SSH keys. If it shows an error, the token is wrong, revoked or belongs to a project that no longer exists. Create a new token as described in [Hetzner setup](https://managerunners.com/docs/manual/hetzner/#create-a-project-and-an-api-token). ## An action fails because the runner is locked Only one lifecycle action, such as pause, resume or delete, runs on a runner at a time. Wait until the runner has reached a stable state, then try again. ## Resume or Duplicate is disabled Hetzner no longer offers the runner's server type in its location. Edit the runner to choose an available server type, or create a new runner. ## The dashboard opens Billing The selected organization has no active plan. Its owner can choose one under **Billing**. If you belong to several organizations, switch to another one with the menu at the top. See [Billing and plans](https://managerunners.com/docs/manual/billing/). ## Create Runner and Edit are missing Your role in the selected organization is **Viewer**. Ask the owner to make you an editor. See [Roles](https://managerunners.com/docs/manual/organizations/#roles). ## Monitoring shows no data - **Waiting for first data:** values appear a few minutes after the server starts. - **No data for some minutes:** the server may be rebooting after automatic updates, or it is overloaded. Check it in the Hetzner Console. - **Monitoring paused:** the organization's plan is not active. See [When the plan ends](https://managerunners.com/docs/manual/monitoring/#when-the-plan-ends). ## You cannot sign in - **Account locked:** wait for the time shown on the sign-in page. - **Forgotten password:** [reset it](https://managerunners.com/docs/manual/account-security/#reset-a-forgotten-password). Reset links expire after 15 minutes. - **Lost authenticator app:** contact [support@managerunners.com](mailto:support@managerunners.com). ## The invitation link does not work Invitation links work once and expire after a week. The invitation must be accepted with an account whose email address matches it. Ask the owner to resend the invitation. See [Invite members](https://managerunners.com/docs/manual/organizations/#invite-members). ## CLI problems Run `manage-runners doctor` for a read-only check of the configuration, credential and API connection. The [agent guide](https://managerunners.com/docs/cli/agents/#exit-codes) lists every exit code and error code. ## Still stuck? Email [support@managerunners.com](mailto:support@managerunners.com) with the runner ID, the time it happened and what you saw. --- # manage-runners CLI > Manage runners, schedules and monitoring from your terminal, scripts and AI agents with the official manage-runners CLI. Source: https://managerunners.com/docs/cli/ `manage-runners` is the official command-line interface for Manage Runners. It talks to the same API as the dashboard, so runners you create in the terminal appear in the dashboard and the other way around. The CLI is open source under the MIT licence. ## What you can do | Task | Commands | | --- | --- | | Log in and manage profiles | `config set-api`, `setup`, `auth login`, `auth status`, `auth logout`, `auth use` | | Choose an organization | `org list`, `org use`, `--org` | | Find server types and prices | `product list`, `product get`, `product locations` | | Manage runners | `runner list`, `runner get`, `runner create`, `runner update`, `runner pause`, `runner resume`, `runner duplicate`, `runner delete`, `runner forget` | | Wait for runners | `runner wait`, `runner watch`, `--wait` | | Read monitoring | `runner metrics` | | Manage schedules | `schedule get`, `schedule set`, `schedule enable`, `schedule disable`, `schedule delete` | | Check your account | `profile show`, `subscription show`, `subscription plans` | | Diagnose problems | `doctor`, `version` | | Update the CLI | `version --check`, `self-update` | | Integrate with agents | `commands`, `help --output json`, `setup skill`, `--agent` | Creating organizations, inviting members, managing billing and creating personal access tokens are only available in the [dashboard](https://app.managerunners.com). ## Get started 1. [Install the CLI](https://managerunners.com/docs/cli/install/). 2. [Log in](https://managerunners.com/docs/cli/authentication/). 3. Follow the task guides for [runners](https://managerunners.com/docs/cli/runners/) and [schedules](https://managerunners.com/docs/cli/schedules/), or browse the [command reference](https://managerunners.com/docs/cli/reference/). ## Output formats Every command supports three output formats: - `--output human` (the default): readable text. - `--output json` or `--json`: one JSON document with `ok`, `command`, `data`, `meta` and `warnings`, or `error` when the command failed. - `--output jsonl`: one JSON line per item for list commands, plus one line per warning. Results and errors are written to standard output. Prompts go to standard error. The exit code tells you whether a command succeeded; see [Exit codes](https://managerunners.com/docs/cli/agents/#exit-codes). ## Safety The CLI treats changes that can cost money or delete data carefully: - Commands that may create paid Hetzner resources (`runner create`, `runner resume`, `runner duplicate`, and `runner update` when it recreates the server) ask for confirmation, or need `--yes`. - Destructive commands (`runner pause`, `runner delete`, `runner forget`, `schedule delete`) ask for confirmation. `runner delete`, `runner forget` and `schedule delete` also need the exact runner ID. - The token the CLI creates when you log in can only read. Write, delete and forget permissions must be requested explicitly. ## For agents and scripts Use `--agent` for JSON output without prompts, discover commands with `manage-runners commands --agent`, and read the [agent guide](https://managerunners.com/docs/cli/agents/) for the full contract. --- # Install the CLI > Install, verify, upgrade and uninstall the manage-runners CLI on Linux, macOS and Windows, and set up shell completion. Source: https://managerunners.com/docs/cli/install/ `manage-runners` is a single binary with no dependencies, available for Linux and macOS (`amd64` and `arm64`) and Windows (`amd64`). ## Install on Linux or macOS ```sh curl -fsSL https://downloads.managerunners.com/cli/latest/install.sh | sh ``` The script detects your system, downloads the latest release, checks its SHA-256 checksum and installs `manage-runners` to `~/.local/bin`. It never uses `sudo` and sends no data besides the downloads. If `~/.local/bin` is not on your `PATH`, the script tells you how to add it. To choose the directory or a version, pass options after `sh -s --`: ```sh curl -fsSL https://downloads.managerunners.com/cli/latest/install.sh | sh -s -- --dir "$HOME/bin" --version 1.0.0 ``` `MANAGE_RUNNERS_INSTALL_DIR` sets the directory as well. To read the script before running it, download it first and run it with `sh install.sh`. ## Download manually Version 1.0.1: | Operating system | Architecture | Archive | | --- | --- | --- | | Linux | amd64 | [`manage-runners_1.0.1_linux_amd64.tar.gz`](https://downloads.managerunners.com/cli/1.0.1/manage-runners_1.0.1_linux_amd64.tar.gz) | | Linux | arm64 | [`manage-runners_1.0.1_linux_arm64.tar.gz`](https://downloads.managerunners.com/cli/1.0.1/manage-runners_1.0.1_linux_arm64.tar.gz) | | macOS | amd64 (Intel) | [`manage-runners_1.0.1_darwin_amd64.tar.gz`](https://downloads.managerunners.com/cli/1.0.1/manage-runners_1.0.1_darwin_amd64.tar.gz) | | macOS | arm64 (Apple silicon) | [`manage-runners_1.0.1_darwin_arm64.tar.gz`](https://downloads.managerunners.com/cli/1.0.1/manage-runners_1.0.1_darwin_arm64.tar.gz) | | Windows | amd64 | [`manage-runners_1.0.1_windows_amd64.zip`](https://downloads.managerunners.com/cli/1.0.1/manage-runners_1.0.1_windows_amd64.zip) | Checksums: [`checksums.txt`](https://downloads.managerunners.com/cli/1.0.1/checksums.txt). Other releases are at `https://downloads.managerunners.com/cli//`, with the version in each file name. ### Verify the download Download `checksums.txt` into the same directory as your archive, then check only your archive: ```sh archive=manage-runners_1.0.1_linux_amd64.tar.gz # the file you downloaded grep -F " $archive" checksums.txt | sha256sum -c - # Linux grep -F " $archive" checksums.txt | shasum -a 256 -c - # macOS ``` The command must print `OK`. Stop if it reports a mismatch. Always use the `checksums.txt` of the release folder you downloaded the archive from. ### Install on Linux or macOS Extract the binary and move it to a directory on your `PATH`: ```sh tar -xzf "$archive" manage-runners mkdir -p ~/.local/bin && mv manage-runners ~/.local/bin/ ``` ### Install on Windows 1. Download the Windows ZIP file and `checksums.txt` from the table above. 2. In PowerShell, run `Get-FileHash -Algorithm SHA256` with the path of the ZIP file and compare the hash with the line for that file in `checksums.txt`. Stop if they differ. 3. Extract the ZIP file and move `manage-runners.exe` to a folder such as `%LOCALAPPDATA%\Programs\manage-runners`. 4. Add that folder to your `PATH` under **Settings > System > About > Advanced system settings > Environment Variables**, then open a new terminal. Besides the binary, each archive contains the licence (`LICENSE`), a `README.md`, the dependency list and third-party notices, a CycloneDX software bill of materials (`cli-sbom.cdx.json`), and the agent skill (`SKILL.md` with `skill-metadata.json`). It contains no credentials or configuration. ## Check the installation ```sh manage-runners version ``` `manage-runners version --output json` shows the version, commit, build date and Go version. Then [log in](https://managerunners.com/docs/cli/authentication/). ## Upgrade Check whether a newer release exists: ```sh manage-runners version --check ``` It reads only `latest.json` from `downloads.managerunners.com`, reports your version, the latest version and whether an update is available, and exits with code 14 when there is one. The CLI never checks for updates on its own. To upgrade, run: ```sh manage-runners self-update ``` `self-update` shows the current and the new version and asks before it changes anything; in scripts and agent mode, pass `--yes`. It downloads the archive for your system from `downloads.managerunners.com`, checks its size and SHA-256 against the release manifest, and replaces the binary it runs from in place, following a symlink to the actual file and keeping its permissions. It works on Linux, macOS and Windows. It never uses `sudo` or administrator rights: if the binary's directory is not writable, it stops and points you to the install script on Linux and macOS, or to the manual download steps on Windows. Development builds cannot update themselves; install a release in the same way. `self-update --version 1.0.0` installs a specific release. Going back to an older release only happens this way, and the prompt calls it a downgrade. When you are already on the version, nothing changes. Updating the binary does not touch your profiles, credentials or an installed agent skill. Afterwards, `manage-runners setup skill status --target ` shows whether the installed skill differs from the new version's. You can also upgrade by running the install script again, or by downloading the new release from [Download manually](#download-manually), verifying it and replacing the binary. ## Uninstall To uninstall: 1. Run `manage-runners auth logout --revoke --profile ` for each profile, to revoke and remove its token. 2. Delete the binary. 3. Delete the `manage-runners` directory in your user configuration directory (for example `~/.config/manage-runners` on Linux). ## Shell completion `manage-runners completion --shell ` prints a completion script for `bash`, `zsh`, `fish` or `powershell`. For example: ```sh # bash, current session source <(manage-runners completion --shell bash) # zsh, current session source <(manage-runners completion --shell zsh) # fish manage-runners completion --shell fish > ~/.config/fish/completions/manage-runners.fish ``` To load it in every session, add the `source` line to your shell's startup file. --- # Log in and authenticate > Log in with your password and 2FA, grant write scopes, import tokens, and use the CLI on headless systems and in CI. Source: https://managerunners.com/docs/cli/authentication/ The CLI authenticates with a [personal access token](https://managerunners.com/docs/manual/access-tokens/) (PAT). It never stores your password or your 2FA secret. ## The API address The CLI stores API addresses in named *profiles*. The `default` profile, used when you don't pass `--profile`, points at `https://api.managerunners.com`, so there is nothing to configure. Other profiles get their address from `config set-api`, which accepts only HTTPS addresses. See [Profiles and organizations](https://managerunners.com/docs/cli/profiles-and-organizations/) for more than one profile. ## Log in interactively ```sh manage-runners setup ``` `setup` logs in to the active profile. It asks for your username (your email address), your password and a 2FA code from your authenticator app. It then creates a PAT named `manage-runners-cli`, valid for 30 days, and stores it in your system's credential store: the Secret Service keyring on Linux, Keychain on macOS, Credential Manager on Windows. `auth login` does the same for a profile you name, and can add scopes: ```sh manage-runners auth login --profile default ``` ### Scopes By default the CLI's token can only read. It gets the scopes `profile:read`, `runners:read`, `schedules:read`, `products:read`, `providers:ssh-keys:read` and `subscriptions:read`. To change runners or schedules, log in again and request the scopes you need, repeating `--scope`: ```sh manage-runners auth login --profile default --scope runners:write --scope schedules:write ``` | Scope | Needed for | | --- | --- | | `runners:write` | `runner create`, `update`, `pause`, `resume`, `duplicate` (`update` and `--wait` also need `runners:read`) | | `runners:delete` | `runner delete` | | `runners:forget` | `runner forget` | | `schedules:write` | `schedule set`, `enable`, `disable`, `delete` | Logging in interactively again replaces the profile's previous token and tries to revoke the old one. If the revocation cannot be confirmed, the login still succeeds with the warning `PREVIOUS_PAT_REVOCATION_UNCONFIRMED`; revoke the old token in the dashboard. Your role in the organization still applies: a viewer cannot change runners, whatever the token's scopes. ### Check and end a session ```sh manage-runners auth status --profile default manage-runners auth logout --profile default --revoke ``` `auth status` shows who you are logged in as, the token's scopes and expiry, and where the token comes from. It never prints the token. `auth logout` removes the stored token; with `--revoke` it also revokes the token in Manage Runners first. You can also revoke it in the dashboard under **Settings** > **Personal access tokens**. When the 30 days are over, log in again. ## Use a token you created in the dashboard You can create a PAT in the dashboard with exactly the scopes and expiry you want, and give it to the CLI. **Store it** in the credential store. Pipe it in, so it does not appear in your shell history or the process list: ```sh your-secret-manager read manage-runners-pat | manage-runners auth login --profile default --token-stdin ``` `--token-env NAME` reads it from the environment variable `NAME` instead. An imported token keeps the scopes it was created with; `--scope` cannot be combined with an import. **Or use it without storing it**, for example in CI. If `MANAGE_RUNNERS_TOKEN` is set, commands use it for that invocation: ```sh export MANAGE_RUNNERS_TOKEN # set by your CI or secret manager manage-runners runner list ``` The global `--token-env NAME` uses another variable for one invocation and takes precedence over `MANAGE_RUNNERS_TOKEN`, which takes precedence over the credential store: ```sh manage-runners --token-env CI_MANAGE_RUNNERS_PAT runner list ``` Never pass a token as a command-line argument. ## Headless systems without a keyring SSH sessions, containers and servers often have no unlocked keyring. You have two options: - **Environment token:** use `MANAGE_RUNNERS_TOKEN` or `--token-env` as shown above. - **File credential store:** pass `--credential-store file` or set `MANAGE_RUNNERS_CREDENTIAL_STORE=file`. The CLI then keeps the token in `manage-runners/credentials.json` in your user configuration directory, readable only by you (mode 0600). It refuses to use the file if others can read it or if it is a symbolic link. The file store is available on Linux and macOS. ```sh export MANAGE_RUNNERS_CREDENTIAL_STORE=file manage-runners auth login --profile default ``` The CLI never falls back to the file store on its own. ## Diagnose problems ```sh manage-runners doctor ``` `doctor` checks the configuration, the credential store, the stored token, its expiry and scopes, and whether the API is reachable. It changes nothing. --- # Profiles and organizations > Keep several API profiles, switch the default profile, and choose the organization your commands work in. Source: https://managerunners.com/docs/cli/profiles-and-organizations/ ## Profiles A profile is a name for an API address with its own stored token. Most people need only the `default` profile, which points at `https://api.managerunners.com` without any setup. Additional profiles help when you want separate tokens, for example a read-only one for everyday use and one with write scopes for changes. Create them with `config set-api`: ```sh manage-runners config set-api --profile admin --url https://api.managerunners.com manage-runners auth login --profile admin --scope runners:write --scope runners:delete ``` Profile names start with a letter and contain up to 64 letters, numbers, `-` and `_`. | Command | What it does | | --- | --- | | `config profiles` or `auth profiles` | List profiles and mark the active one | | `config show` | Show the active profile's API address | | `auth use ` | Make a profile the active one | | `--profile ` | Use a profile for one command | The configuration is stored in `manage-runners/config.json` in your user configuration directory (for example `~/.config` on Linux). It contains no secrets; tokens are kept in the [credential store](https://managerunners.com/docs/cli/authentication/). ## Organizations Runners, schedules, metrics and the subscription belong to an [organization](https://managerunners.com/docs/manual/organizations/). Without a selection, commands use your default organization. ```sh manage-runners org list ``` `org list` shows each organization's ID, name and your role (`OWNER`, `EDITOR` or `VIEWER`), and marks your default organization and the selected one. To work in another organization: ```sh # for one command manage-runners --org "Platform Team" runner list # for every command of the profile manage-runners org use "Platform Team" # back to the default organization manage-runners org use --clear ``` `--org` and `org use` accept an organization ID or name. The CLI looks for an exact ID first, then an exact name, then a unique name ignoring case. An unknown value fails with `ORGANIZATION_NOT_FOUND`, an ambiguous name with `ORGANIZATION_AMBIGUOUS`, before anything else is requested. `--org` applies to `runner`, `schedule`, `subscription` and `provider` commands and overrides the profile's selection. Organization IDs are long numbers. In JSON output they are strings; keep them as strings in scripts. ### Roles and token scopes What a command may do is the intersection of the token's scopes and your role in the organization. Viewers can read runners, schedules, metrics and the subscription. Editors can also change runners and schedules. If your role does not allow an action, the command fails with `ORGANIZATION_PERMISSION_DENIED` and exit code 4, naming the organization and your role. Creating and renaming organizations and managing members and invitations are only possible in the dashboard. ### Downgrading the CLI Older CLI versions without organization support reject a configuration that stores an organization. Before installing such a version, run `manage-runners org use --clear --profile ` for every profile listed by `config profiles`. --- # Manage runners with the CLI > List, create, update, pause, resume, duplicate and delete runners, wait for them, and read their metrics from the terminal. Source: https://managerunners.com/docs/cli/runners/ The examples use the active profile and organization. Add `--profile` or `--org` to choose others, and `--output json` for scripts. Commands that change runners need the scopes from [Authentication](https://managerunners.com/docs/cli/authentication/#scopes). `runner update` and `--wait` also need `runners:read`, which the CLI's login token always has. ## List and inspect ```sh manage-runners runner list manage-runners runner get --id 812999368881481087 manage-runners runner get --name build-01 ``` Runner IDs are long numbers; treat them as strings. `runner get --name` needs an exact, unique name. The `state` field uses the API names: `CREATING`, `CONFIGURING`, `READY` (shown as **Active** in the dashboard), `PAUSED`, `UNKNOWN` and `INVALID_GITLAB_TOKEN`. See [Runner states](https://managerunners.com/docs/manual/concepts/#runner-states). ## Find a server type and location ```sh manage-runners product list manage-runners product get --id hz-cpx31 manage-runners product locations --id hz-cpx31 ``` `product locations` shows where Hetzner offers the server type and Hetzner's monthly net price in each location. Use the location code, for example `fsn1`, with `runner create`. To see the SSH keys of your Hetzner project, pass the Hetzner token on standard input or through an environment variable: ```sh manage-runners provider hetzner ssh-keys --token-env HCLOUD_TOKEN ``` For an existing runner, `runner ssh-keys --id ` lists the keys available with the runner's stored Hetzner token. ## Create a runner The CLI reads the GitLab runner token and the Hetzner token from environment variables you name, so they never appear on the command line: ```sh export GLRT_TOKEN HCLOUD_TOKEN # set them from your secret manager manage-runners runner create \ --name build-01 \ --product-id hz-cpx31 \ --location fsn1 \ --executor docker \ --concurrency 8 \ --gitlab-host https://gitlab.com/ \ --runner-token-env GLRT_TOKEN \ --hetzner-token-env HCLOUD_TOKEN \ --ssh-key-id 1234567 \ --label role=ci-runner \ --monitoring on \ --wait ``` | Flag | Required | Description | | --- | --- | --- | | `--name` | yes | Letters, numbers, spaces and dashes | | `--product-id` | yes | From `product list` | | `--location` | yes | From `product locations` | | `--executor` | yes | `docker`, `dind` or `shell` | | `--concurrency` | yes | At least 1 | | `--gitlab-host` | yes | Base URL of your GitLab instance | | `--runner-token-env` | yes | Name of the variable holding the `glrt-` token | | `--hetzner-token-env` | yes | Name of the variable holding the Hetzner token | | `--ssh-key-id` | no | Hetzner SSH key ID, repeatable | | `--label` | no | Hetzner label, repeatable | | `--monitoring on\|off` | no | Needs an active plan to turn on | | `--wait` | no | Wait until the runner reaches a final state | | `--yes` | no | Confirm creating paid resources without a prompt | `runner create` creates a paid Hetzner server, so it asks `create runner build-01 and potentially create paid resources? [y/N]`. Pass `--yes` in scripts. Without a terminal and without `--yes`, it fails. Each create request carries an idempotency key. The CLI generates a new one per invocation; pass your own with `--idempotency-key` (16 to 128 letters, digits, `.`, `_` or `-`) to make a script's retry safe. For the same user, organization, route, key and request, the API returns the first result until 24 hours after the first attempt; after that, the same request creates another runner. A different request with the same key, or a retry while the first attempt has not completed, is rejected as a conflict. Check `runner list` before retrying an old create. See [Idempotency and unknown outcomes](https://managerunners.com/docs/cli/agents/#idempotency-and-unknown-outcomes). ## Wait for a runner `--wait` on `create`, `update`, `pause`, `resume` and `duplicate` waits until the runner reaches `READY`, `PAUSED`, `UNKNOWN` or `INVALID_GITLAB_TOKEN`, for at most `--timeout` (default 10 minutes). Check the returned state: reaching `UNKNOWN` or `INVALID_GITLAB_TOKEN` ends the wait too. To wait later or for a specific state: ```sh manage-runners runner wait --id 812999368881481087 --state READY --timeout 15m manage-runners runner watch --id 812999368881481087 ``` If the wait times out, the command exits with code 7 (`TIMEOUT`). If it fails for another reason, for example a token without `runners:read`, it exits with that error. In both cases the change itself was accepted and is not undone; check the runner with `runner get`. ## Update a runner ```sh manage-runners runner update --id 812999368881481087 --name build-02 --label role=ci-runner manage-runners runner update --id 812999368881481087 --concurrency 4 --yes --wait ``` Flags you leave out keep their current values. `--label` and `--ssh-key-id` replace the whole list. > `--product-id`, `--gitlab-host`, `--runner-token-env`, `--concurrency`, `--executor`, `--ssh-key-id` and `--monitoring` recreate an active runner's server and interrupt its jobs. The CLI asks for confirmation, or needs `--yes`. `--name`, `--label` and `--hetzner-token-env` alone never recreate the server. See [Changes that recreate the server](https://managerunners.com/docs/manual/concepts/#changes-that-recreate-the-server). The location cannot be changed. ## Pause, resume and duplicate ```sh manage-runners runner pause --id 812999368881481087 --yes manage-runners runner resume --id 812999368881481087 --yes --wait manage-runners runner duplicate --id 812999368881481087 --yes ``` `pause` deletes the server and keeps the IP addresses. `resume` and `duplicate` create servers and may cost money. All three ask for confirmation unless you pass `--yes`. ## Delete a runner Deleting needs the `runners:delete` scope and the runner ID twice, as `--id` and `--confirm`: ```sh manage-runners runner delete --id 812999368881481087 --confirm 812999368881481087 --yes ``` Interactively, the CLI asks you to confirm and to type the ID. Delete removes the server, the IP addresses and the runner's schedule. It does not remove the runner from GitLab. If deletion cannot be confirmed with Hetzner, the runner is kept and the command fails. Run it again later. ## Forget an Unknown runner `runner forget` only works on a runner in the `UNKNOWN` state. It removes the record from Manage Runners and leaves any server and IP addresses in Hetzner untouched. It needs the `runners:forget` scope and the same confirmation as `delete`: ```sh manage-runners runner forget --id 812999368881481087 --confirm 812999368881481087 --yes ``` Never use `forget` instead of `delete`. Try [recovering the runner](https://managerunners.com/docs/manual/troubleshooting/#a-runner-is-unknown) first, and clean up Hetzner yourself afterwards. ## Read monitoring data ```sh manage-runners runner metrics manage-runners runner metrics --name build-01 --range 7d --output json ``` Without `--id` or `--name`, `runner metrics` covers every active runner with monitoring on. `--range` accepts `1h`, `24h` (default), `7d`, `30d` and `90d`. Human output shows the latest CPU, RAM and disk usage and a summary of the history; JSON includes the full history. - `latest` is empty until the first sample arrives, and `stale` marks samples older than three minutes. - A runner that is not monitored or not active fails with `NOT_MONITORED` (exit code 5). - Without an active plan, the command fails with `SUBSCRIPTION_REQUIRED` (exit code 4). - If the history is shorter than the range, a `RANGE_EXCEEDS_HISTORY` warning lists the available ranges. ## If a change has an unknown outcome If the connection fails while a change is in progress, the CLI exits with code 10 (`UNKNOWN_OUTCOME`). The change may or may not have happened. Check the runner with `runner list` or `runner get` before you try again; never retry blindly. --- # Schedules with the CLI > Create, read, enable, disable and delete runner schedules from the terminal. Source: https://managerunners.com/docs/cli/schedules/ Schedules pause and resume a runner on a weekly timetable. They need a Pro or Enterprise plan; [Schedules](https://managerunners.com/docs/manual/schedules/) in the manual explains how they work. Reading needs the `schedules:read` scope, which the CLI's login token has; changes need `schedules:write`: ```sh manage-runners auth login --profile default --scope schedules:write ``` Check whether your organization's plan includes schedules: ```sh manage-runners subscription show ``` ## Create or replace a schedule ```sh manage-runners schedule set --runner-id 812999368881481087 \ --zone-id Europe/Berlin \ --start 07:00 --stop 19:00 \ --day Mon --day Tue --day Wed --day Thu --day Fri \ --enabled ``` | Flag | Description | | --- | --- | | `--runner-id` | The runner the schedule belongs to | | `--zone-id` | IANA time zone, for example `Europe/Berlin` or `America/New_York` | | `--start` | Start time, `HH:MM` | | `--stop` | Stop time, `HH:MM`, later than `--start` | | `--duration-minutes` | Instead of `--stop`: window length, 1 to 1440 minutes | | `--day` | `Mon`, `Tue`, `Wed`, `Thu`, `Fri`, `Sat` or `Sun`; repeat for each day, at least one | | `--enabled` | Enable the schedule. Pass `--enabled=false` to save it disabled. | Give exactly one of `--stop` and `--duration-minutes`. `--enabled` must always be given explicitly. `schedule set` replaces any existing schedule of the runner. ## Read, enable and disable ```sh manage-runners schedule get --runner-id 812999368881481087 manage-runners schedule disable --runner-id 812999368881481087 manage-runners schedule enable --runner-id 812999368881481087 ``` A disabled schedule keeps its settings and does nothing until you enable it again. ## Delete ```sh manage-runners schedule delete --runner-id 812999368881481087 --confirm 812999368881481087 --yes ``` Deleting is permanent. Interactively, the CLI asks you to confirm and to type the runner ID. Deleting a runner deletes its schedule as well. ## Errors Without a Pro or Enterprise plan, schedule commands fail with exit code 4. A runner without a schedule makes `schedule get` fail with exit code 5. Invalid times, days or zones fail with exit code 2 before anything is sent, or with exit code 7 if the API rejects them. --- # The CLI for AI agents and automation > Agent mode, command discovery, the JSON contract, exit and error codes, confirmations, scopes, and the embedded agent skill. Source: https://managerunners.com/docs/cli/agents/ This page is the contract for AI agents and scripts that operate Manage Runners through `manage-runners`. It is also available as [Markdown](https://managerunners.com/docs/cli/agents/index.md), and the whole documentation as one file at [/llms-full.txt](https://managerunners.com/llms-full.txt). ## Roles: the human sets up, the agent operates A human installs the CLI, logs in and decides what the agent may do: 1. [Install](https://managerunners.com/docs/cli/install/) the CLI. 2. Give the agent a token, either: - **interactive login** with `manage-runners setup` or `auth login`, which yields a read-only token for 30 days, plus write scopes only if the human adds them with `--scope`, or - **a dashboard token** with exactly the scopes and expiry the task needs, provided to the agent through its secret store. See [Personal access tokens](https://managerunners.com/docs/manual/access-tokens/). 3. Optionally install the [agent skill](#the-agent-skill). The agent then runs commands with `--agent`, reads the results as JSON, and asks the human before anything that costs money or deletes data. ## Agent mode ```sh manage-runners runner list --agent ``` `--agent` means JSON output and no prompts. It is the same as `--output json --non-interactive`. In agent mode, a command that would need an answer fails instead of waiting for one. ## Discover commands ```sh manage-runners commands --agent manage-runners help runner delete --agent ``` `commands` returns the catalog of every command. Each entry has: | Field | Meaning | | --- | --- | | `name` | Dotted name, for example `runner.delete` | | `path` | The words to type after `manage-runners`, for example `["runner", "delete"]` | | `summary` | One-line description | | `mutation` | `true` if the command changes local configuration or remote state | | `destructive` | `true` if it deletes or stops something | | `paid_resource_effect` | `create`, `recreate`, `delete` or `null`: what it does to paid Hetzner resources | | `required_scopes` | Token scopes the command needs | | `required_flags` | Flags that must be given | | `confirmation` | `paid_resource`, `runner_id` or `null`, see [Confirmations](#confirmations) | | `supports_json` | Whether JSON output is supported | | `supports_non_interactive` | `false` for commands that need a human at a terminal, such as `setup` | `help --agent` returns the same entry plus every flag with its usage text and whether it is required. The [command reference](https://managerunners.com/docs/cli/reference/) shows the catalog and the help text of every command. ## Output Success: ```json { "ok": true, "command": "runner.get", "data": { "profile": "default", "origin": "https://api.managerunners.com", "runner": { "runnerId": "812999368881481087", "name": "build-01", "state": "READY" } }, "meta": { "schema_version": "1", "cli_version": "1.0.0", "api_version": "1", "request_id": "deploy-42" }, "warnings": [] } ``` Failure: ```json { "ok": false, "command": "runner.delete", "error": { "type": "usage", "code": "USAGE", "message": "--yes is required in non-interactive mode", "retryable": false, "unknown_outcome": false, "http_status": null, "field_errors": [], "details": {} }, "meta": { "schema_version": "1", "cli_version": "1.0.0" }, "warnings": [] } ``` The examples are abbreviated: the shape of `data` depends on the command, so read it from a real response. Both results and errors are written to standard output; prompts and nothing else go to standard error. Always check the exit code and `ok`. - `--request-id ID` sends a request ID (1 to 128 safe characters) to the API and echoes it in `meta.request_id`, which helps to correlate logs. - `--output jsonl` writes one JSON line per item of a list, and one line `{"type": "warning", ...}` per warning. An empty list writes nothing. - IDs of runners and organizations are decimal strings. Keep them as strings; they do not fit into a double-precision number. ## Exit codes | Code | Meaning | What to do | | --- | --- | --- | | 0 | Success | | | 2 | Invalid command, flag or value, or a missing confirmation | Fix the command. Nothing was sent. | | 3 | Token missing, invalid or expired | Ask the human to log in again. | | 4 | Missing scope, role or plan | Do not retry. See the error code. | | 5 | Runner, schedule or organization not found, or not monitored | Check the ID and organization. | | 6 | The runner's state does not allow the action, or a name is ambiguous | Read the runner's state first. | | 7 | The API rejected the input, or waiting timed out after the change was accepted | Fix the input, or check the runner's state. | | 8 | Rate limited or temporarily unavailable | Retry later with backoff. | | 9 | The API could not be reached | Check connectivity. Before repeating a change, check whether it happened. | | 10 | A change may or may not have happened | Do not retry. Read the state and reconcile first. | | 11 | `auth logout --revoke` could not confirm revocation or local removal | Check the token in the dashboard. | | 12 | Configuration or credential store problem | Run `manage-runners doctor`. | | 13 | Unexpected API response, too large a response, or an unsupported version; for `self-update`, a release or download that failed its checks | Update the CLI; for metrics, use a shorter range. Do not retry a rejected download. | | 14 | `version --check`: an update is available (`ok` is `true`) | Tell the human; update only with their consent. | | 70 | Internal error | Report it. | ### Error codes The most important values of `error.code`: | Code | Exit | Meaning | | --- | --- | --- | | `USAGE` | 2 | Invalid input or missing confirmation | | `ORGANIZATION_AMBIGUOUS` | 2 | `--org` matches several organizations by name | | `UNAUTHENTICATED` | 3 | No valid token | | `FORBIDDEN` | 4 | The token lacks a scope, or the plan does not include the feature | | `SUBSCRIPTION_REQUIRED` | 4 | Monitoring needs an active plan. The same HTTP 403 is used for a missing scope, so this is the likely, not certain, cause. | | `ORGANIZATION_PERMISSION_DENIED` | 4 | Your role in the organization does not allow the action | | `NOT_RELEASE_BUILD` | 2 | A development or modified build cannot run `self-update`; `error.details.hint` names the install script (Linux, macOS) or the manual download steps (Windows) | | `NOT_FOUND` | 5 | The runner or schedule does not exist in the selected organization | | `ORGANIZATION_NOT_FOUND` | 5 | The organization is not among your memberships | | `NOT_MONITORED` | 5 | The runner exists but is not active or has monitoring off | | `RELEASE_NOT_FOUND` | 5 | The release given to `self-update --version` does not exist | | `CONFLICT` | 6 | The runner's state does not allow the action | | `AMBIGUOUS` | 6 | Several runners have that name; use `--id` | | `VALIDATION` | 7 | The API rejected the input | | `TIMEOUT` | 7 | Waiting for a runner timed out; the change itself was accepted | | `RETRYABLE` | 8 | Try again later | | `NETWORK` | 9 | Network error | | `UNKNOWN_OUTCOME` | 10 | The change may have happened; reconcile before retrying | | `REVOCATION_UNCONFIRMED` | 11 | Token revocation could not be confirmed | | `CONFIG`, `CREDENTIAL_STORE` | 12 | Local configuration or credential store problem | | `INSTALL_DIR_NOT_WRITABLE`, `UPDATE_FAILED` | 12 | `self-update` cannot write or replace the binary, or the binary changed while it ran; when the directory is not writable, `error.details.hint` names the install script (Linux, macOS) or the manual download steps (Windows) | | `INCOMPATIBLE_RESPONSE`, `RESPONSE_TOO_LARGE` | 13 | The API response or release manifest could not be used | | `PLATFORM_NOT_RELEASED` | 13 | The release has no build for this operating system and CPU | | `DOWNLOAD_REJECTED` | 13 | The download failed its size, SHA-256 or archive checks, or was redirected to another host; nothing was changed | Warnings in `warnings` do not change the exit code. Examples: `TOKEN_ENV` and `TOKEN_ENV_OVERRIDES_STORE` (a token came from the environment), `RANGE_EXCEEDS_HISTORY` (metrics history is shorter than the range), `RUNNER_WARNING` (a message from the API about the runner). ## Confirmations In agent mode the CLI never prompts. Commands that would ask a human must be confirmed with flags, and the agent may only add these flags when the human has approved the specific action. | Catalog `confirmation` | Commands | Non-interactive confirmation | | --- | --- | --- | | `paid_resource` | `runner create`, `runner resume`, `runner duplicate`, `runner pause`, and `runner update` when it recreates the server | `--yes` | | `runner_id` | `runner delete`, `runner forget` | `--yes` and `--confirm `, exactly equal to `--id` | | `runner_id` | `schedule delete` | `--yes` and `--confirm `, exactly equal to `--runner-id` | | `self_update` | `self-update` | `--yes` | | `null` | every other command | none | `runner update` needs `--yes` only with `--product-id`, `--gitlab-host`, `--runner-token-env`, `--concurrency`, `--executor`, `--ssh-key-id` or `--monitoring`, because those recreate an active runner's server. `--name`, `--label` and `--hetzner-token-env` alone do not. A missing confirmation fails with exit code 2 before anything is sent. `self-update` reads the release manifest first, so it can report that nothing needs to change, but downloads nothing without confirmation. Never run `self-update` unless the human asked for it or agreed to it; `version --check` is safe to run. ## Paid and destructive commands Treat every command with `mutation: true` as potentially billable, and check `paid_resource_effect`: - `create`: `runner create`, `runner resume` and `runner duplicate` create Hetzner servers, which Hetzner bills to the user. - `recreate`: `runner update` may delete and recreate an active runner's server, interrupting its jobs. - `delete`: `runner pause` and `runner delete` delete servers. `runner delete` also deletes the IP addresses and the schedule. `runner forget` only removes an `UNKNOWN` runner's record and leaves the server untouched. It is never a substitute for `runner delete`. ## Scopes | Scope | Commands | | --- | --- | | `profile:read` | `auth status`, `profile show`, `org list`, `org use`, resolving `--org` | | `runners:read` | `runner list`, `get`, `watch`, `wait`, `metrics`, `ssh-keys`, `update`, and `--wait` on any runner change | | `runners:write` | `runner create`, `update`, `pause`, `resume`, `duplicate` | | `runners:delete` | `runner delete` | | `runners:forget` | `runner forget` | | `schedules:read` | `schedule get` | | `schedules:write` | `schedule set`, `enable`, `disable`, `delete` | | `products:read` | `product list`, `get`, `locations` | | `providers:ssh-keys:read` | `provider hetzner ssh-keys` | | `subscriptions:read` | `subscription show`, `subscription plans` | `runner update` needs both `runners:read` and `runners:write`, because it reads the runner before writing the merged settings. `--wait` on `create`, `update`, `pause`, `resume` or `duplicate` polls the runner and needs `runners:read` as well. If polling fails, for example with exit code 4 for a missing scope or 7 for a timeout, the change itself was already accepted and is not undone: read the runner before doing anything else. The token's scopes and the member's role both apply. A token cannot manage billing, organizations, members, invitations or other tokens. Imported tokens keep the scopes they were created with; the CLI cannot add scopes to them. ## Credentials for agents - Prefer a token passed through the environment: `MANAGE_RUNNERS_TOKEN`, or `--token-env NAME` for a variable with another name. Nothing is stored. - `auth status --agent` reports where the token comes from in `credential.source` (`environment`, `keyring` or `file`). It never prints the token. - Never print a token, pass it as a literal argument, or write it into files or logs. - Use the file credential store (`--credential-store file`) only when the human agreed to it. - Do not change profiles you were not asked to use. ## Idempotency and unknown outcomes `runner create` and `runner duplicate` send an idempotency key. The CLI generates a random key for each invocation unless you pass `--idempotency-key` (16 to 128 letters, digits, `.`, `_` or `-`). The API deduplicates a request only when the user, organization, route, key and request are all the same. The 24 hours below count from the first attempt with that key, not from when it finished: - **Completed first attempt, retried within 24 hours of the first attempt:** the API returns the original result and creates nothing new. - **Completed first attempt, retried later than that:** the key is forgotten, and the same request creates another runner. - **First attempt not completed** (still running, or interrupted before its result was stored): the API rejects every retry with that key as a conflict (exit code 6), also after 24 hours. Read the state instead of retrying. - **Same key, different request:** the API rejects it as a conflict (exit code 6). So reusing a key only protects a retry made soon after the first attempt, by the same user in the same organization, with the same flags. Never rely on an old key: before retrying a create or duplicate, list the runners and check whether the first attempt already created one. When a change ends with exit code 10 (`UNKNOWN_OUTCOME`), the change may have happened. `error.details` may contain `retryGuidance` and `idempotencyKey`. Read the runner list or the runner, decide what actually happened, and only then continue. ## Organizations Without `--org` or a stored organization, commands use the user's default organization. Use `org list --agent` to see memberships and roles, and `--org ID_OR_NAME` for one invocation. Store an organization with `org use` only when asked. See [Profiles and organizations](https://managerunners.com/docs/cli/profiles-and-organizations/). ## The agent skill The CLI embeds a skill file that tells agents how to use it safely. Install it for your agent: ```sh manage-runners setup skill install --target claude # ~/.claude/skills/manage-runners manage-runners setup skill install --target codex # ~/.codex/skills/manage-runners manage-runners setup skill install --target opencode # opencode skills directory in your user config directory manage-runners setup skill install --path ./skills/manage-runners ``` `setup skill status` reports whether it is installed and unchanged, and `setup skill remove` removes an unmodified copy. `--dry-run` shows what would change. An existing file that the CLI did not install, or a modified copy, is only replaced with `--force`. This is the skill embedded in `manage-runners` (skill version 1): ````markdown --- name: manage-runners description: Operate manage-runners safely through the official CLI. metadata: owner: manage-runners version: "1" --- # Manage Runners Use `manage-runners commands --agent` to discover supported operations and required scopes. Interactive `auth login` and `setup` request `profile:read`, `runners:read`, `schedules:read`, `products:read`, `providers:ssh-keys:read`, and `subscriptions:read` by default. Add write, delete, or forget scopes only when explicitly authorized. PAT imports keep the scopes granted by the server. When a keyring is unavailable, a set `MANAGE_RUNNERS_TOKEN` is used automatically as the PAT for read and runner commands; `--token-env ENV_NAME` overrides it for one invocation. `auth status --agent` reports the credential source. Never print either variable's value; `auth login --token-env` instead imports a PAT into the credential store. To store a credential without a keyring, pass `--credential-store file` or set `MANAGE_RUNNERS_CREDENTIAL_STORE=file`. The CLI keeps only a scoped, expiring PAT in a 0600 file, never the password or 2FA secret; tell the user so, and that it can be revoked in the dashboard or with `auth logout --revoke`. Never select the file store without the user's agreement. Always use `--agent` for automation. Treat mutation commands as potentially billable and require the caller to supply every confirmation requested by command discovery. `runner update` with `--product-id`, `--gitlab-host`, `--runner-token-env`, `--concurrency`, `--executor`, `--ssh-key-id` or `--monitoring` deletes and recreates an active runner's VM and needs `--yes`; `--name`, `--label` and `--hetzner-token-env` alone do not. Use `runner metrics --agent` (optionally `--id`/`--name` and `--range 1h|24h|7d|30d|90d`) to read resource monitoring. `SUBSCRIPTION_REQUIRED` means monitoring needs an active paid subscription; do not retry. Only change monitoring when explicitly asked. Runners, schedules, metrics and the subscription belong to an organization. Without `--org` and a stored organization, commands use the caller's default organization. Use `org list --agent` to see memberships and roles, `--org ID_OR_NAME` for one invocation, or `org use ID_OR_NAME` (`org use --clear`) to store one in the profile only when asked. `ORGANIZATION_PERMISSION_DENIED` means the member's role does not allow the action; do not retry. `ORGANIZATION_NOT_FOUND` means the organization is not among the caller's memberships. `version --check --agent` reports whether a newer CLI release exists and exits 14 when one does; it is safe to run. Never run `self-update` without the user's consent, and pass `--yes` only after they agreed to that update. Never print credentials, pass a token as a literal command argument, or change an unrelated manage-runners profile. ```` ## Machine-readable documentation - Every page of these docs is available as Markdown: add `index.md` to the page URL, for example [this page as Markdown](https://managerunners.com/docs/cli/agents/index.md). - [/llms.txt](https://managerunners.com/llms.txt) lists all pages with their Markdown URLs. - [/llms-full.txt](https://managerunners.com/llms-full.txt) contains the whole documentation, including the command reference, in one file. --- # CLI command reference > Every manage-runners 1.0.1 command with its scopes, safety properties and help text. Source: https://managerunners.com/docs/cli/reference/ This reference is generated from `manage-runners` itself. Each page lists the command's required token scopes, whether it changes state or creates paid resources, which confirmation it needs, and its full help text. The [agent guide](https://managerunners.com/docs/cli/agents/) explains how to read these properties. ## Commands ### general | Command | Summary | | --- | --- | | [`manage-runners commands`](https://managerunners.com/docs/cli/reference/commands/) | List CLI commands | | [`manage-runners help`](https://managerunners.com/docs/cli/reference/help/) | Show command help | | [`manage-runners version`](https://managerunners.com/docs/cli/reference/version/) | Show CLI version metadata; --check compares it with the latest release | | [`manage-runners self-update`](https://managerunners.com/docs/cli/reference/self-update/) | Replace this binary with the latest release, or --version, after verifying its SHA-256 | | [`manage-runners completion`](https://managerunners.com/docs/cli/reference/completion/) | Generate shell completion scripts | | [`manage-runners setup`](https://managerunners.com/docs/cli/reference/setup/) | Run the human setup wizard | | [`manage-runners doctor`](https://managerunners.com/docs/cli/reference/doctor/) | Run read-only diagnostics | ### config | Command | Summary | | --- | --- | | [`manage-runners config show`](https://managerunners.com/docs/cli/reference/config-show/) | Show effective non-secret configuration | | [`manage-runners config profiles`](https://managerunners.com/docs/cli/reference/config-profiles/) | List configured API profiles | | [`manage-runners config set-api`](https://managerunners.com/docs/cli/reference/config-set-api/) | Store an API origin after HTTPS validation; the default profile otherwise uses https://api.managerunners.com | ### setup | Command | Summary | | --- | --- | | [`manage-runners setup skill`](https://managerunners.com/docs/cli/reference/setup-skill/) | Install or manage the embedded agent skill | ### auth | Command | Summary | | --- | --- | | [`manage-runners auth login`](https://managerunners.com/docs/cli/reference/auth-login/) | Store a PAT from stdin or a named environment variable | | [`manage-runners auth status`](https://managerunners.com/docs/cli/reference/auth-status/) | Show authentication status without printing the token | | [`manage-runners auth logout`](https://managerunners.com/docs/cli/reference/auth-logout/) | Remove the local credential; optionally revoke the current PAT | | [`manage-runners auth profiles`](https://managerunners.com/docs/cli/reference/auth-profiles/) | List local profiles without credentials | | [`manage-runners auth use`](https://managerunners.com/docs/cli/reference/auth-use/) | Select the default profile | ### runner | Command | Summary | | --- | --- | | [`manage-runners runner list`](https://managerunners.com/docs/cli/reference/runner-list/) | List owned runners | | [`manage-runners runner get`](https://managerunners.com/docs/cli/reference/runner-get/) | Get one runner by exact ID or unique name | | [`manage-runners runner watch`](https://managerunners.com/docs/cli/reference/runner-watch/) | Poll a runner until a target or terminal state | | [`manage-runners runner metrics`](https://managerunners.com/docs/cli/reference/runner-metrics/) | Show resource monitoring metrics for one or all monitored runners | | [`manage-runners runner ssh-keys`](https://managerunners.com/docs/cli/reference/runner-ssh-keys/) | List SSH keys available through the runner provider credential | | [`manage-runners runner create`](https://managerunners.com/docs/cli/reference/runner-create/) | Create one runner; may create paid Hetzner resources | | [`manage-runners runner update`](https://managerunners.com/docs/cli/reference/runner-update/) | Update one runner; product, GitLab host, runner token, concurrency, executor, SSH key or monitoring changes recreate an active runner's VM | | [`manage-runners runner pause`](https://managerunners.com/docs/cli/reference/runner-pause/) | Pause a runner and delete its active VM | | [`manage-runners runner resume`](https://managerunners.com/docs/cli/reference/runner-resume/) | Resume a paused runner; may create paid Hetzner resources | | [`manage-runners runner duplicate`](https://managerunners.com/docs/cli/reference/runner-duplicate/) | Duplicate a runner; may create paid Hetzner resources | | [`manage-runners runner delete`](https://managerunners.com/docs/cli/reference/runner-delete/) | Delete an active or paused runner | | [`manage-runners runner forget`](https://managerunners.com/docs/cli/reference/runner-forget/) | Remove only an UNKNOWN dashboard record | | [`manage-runners runner wait`](https://managerunners.com/docs/cli/reference/runner-wait/) | Wait for a runner target state after a mutation | ### schedule | Command | Summary | | --- | --- | | [`manage-runners schedule get`](https://managerunners.com/docs/cli/reference/schedule-get/) | Read a runner schedule | | [`manage-runners schedule set`](https://managerunners.com/docs/cli/reference/schedule-set/) | Create or replace a runner schedule | | [`manage-runners schedule enable`](https://managerunners.com/docs/cli/reference/schedule-enable/) | Enable an existing schedule | | [`manage-runners schedule disable`](https://managerunners.com/docs/cli/reference/schedule-disable/) | Disable a schedule without deleting it | | [`manage-runners schedule delete`](https://managerunners.com/docs/cli/reference/schedule-delete/) | Permanently delete a schedule | ### product | Command | Summary | | --- | --- | | [`manage-runners product list`](https://managerunners.com/docs/cli/reference/product-list/) | List GitLab runner products | | [`manage-runners product get`](https://managerunners.com/docs/cli/reference/product-get/) | Get one product by exact ID | | [`manage-runners product locations`](https://managerunners.com/docs/cli/reference/product-locations/) | Show bookable datacenters and prices for a product | ### provider | Command | Summary | | --- | --- | | [`manage-runners provider hetzner ssh-keys`](https://managerunners.com/docs/cli/reference/provider-hetzner-ssh-keys/) | Validate a Hetzner token and list SSH keys | ### profile | Command | Summary | | --- | --- | | [`manage-runners profile show`](https://managerunners.com/docs/cli/reference/profile-show/) | Show the current non-sensitive user profile | ### subscription | Command | Summary | | --- | --- | | [`manage-runners subscription show`](https://managerunners.com/docs/cli/reference/subscription-show/) | Show the current subscription and schedule entitlement | | [`manage-runners subscription plans`](https://managerunners.com/docs/cli/reference/subscription-plans/) | List available subscription plans | ### org | Command | Summary | | --- | --- | | [`manage-runners org list`](https://managerunners.com/docs/cli/reference/org-list/) | List your organizations with role and default marker | | [`manage-runners org use`](https://managerunners.com/docs/cli/reference/org-use/) | Store the organization for the profile's organization-scoped commands, or clear it | ## Global flags These flags work with every command. ```text --agent agent mode: JSON and non-interactive --api-url string API origin; must match the selected profile --credential-store string credential store: keyring|file, also via $MANAGE_RUNNERS_CREDENTIAL_STORE; file keeps only a scoped, expiring PAT in a 0600 file, never your password or 2FA secret (default "keyring") --json emit JSON --no-color disable color output --non-interactive disable prompts --org string organization id or name for runner, schedule, subscription and provider commands; overrides the profile's organization --output string output format: human|json|jsonl (default "human") --profile string configured API profile --request-id string request ID sent to the API --timeout duration maximum command duration (for example 30s) --token-env string named PAT environment variable for this invocation; overrides $MANAGE_RUNNERS_TOKEN; nothing is stored ``` --- # manage-runners commands > List CLI commands Source: https://managerunners.com/docs/cli/reference/commands/ | | | | --- | --- | | Required scopes | none | | Required flags | none | | Changes state | no | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text List CLI commands Usage: manage-runners commands [flags] ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help commands --output json`. --- # manage-runners help > Show command help Source: https://managerunners.com/docs/cli/reference/help/ | | | | --- | --- | | Required scopes | none | | Required flags | none | | Changes state | no | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text Show command help Usage: manage-runners help [flags] Flags: -h, --help help for help ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help help --output json`. --- # manage-runners version > Show CLI version metadata; --check compares it with the latest release Source: https://managerunners.com/docs/cli/reference/version/ | | | | --- | --- | | Required scopes | none | | Required flags | none | | Changes state | no | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text Show CLI version metadata; --check compares it with the latest release Usage: manage-runners version [flags] Flags: --check also read the latest release from the downloads server; exits 14 when an update is available ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help version --output json`. --- # manage-runners self-update > Replace this binary with the latest release, or --version, after verifying its SHA-256 Source: https://managerunners.com/docs/cli/reference/self-update/ | | | | --- | --- | | Required scopes | none | | Required flags | none | | Changes state | yes | | Destructive | no | | Paid resource effect | none | | Confirmation | `self_update` | | Non-interactive use | supported | ## Usage ```text Replace this binary with the latest release, or --version, after verifying its SHA-256 Usage: manage-runners self-update [flags] Flags: --version string install this release (MAJOR.MINOR.PATCH) instead of the latest; required to downgrade --yes confirm replacing the installed binary; required in non-interactive mode ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help self-update --output json`. --- # manage-runners config show > Show effective non-secret configuration Source: https://managerunners.com/docs/cli/reference/config-show/ | | | | --- | --- | | Required scopes | none | | Required flags | none | | Changes state | no | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text Show effective non-secret configuration Usage: manage-runners config show [flags] Flags: --profile string configuration profile ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help config show --output json`. --- # manage-runners config profiles > List configured API profiles Source: https://managerunners.com/docs/cli/reference/config-profiles/ | | | | --- | --- | | Required scopes | none | | Required flags | none | | Changes state | no | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text List configured API profiles Usage: manage-runners config profiles [flags] ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help config profiles --output json`. --- # manage-runners config set-api > Store an API origin after HTTPS validation; the default profile otherwise uses https://api.managerunners.com Source: https://managerunners.com/docs/cli/reference/config-set-api/ | | | | --- | --- | | Required scopes | none | | Required flags | `--profile`, `--url` | | Changes state | yes | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text Store an API origin after HTTPS validation; the default profile otherwise uses https://api.managerunners.com Usage: manage-runners config set-api [flags] Flags: --profile string profile --url string url ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help config set-api --output json`. --- # manage-runners completion > Generate shell completion scripts Source: https://managerunners.com/docs/cli/reference/completion/ | | | | --- | --- | | Required scopes | none | | Required flags | `--shell` | | Changes state | no | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text Generate shell completion scripts Usage: manage-runners completion [flags] Flags: --shell string shell ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help completion --output json`. --- # manage-runners setup > Run the human setup wizard Source: https://managerunners.com/docs/cli/reference/setup/ | | | | --- | --- | | Required scopes | none | | Required flags | none | | Changes state | yes | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | not supported | ## Usage ```text Run the human setup wizard Usage: manage-runners setup [flags] manage-runners setup [command] Available Commands: skill Install or manage the embedded agent skill ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help setup --output json`. --- # manage-runners setup skill > Install or manage the embedded agent skill Source: https://managerunners.com/docs/cli/reference/setup-skill/ | | | | --- | --- | | Required scopes | none | | Required flags | none | | Changes state | yes | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text Install or manage the embedded agent skill Usage: manage-runners setup skill [flags] Flags: --dry-run report changes without writing --force replace an existing skill --path string custom skill directory --target string official agent target: opencode|claude|codex ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help setup skill --output json`. --- # manage-runners doctor > Run read-only diagnostics Source: https://managerunners.com/docs/cli/reference/doctor/ | | | | --- | --- | | Required scopes | none | | Required flags | none | | Changes state | no | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text Run read-only diagnostics Usage: manage-runners doctor [flags] Flags: --profile string configuration profile ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help doctor --output json`. --- # manage-runners auth login > Store a PAT from stdin or a named environment variable Source: https://managerunners.com/docs/cli/reference/auth-login/ | | | | --- | --- | | Required scopes | none | | Required flags | none | | Changes state | yes | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text Log in interactively, or import a PAT from stdin or a named environment variable. The CLI stores only a scoped, expiring personal access token (PAT), never your password or 2FA secret. It uses the system keyring by default; on headless systems without one, pass --credential-store file (or set MANAGE_RUNNERS_CREDENTIAL_STORE=file) to keep the PAT in a 0600 file under the user config directory. Revoke the PAT in the dashboard or with `manage-runners auth logout --revoke`. Usage: manage-runners auth login [flags] Flags: --profile string configuration profile --scope strings additional PAT scope (repeatable; interactive login only) --token-env string read token from a named environment variable --token-stdin read token from stdin ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help auth login --output json`. --- # manage-runners auth status > Show authentication status without printing the token Source: https://managerunners.com/docs/cli/reference/auth-status/ | | | | --- | --- | | Required scopes | `profile:read` | | Required flags | none | | Changes state | no | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text Show authentication status without printing the token Usage: manage-runners auth status [flags] Flags: --profile string configuration profile ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help auth status --output json`. --- # manage-runners auth logout > Remove the local credential; optionally revoke the current PAT Source: https://managerunners.com/docs/cli/reference/auth-logout/ | | | | --- | --- | | Required scopes | none | | Required flags | none | | Changes state | yes | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text Remove the local credential; optionally revoke the current PAT Usage: manage-runners auth logout [flags] Flags: --profile string configuration profile --revoke revoke the current PAT remotely before local removal ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help auth logout --output json`. --- # manage-runners auth profiles > List local profiles without credentials Source: https://managerunners.com/docs/cli/reference/auth-profiles/ | | | | --- | --- | | Required scopes | none | | Required flags | none | | Changes state | no | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text List local profiles without credentials Usage: manage-runners auth profiles [flags] ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help auth profiles --output json`. --- # manage-runners auth use > Select the default profile Source: https://managerunners.com/docs/cli/reference/auth-use/ | | | | --- | --- | | Required scopes | none | | Required flags | none | | Changes state | yes | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text Select the default profile Usage: manage-runners auth use [flags] ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help auth use --output json`. --- # manage-runners runner list > List owned runners Source: https://managerunners.com/docs/cli/reference/runner-list/ | | | | --- | --- | | Required scopes | `runners:read` | | Required flags | none | | Changes state | no | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text List owned runners Usage: manage-runners runner list [flags] Flags: --profile string configuration profile ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help runner list --output json`. --- # manage-runners runner get > Get one runner by exact ID or unique name Source: https://managerunners.com/docs/cli/reference/runner-get/ | | | | --- | --- | | Required scopes | `runners:read` | | Required flags | none | | Changes state | no | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text Get one runner by exact ID or unique name Usage: manage-runners runner get [flags] Flags: --id string runner id --name string exact runner name --profile string configuration profile ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help runner get --output json`. --- # manage-runners runner watch > Poll a runner until a target or terminal state Source: https://managerunners.com/docs/cli/reference/runner-watch/ | | | | --- | --- | | Required scopes | `runners:read` | | Required flags | `--id` | | Changes state | no | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text Poll a runner until a target or terminal state Usage: manage-runners runner watch [flags] Flags: --id string id --interval string polling interval --profile string configuration profile --timeout string maximum polling duration ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help runner watch --output json`. --- # manage-runners runner metrics > Show resource monitoring metrics for one or all monitored runners Source: https://managerunners.com/docs/cli/reference/runner-metrics/ | | | | --- | --- | | Required scopes | `runners:read` | | Required flags | none | | Changes state | no | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text Show resource monitoring metrics for one or all monitored runners Usage: manage-runners runner metrics [flags] Flags: --id string runner id; omit --id and --name for all monitored runners --name string exact runner name --profile string configuration profile --range string history range: 1h|24h|7d|30d|90d (default "24h") ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help runner metrics --output json`. --- # manage-runners runner ssh-keys > List SSH keys available through the runner provider credential Source: https://managerunners.com/docs/cli/reference/runner-ssh-keys/ | | | | --- | --- | | Required scopes | `runners:read` | | Required flags | `--id` | | Changes state | no | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text List SSH keys available through the runner provider credential Usage: manage-runners runner ssh-keys [flags] Flags: --id string id --profile string configuration profile ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help runner ssh-keys --output json`. --- # manage-runners runner create > Create one runner; may create paid Hetzner resources Source: https://managerunners.com/docs/cli/reference/runner-create/ | | | | --- | --- | | Required scopes | `runners:write`; also `runners:read` with `--wait` | | Required flags | none | | Changes state | yes | | Destructive | no | | Paid resource effect | `create` | | Confirmation | `paid_resource` | | Non-interactive use | supported | > This command may create paid Hetzner resources. Read [confirmations](https://managerunners.com/docs/cli/agents/#confirmations) before running it non-interactively. ## Usage ```text Create one runner; may create paid Hetzner resources Usage: manage-runners runner create [flags] Flags: --concurrency int runner concurrency --executor string runner executor --gitlab-host string GitLab host --hetzner-token-env string environment variable containing the Hetzner token --idempotency-key string idempotency key --interval duration polling interval (default 2s) --label stringArray runner label --location string Hetzner location --monitoring string resource monitoring: on|off; on requires an active paid subscription --name string runner name --product-id string product id --profile string configuration profile --runner-token-env string environment variable containing the runner token --ssh-key-id stringArray SSH key id --timeout duration maximum wait duration (default 10m0s) --wait wait for a terminal runner state --yes confirm the paid resource operation ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help runner create --output json`. --- # manage-runners runner update > Update one runner; product, GitLab host, runner token, concurrency, executor, SSH key or monitoring changes recreate an active runner's VM Source: https://managerunners.com/docs/cli/reference/runner-update/ | | | | --- | --- | | Required scopes | `runners:read`, `runners:write` | | Required flags | `--id` | | Changes state | yes | | Destructive | no | | Paid resource effect | `recreate` | | Confirmation | `paid_resource` | | Non-interactive use | supported | > This command may delete and recreate an active runner's VM. Read [confirmations](https://managerunners.com/docs/cli/agents/#confirmations) before running it non-interactively. ## Usage ```text Update one runner; product, GitLab host, runner token, concurrency, executor, SSH key or monitoring changes recreate an active runner's VM Usage: manage-runners runner update [flags] Flags: --concurrency int runner concurrency --executor string runner executor --gitlab-host string GitLab host --hetzner-token-env string environment variable containing the Hetzner token --id string id --interval duration polling interval (default 2s) --label stringArray runner label --monitoring string resource monitoring: on|off; on requires an active paid subscription --name string runner name --product-id string product id --profile string configuration profile --runner-token-env string environment variable containing the runner token --ssh-key-id stringArray SSH key id --timeout duration maximum wait duration (default 10m0s) --wait wait for a terminal runner state --yes confirm recreating an active runner's VM; required with --product-id, --gitlab-host, --runner-token-env, --concurrency, --executor, --ssh-key-id or --monitoring ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help runner update --output json`. --- # manage-runners runner pause > Pause a runner and delete its active VM Source: https://managerunners.com/docs/cli/reference/runner-pause/ | | | | --- | --- | | Required scopes | `runners:write`; also `runners:read` with `--wait` | | Required flags | `--id` | | Changes state | yes | | Destructive | yes | | Paid resource effect | `delete` | | Confirmation | `paid_resource` | | Non-interactive use | supported | > This command deletes Hetzner resources. Read [confirmations](https://managerunners.com/docs/cli/agents/#confirmations) before running it non-interactively. ## Usage ```text Pause a runner and delete its active VM Usage: manage-runners runner pause [flags] Flags: --id string id --interval duration polling interval (default 2s) --profile string configuration profile --timeout duration maximum wait duration (default 10m0s) --wait wait for a terminal runner state --yes confirm the destructive operation ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help runner pause --output json`. --- # manage-runners runner resume > Resume a paused runner; may create paid Hetzner resources Source: https://managerunners.com/docs/cli/reference/runner-resume/ | | | | --- | --- | | Required scopes | `runners:write`; also `runners:read` with `--wait` | | Required flags | `--id` | | Changes state | yes | | Destructive | no | | Paid resource effect | `create` | | Confirmation | `paid_resource` | | Non-interactive use | supported | > This command may create paid Hetzner resources. Read [confirmations](https://managerunners.com/docs/cli/agents/#confirmations) before running it non-interactively. ## Usage ```text Resume a paused runner; may create paid Hetzner resources Usage: manage-runners runner resume [flags] Flags: --id string id --interval duration polling interval (default 2s) --profile string configuration profile --timeout duration maximum wait duration (default 10m0s) --wait wait for a terminal runner state --yes confirm the destructive operation ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help runner resume --output json`. --- # manage-runners runner duplicate > Duplicate a runner; may create paid Hetzner resources Source: https://managerunners.com/docs/cli/reference/runner-duplicate/ | | | | --- | --- | | Required scopes | `runners:write`; also `runners:read` with `--wait` | | Required flags | `--id` | | Changes state | yes | | Destructive | no | | Paid resource effect | `create` | | Confirmation | `paid_resource` | | Non-interactive use | supported | > This command may create paid Hetzner resources. Read [confirmations](https://managerunners.com/docs/cli/agents/#confirmations) before running it non-interactively. ## Usage ```text Duplicate a runner; may create paid Hetzner resources Usage: manage-runners runner duplicate [flags] Flags: --id string id --idempotency-key string idempotency key --interval duration polling interval (default 2s) --profile string configuration profile --timeout duration maximum wait duration (default 10m0s) --wait wait for a terminal runner state --yes confirm the destructive operation ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help runner duplicate --output json`. --- # manage-runners runner delete > Delete an active or paused runner Source: https://managerunners.com/docs/cli/reference/runner-delete/ | | | | --- | --- | | Required scopes | `runners:delete` | | Required flags | `--id` | | Changes state | yes | | Destructive | yes | | Paid resource effect | `delete` | | Confirmation | `runner_id` | | Non-interactive use | supported | > This command deletes Hetzner resources. Read [confirmations](https://managerunners.com/docs/cli/agents/#confirmations) before running it non-interactively. ## Usage ```text Delete an active or paused runner Usage: manage-runners runner delete [flags] Flags: --confirm string runner id confirmation --id string id --profile string configuration profile --yes confirm the destructive operation ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help runner delete --output json`. --- # manage-runners runner forget > Remove only an UNKNOWN dashboard record Source: https://managerunners.com/docs/cli/reference/runner-forget/ | | | | --- | --- | | Required scopes | `runners:forget` | | Required flags | `--id` | | Changes state | yes | | Destructive | yes | | Paid resource effect | none | | Confirmation | `runner_id` | | Non-interactive use | supported | > This command permanently removes data. Read [confirmations](https://managerunners.com/docs/cli/agents/#confirmations) before running it non-interactively. ## Usage ```text Remove only an UNKNOWN dashboard record Usage: manage-runners runner forget [flags] Flags: --confirm string runner id confirmation --id string id --profile string configuration profile --yes confirm the destructive operation ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help runner forget --output json`. --- # manage-runners runner wait > Wait for a runner target state after a mutation Source: https://managerunners.com/docs/cli/reference/runner-wait/ | | | | --- | --- | | Required scopes | `runners:read` | | Required flags | `--id` | | Changes state | no | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text Wait for a runner target state after a mutation Usage: manage-runners runner wait [flags] Flags: --id string id --interval string polling interval --profile string configuration profile --state string target runner state --timeout string maximum polling duration ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help runner wait --output json`. --- # manage-runners schedule get > Read a runner schedule Source: https://managerunners.com/docs/cli/reference/schedule-get/ | | | | --- | --- | | Required scopes | `schedules:read` | | Required flags | `--runner-id` | | Changes state | no | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text Read a runner schedule Usage: manage-runners schedule get [flags] Flags: --profile string configuration profile --runner-id string runner-id ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help schedule get --output json`. --- # manage-runners schedule set > Create or replace a runner schedule Source: https://managerunners.com/docs/cli/reference/schedule-set/ | | | | --- | --- | | Required scopes | `schedules:write` | | Required flags | `--runner-id` | | Changes state | yes | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text Create or replace a runner schedule Usage: manage-runners schedule set [flags] Flags: --day stringArray day of week --duration-minutes int schedule duration in minutes --enabled enable the schedule --profile string configuration profile --runner-id string runner-id --start string start time in HH:MM --stop string stop time in HH:MM --zone-id string IANA time zone ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help schedule set --output json`. --- # manage-runners schedule enable > Enable an existing schedule Source: https://managerunners.com/docs/cli/reference/schedule-enable/ | | | | --- | --- | | Required scopes | `schedules:write` | | Required flags | `--runner-id` | | Changes state | yes | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text Enable an existing schedule Usage: manage-runners schedule enable [flags] Flags: --profile string configuration profile --runner-id string runner-id ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help schedule enable --output json`. --- # manage-runners schedule disable > Disable a schedule without deleting it Source: https://managerunners.com/docs/cli/reference/schedule-disable/ | | | | --- | --- | | Required scopes | `schedules:write` | | Required flags | `--runner-id` | | Changes state | yes | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text Disable a schedule without deleting it Usage: manage-runners schedule disable [flags] Flags: --profile string configuration profile --runner-id string runner-id ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help schedule disable --output json`. --- # manage-runners schedule delete > Permanently delete a schedule Source: https://managerunners.com/docs/cli/reference/schedule-delete/ | | | | --- | --- | | Required scopes | `schedules:write` | | Required flags | `--runner-id` | | Changes state | yes | | Destructive | yes | | Paid resource effect | none | | Confirmation | `runner_id` | | Non-interactive use | supported | > This command permanently removes data. Read [confirmations](https://managerunners.com/docs/cli/agents/#confirmations) before running it non-interactively. ## Usage ```text Permanently delete a schedule Usage: manage-runners schedule delete [flags] Flags: --confirm string runner id confirmation --profile string configuration profile --runner-id string runner-id --yes confirm the destructive operation ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help schedule delete --output json`. --- # manage-runners product list > List GitLab runner products Source: https://managerunners.com/docs/cli/reference/product-list/ | | | | --- | --- | | Required scopes | `products:read` | | Required flags | none | | Changes state | no | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text List GitLab runner products Usage: manage-runners product list [flags] Flags: --profile string configuration profile ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help product list --output json`. --- # manage-runners product get > Get one product by exact ID Source: https://managerunners.com/docs/cli/reference/product-get/ | | | | --- | --- | | Required scopes | `products:read` | | Required flags | `--id` | | Changes state | no | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text Get one product by exact ID Usage: manage-runners product get [flags] Flags: --id string id --profile string configuration profile ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help product get --output json`. --- # manage-runners product locations > Show bookable datacenters and prices for a product Source: https://managerunners.com/docs/cli/reference/product-locations/ | | | | --- | --- | | Required scopes | `products:read` | | Required flags | `--id` | | Changes state | no | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text Show bookable datacenters and prices for a product Usage: manage-runners product locations [flags] Flags: --id string id --profile string configuration profile ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help product locations --output json`. --- # manage-runners provider hetzner ssh-keys > Validate a Hetzner token and list SSH keys Source: https://managerunners.com/docs/cli/reference/provider-hetzner-ssh-keys/ | | | | --- | --- | | Required scopes | `providers:ssh-keys:read` | | Required flags | none | | Changes state | no | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text Validate a Hetzner token and list SSH keys Usage: manage-runners provider hetzner ssh-keys [flags] Flags: --profile string configuration profile --token-env string read provider token from a named environment variable --token-stdin read provider token from stdin ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help provider hetzner ssh-keys --output json`. --- # manage-runners profile show > Show the current non-sensitive user profile Source: https://managerunners.com/docs/cli/reference/profile-show/ | | | | --- | --- | | Required scopes | `profile:read` | | Required flags | none | | Changes state | no | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text Show the current non-sensitive user profile Usage: manage-runners profile show [flags] Flags: --profile string configuration profile ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help profile show --output json`. --- # manage-runners subscription show > Show the current subscription and schedule entitlement Source: https://managerunners.com/docs/cli/reference/subscription-show/ | | | | --- | --- | | Required scopes | `subscriptions:read` | | Required flags | none | | Changes state | no | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text Show the current subscription and schedule entitlement Usage: manage-runners subscription show [flags] Flags: --profile string configuration profile ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help subscription show --output json`. --- # manage-runners subscription plans > List available subscription plans Source: https://managerunners.com/docs/cli/reference/subscription-plans/ | | | | --- | --- | | Required scopes | `subscriptions:read` | | Required flags | none | | Changes state | no | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text List available subscription plans Usage: manage-runners subscription plans [flags] Flags: --profile string configuration profile ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help subscription plans --output json`. --- # manage-runners org list > List your organizations with role and default marker Source: https://managerunners.com/docs/cli/reference/org-list/ | | | | --- | --- | | Required scopes | `profile:read` | | Required flags | none | | Changes state | no | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text List your organizations with role and default marker Usage: manage-runners org list [flags] Flags: --profile string configuration profile ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help org list --output json`. --- # manage-runners org use > Store the organization for the profile's organization-scoped commands, or clear it Source: https://managerunners.com/docs/cli/reference/org-use/ | | | | --- | --- | | Required scopes | `profile:read` | | Required flags | none | | Changes state | yes | | Destructive | no | | Paid resource effect | none | | Confirmation | none | | Non-interactive use | supported | ## Usage ```text Store the organization for the profile's organization-scoped commands, or clear it Usage: manage-runners org use [flags] Flags: --clear remove the stored organization so the default organization is used --profile string configuration profile ``` Every command also accepts the [global flags](https://managerunners.com/docs/cli/reference/#global-flags). For machine-readable help, run `manage-runners help org use --output json`.