> Documentation version: 3. [HTML page](overview.html)

<a id="how-a-roc-repository-is-maintained"></a>

# How a Roc repository is maintained

This manual covers the shared tooling, workflow boundaries and evidence needed
to build, test and distribute Roc packages and platforms reliably. It explains
which concrete risks an opinionated practice addresses, how its controls work,
and what the resulting evidence can establish.

Product-specific security design and project governance remain with maintainers.
The model supplies reusable automation and integration contracts; it does not
establish that a product’s algorithms, native host or dependencies are secure.

<a id="scope-and-design-principles"></a>

## Scope and design principles

Shared tools own input validation, artifact identities, bounded execution and
diagnostics. Workflows own when those tools run, which source and artifacts
they receive, and the authority each job holds. Evidence connects the selected
inputs, actual execution and published bytes so a maintainer can investigate
failures and decide what to do next.

Each chapter explains its relevant failure or attack scenario, guiding principle,
specific controls, verification and remaining assumptions. The
[risk and control reference](risks-and-controls.md#risk-and-control-reference)
indexes those explanations. It is a navigation aid, not another specification
or a claim that every control has been deployed in every consumer.

Experience and primary technical research inform the choices. A standard can
reveal an omitted risk; satisfying a framework is not itself the reason to add
a control. Prefer a shared, testable mechanism that addresses an identified
failure over a new service, permission or mandatory check with no clear benefit.

<a id="why-a-shared-baseline-helps"></a>

## Why a shared baseline helps

Keeping a Roc project in good shape means juggling several things that move at
different speeds. The compiler is still changing, and breaking changes are
routine. A bug can sit in the compiler, in a platform, in a dependency, or in
the project itself. Releases rarely line up: a package may need a platform
release that has not happened, or a fix may be merged long before users can
download it. Each repository that solves these problems alone solves them
slightly differently, and each difference is something a maintainer has to
remember.

A common baseline is the answer this manual offers. It records the practices
that have worked across these repositories and the reasons behind them, so that
a lesson learnt in one place is applied everywhere. The practices are
opinionated, and they are not finished: when experience shows a better way, the
baseline changes here first and the repositories follow.

One decision shapes most of the rest. The package or platform always meets the
newest compiler, because that is what its users will install. The repository’s
own tooling stays on a compiler the maintainer chose and moves only when the
maintainer moves it, so that scripts, checks and release steps keep working on
the day a new compiler breaks something.

<a id="the-model-in-one-page"></a>

## The model in one page

| Concern | Practice |
| --- | --- |
| Package compiler | The latest published Roc nightly. The package, platform and examples carry no pin. |
| Tooling compiler | ` roc-stable `: one release named in ` Blueprint.roc ` and repeated in each script’s ` roc ` header field, changed by a reviewed pull request. |
| Tools and toolchains | Declared in ` Blueprint.roc `, pinned by ` Blueprint.lock `, identical for contributors and CI. |
| Automation | Released utilities through Blueprint tasks; product-specific Roc scripts under ` scripts/ ` run by ` roc-stable ` where needed. |
| Repository examples | Depend on the working tree by relative path. |
| Pull requests | Scripts pass on ` roc-stable `; the working tree passes on the latest nightly; a platform’s committed host bindings match what that nightly generates. |
| A release | One immutable release holding the bundle, an examples archive pinned to that bundle, a documentation archive, and the manual where there is one. Every asset is tested as the exact bytes that are published. |
| Nightly | Runs the latest release’s examples archive on one selected nightly. Example failures require compatibility investigation; incomplete execution requires setup repair or rerun. |
| Upkeep | Blueprint, the lock, the tooling compiler, the scripts and a platform’s host bindings are each changed by hand, in a pull request. |

<a id="three-compilers-three-jobs"></a>

## Three compilers, three jobs

There are three compiler roles. A consumer of released utilities need not install
their implementation compiler; a repository with local source tooling names it
explicitly. Each role has one job, and they are never interchangeable.

| Compiler | Selected by | Used for |
| --- | --- | --- |
| Blueprint’s own; it has no command name | The ` blueprint ` binary | Evaluating ` Blueprint.roc ` |
| ` roc-stable ` | The release tag named in ` Blueprint.roc ` | Running the repository’s automation scripts |
| ` roc `, the latest nightly | Nothing: it is whatever [` roc-lang/nightlies `](https://github.com/roc-lang/nightlies) published most recently | Checking, testing, bundling and running the package, the platform and their examples |

A maintainer chooses the second and observes the third. The first is hidden:
` blueprint ` fetches it when needed, as described in
[Get ` blueprint `](environment.md#get-the-blueprint-binary).

Blueprint has a compiler of its own because Blueprint is itself written in Roc.
It has to evaluate ` Blueprint.roc ` before any environment exists, so it cannot
take its compiler from the environment that file describes: that would be a
bootstrap problem. Each ` blueprint ` release therefore fixes the one compiler it
was built with.

Three compilers is more than anyone wants, and the arrangement is accepted as
temporary. It follows from Roc having only nightly builds. Once Roc 0.1 is
released, Blueprint and most repository tooling are expected to settle on that
release, which leaves two compilers to think about: the released one that
tooling runs on, and the nightly that packages are tested against.

` roc-stable ` exists so that repository tooling keeps working when a nightly
breaks something. The package deliberately floats, because the question a
maintainer needs answered is whether the package works with the compiler users
will install today. "Stable" means only that the repository does not move the
tag without review. There is no shared registry of stable versions, and
repositories need not agree.

"Latest nightly" means the most recent release published by ` roc-lang/nightlies `.
This model treats that as the last good build and does not check upstream CI
separately.

CI installs that compiler as ` roc ` with the official
[` roc-lang/setup-roc `](https://github.com/roc-lang/setup-roc) action, which is
also how it is named on a contributor’s machine. The Blueprint environment
provides ` roc-stable ` and no ` roc `, so the two names never collide.

<a id="what-each-workflow-answers"></a>

## What each workflow answers

**The three workflows and the question each one answers**

![The three workflows and the question each one answers](images/diagram-dc82f98e7091b5be6324daf6883bf0a0fb6148eb73a7b62d685933c1cc3d473f.svg)

` ci.yml ` tests the working tree. ` release.yml ` tests and publishes artifacts.
` nightly.yml ` tests what users already have. Each can fail without the others
being wrong: a new nightly can break ` ci.yml ` on an untouched pull request, and
` nightly.yml ` can fail while the default branch is green because the fix has not
been released. [The three workflows](workflows.md#the-three-workflows)
describes each in full.

<a id="a-pure-roc-package"></a>

## A Roc package

Roc packages contain Roc code. Platforms provide the host implementation and
may include native libraries.

The one-runner testing profile applies to a package repository when all of
these hold:

- it publishes a package and has no host or platform code;


- it fetches no native build inputs;


- none of its code behaves differently from one target to another.


Such a package is expected to work wherever Roc does. A difference between
targets is a compiler defect to report upstream, not something the package’s
own CI is there to find. It therefore tests on one runner.

| Concern | A Roc package |
| --- | --- |
| Runners | One. ` ci.yml `, the test job of ` release.yml ` and ` nightly.yml ` each run on ` ubuntu-latest ` only. |
| Required status checks | The job names themselves. With no matrix there is no aggregate job. |
| Examples | Run on a published platform, such as basic-cli, and are tested on the one runner. |
| Chapters that do not apply | [Maintain a platform](platforms.md#maintain-a-platform) and [Publish linker inputs from a pull request](linker-input-releases.md#publish-linker-inputs-from-a-pull-request): host bindings, native build inputs, rebuild selection and ` actions/publish-build-inputs `. |

Everything else applies unchanged: the two compilers, the Blueprint
environment, the Roc scripts, the three workflows, and what a release contains.

The cost is stated here so that it is a decision and not an accident: a
compiler defect that appears on one target only is not detected by this
package’s CI.

A package leaves this profile as soon as it gains behaviour that can differ by
target, for example when it starts a process, interprets file paths, or depends
on the width of a pointer. It then adds a runner for each target it claims, and
takes on the matrix and the aggregate job described in
[Continuous integration](workflows.md#continuous-integration).

<a id="what-is-shared-and-what-a-repository-owns"></a>

## What is shared and what a repository owns

Anything two repositories need identically belongs in roc-automation, referenced
by full commit SHA. A repository keeps only what knows its own package.

| Lives in roc-automation | Lives in the repository |
| --- | --- |
| ` actions/setup-blueprint `: install Nix and the verified ` blueprint ` binary | ` Blueprint.roc ` and ` Blueprint.lock ` |
| ` actions/nightly-report `: keep the nightly tracking issue | The test job of ` nightly.yml `, its matrix and its schedule |
| ` actions/build-docs `: render an AsciiDoc manual as a site and PDF | ` docs/*.adoc ` |
| ` actions/publish-release `: stage a draft release, verify every asset, then publish | What a release contains, and the jobs that build and test it |
| ` actions/publish-build-inputs `: publish linker inputs from a pull request | The producer workflow and its build recipe |
| The ` check-settings ` task: compare a repository’s GitHub settings with this manual | The settings themselves, applied by a maintainer |
| This manual | Thin caller workflows, ` scripts/ `, tests and expected output |

[Shared actions](actions.md#shared-actions) is the reference for each
action.

<a id="what-the-model-does-not-do"></a>

## What the model does not do

- It does not make package builds reproducible. The package compiler floats by
  design; only the tooling environment is pinned.

- It does not verify upstream compiler quality beyond using a published nightly.


- It does not support holding a package on an older compiler line. There are no
  compiler-compatibility branches: a release works with the compilers named in
  its notes, and a patch release follows when a newer compiler breaks it.

- It does not describe application repositories that publish no package. They
  can use the environment and script conventions, and have no release or
  nightly workflow.

