# Actions

Rebasely Actions runs your CI on every push and pull request. Workflows live in `.rebasely/workflows/`, each job runs in its own Cloudflare Sandbox, and every job reports a check on the commit.

*Diagram: A push or a pull request event starts the workflows in .rebasely/workflows that match it. Each job of the run gets its own Cloudflare Sandbox: it checks out the commit, runs the steps and streams its log live, with secrets masked. Each job reports a commit status, which pull requests show as checks and protected branches can require.*

*An event starts the matching workflows; each job runs in a fresh sandbox and reports a status on the commit.*

## Your first workflow

### 1. Add a workflow file

Create `.rebasely/workflows/ci.yml`:

```yaml
name: ci
on:
  push:
    branches: ["**"]
  pull_request:
    branches: [main]
jobs:
  test:
    runs-on: { image: node24, instance: lite }
    steps:
      - uses: duragit/checkout@v1
      - uses: duragit/cache@v1
        with:
          key: npm
          key-files: [package-lock.json]
          paths: [~/.npm]
      - run: npm ci
      - run: npm test
```

### 2. Push it

```sh
git add .rebasely/workflows/ci.yml
git commit -m "Add CI"
git push
```

### 3. Watch the run

The repository's Actions tab lists the run; a job's page streams its log live. From a terminal:

```sh
rebasely runs list
rebasely runs logs <run> --follow
```

A repository that still has a `.duragit/workflows` folder keeps working: Rebasely reads `.rebasely/workflows` when it exists, and the old folder otherwise.

## When workflows run

| Event | Runs on |
| --- | --- |
| `push` | Pushes to branches and tags, filtered by `branches`, `tags` and `paths`. Live-branch checkpoints only with `checkpoints: true`. |
| `pull_request` | Opening, reopening and pushing to a pull request, on the result of the merge. [Checks on pull requests](https://rebasely.com/docs/pull-requests#checks). |
| `schedule` | A cron, in UTC, at most every 5 minutes, on the default branch. |
| `workflow_dispatch` | By hand: the Run a workflow form, `rebasely dispatch` or the API, with inputs. |
| `sandbox` | A [sandbox](https://rebasely.com/docs/sandboxes)'s checks, on request. Never with secrets. |

`git push -o ci.skip` starts nothing. [Workflow syntax](https://rebasely.com/docs/workflow-syntax#on) has every filter.

## Runners: images and instances

Each job starts a fresh container from its image on Cloudflare Sandboxes (Linux, x86\_64), works in `/workspace`, and is gone when the job ends. `runs-on` picks the image and the instance; the default is `node24` on `basic`.

| Image | What it has |
| --- | --- |
| `node24` | Node.js 24, npm, corepack, git, curl, jq, tar, unzip and the usual shell tools (the default) |
| `gitbox` | git and Node.js, small |
| `builder` | Go, Python, Node.js, build tools, apko and crane (standard-1 or larger) |
| `deploy` | Node.js 24 and wrangler, for `duragit/wrangler@v1` (standard-1 or larger) |

| Instance | vCPU | Memory | Disk |
| --- | --- | --- | --- |
| lite | 1/16 | 256 MiB | 2 GB |
| basic | 1/4 | 1 GiB | 4 GB |
| standard-1 | 1/2 | 4 GiB | 8 GB |
| standard-2 | 1 | 6 GiB | 12 GB |
| standard-3 | 2 | 8 GiB | 16 GB |
| standard-4 | 4 | 12 GiB | 20 GB |

> **Note:** More images (Python, Go, Rust, Java) are planned; a workflow that names one today fails with "not available yet". On the free plan the largest instance is standard-1 and a job runs at most 60 minutes.

## Secrets

Add secrets to an organization, a repository or a deployment environment in their Actions settings (it needs a recent confirmation with Google or a passkey). Values are write-only: nobody can read one back. A step gets a secret only when it names it:

```yaml
- run: ./deploy.sh
  env:
    API_TOKEN: ${{ secrets.API_TOKEN }}
```

- An environment's secret wins over the repository's, which wins over the organization's.
- A secret can instead be bound to a host: the job sees a placeholder, and Rebasely adds the real value only to requests to that host.
- Values are masked in logs; write more values to mask, one per line, to `$DURAGIT_MASK`.
- Runs started by people who are not established writers, and every sandbox run, get no secrets.

## Who can start what

A run is trusted when whoever started it is an established writer of the organization (an account 7 days old or verified). For a pull request, its author and everyone who pushed to it must be. An untrusted run waits until a different established writer approves it, at that commit, and then runs without secrets, without pushing, and on at most a basic instance.

## Network

By default a job reaches the package registries it needs (npm, PyPI, crates.io, the Go proxy, Debian and Wolfi packages) for reading only. List more hosts under a job's `egress`; that needs a verified owner or a paid plan.

## Checks, logs and artifacts

- Each job reports a commit status named `duragit/<workflow>/<job>`. Pull requests show them as checks, and [branch protection](https://rebasely.com/docs/pull-requests#protection) can require them.
- Logs stream live and are kept 30 days on the free plan; a job's log is cut at 64 MiB.
- `duragit/upload-artifact@v1` keeps files for 30 days; `duragit/cache@v1` reuses dependencies between runs.
- Cancel a run from its page or with `rebasely runs cancel <run>`. A job that failed because of Rebasely itself is retried once.

CLI:

```sh
rebasely runs list --branch main
rebasely runs logs <run> --job test --follow
rebasely dispatch deploy.yml --ref main --input target=staging
```

API:

```
GET  /api/v1/repos/<org>/<repo>/actions/runs
POST /api/v1/repos/<org>/<repo>/actions/runs/<id>/cancel
POST /api/v1/repos/<org>/<repo>/actions/workflows/deploy.yml/dispatches
```

---

Source: https://rebasely.com/docs/actions
