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.