> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reasonos.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Hosted CI

> How ReasonOS runs your CI workflows off your machine — push and change-request triggered runs, live logs and pipeline views, required checks, secrets, and environments.

The workflows you declare in `ci.rbs` don't only run where you type
`rbs ci run`. When your project is hosted on ReasonOS, the platform watches
every push and change request, plans the matching workflows, and executes
them off your machine — one run per matched workflow, pinned to the exact
commit that caused it. You watch runs, stream their logs, and read per-job
results in your project's **Runs** view, and required checks gate change
requests on those same results.

This page covers what the platform does with your workflows. For writing
them — triggers, jobs, steps, matrices, affected-package detection — see
[CI workflows](/ci/overview). The definitions are identical: anything that
runs with `rbs ci run` locally is what the platform runs for you.

## How runs start

Three trigger paths produce hosted runs today:

* **Pushes.** Every push to a hosted project — a branch push, a new branch,
  or a tag push — is matched against your workflows' `push` triggers,
  including `branches`, `tags`, and path filters. Merging a change request
  moves the target branch, so merges trigger push workflows too.
* **Change requests.** Opening a change request starts runs for matching
  `pull_request` workflows, and every subsequent push to its source branch
  starts new ones. Runs always judge the branch's **live head** — never a
  stale revision — so a green check means the code as it stands now.
* **Manual.** The **Run workflows** button on the Runs view queues every
  workflow that declares a `manual` trigger against the default branch's
  head.

Every run executes at exactly the commit that caused it, even if the branch
has moved on by the time the run starts. And a broken `ci.rbs` is never
silence: if planning fails on a push, the failure shows up in the Runs list
as an errored run with the message attached.

<Note>
  `schedule` and `webhook` triggers parse in `ci.rbs` but the platform does not
  fire them yet — there is no hosted cron and no inbound webhook receiver. A
  `schedule` trigger only matches when you invoke
  `rbs ci run --event schedule` yourself.
</Note>

## Where runs execute

Hosted runs execute on the platform, not on your machine and not on your
branch nodes. For each run, the platform makes a fresh, full clone of the
project at the triggering commit and executes the workflow through the same
engine `rbs ci run` uses locally. Jobs are submitted to a job scheduler and
dispatched to workers with their `needs` edges preserved — independent jobs
run in parallel, and the `rbs` commands inside a job's steps share one build
cache across jobs, so incremental pushes rebuild only what changed.

CI compute is deliberately separate from your branch nodes: a heavy run
never competes with your editor session, and nothing a CI job does can touch
a node's working tree.

Concurrency is bounded per organization. Runs beyond the cap queue as
`pending` and start as slots free up.

<Note>
  Today, runs execute on compute managed alongside the platform's core
  services. Dedicated per-organization worker pools with autoscaling — and a
  shared pool for entry tiers — are in progress. They replace the execution
  backend, not the model: workflows, runs, and everything on this page stay
  the same.

  One workflow feature doesn't execute on the hosted worker path yet:
  [matrix jobs](/ci/overview#matrix-jobs). They work with local `rbs ci run`;
  a hosted run that uses one reports the limitation rather than failing
  mysteriously.
</Note>

## Watching runs

Your project's **Runs** view in the ReasonOS web app is the CI surface:

* **The list** shows every run, newest first — status, run number and
  workflow, what triggered it (Push, Change request, Manual), branch,
  commit, finished-job counts, duration, and age. The list refreshes itself
  while any run is live.
* **A run's page** shows the **pipeline graph** — the planned job DAG, laid
  out by dependency depth, with each job's live status. The graph renders
  from the stored plan, so you see the whole pipeline before, during, and
  after execution.
* **Jobs** expand into their steps: status, duration, exit code, and each
  step's captured output.
* **The transcript** streams live. Output appears as the build prints it,
  like a terminal; when the run finishes, the full transcript is stored
  with the run. Very long transcripts keep the tail (the part debugging
  reads first), and the view says so when earlier output was trimmed.

Statuses keep two failure words apart on purpose: **failed** means your
build's verdict — a test failed, a step exited non-zero. **error** means the
platform could not run the workflow — a clone failed, planning broke — and
the run carries the message explaining why.

Run history persists with the project, so the Runs list is your CI history
across pushes, merges, and manual triggers.

<Note>
  A run's record is its plan, per-job and per-step results, and the
  transcript. There is no separate per-run artifact store yet — build outputs
  flow through the build cache like any other `rbs` outputs. Jobs that
  executed on the worker path may show their status without per-step rows
  ("No step records for this job"); per-step detail there is in progress.
</Note>

The ReasonOS editor's **Jobs** view is a different surface: it submits and
watches ad-hoc jobs on your build cluster (a command or script with CPU/GPU
requests). CI runs live in the project's Runs view, not there.

## Checks on change requests

A change request's merge box shows its CI verdict:

* **One summary row** — "All 2 checks passed", "1 of 2 not successful",
  "1 check still running" — expandable to the individual checks.
* **Each check links to its run**, because "which check failed" is always
  followed by "show me the output". Failures expand by default.
* **Waiting and failing are different sentences.** A required workflow that
  has no run yet for the current revision reads as *hasn't run*, never as
  passed and never as failed.

To make workflows **required**, open **Settings → Branch rules** and pick
them under **Required checks** in a ruleset for the target branch. The picker
offers workflows that have run in the project. With required checks in
place:

* Merging is refused until each required workflow has **succeeded at the
  change request's live head**. The newest run per workflow wins — a
  re-run into failure reads as failing, and a green run on an older commit
  satisfies nothing.
* Pushing new commits to the source branch re-runs the checks for the new
  head; the merge button stays disabled until they pass again.

## Secrets, environments, and trust

Hosted runs get configuration your laptop doesn't have to carry. All of it
lives in **Settings → Secrets & environments** (per project) and in
organization settings (org-wide).

### CI secrets

Store CI-class secrets at project or organization scope. Values are
write-only — they go in through settings and never come back out through any
view or endpoint. During a run they are injected as plain environment
variables, so a step reads `$DEPLOY_TOKEN` like any other variable.

* A secret marked **protected refs only** is withheld from runs on any
  branch other than the default branch — deploy credentials stay off topic
  branches. (Protected currently means the default branch.)
* Secrets are delivered to jobs when they actually start executing, never
  stored in queued job specs.

### Environments

Environments (dev, staging, prod, and any you add) name the deployment
targets a secret's value varies by. Each carries a branch pattern —
`main`, `release/*` — and **a run learns its environment from its ref**:
a push to `main` resolves prod-scoped values because prod claims `main`,
with no change to your `ci.rbs`. A value stored without an environment
applies everywhere; an environment-scoped value shadows it there only.

### Context variables

On top of the [trigger context rbs itself sets](/ci/overview#environment-variables)
(`CI_EVENT_TYPE`, `CI_REF`, `CI_BRANCH`, `CI_PR_NUMBER`), the platform adds:

| Variable         | Meaning                                                  |
| ---------------- | -------------------------------------------------------- |
| `CI_COMMIT_SHA`  | The exact commit the run executes                        |
| `CI_RUN_NUMBER`  | The run's number in this project                         |
| `CI_SOURCE`      | What caused the run: `push`, `pull_request`, or `manual` |
| `CI_ENVIRONMENT` | The environment the run's ref resolved to, when one did  |

### Pinning CI definitions

By default, each run uses its own commit's `ci.rbs` files — which means a
topic branch can edit the very workflow that judges it. The **Where CI comes
from** setting closes that: pin CI definitions to a branch (say `main`), and
every run swaps in the pinned branch's `ci.rbs` files before planning. A
topic branch can change the code a workflow judges, never the workflow —
and it can't smuggle in a new `ci.rbs` either, because the commit's own
files are removed first. Runs *on* the pinned branch keep their own
definitions; those commits already passed whatever review guards the branch.

<Note>
  The pin covers `ci.rbs` files. A workflow declared in `WORKSPACE.rbs` is not
  overlaid — keep workflows in `ci.rbs` files if you rely on pinning.
</Note>

## Running CI on your own fleet

Independent of the hosted trigger paths, `rbs ci run` can fan a workflow's
jobs onto a build cluster you operate yourself:

```bash theme={null}
rbs ci run --remote host:8980
# or, with $RBS_REMOTE set:
rbs ci run --remote
```

Each job becomes a cluster job with its dependencies preserved, workers
check the repository out at the triggering commit, logs stream back to your
terminal, and every `rbs` command inside the jobs shares the cluster's
cache. This is a manual invocation from your machine — the hosted platform
is what turns pushes into runs automatically. See
[Remote cache & execution](/ci/remote-execution) for running the cluster
itself.

## CI events also drive QA

If QA is enabled for the project, the same events that start CI runs can
start QA runs: a push to the default branch answers QA's "a new build
lands" trigger, and change-request events answer its "a pull request
touches this" trigger, alongside QA's own schedules and manual runs. QA
runs have their own view in the project — they are test-session runs
against an environment, not workflow runs, and they don't appear in the
Runs list.

## Local and hosted are the same CI

There is one CI system with two entry points:

* **Locally**, `rbs ci run` executes a workflow right now, in your
  workspace — the fast loop while you're writing or debugging a pipeline,
  with `rbs ci plan` to see exactly what an event would run. See
  [CI workflows](/ci/overview).
* **Hosted**, the platform runs the same definitions on every push, change
  request, and manual trigger, stores the history, streams the logs, and
  gates merges on the results.

A workflow that passes locally is the workflow the platform runs — same
files, same engine, same DAG.
