Open-source project
nlewo/comin avatar
nlewo/comin

comin lets the NixOS machine pull its own configuration

GitOps For NixOS Servers and Laptops

1,181 stars74 forksGoMIT

At a glance

What is it?
comin is a MIT licensed Go tool that runs on a NixOS machine, polls Git repositories on a timer and deploys the configuration associated with that machine, which is the opposite of the usual push model. It supports flake and non-flake repositories, several remotes, testing branches, commit signature checks, machine migrations and a Prometheus exporter, and it also manages nix-darwin for macOS.
Who is it for?
comin suits a team that wants Git to be the only way a machine's configuration changes, and that would rather have each host fetch its own configuration than open an inbound path to every machine. It does not suit a team whose deployment model already includes a central runner with credentials for every host, and it is the wrong tool for a machine that is not NixOS or nix-darwin.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 7, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • nlewo/comin1,181 ★ · +78
Star history
Repository2026-10-212026-11-07
nlewo/comin1.1k1.2k

78 Stars in the last 17 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

Pull mode moves the initiative to the machine

comin is described as a NixOS deployment tool operating in pull mode. Running on a machine, it periodically polls Git repositories and deploys the NixOS configuration associated to the machine.

That single sentence is the whole architecture, and everything else in the project follows from it. The usual GitOps shape is push: a pipeline holds credentials for the target, connects to it, and rebuilds the configuration there. In pull mode the relationship is inverted. The machine holds the credentials, it goes and fetches, and it decides when to apply what it found. Nothing needs to connect in to the machine, which removes a whole class of network exposure and is why the model suits laptops and machines in networks that cannot be reached from a build server.

The cost of the inversion is that the machine is the one polling, so the credential for the infrastructure repository lives on the machine it configures. The project has a documentation page on authentication for that reason, and a separate page on how to migrate a configuration from one machine to another, which is the operation you need when the credential and the identity move together.

The audience is a team that has already committed to NixOS as its configuration system, manages configuration in Git, and wants the machines to be self-updating without a central deployment service. The project is written in Go, the module is github.com/nlewo/comin, and it is MIT licensed.

The flake module wires up a systemd service and a timer

The quick start is a flake, and the interesting part of it is the module configuration rather than the flake plumbing. The comin.nixosModules.comin module is added to the machine's modules alongside a configuration block that enables the service and declares the remote:

nix
modules = [
  comin.nixosModules.comin
  ({
    services.comin = {
      enable = true;
      remotes = [{
        name = "origin";
        url = "https://gitlab.com/your/infra.git";
        branches.main.name = "main";
      }];
    };
  })
]

The service that this enables periodically pulls the main branch of the repository and deploys the NixOS configuration corresponding to the machine hostname, in the example myMachine, and the README states the timing plainly: a new commit in the main branch is deployed in the next 60 seconds.

The branch mapping is a first class part of the configuration rather than an assumption, since branches.main.name = 'main' says which remote branch to track. That structure is what makes the testing branch feature work, and it also gives you the shape of the configuration for a machine that tracks a different branch deliberately, which is a common way to stage a change before it goes to everyone.

The module options are extensive and the README does not pretend otherwise, pointing instead to the generated module options documentation for the full list. The design documentation is also linked, along with advanced configuration, howtos and contribute pages.

Several remotes, so one dead remote is not an outage

The feature list is where the operational thinking shows, and two entries are about failure rather than about features.

The first is support for polling multiple Git remotes to avoid SPOF. The second is support for testing branches to try changes.

Multiple remotes matter because the obvious single-remote design has a single point of failure that is easy to miss. If the one remote a fleet of machines polls is unreachable, every machine in the fleet stops updating, and the symptom looks like a network problem rather than a repository problem. With more than one remote configured, comin can carry on with whatever it can reach, which is the same reasoning that makes content delivery networks redundant.

Testing branches address a different risk, which is that a configuration change is applied everywhere at once. The howto on how to test a NixOS configuration change is a separate document from the main one, and the branch mapping in the module configuration is the mechanism: point a machine at a branch, and the changes on that branch are what it deploys.

There is also a third operational feature worth naming, support for machines migrations, and the fast iterations with local remotes howto, which covers the workflow of testing a change against a local repository before it goes to the shared one. Together, the three cover the cycle of a change: try it locally, stage it on a branch, roll it out through a remote that is not the only one.

Signature checking and system profiles are the admin surfaces

Two features in the list are about the state of the machine rather than about fetching configuration, and they are the ones an operator will configure first.

The first is the optional check of GPG and SSH Git commit signatures. The howto is titled check Git commit signatures, and the word optional matters, because signature verification is only useful if the verification keys are on the machine and the trust model is decided in advance. It is a meaningful control for a pull mode agent, because the agent is the thing that applies whatever it finds, so being able to say that only signed commits are applied is a real property of the deployment rather than a property of the pipeline.

The second is the creation and deletion of system profiles, listed as pushpin in the feature list. This is the mechanism by which an applied configuration becomes the running system, and the ability to create and delete them is what lets a machine move between configurations without a manual step.

The Go dependency list explains how the first one is implemented. github.com/ProtonMail/go-crypto is the GPG implementation, and golang.org/x/crypto supplies the SSH primitives, so both signature schemes are verified in process rather than by shelling out to gpg or ssh-keygen. The presence of a second signature scheme matters, because GPG alone is increasingly awkward to configure on a fresh machine and SSH signing is the path most of the Nix ecosystem has already taken.

The rest of the dependency set is what you would expect from a small daemon: go-git for the Git client, go-co-op/gocron for the polling schedule, cobra for the command line, logrus for logging, and the Prometheus client for the metrics.

Observability, a terminal UI and desktop notifications

comin exposes itself through Prometheus metrics, and the module options documentation links the exporter configuration under services.comin.exporter. For a pull mode agent, metrics are not a luxury, because the failure mode of a polling agent is silence. A machine that has stopped polling looks exactly like a machine that has nothing to deploy, and the only way to tell the difference is a signal from the agent itself.

The dependency list also shows a terminal interface and desktop notifications. charm.land/lipgloss and github.com/charmbracelet/bubbletea are the TUI framework, with bubbles for widgets, and github.com/gen2brain/beeep is a cross platform desktop notification library. There is also github.com/dustin/go-humanize for rendering sizes and durations in a readable form, and github.com/google/uuid for identifiers.

A pull mode agent that runs on a laptop needs a different interface from one that runs on a headless server, and a terminal UI with notifications is a plausible way to tell a laptop user that their configuration just changed underneath them. The README does not describe the interface in detail, so the extent of it is something to check in the code.

The communication path is gRPC and protobuf, google.golang.org/grpc and google.golang.org/protobuf, and they are in the direct dependency list rather than the indirect one, which suggests the tool exposes an API surface of its own rather than only being a command line program.

nix-darwin, migrations and where the project stands

The feature list includes Git push to deploy NixOS configurations, or a nix-darwin configuration, with the howto linked, and the support for machines migrations is listed separately. Those two together mean comin is not strictly a NixOS server tool.

A nix-darwin configuration is the macOS equivalent of a NixOS one, and the same pull model applies to it, so a laptop in the fleet is configured the same way as a server. The migration support is the piece that makes that practical, since moving a configuration from one machine to another means the machine identity, the credential and the configuration all have to move in step.

On the state of the project, the repository is not archived and the last push was on 2026-10-12, with releases v0.12.0 in March 2026, v0.13.0 in May and v0.14.0 in July, and the v0.14.0 release note is SSH support. That is a useful signal about where the project is going, because a pull mode agent with SSH support can be driven from outside as well, which blurs the line with the push model it was designed to avoid.

The version numbers are still in the zero series, which in Go usually means the API is not settled, and for a tool that is installed into a fleet that is worth remembering. The repository is laid out as a conventional Go project with main.go, cmd/, internal/, pkg/ and nix/ directories alongside flake.nix, flake.lock and default.nix, and the community runs a Matrix room at #nixos-comin on matrix.org. The licence is MIT, and the documentation set, howtos, advanced configuration, authentication, generated module options, design and contribute, is the reference for all of the above.

Editorial conclusion

comin suits a team that wants Git to be the only way a machine's configuration changes, and that would rather have each host fetch its own configuration than open an inbound path to every machine. It does not suit a team whose deployment model already includes a central runner with credentials for every host, and it is the wrong tool for a machine that is not NixOS or nix-darwin. Verify first the polling interval against how quickly you need a change to land, since the README's example describes a deployment within the next 60 seconds, and read the authentication documentation, because pull mode means the credential for your infrastructure repository lives on the machine it configures.

Frequently asked questions

What does comin do on a NixOS machine?

It runs as a service that periodically polls Git repositories and deploys the NixOS configuration associated to the machine, in pull mode, so a new commit on the tracked branch is applied by the machine itself rather than pushed to it.

How do I enable comin in a NixOS flake?

Add comin.nixosModules.comin to the machine's modules, enable services.comin and declare a remote with its url and branch mapping, as in the README's example that tracks the main branch of a GitLab infrastructure repository.

How quickly does a commit reach the machine with comin?

The README's example says a new commit in the main branch of the infrastructure repository is deployed in the next 60 seconds, and the polling schedule is among the module options described in the generated module options documentation.

Can comin work with more than one Git remote?

Yes. The feature list includes polling multiple Git remotes to avoid a single point of failure, with the remotes declared in the services.comin configuration and documented in the generated module options page.

Does comin verify commit signatures?

It can, optionally, checking GPG and SSH Git commit signatures, and there is a howto on the topic. The Go dependencies include ProtonMail go-crypto for GPG and golang.org/x/crypto for the SSH side.

Official sources

  1. Issues
  2. License: MIT
  3. nlewo/comin on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/nlewo-comin.svg)](https://hysenlabs.com/projects/nlewo-comin)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/nlewo-comin.svg)](https://hysenlabs.com/projects/nlewo-comin)

Was this useful?