---
title: "Machine runner 3 configuration reference"
description: "Reference for the machine runner 3 YAML configuration file parameters."
platform: "Cloud, Server"
doc_version: "unversioned"
last_updated: "2026-10-14"
---

> For current CircleCI product defaults, deprecated patterns, and Cloud/Server differences, see [AGENTS.md](https://circleci.com/docs/AGENTS.md).
>
> For the complete documentation index and site structure, see [llms.txt](https://circleci.com/docs/llms.txt).

# Machine runner 3 configuration reference

A YAML file is used to configure the machine runner, how it communicates with CircleCI’s servers, and how it will launch the task-agent. This page explains all available parameters.

## Introduction

The configuration file uses the following format with the various parameters explained in more detail below, and is by default located at `/etc/circleci-runner/circleci-runner-config.yaml` on Linux machines.

```yaml
api:
  auth_token: << AUTH TOKEN >>
runner:
  name: runner-name-001
  working_directory: "/var/lib/circleci-runner/workdir"
  cleanup_working_directory: true
logging:
  level: "info"
  format: "text"
  file: "-"
```

Machine runner can also be configured via environment variables. These will be prioritized over the YAML file, if set.

* * *

### `api.auth_token`

`$CIRCLECI_RUNNER_API_AUTH_TOKEN`

The token is used to identify the machine runner to CircleCI and can be generated by the [CircleCI CLI](https://circleci.com/docs/guides/toolkit/circleci-cli/). An existing token may be shared among many installations, but this token only allows a particular `resource_class` to be specified.

* * *

### `api.url`

`$CIRCLECI_RUNNER_API_URL`

The URL points to `https://runner.circleci.com` by default. Do not modify it unless you have a CircleCI Server installation. In that case, set it to the URL of your Server installation.

* * *

### runner.name

`$CIRCLECI_RUNNER_NAME`

`RUNNER_NAME` is a unique name of your choosing assigned to this particular machine runner. CircleCI recommends using the hostname of the machine so that it can be used to identify the agent when viewing statuses and job results in the CircleCI web app. The only special characters accepted in `RUNNER_NAME` are `. () - _`.

* * *

### logging.level

`$CIRCLECI_RUNNER_LOGGING_LEVEL`

This sets the logging level for the `circleci-runner` service. The available logging levels are `debug`, `info`, `warn`, and `error`. By default, the logging level is set to `info`.

Example:

```yaml
logging:
  level: "info"
```

* * *

### logging.format

`$CIRCLECI_RUNNER_LOGGING_FORMAT`

This sets the logging format for the `circleci-runner` service used for stderr and file logging. The available formats are:

*   `color`: The default logging format, with color.
    
*   `text`: Disables color but maintains standard logging output.
    
*   `json`: Outputs logs in JSON format.
    
*   `none`: Disables logging entirely.
    

Example:

```yaml
logging:
  format: "color"
```

* * *

### logging.file

`$CIRCLECI_RUNNER_LOGGING_FILE`

This controls the file where the machine runner and task-agent logs will go. See [Runner Concepts](https://circleci.com/docs/runner/runner-concepts/#task-agent) for more information on task-agent.

Example:

```yaml
logging:
  file: "-"
```

* * *

### runner.task\_agent\_directory

`$CIRCLECI_RUNNER_TASK_AGENT_DIRECTORY`

This parameter specifies the directory path where the task-agent binary is downloaded and executed by machine runner, defaulting to `~/.local/libexec/circleci`.

```yaml
runner:
  task_agent_directory: "~/.local/libexec/circleci"
```

* * *

### runner.command\_prefix

`$CIRCLECI_RUNNER_COMMAND_PREFIX`

This prefix takes a YAML list of arguments that wraps and runs the task-agent.

For example, `sudo` can elevate permissions:

```yaml
runner:
  command_prefix: ["sudo", "-niHu", "USERNAME", "--"]
```

The prefix can also be a custom script. The arguments passed to the script will launch the task-agent.

The custom script must:

*   Take great care to ensure the task-agent (that is, the arguments passed to it) runs.
    
*   Forward the exit code from task-agent as its own exit code.
    

Example script saved as `/var/opt/circleci/wrapper.sh`:

```bash
#!/bin/bash

task_agent_cmd=${@:1}
echo "About to run CircleCI task agent: ${task_agent_cmd}"
$task_agent_cmd
exit=$?
echo "CircleCI task agent finished."
exit $exit
```

Here is the configuration snippet for the example above:

```yaml
runner:
  command_prefix: ["/var/opt/circleci/wrapper.sh"]
```

* * *

### runner.working\_directory

`$CIRCLECI_RUNNER_WORK_DIR`

This directory takes a fully qualified path and allows you to control the default working directory used by each job. If the directory already exists, the task-agent will need permissions to write to the directory. If the directory does not exist, then the task-agent will need permissions to create the directory.

These directories will not be removed automatically, see `cleanup_working_directory` to configure cleanup of directory.

For Machine Runner 3.0, the `%s` substitution feature is not supported. The `%s` value in the working directory path would be interpreted as a literal value.

Example:

```yaml
runner:
  working_directory: "/var/lib/circleci-runner/workdir"
```

* * *

### runner.cleanup\_working\_directory

`$CIRCLECI_RUNNER_CLEANUP_WORK_DIR`

This flag enables you to control the working directory cleanup after each job.

The possible values are:

*   `true`
    
*   `false`
    

The default value is `false`.

Example:

```yaml
runner:
  cleanup_working_directory: true
```

* * *

### runner.use\_home\_ssh\_dir\_for\_checkout\_keys

`$USE_HOME_SSH_DIR_FOR_CHECKOUT_KEYS`

This flag enables you to use the home directory of the user running the self-hosted runner instance for storing SSH checkout keys.

The possible values are:

*   `true`
    
*   `false`
    

The default value is `false`.

Example:

```yaml
runner:
   use_home_ssh_dir_for_checkout_keys: true
```

* * *

### runner.mode

`$CIRCLECI_RUNNER_MODE`

This parameter allows you to specify whether you want to terminate this self-hosted runner process upon completion of a job (`single-task`), or to continuously poll for new available jobs (`continuous`).

The possible values are:

*   `continuous`
    
*   `single-task`
    

The default value is `continuous`.

Example:

```yaml
runner:
  mode: continuous
```

When using `single-task` mode, the runner process will restart while the machine instance will continue. However, you may find it useful to terminate the machine instance itself. You can do this on Linux based machines by adding the following to the systemd unit file:

```bash
ExecStopPost=shutdown now -h
Restart=no
User=root
```

However to avoid running as root we recommend stepping down the `circleci` user using `runner.command_prefix` as in our [example above](#runner-command-prefix).

Example:

```yaml
runner:
  command_prefix: ["sudo", "-niHu", "circleci", "--"]
  mode: single-task
```

* * *

### runner.cache\_task\_agent

`$CIRCLECI_RUNNER_CACHE_TASK_AGENT`

When set to true, machine runner will not clear the task-agent cache when the agent shuts down. On startup, the machine agent checks for an already downloaded task agent. It uses that task-agent unless a newer version is available for download. This feature is off by default. This may be particularly useful for Windows which relies on `single-task` mode.

Example:

```yaml
runner:
  cache_task_agent: true
```

* * *

### runner.max\_run\_time

`$CIRCLECI_RUNNER_MAX_RUN_TIME`

This value can be used to override the default maximum duration the task-agent will run each job. Note that the value is a string with the following unit identifiers `h`, `m` or `s` for hours, minutes, and seconds respectively:

Here are a few valid examples:

*   `72h` - 3 days
    
*   `1h30m` - 1 hour 30 minutes.
    
*   `30s` - 30 seconds
    
*   `50m` - 50 minutes
    
*   `1h30m20s` - An overly specific (yet still valid) duration.
    

The default value is 5 hours.

Example:

```yaml
runner:
  max_run_time: 5h
```

#### Customizing job timeouts and drain timeouts

If you would like to customize the job timeout setting, you can “drain” the job by sending the machine runner a termination (TERM) signal. This causes the machine runner to attempt to gracefully shut down. When this TERM signal is received, the machine runner enters _draining_ mode. This prevents the machine runner from accepting any new jobs, but still allows any current active job to be completed. At the end of _draining_, the machine runner then signals the task-agent to cancel any active job (by sending it a TERM signal).

If the task-agent does not exit a brief period after the TERM, the machine runner will manually kill it by sending it a KILL signal.

Draining can end in one of two ways:

*   The task has been in the draining state for longer than the configured `max_run_time`.
    
*   An additional TERM signal is received by the machine runner during _draining_.
    

With [`runner.enable_unsafe_retries`](#runner-enable-unsafe-retries) enabled, the machine runner does not drain. It releases the active job for a retry and exits.

* * *

### runner.idle\_timeout

`$CIRCLECI_RUNNER_IDLE_TIMEOUT`

This timeout will enable a machine runner to terminate if no task has been claimed within the given time period. The value is a string with the following unit identifiers: `h`, `m` or `s` for hours, minutes, and seconds respectively (for example, `5m` is 5 minutes).

The default behaviour is to never time out due to inactivity.

Example:

```yaml
runner:
  idle_timeout: 1h
```

* * *

### runner.enable\_unsafe\_retries

`$CIRCLECI_RUNNER_ENABLE_UNSAFE_RETRIES`

This flag enables machine runner to release a running job for a retry when the runner shuts down, instead of failing the job.

A retried job reruns from the start, including steps that already ran. Only enable this flag for idempotent jobs, which are safe to run more than once. Avoid it for jobs with side effects such as deployments or database changes.

Unsafe retries suit hosts on spot instances, which cost less than dedicated instances, but the provider can reclaim them with little warning.

With unsafe retries enabled:

*   When the runner receives a `SIGINT`, `SIGTERM`, or `SIGHUP` signal, it releases the running job. The runner does not wait for the job to finish.
    
*   Any runner for the same resource class can claim the released job.
    
*   CircleCI allows up to three retries per job. After that, the job fails.
    
*   Any other error still fails the job. This includes errors in job steps and jobs that exceed `max_run_time`.
    

The default value is `false`.

Example:

```yaml
runner:
  enable_unsafe_retries: true
```

* * *

### `runner.ssh.advertise_addr`

`$CIRCLECI_RUNNER_SSH_ADVERTISE_ADDR`

This parameter enables the “Rerun job with SSH” feature. Before enabling this feature, review the [important considerations](#considerations-before-enabling-ssh-debugging). This parameter applies to machine runner 3 only. For container runner, refer to [Enable Rerun Job With SSH](https://circleci.com/docs/runner/container-runner-installation/#enable-rerun-job-with-ssh).

The address is of the form `**host:port**` and is displayed in the “Enable SSH” and “Wait for SSH” sections for a job that is rerun.

While the presence of the `runner.ssh.advertise_addr` variable enables the “Rerun job with SSH” feature, the value it holds is for publishing purposes only in the web app. The address does not need to match the actual host and port of the machine that the self-hosted runner is installed on, and can be a proxy configuration.

Example:

```yaml
runner:
  ssh:
    advertise_addr: HOSTNAME:54782
```

#### Considerations before enabling SSH debugging

Task-agent runs an embedded SSH server and agent on a dedicated port when the “Rerun job with SSH” option is activated. This feature will not affect any other SSH servers or agents on the system that the self-hosted runner is installed on.

*   The host port used by the SSH server is currently fixed to `**54782**`. Ensure this port is unblocked and available for SSH connections. A port conflict can occur if multiple machine runners are installed on the same host.
    
*   The SSH server will inherit the same user privileges and associated access authorizations as the task-agent, defined by the [runner.command\_prefix parameter](#runner-command-prefix).
    
*   The SSH server is configured for public key authentication. Anyone with permission to initiate a job can rerun it with SSH. However, only the user who initiated the rerun will have their SSH public keys added to the server for the duration of the SSH session.
    
*   Rerunning a job with SSH holds the job open for **two hours** if a connection is made to the SSH server. If no connection is made the job is held open for **ten minutes** unless cancelled. While in this state, the job is counted against an organization’s concurrency limit, and the task-agent will be unavailable to handle other jobs.
    
*   Cancel an SSH rerun job explicitly (through the web UI or CLI) when you finish debugging.
    

* * *

### Basic full configuration for a machine runner

The fields you must set for a specific job to run using your self-hosted runners are:

*   `machine: true`
    
*   `resource_class: <namespace>/<resource-class>`
    

Simple example of how you could set up a job:

```yaml
version: 2.1

workflows:
  build-workflow:
    jobs:
      - runner
jobs:
  runner:
    machine: true
    resource_class: <namespace>/<resource-class>
    steps:
      - run: echo "Hi I'm on Runners!"
```

The job will then execute using your self-hosted runner when you push the `.circleci/config.yml` to your VCS provider.