Get started
How it works
The parts of HookCI, what each one does, and what happens between a push and a check on your pull request.
HookCI has two halves. The hub is a small service that talks to GitHub and Slack. The agent is a single Go binary that runs on your Linux server and executes your checks. The hub never runs your code, and the agent never accepts inbound connections.
The parts
| Part | Where it runs | What it does |
|---|---|---|
| GitHub App | GitHub | Sends push and pull request webhooks to the hub. Receives check runs and annotations from the hub. Gives the agent short-lived tokens to clone. |
Slack app (@hookci) |
Slack | Receives /hookci commands. Shows run messages, failure alerts, and the App Home. |
| Hub | Cloudflare Workers with D1, R2, and Durable Objects | Verifies webhooks, decides which agent runs a job, tracks run state, writes check runs and Slack messages, stores logs. |
| Agent | Your server | Keeps one outbound WebSocket to the hub, clones the repository, runs checks, streams results and logs back. |
| Jobs | Your server | Each job runs as the unprivileged user hookci-run in its own systemd transient unit under hookci.slice, with CPU, memory, task, and time limits. |
The hosted hub is at ci.webuno.io. You can also run your own copy; see Self-host overview.
What stays where
- Your source code is cloned by the agent from GitHub straight onto your server. It is never sent to the hub. The hub receives results, annotations, and logs.
- Your secrets stay with you. The agent masks values listed in
redactin logs before they leave the server. - The connection is outbound only. The agent dials the hub on port 443 over a WebSocket at
/v1/agent/connect. You open no inbound port and no SSH access. - The agent credential is created when you pair, and the hub stores only a hash of it. See Pair an agent.
Life of a run
- GitHub sends a webhook. A push or a pull request event reaches the hub through the GitHub App (arrow 1). The hub checks the signature and finds the repository and the agent bound to it.
- The hub hands the job to your agent. If the agent is connected, the hub sends the run over its WebSocket (arrow 2). Otherwise the check shows “Agent offline” and the run waits until the agent reconnects. A new push to the same branch supersedes older runs of that branch.
- The agent clones and plans. It requests a short-lived installation token, clones the repository itself from GitHub (arrow 3), and reads
.hookci.yml. With no file, it detects checks from the project files. Jobs run in dependency order (needs), in parallel up to the slot count. - Jobs run in isolation. Each job runs as
hookci-runin a systemd transient unit with its own network namespace. Outbound traffic goes through an egress proxy that allows only the hostnames you list. See Isolation and egress. - Results stream back. The agent sends step events, annotations, and logs to the hub. The hub updates the
hookcicheck run and onehookci/<job>check run per job on the commit, and posts or edits the run message in Slack (arrow 4). See GitHub Checks and Slack. - The run ends. The aggregate check becomes success, failure, or cancelled. If a job failed, the hub sends one failure alert with the failed step and the last log lines.
Run states
A run moves through these states. You see them in hookci status, in Slack, and in check titles.
| State | Meaning |
|---|---|
received |
The hub has accepted the run. |
queued |
Waiting to start, for example until the agent reconnects. |
gated |
A fork pull request waiting for approval. |
running |
The agent is executing jobs. |
verifying, rolling_back |
Deploy phases. See Deploys. |
success, failed |
Final result of the checks. |
cancelled, superseded |
Stopped, or replaced by a newer commit. |
interrupted |
The run did not finish, for example because the agent was revoked or stopped. |
skipped |
The run was skipped. |
If the agent goes away
The agent reconnects on its own with a backoff that tops out at 30 seconds. The systemd unit restarts it if the process exits, except when the hub says the agent was revoked. If the hub has not heard from the agent for 10 minutes, new runs show “Agent offline” on the check, and the admin who paired the agent gets a direct message in Slack. See Troubleshooting.
Next
- Quickstart to set it up.
- Hosted overview for accounts and what the hub manages.
- Security and data for what the hub stores.