Skip to content

ADR 0007 — What cratly asks of its host, and where that could be answered differently

  • Status: Proposed
  • Date: 2026-09-13
  • Context repos: cratly.io site (this repo), editor

Problem

The editor is a browser application with no backend: what it can do, it does as the signed-in user against a GitLab instance. That has carried the product a long way — the review workflow, the drafts, the build, the preview are all GitLab's, and none of them had to be written.

It also means one supplier decides what cratly can offer. Two pressures make that worth examining now:

  1. A shared runner fleet is shared with everything else on it. Site builds are short — ten to fifteen seconds — but they queue behind work that has nothing to do with any site, and a build waiting for a free runner is indistinguishable, from the outside, from a build that is slow.
  2. Not every customer has GitLab, and of those who do, not every one wants the editor to reach it.

The naive reading of "make the host exchangeable" is that cratly needs somewhere to keep files. Counting what the editor actually asks for says otherwise. Its GitLab service has 24 methods:

What it asks forMethods
Merge requests — open, read, update, merge, rebase, merge-base, delete, their pipelines9
Branches — create, delete, list, compare, protection state7
Files and commits — getFile, getTree, commit3
Pipelines and artefacts — read jobs, retry, download the archive3
Session — current user, project2

Storing the file tree is three of them. The other twenty-one are a review workflow and a build. An interface offering a file tree and nothing else would replace the easy eighth and leave the rest unbuilt — which is the trap this decision exists to name.

A second finding belongs here: GitLab does not sit behind one seam today. Besides services/gitlab.js, the auth store, the repo store, useMergeFromMain, lib/connections and two views address api/v4 or the instance URL directly.

Decision

The contract is written in cratly's own concepts, not in GitLab's API.

Four of them, and a host is a host when it answers all four:

  • A file tree, and everything that happens to one: reading it, writing a set of changes as one atomic unit, moving and deleting within it, and validating what a change would produce before it is written. This is the centre — every other concept refers to a state of this tree.
  • A draft — a named, isolated state of the tree that a person works in without touching what is published, and that can be compared against what is.
  • A review — a draft offered for publication, with the discussion and the decision recorded against it, and the means to bring it up to date with what has been published meanwhile.
  • A build — a draft or the published state turned into a site, with a status that can be polled, a report that can be read (see ADR 0006), and a result that can be served as a preview.

Authentication is separate from all four and is expressed as OIDC, so a host is named by an issuer rather than by a product.

GitLab becomes one implementation of that contract — branches for drafts, merge requests for reviews, pipelines for builds — rather than the shape the editor is written in. A bespoke service is another: it can answer the same four far more directly, because it need not be a git host to do so.

Before any of that, the seams are collected. Every direct reach for api/v4 or an instance URL outside the service layer is a place the contract cannot cover. That work is worth doing on its own, whatever is decided about a second implementation.

What this does not decide

Whether a bespoke host gets built, and whether it stores its trees in git at all. Naming the contract is what makes that a question that can be answered later rather than one that has to be answered first.

Consequences

  • The editor's service layer is written against the contract, and its vocabulary changes from branches and merge requests to drafts and reviews. The documented workflow already speaks that way; the code does not yet.
  • A second implementation is measurable against the first: whatever GitLab answers, the contract has to ask for.
  • The runner pressure is not waiting for any of this. The published pipeline templates take runner_tags, so a site can be built on runners kept for site builds — see the pipeline reference.
  • Where a host cannot answer a concept — a service with no review step, say — the editor has to say so rather than hide it. A capability a host lacks is not a feature the editor may silently drop.

See also