How it works

GitHub runs the show.
Your machine runs the job.

OwnCI doesn’t implement a CI protocol. It downloads, registers, supervises and cleans up the official GitHub Actions runner, and configures it so every job runs inside a Docker container.

Who owns what

A clear split of responsibilities.

GitHub keeps

  • Your workflow files and when they trigger
  • Queuing and scheduling jobs
  • The check on the pull request
  • Job logs in the Actions tab

OwnCI takes care of

  • Downloading the pinned runner and verifying its checksum
  • Registering it with an opt-in ownci label
  • Supervising the process: start, stop, restart with backoff
  • Enforcing container jobs and wiping the workspace after each
  • Reporting what is actually true with status and doctor
  • Unregistering and removing everything with uninstall

One job, start to finish

From push to green check.

01You push

A pull request triggers a workflow whose job says runs-on: [ownci].

02GitHub queues it

The job waits for an online runner with the ownci label.

03Your runner takes it

The official runner, supervised by OwnCI, runs the job inside a container on your Docker.

04Wiped for the next

A hook wipes the workspace in a throwaway, network-less container. If that fails, the job fails visibly.

Two ways to run

Pick the mode that fits your workflows.

Both keep every job in a container. They differ in where the runner itself lives.

HOST MODE · DEFAULT

Jobs declare their container

The runner runs on your machine, and every job must say container:. A job without one is rejected by the runner, so nothing runs directly on your host.

workflow.yml
jobs:
  build:
    runs-on: [ownci]
    container: ubuntu:24.04     # required in host mode
    steps:
      - uses: actions/checkout@v4
      - run: make test
CONTAINER-RUNNER MODE

Workflows run unchanged

The runner itself runs in a container, a fresh one for every job. Jobs without container: run inside it as your user, with sudo; jobs with one behave as in host mode.

workflow.yml
jobs:
  build:
    runs-on: [ownci]            # no container: needed
    steps:
      - uses: actions/checkout@v4
      - run: sudo apt-get install -y jq && make test

Choose it with ownci setup --repo owner/name --mode container-runner, or switch an existing runner with ownci stop, then ownci setup --force --mode container-runner. The default image is the official ghcr.io/actions/actions-runner, pinned by digest. Details in the docs →

For teams

One workflow, everyone’s own machine.

Give each developer’s runner an extra label, dev- plus their GitHub username, and let the workflow pick the runner of whoever triggered it. Your pushes run on your machine, your teammate’s on theirs.

workflow.yml
jobs:
  build:
    runs-on: [ownci, "dev-${{ github.actor }}"]   # the user who opened or pushed to the PR
    container: node:22
    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm run build

If someone’s runner is offline, their job waits in the queue. The label routes jobs; it doesn’t stop someone who edits the workflow from picking another runner.Let only maintainers decide →

Next

Know exactly what a container does and doesn’t protect.

Read the trust model before you set up your first runner.

Security