Run ngit-ci
ngit-ci is the reference coordinator for Nostr CI, the CI extension to NIP-34 published as NIP-C1. Start by reading Understanding Nostr CI. Run ngit-ci to provide CI for the repositories you point it at. It watches them over Nostr, runs their workflows when a push, pull request, or manual trigger arrives, and publishes signed results that ngit and GitWorkshop show against commits and pull requests with the trust context the protocol carries.
There is no forge server and no runner registration. Several coordinators can serve the same repository, and trust is decided at the edges: every result is an attestation signed by its publishing key, and clients decide which keys mean something. The protocol separates the coordinator that schedules work from the compute providers that execute it. Act uses the coordinator's execution backend; experimental Nix jobs run on separately identified trusted providers. A coordinator with runner = "none" can plan Nix workflows without local compute.
What it does
- Watch. Advertise itself on index relays, list the repositories it is ready to serve so maintainers find it in GitWorkshop's coordinator directory, and subscribe to repository state, pull requests, and manual triggers on each repository's own relays.
- Plan. On a trigger, sparse-fetch only the CI paths at the exact commit and match
.ngit/act/workflows/, plus.ngit/nix/workflows/when enabled. - Run. Execute each claimed workflow with
act, every job in its own container, or hand each job to a sandbox adapter such as the first-party microVM adapter. For Nix, allocate jobs to compatible trusted providers which execute flake outputs and sign their own Job Results. - Publish. Sign act Job Results or accept verified Nix provider results, publish Workflow Progress while the run is live, then sign a Workflow Result quoting those Job Results. Repository Status confirms what it is acting on.
What ngit-ci implements
ngit-ci implements the request-gated, operator-selected corner of the specification. Maintainers and client authors integrating against a live coordinator should expect the right-hand column.
| Topic | Specification | ngit-ci today |
|---|---|---|
Admission (M) | operator-selected, maintainer-request, or open | Always operator-selected; repositories come from the operator's allowlist |
Execution (X) | automatic or request-required | request-required by default |
Runner families (W) | Any; act and nix are named as examples | act plus explicitly enabled experimental nix; Nix selectors name native systems offered by trusted providers |
| Where jobs run | Coordinator or separate compute providers | Act backend or separate Nix providers, optionally using Firecracker |
| Job Result signer | May differ from the coordinator | Coordinator for act; selected provider for Nix |
o values | push, pull_request, schedule, manual | schedule is never produced |
in-progress job tag on Progress | Defined | Not emitted |
| Secret sealing to a NIP-46 bunker | Defined through the reserved name | Implemented, with an operator fallback bunker that is outside the protocol |
Act workflows are claimed as whole files using their runner labels. Nix jobs are allocated individually by native system, isolation, and available capacity. Independent jobs can run simultaneously on separate machines; a dependent app waits for successful signed results and receives verified predecessor artifacts. Paid compute marketplaces remain direction.
Choose a deployment
| Environment | Starting point | Why |
|---|---|---|
| Fresh VPS or any Docker host | Docker or Podman | The recommended layout, with a Docker-in-Docker sidecar or a host daemon socket |
| NixOS | Flake modules | Declarative coordinator and adapter services with protected credentials |
| Proxmox | Unprivileged LXC | Fits an existing virtualisation host; KVM sandboxing needs a VM instead |
| Untrusted workflows | microVM adapter | A fresh QEMU/KVM microVM per job, destroyed afterwards |
| Custom host | Static release archives or cargo install ngit-ci | Tagged releases publish statically linked x86_64 Linux binaries as NIP-82 assets; the host still needs git, act 0.2.86 or newer, and a container daemon or an adapter |
Coordinate Nix jobs on remote workers
The Nix path is experimental and opt-in. On NixOS, enable experimentalNix, configure nixProviders with the trusted provider public keys, and choose runner = "none" when the coordinator should perform no local act execution. On each worker, enable services.ngit-ci-nix-provider, trust the coordinator key, and advertise the native systems it can execute.
Use a shared discovery/inbox relay that accepts provider advertisements and allocations. Repository GRASP relays may accept results while refusing those standalone advertisements. The NixOS guide has the module configuration; the provider guide owns options, recovery, caches, and transport limits.
For two one-slot workers, set each provider's maxJobs = 1 and, when using Firecracker, its adapter's maxJobs = 1. Advertisements report total and free capacity. Workers reserve their own slots and reject races before execution; the coordinator can reassign safely rejected work or wait for capacity. This is not a global lock for production publication: design release ordering explicitly when several providers can execute a publishing app.
Direct providers are for trusted work. Nix's derivation sandbox does not isolate arbitrary flake apps from the worker host. Ordinary PR jobs require hardware isolation and secret-free jobs; use the Firecracker adapter for that boundary. A provider's network policy must permit the source mirrors, caches, Blossom servers, and any remote signer required by authorized apps.
Before adopting directory artifacts or packaging options, upgrade providers and their Firecracker guest templates, then the coordinator. Older providers reject extended allocations, and older coordinators cannot resolve manifests. The artifact walkthrough explains the workflow migration; product references remain separately pinned until the release import runs.
Container quick start
From a clean checkout of the repository:
bash
NGIT_CI_REPOS=npub1.../my-repo docker compose up --build -dThat starts the coordinator plus a dedicated Docker-in-Docker daemon for job containers, watching the repositories listed in NGIT_CI_REPOS. The coordinator generates its signing key on first start and keeps all state in the coordinator-data volume. The Docker guide covers prerequisites, persistence, the host-socket variant, and upgrades.
A running coordinator serves nothing yet. Maintainers of the listed repositories must request service, as described below.
Configure the coordinator
Configure ngit-ci is the imported reference for every option, the Service Request policy, host requirements, the build cache, identity keys, multi-architecture layouts, resource limits, and per-repository secrets. Every option is accepted as a CLI flag, an NGIT_CI_* environment variable, or a .env entry.
The generated reference is the machine-checked authority for names, defaults, validation rules, and secret precedence. The coordinator and the microVM adapter are separate processes, so their pages stay separate and options cannot be applied to the wrong service:
The reference is labelled upcoming because it follows an immutable commit selected from the source repository’s current HEAD during sync. The exports and operator guides share that commit. Its package version does not imply that this snapshot is a stable release; each page records its exact provenance.
Choose an execution boundary
| Runner | Isolation | Use when |
|---|---|---|
Embedded act | Per-job container on the coordinator's host | You control the repositories and the host runtime |
| Socket adapter | Adapter-defined | You already operate a sandbox that speaks the Loom execution-adapter contract |
| First-party act microVM adapter | Fresh QEMU/KVM VM per job | You run act workflows you do not fully trust |
| Direct Nix provider | Nix build sandbox; apps execute on the provider host | You trust the workflows and dedicate the worker appropriately |
| Nix provider with Firecracker | Fresh hardware VM for checkout, evaluation, builds, and apps | You serve ordinary PR builds or need a stronger host boundary |
The socket contract is Loom's, adopted unchanged, so the existing Loom adapters work as they are. Run the microVM adapter covers the first-party one.
Execution policy and getting listed
By default, push and pull request workflows wait for a maintainer's standing Service Request addressed to this coordinator. Automatic execution is an explicit trust and resource decision, not a quick-start default, and runs it produces can never be rated maintainer-directed by clients. See the Service Request policy.
Listing a repository in NGIT_CI_REPOS discovers it and advertises the coordinator as ready for it, which is what puts you in GitWorkshop's coordinator directory for that repository. The maintainer then requests service from GitWorkshop or with ngit ci request, as in Request service. Manual triggers bypass the standing gate for one run. Any payment or terms are settled between you and the maintainer out of band; the advertisement only says whether you bill.
Secrets
Secrets reach only runs whose trigger a confirmed maintainer authored. A third-party pull request always runs with empty secrets, so a contributor cannot lift a deploy token by editing a workflow. Values are never published; the Repository Status lists only the names in use.
For Nix, a job must name every secret it needs. The coordinator encrypts those values to the selected trusted provider; the app reads job-private files after its tool closure is built. Exact granted values are redacted from public log excerpts and scalar outputs, but transformed values and artifact contents are not covered. Keep secrets out of logs and artifacts. See secret-bearing work.
Values arrive by two paths:
- Operator-provisioned. Environment variables or systemd credentials keyed to a repository alias, described under per-repo secrets.
- Maintainer-provisioned over Nostr. Set
NGIT_CI_NOSTR_SECRET_RELAYSto at least one inbox relay and the coordinator advertises a secrets key. Maintainers then provision values from GitWorkshop, encrypted to that key, and can bind their repository to their own NIP-46 bunker so the coordinator never holds the values at rest.
The generated secret resolution page owns the precedence between the two. The authorization rule, its decision sequence, and its regression coverage are in the repository's secret-authorization.md.
Protect the important boundaries
Identity
The coordinator's key is its reputation: clients attach trust context to it, and maintainers request service from it by pubkey. Supply it through a protected environment variable or a service credential, never on the command line, and back up the generated key from the data volume before you rely on it. See coordinator identity key.
Container runtime
CI executes repository code
The coordinator never runs workflow steps on its host, but its container runtime is still a high-value boundary. Job containers get no daemon socket by default, workflows that declare their own containers are refused under the default policy, and the operator dictates per-job resource caps. Keep those defaults unless you trust every workflow author, and use the microVM adapter for the rest.
See job container policy.
Storage and uploads
State lives in the work directory: the identity key, queue state, processed event ids, and the trust-scoped build cache. Logs and artifacts leave the host only when you enable Blossom uploads, and the uploaded files are then public by content hash. Enable uploads deliberately and cap them.
Network
The coordinator needs outbound access to relays, Git servers, and Blossom. It exposes nothing inbound. Job containers get outbound access too; if that is too much for the workflows you serve, the microVM adapter's outbound-only networking is the stronger boundary.
Next
- Use Nostr CI: what maintainers do once you are listed
- act workflow files: Actions-compatible jobs
- Nix workflow files: flake outputs and cross-provider dependencies
- Understanding Nostr CI
- Host ngit-grasp
- Self-hosting overview