# FAQs

Frequently asked questions about Copia Actions Runners, including compatibility with GitHub Actions, security, troubleshooting, and platform support.

## General

<details>

<summary><strong>Do I need to enable Actions on each repository?</strong></summary>

Yes. Actions are enabled per-repository. Go to your repository on Copia, then **Settings > Actions**, and check **Enable Repository Actions**.

</details>

<details>

<summary><strong>Where do workflow files go?</strong></summary>

Workflow files are stored in the `.copia/workflows/` directory of your repository, with a `.yaml` or `.yml` extension. For example: `.copia/workflows/ci.yaml`.

</details>

<details>

<summary><strong>Can I trigger a workflow manually?</strong></summary>

Yes. Add `workflow_dispatch` to your workflow's `on:` triggers, then use the **Run Workflow** button on the Actions tab in the Copia UI.

</details>

<details>

<summary><strong>Can I run workflows on a schedule?</strong></summary>

Scheduling workflows is not available at this time.

</details>

## Compatibility with GitHub Actions

<details>

<summary><strong>How compatible is Copia Actions with GitHub Actions?</strong></summary>

Copia Actions workflow syntax is designed to be largely compatible with GitHub Actions. Most GitHub Actions workflows can be adapted with minimal changes. The main differences are:

* Workflow files go in `.copia/workflows/` instead of `.github/workflows/`.
* Some advanced syntax features are not yet supported (see below).
* Actions are downloaded from GitHub by default, but you can use absolute URLs to reference actions from any Git repository.

</details>

<details>

<summary><strong>Which GitHub Actions syntax features are not supported?</strong></summary>

The following workflow syntax features are currently **not supported** and will be ignored if present:

| Feature                                     | Notes                                                    |
| ------------------------------------------- | -------------------------------------------------------- |
| `concurrency`                               | Running a single job at a time is not enforced           |
| `permissions` / `jobs.<job_id>.permissions` | Job-level permission scoping is not available            |
| `jobs.<job_id>.timeout-minutes`             | Job timeouts are not enforced via this field             |
| `jobs.<job_id>.continue-on-error`           | Jobs will not continue on error                          |
| `jobs.<job_id>.environment`                 | Environment protection rules are not available           |
| Complex `runs-on`                           | Only `runs-on: label` or `runs-on: [label]` is supported |

</details>

<details>

<summary><strong>Are there any other differences from GitHub Actions?</strong></summary>

Yes, a few additional differences to be aware of:

* **Package registry tokens:** The automatic job token cannot currently publish to package registries. Use a Personal Access Token (PAT) stored as a secret instead.
* **Problem matchers:** Scanning action output for regex patterns and surfacing annotations in the UI is not supported.
* **Error annotations:** Not supported.
* **Expression functions:** Only `always()` is supported as a status check function.
* **Pre/Post steps:** These run correctly, but do not have their own section in the job log UI.
* **Service containers:** These run correctly, but do not have their own section in the job log UI.
* **Pull request ref:** For `pull_request` events, the ref is `refs/pull/:prNumber/head` (the PR head), not `refs/pull/:prNumber/merge` (the merge preview) as in GitHub Actions.

</details>

<details>

<summary><strong>Can I use actions from GitHub?</strong></summary>

Yes. By default, actions referenced without a full URL (like `actions/checkout@v4`) are downloaded from GitHub. You can also use absolute URLs to reference actions from any accessible Git repository:

{% code title="example: uses with absolute URL" %}

```yaml
uses: https://github.com/actions/checkout@v4
uses: https://your-internal-server.com/org/my-action@main
```

{% endcode %}

The `https://` or `http://` prefix is required when using absolute URLs.

</details>

<details>

<summary><strong>Should I use `${{ github.xyz }}` or `${{ gitea.xyz }}` in my workflows?</strong></summary>

Both `${{ github.xyz }}` and `${{ gitea.xyz }}` are supported and behave identically. You can use either. We recommend `${{ github.xyz }}` for maximum compatibility if you also use GitHub Actions.

</details>

## Runners

<details>

<summary><strong>What operating systems are supported for runners?</strong></summary>

The runner binary is available for **Linux**, **macOS**, and **Windows**. Other operating systems may work if supported by Go and Docker, but are untested.

When running jobs directly on the host (not in Docker containers), be aware of environment differences. For example, `bash` is typically not available on Windows — you will need to set `powershell` as the default shell:

{% code title="example: set default shell to powershell" %}

```yaml
defaults:
  run:
    shell: powershell
```

{% endcode %}

</details>

<details>

<summary><strong>Can I register runners at the organization level or repository level?</strong></summary>

Runners can be registered at two levels:

* **Organization level** — The runner serves all repositories in your organization.
* **Repository level** — The runner serves only that specific repository.

A repository may use organization-level runners even if it has its own repository-level runners.

</details>

<details>

<summary><strong>What are runner labels and how do they work?</strong></summary>

Labels determine which jobs a runner can accept and how those jobs are executed. When a workflow specifies `runs-on: ubuntu-latest`, the job is routed to a runner with a matching `ubuntu-latest` label.

Labels also encode the execution mode. For example:

* `ubuntu-latest:docker://node:16-bullseye` — Run in Docker using the specified image
* `linux_amd64:host` — Run directly on the host machine

See [Runner Setup — Labels](broken://pages/72f38d5498ddd1a2347ee4882c33159cdf37a790#labels) for details.

</details>

<details>

<summary><strong>What if `runs-on` specifies multiple labels like `[label_a, label_b]`?</strong></summary>

This is valid syntax. It means the job should run on a runner that has **both** labels. The runner must have all specified labels registered.

</details>

<details>

<summary><strong>What is the difference between agent labels and custom labels?</strong></summary>

Agent labels are reported to Copia by the runner during registration. Custom labels can be added manually by an administrator. However, a custom label may not map to an environment the runner knows how to handle. If you need to change a runner's labels, we recommend re-registering the runner or updating the `runners.labels` section in the runner's `config.yaml` and restarting.

</details>

<details>

<summary><strong>Can I use Copia-hosted runners?</strong></summary>

Not at launch. Copia Actions Runners currently supports **self-hosted runners only** — you provide and manage the machines that execute jobs. Copia-hosted runners are planned for a future release.

</details>

## Security

<details>

<summary><strong>What permissions does a runner have?</strong></summary>

Runners have **no standing permissions** on your Copia instance. They can only connect and poll for jobs. When a job is assigned, the runner receives a temporary, scoped token that grants access to the repository associated with that job. The token expires when the job completes.

Additional permissions can be granted through secrets. See [Variables and Secrets](broken://pages/ed793979bc787c9181946128167cfbef8f8700ef).

</details>

<details>

<summary><strong>How do I protect against malicious workflows?</strong></summary>

There are two main threat vectors: untrusted runners and malicious workflows.

An untrusted runner could steal code or secrets from jobs it executes. Only register runners you control on trusted infrastructure. Only provide runners to organizations and repositories you trust. Run jobs in Docker containers for isolation. Avoid host mode unless necessary. Use ephemeral runners for high-security environments — they execute one job and terminate.\
\
A workflow could run harmful code on your runner. Only register runners you control on trusted infrastructure. Only provide runners to organizations and repositories you trust. Run jobs in Docker containers for isolation. Avoid host mode unless necessary. For pull requests from forks, require approval before workflows run. Use ephemeral runners for high-security environments — they execute one job and terminate.

</details>

<details>

<summary><strong>Why should I use Docker mode?</strong></summary>

Docker mode runs each job in a fresh, isolated container. This prevents jobs from:

* Interfering with each other
* Leaving artifacts on the runner host
* Accessing the runner's filesystem or other processes

It also ensures reproducibility — the same Docker image produces the same environment every time.

</details>

## Troubleshooting

<details>

<summary><strong>My runner shows as "Offline" in the Copia UI</strong></summary>

* Verify the runner process is still running (`./act_runner daemon` or the Docker container).
* Check that the runner can reach your Copia instance over the network.
* If using a self-hosted Copia instance, confirm the instance URL is correct and not a loopback address.

</details>

<details>

<summary><strong>Jobs fail with "checkout" errors</strong></summary>

* Ensure the job container can reach your Copia instance. The `actions/checkout` action clones your repository by connecting to the instance URL.
* Do not use `127.0.0.1` or `localhost` as the instance URL — job containers run in separate network namespaces and cannot reach loopback addresses on the host.

</details>

<details>

<summary><strong>Windows runner fails because `bash` is not found</strong></summary>

On Windows, `bash` is not available by default. Set `powershell` as the default shell for your workflow:

{% code title="example: set default shell to powershell" %}

```yaml
defaults:
  run:
    shell: powershell
```

{% endcode %}

Or per-step:

{% code title="example: per-step powershell" %}

```yaml
steps:
  - name: Run script
    run: Get-Process
    shell: powershell
```

{% endcode %}

</details>

<details>

<summary><strong>The `.runner` file is corrupted</strong></summary>

If the `.runner` file (created during registration) becomes corrupted or the runner fails to start, delete the file and re-register:

{% code title="example: re-register runner" %}

```bash
rm .runner
./act_runner register --no-interactive --instance https://app.copia.io --token <token> --name <name>
```

{% endcode %}

</details>

<details>

<summary><strong>Git LFS files fail to download in workflows</strong></summary>

If your repository uses Git LFS and workflows fail to download LFS objects, this may be related to a known authentication issue. As a workaround, store an access token as a secret and configure the workflow to use it for LFS operations. Contact Copia support for the latest guidance.

</details>

> Note for Self-Hosted Copia customers: All troubleshooting steps apply equally. Replace `https://app.copia.io` with your instance URL.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.copia.io/docs/actions/faqs.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
