Documentation

Last updated: 2026-09-27

Getting started: Workflows

This guide runs a build on a push, locally:

  • start Everlock with git over HTTP, which serves the runner protocol too
  • create a repository and clone it over HTTP
  • register a forgejo-runner against your instance
  • push a workflow and watch the run
  • add a secret and see it masked in the log

Everlock speaks the runner protocol itself, so a stock forgejo-runner takes the work. There is no CI service to install alongside it.


1. Start Everlock with git over HTTP

The parts that trip people up:

  • --backend-git-http enables the backend. On its own, --backend-git-http-vhost only names the host.
  • All runtime flags go after the serve subcommand.
  • One flag serves three things: the git transport, the web UI, and the runner protocol. A runner's instance URL is the host it clones from, so they cannot be separated.

Grab the binary from the download page and start it:

./everlock serve \
  --backend-git-http \
  --backend-git-http-vhost localhost \
  --backend-admin-ssh \
  --frontend-ssh \
  --frontend-ssh-listen 127.0.0.1:2222 \
  --admin-user admin \
  --admin-password change-me

What this does:

  • starts the HTTP frontend on its default 0.0.0.0:8080 (auto-enabled because an HTTP backend is on)
  • serves git, the browser surface and the runner protocol at http://localhost:8080
  • opens the admin console on SSH port 2222
  • bootstraps an admin user

Open http://localhost:8080 in a browser and you get the repository list — empty for now.


2. Create a repository

Connect to the admin console:

ssh -p 2222 admin@localhost

Create a repository:

/git repo create demo
  created repository 'demo'
  owner: admin (*/git/demo)

Clone it over HTTP, authenticating as the admin user:

git clone http://admin@localhost:8080/demo.git
cd demo

Git prompts for the password (change-me). An API key works in place of it, as any username: git clone http://x:evapi_…@localhost:8080/demo.git.


3. Mint a runner registration token

In the admin console:

/git runner token
  <token>

  Register a runner with:
    forgejo-runner register --instance <url> --token <token>
  The token works once and is not shown again.

The registry of runners is what gates workflows — an instance with no runner registered answers the protocol and hands out no work. Copy the token.


4. Register and start the runner

In another terminal, register against your instance and start the daemon:

forgejo-runner register --instance http://localhost:8080 --token <token>
forgejo-runner daemon

Back in the admin console, confirm it arrived:

/git runner list
  name       uuid      labels          version   ephemeral   last seen
  my-runner  a1b2c3…   ubuntu-latest   v6.x      no          just now

The runner is now waiting for work. It will stay idle at no cost — an idle runner writes nothing.


5. Push a workflow

Everlock reads workflows from .forgejo/workflows/ in the pushed commit. That directory existing is what enrols the repository; there is no switch to flip.

mkdir -p .forgejo/workflows
cat > .forgejo/workflows/build.yml <<'YAML'
name: build
on: [push]

jobs:
  greet:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: echo "built $GITHUB_SHA"
YAML

git add .forgejo
git commit -m "add a workflow"
git push

The push starts a run. runs-on must match a label your runner registered with — ubuntu-latest above — or the task waits for a runner that never claims it.


6. Watch the run

/git workflow list demo
  repo  run  when   status     ref                commit    subject
  demo  1    now    success    refs/heads/main    a1b2c3d   add a workflow

Read its log:

/git workflow log demo last

last is the most recent run; a run id or a suffix of one also works, and a third argument picks one job out of a multi-job run.

In the browser, the repository now has a Workflows tab — it appears once a run exists. Each workflow is a pill; selecting one filters the runs beneath it. A run's page shows every job with its status, what it waited for, and its log.


7. Add a secret

Secrets are per repository. owner sets and lists them; writer consumes them, because pushing a workflow is enough to use one.

/git secret set demo API_TOKEN s3cr3t
/git var set demo ENVIRONMENT staging
/git var list demo
  name          kind      value     set by   set at
  API_TOKEN     secret    —         admin    now
  ENVIRONMENT   variable  staging   admin    now

Use them in a step, then push:

      - run: echo "$TOKEN in $ENVIRONMENT"
        env:
          TOKEN: ${{ secrets.API_TOKEN }}
          ENVIRONMENT: ${{ vars.ENVIRONMENT }}

The log shows *** where the secret's value would have been. Masking is what protects it: logs are readable by everyone who can read the repository, while the store behind them needs a store grant.


8. Optional: start a run by hand

A workflow that declares workflow_dispatch can be started without a commit:

on:
  push:
  workflow_dispatch:

After pushing that, run it from the console or from the start control on the workflow's pill in the browser:

/git workflow start demo build

Only workflows declaring workflow_dispatch are offered — the declaration is the author saying the workflow makes sense run by hand.


9. Operator notes

  • The runner registry is the gate. There is no per-repository switch and no config flag for workflows. Registration takes an operator-minted token, which also decides which machine executes.
  • Write access is execution access. Anyone who can push a commit to a repository can change what runs on your runner. A repository whose workflows should not run is one whose write grants are narrower.
  • Checkout uses a scoped credential. Each task gets a share identity holding reader on that one repository, deleted when the task ends. It clones its own repository and is refused on any other.
  • A quiet runner is requeued, not failed. A lease is a 90-second silence budget extended by any report. One lapse requeues the task, assuming the runner died; a second lapse fails it.
  • Runs are stored, not just logged. Two files per run in the everlock-workflows store — run.toml with the run and all its jobs, plus one log file per job.
  • For production, put the instance on a real host with HTTPS rather than localhost, and set it with /server settings set git.http.vhost git.example.com — the change applies live. The runner's --instance URL must match.

git workflows ci runners getting-started