Introduction

Omnix aims to supplement the Nix CLI to improve developer experience. View the Github repo for ongoing progress.

Omnix Logo

Install

To install Omnix, you first need Nix installed,1 before running the following:

# Install omnix (using om.cachix.org Nix cache)
nix --accept-flake-config profile install github:juspay/omnix

# Make sure that the `om` command works
om --help

Next Steps

Checkout the CLI commands available.

Discussion

For discussing Omnix, use Github Discussions or Zulip.

1

We also plan to provide a static binary. See #207

The om CLI

The Omnix CLI currently provides a fully-functioning health and ci commands. The show command has basic functionality, whereas the init command can be used to scaffold new projects using Nix. The develop command enriches flakes support when used with direnv.

Show

The om show command seeks to provide a better nix flake show experience.

warning

Currently, om show is a wrapper on nix flake show, but with support for flake schemas. More is planned for om show. See issue #162.

Usage

Run om show on any flake - via URL or local path.

$ om show github:srid/nixos-config
[..]
๐Ÿ“ฆ Packages (nix build github:srid/nixos-config#<name>)
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ name     โ”‚ description                                           โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ activate โ”‚ Activate NixOS/nix-darwin/home-manager configurations โ”‚
โ”‚ update   โ”‚ Update the primary flake inputs                       โ”‚
โ”‚ default  โ”‚ Activate NixOS/nix-darwin/home-manager configurations โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

๐Ÿš Devshells (nix develop github:srid/nixos-config#<name>)
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ name    โ”‚ description                      โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ default โ”‚ Dev environment for nixos-config โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

๐Ÿ” Checks (nix flake check)
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ name       โ”‚ description โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ pre-commit โ”‚ N/A         โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

๐Ÿง NixOS Configurations (nixos-rebuild switch --flake github:srid/nixos-config#<name>)
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ name       โ”‚ description โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ gate       โ”‚ N/A         โ”‚
โ”‚ vixen      โ”‚ N/A         โ”‚
โ”‚ pureintent โ”‚ N/A         โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

๐Ÿ Darwin Configurations (darwin-rebuild switch --flake github:srid/nixos-config#<name>)
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ name       โ”‚ description โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ appreciate โ”‚ N/A         โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

๐Ÿ”ง NixOS Modules
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ name    โ”‚ description โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ common  โ”‚ N/A         โ”‚
โ”‚ default โ”‚ N/A         โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

๐ŸŽจ Overlays
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ name    โ”‚ description โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ default โ”‚ N/A         โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

om health

The om health command checks the health of your Nix install. Furthermore, individual projects can configure their own health checks in their flake.nix. For example, the nammayatri project checks that the cachix cache is in use.

note

History: om health was formerly called nix-health.

Checks performed

CheckConfigurable in flake.nix?
Flakes are enabled-
Nix version is not too oldYes
Nix runs natively (no rosetta)1Yes
Builds use multiple cores (max-jobs)Yes
Nix Caches in useYes
$USER is in trusted-users-
Direnv: installed and activatedYes
Dotfiles are managed by NixYes
Min RAM / Disk spaceYes
1

This check is only performed on macOS with Apple Silicon.

Note that some checks are considered non-essential. For eg., the disk space check looks for 1TB+ disk space, but if the user is on a laptop with 256GB SSD, the check will report a warning instead of failing. This can also be configured in per-project basis from flake.nix (see below).

Usage

om health

To run use the health check configuration specified in a project flake, pass that flake as an argument. For eg., to run halth checks defined from the nammayatri project, run:

# The argument can be any flake URL (including a local path)
om health github:nammayatri/nammayatri

Per-project configuration

To add project specific health checks or configure health checks, add the following to your om.yaml:

health:
  default:
    caches:
      required:
        - "https://ourproject.cachix.org"

To see all available configuration options, run om health --dump-schema. This will dump the schema of the configuration in JSON format. Convert that to YAML to see what can be added under the om.health.default key of your om.yaml.

$ om health --dump-schema | nix run nixpkgs#yq-go -- -P

This will output:

flake-enabled: {}
nix-version:
  min-required: 2.16.0
rosetta:
  enable: true
  required: true
max-jobs: {}
trusted-users: {}
caches:
  required:
    - https://cache.nixos.org/
direnv:
  enable: true
  required: false
shell:
  enable: true
  required: false

Adding devShell check

You can automatically run om health as part of direnv invocation; see om develop for details.

Develop

The om develop command should be used indirectly in direnv, via the use omnix directive in your .envrc.

Getting started

  1. Put this in your .envrc file:

    source_url https://raw.githubusercontent.com/juspay/omnix/75ed48923835963e2f18baba08f54a8adc307ba2/omnixrc "sha256-8C2Jb5bHx/0cvm1+9gOlBEdWzbikCWT5UsJWewUAFt4="
    watch_file om.yaml
    use omnix
    
  2. You should also create an empty (or fleshed out) om.yaml file in your project to avoid Nix evaluation:

    touch om.yaml
    

What does it do?

use omnix wraps use flake (of nix-direnv) providing additional capabilities:

  • Run om health to check the health of the Nix environment.
    • Run cachix use automatically if the project uses cachix.
  • Print a welcome text after spawning the Nix devshell.

The ideal goal here being that cdโ€™ing to a project should do everything necessary to get you started immediately.

Welcome text

The welcome text can be configured in your om.yaml file. For example:

develop:
  default:
    readme: |
      ๐Ÿพ Welcome to the **omnix** project

      To run omnix,

      ```sh-session
      just watch <args>
      ```

      (Now, as you edit the Rust sources, the above will reload!)

      ๐ŸŽ๐ŸŽ Run 'just' to see more commands. See <https://nixos.asia/en/vscode> for IDE setup.

om ci

om ci runs CI for your project. It builds all outputs in the flake, or optionally its sub-flakes. You can run om ci locally or in an actual CI envirnoment, like GitHub Actions. Using devour-flake it will automatically build the following outputs:

TypeOutput Key
Standard flake outputspackages, apps, checks, devShells
NixOSnixosConfigurations.*
nix-darwindarwinConfigurations.*
home-managerlegacyPackages.${system}.homeConfigurations.*

The stdout of om ci run will be a list of store paths built.

tip

If you are familiar with nixci, om ci is basically the successor to nixci.

Basic Usage

om ci run accepts any valid flake URL or a Github PR URL.

# Run CI on current directory flake
$ om ci # Or `om ci run` or `om ci run .`

# Run CI on a local flake (default is $PWD)
$ om ci run ~/code/myproject

# Run CI on a github repo
$ om ci run github:hercules-ci/hercules-ci-agent

# Run CI on a github PR
$ om ci run https://github.com/srid/emanote/pull/451

# Run CI only the selected sub-flake
$ git clone https://github.com/srid/haskell-flake && cd haskell-flake
$ om ci run .#default.dev

# Run CI remotely over SSH
$ om ci run --on ssh://myname@myserver ~/code/myproject

Using in Github Actions

In addition to serving the purpose of being a โ€œlocal CIโ€, om ci can be used in Github Actions to enable CI for your GitHub repositories.

Standard Runners

Add this to your workflow file (.github/workflows/ci.yml) to build all flake outputs using GitHub provided runners:

      - uses: actions/checkout@v4
      - uses: DeterminateSystems/nix-installer-action@main
      - name: Install omnix
        run: nix --accept-flake-config profile install "github:juspay/omnix"
      - run: om ci

Self-hosted Runners with Job Matrix

Hereโ€™s a more advanced example that configures a job matrix. This is useful when you want to run the CI on multiple systems (e.g. aarch64-linux, aarch64-darwin), each captured as a separate job by GitHub, as shown in the screenshot below. It also, incidentally, demonstrates how to use self-hosted runners.

The om ci gh-matrix command outputs the matrix JSON for creating a matrix of job variations. An example configuration, using self-hosted runners, is shown below.

note

This currently requires an explicit CI configuration in your flake, setting om.ci.default.root.dir to ..

# Run on aarch64-linux and aarch64-darwin
jobs:
  configure:
    runs-on: x86_64-linux
    outputs:
      matrix: ${{ steps.set-matrix.outputs.matrix }}
    steps:
     - uses: actions/checkout@v4
     - id: set-matrix
       run: |
         set -euxo pipefail
         MATRIX="$(om ci gh-matrix --systems=x86_64-linux,aarch64-darwin | jq -c .)"
         echo "matrix=$MATRIX" >> $GITHUB_OUTPUT
  nix:
    runs-on: ${{ matrix.system }}
    needs: configure
    strategy:
      matrix: ${{ fromJson(needs.configure.outputs.matrix) }}
      fail-fast: false
    steps:
      - uses: actions/checkout@v4
      - run: om ci run --systems "${{ matrix.system }}" ".#default.${{ matrix.subflake }}"

tip

If your builds fail due to GitHubโ€™s rate limiting, consider passing --extra-access-tokens (see an example PR). If you get rate limits when accessing github:nix-systems, use this workaround.

Configuring

By default, om ci will build the top-level flake, but you can tell it to build sub-flakes (here, ./dir1 and ./dir2) by adding the following to your Om configuration:

# myproject/flake.nix
{
  om.ci.default = {
    dir1 = {
      dir = "dir1";
    };
    dir2 = {
      dir = "dir2";
      overrideInputs.myproject = ./.;
    };
  }
}

You can have more than one CI configuration. For eg., om ci run .#foo will run the configuration from om.ci.foo flake output.

Custom CI actions

You can define custom CI actions in your flake, which will be run as part of om ci run. For example, to run tests in the nix develop shell:

{
  om.ci.default = {
    root = {
      dir = ".";
      steps = {
        # The build step is enabled by default. It builds all flake outputs.
        build.enable = true;
        # Other steps include: lockfile & flake-check

        # Users can define custom steps to run any arbitrary flake app or devShell command.
        custom = {
          # Here, we run cargo tests in the nix shell
          # This equivalent to `nix develop .#default -c cargo test`
          cargo-test = {
            type = "devshell";
            # name = "default"
            command = [ "cargo" "test" ];
          };

          # We can also flake apps
          # This is equivalent to `nix run .#check-closure-size`
          closure-size = {
            type = "app";
            name = "check-closure-size";
          };
        };
      };
    };
  };
}

For a real-world example of custom steps, checkout Omnixโ€™s configuration.

Examples

Some real-world examples of how om ci is used with specific configurations:

warning

These examples use the predecessor, nixci, so you want to replace nixci with om ci wherever applicable.

What it does

  • Check that the Nix version is not tool old (using om health)
  • Determine the list of flakes in the repo to build
    • By default, this is the root flake.
    • The user can also explicitly specify multiple sub-flakes in om.ci.default output of their root flake.
  • For each (sub)flake identified, om ci run will run the following steps:
    • Check that flake.lock is up to date, if applicable.
    • Build all flake outputs, using devour-flake1
      • Then, print the built store paths to stdout
    • If the flake-check step is enabled (example), run nix flake check
    • Run user defined custom steps
1

Support for flake-schemas is planned

See also

  • github-nix-ci - A simple NixOS & nix-darwin module for self-hosting GitHub runners
  • jenkins-nix-ci - Jenkins NixOS module that supports nixci (predecessor of om ci) as a Groovy function
  • cachix-push - A flake-parts module that provides an app to enable whitelisted pushing and pinning of store paths to cachix.

om init

The om init command provides a better nix flake init experience. Specifically, it provides:

  1. a registry of flake templates that you can choose from
  2. support for template paramters that can be filled in by the user

To get started, run:

om init -o ~/myproject

This will prompt you to choose a template from the builtin registry (see below section), and then initialize it in the myproject directory.

Builtin registry

The builtin registry (stored in a flake) contains the following templates:

Initializing your own project templates

If your flake provides a om.templates output (see below section), then om init will recognize it. For example:

om init -o ~/myproject github:srid/haskell-flake

Because haskell-flake has a om.templates output, om init will prompt you to fill in the parameters defined in the template and initialize it.

You can also explicitly specify the template to choose from the flake:

om init -o ~/myproject github:srid/haskell-flake#haskell-flake

If there are multiple templates in the flake (as is the case with the builtin registry), omnix will the prompt the user to choose from them.

Configuration spec

Omnix templates can be defined by adding a om.template flake output configuration. This should be an attrset of templates. The value should contain the keys template (referring to original flake template) as well as params, defined as follows:

There are two kinds of params. String params are defined as follows:

{
  name = "package-name";
  description = "Name of the Rust package";
  placeholder = "rust-nix-template";
}

Here, when prompting for this param, the user-provided value if any will replace the given placeholder text across all files in the template.

Boolean params are defined as follows:

{
  name = "vscode";
  description = "Include the VSCode settings folder (./.vscode)";
  paths = [ ".vscode" ];
  value = true;
}

Here, if the user enables this param, the path globs specified in paths will be retained in the template. Otherwise, the paths will be deleted. The value key provides a default value; which key is supported for string params as well.

Both parameter types are distinguished by the presence of the relevant keys (placeholder for string, paths for boolean).

Testing templates

The configuration can also include a tests key that defines a list of tests to run on the template. Each test is an attrset with params and asserts keys that indicates the parameter values to test along with the path existance assertions. For example:

{
  tests = {
    default = {
      # systems = [ ]; # Optional whitelist of systems to limit this test to
      params = {
        username = "john";
        git-email = "[email protected]";
        git-name = "John Doe";
        neovim = true;
      };
      asserts = {
        # Path assertion tests under template output
        source = {
          # true means the path must exist; false means it must not exist
          "modules/home/neovim/default.nix" = true;
          ".github/workflows" = false;
        };
        # Path assertion tests under the output of a Nix package
        packages."homeConfigurations.john.activationPackage" = {
          "home-path/bin/nvim" = true;
        };
      };
    };
  };
}

Omnix Configuration

You can configure Omnixโ€™s behaviour on your repository by creating a top-level om.yaml file. If there is no om.yaml file, Omnix will evaluate the flakeโ€™s .#om output instead. Prefer creating a om.yaml in general, as it is faster to read than evaluating complex Nix flakes.

note

For am example om.yaml, see that of omnix itself

Release history

Unreleased

Enhancements

  • om develop: New command
  • om init
    • Initial working version of om init command
  • om health
    • Display Nix installer used (supports DetSys installer)
    • Display information in Markdown
    • Remove RAM/disk space checks, moving them to โ€œinformationโ€ section
    • Add shell check, to ensure its dotfiles are managed by Nix.
    • Add --json that returns the health check results as JSON
  • om ci
    • Support for remote builds over SSH (via --on option)
    • Support for CI steps
      • Run nix flake check on all subflakes (#200)
      • Ability to add a custom CI step. For example, to run arbitrary commands.
    • Add --accept-flake-config
    • Add --results=FILE to store CI results as JSON in a file
    • Misc
      • Avoid running nix-store command multiple times (#224)
      • Locally cache github:nix-systems (to avoid Github API rate limit)

Fixes

  • om ci run: The --override-input option mandated flake/ prefix (nixci legacy) which is no longer necessary in this release.
  • om health: Use whoami to determine username which is more reliable than relying on USER environment variable

Backward-incompatible changes

  • nix-health and nixci flake output configurations are no longer supported.
  • om ci build has been renamed to om ci run.

0.1.0 (2024-08-08)

Initial release of omnix.