# Nix O'matic > Reproducible environments. Made easy. Nix O'matic lets you spin up any development environment in seconds using Nix, with support for package versioning, pinning, and multiple runtimes. --- Source: https://nixomatic.com/index.md # Nix O'matic Reproducible environments. Made easy. Spin up any environment in seconds with a single `nix develop` command. Mix and match packages from any [nixpkgs](https://github.com/NixOS/nixpkgs) revision — no install, no setup, fully reproducible. ## Spin up any environment in seconds ### Using Nix Use [`nix develop`](https://nixos.org/download/) to get started: ```bash nix \ --extra-experimental-features 'nix-command flakes' \ develop 'https://nixomatic.com/?packages=cowsay' \ --accept-flake-config \ --command -- cowsay 'Hello, world!' ``` ```text _______________ < Hello, world! > --------------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || || ``` ### Using Docker ```bash docker run -v nix-store:/nix --rm nixos/nix nix \ --extra-experimental-features 'nix-command flakes' \ --option build-users-group "" \ develop 'https://nixomatic.com/?packages=cowsay' \ --accept-flake-config \ --command -- cowsay 'Hello, world!' ``` ```text _______________ < Hello, world! > --------------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || || ``` ## One command. Any environment. Nix O'matic generates Nix flakes on-the-fly so you can get the exact tools you need, instantly. - **Any package, any version**: Request any package from `nixpkgs` by name, pin an exact version with `nodejs@20.11.1`, or lock to a precise revision with `python3:3b93cf5`. - **No Nix? Need a sandbox?**: Run any environment through the official `nixos/nix` Docker image — no Nix install required, and nothing touches your host. Perfect for trying before you install, or for running untrusted code in an isolated container even when Nix is already on your machine. - **Fully reproducible**: Every environment is generated from real nixpkgs revisions, so the shell you get today is the shell you'll get a year from now. - **Mix revisions freely**: Combine packages that only coexist across different nixpkgs revisions in a single shell — no dependency conflicts, no manual overlays. - **CI/CD ready**: Drop the [GitHub Action](https://github.com/marketplace/actions/nixomatic-action) into any workflow for reproducible CI environments with exactly the packages and versions you pin. - **Built for AI agents**: The [Agent Skill](https://docs.nixomatic.com/agent-skill) lets Claude Code and Codex auto-detect dependencies and run your project in a configured Nix environment. [See all usage examples](https://docs.nixomatic.com/) --- Source: https://docs.nixomatic.com/index.md # Documentation Common ways to use `nix develop` with Nix O'matic. ## Single package Ask for a single package by name: ### Using Nix ```bash nix \ --extra-experimental-features 'nix-command flakes' \ develop 'https://nixomatic.com/?p=cowsay' \ --accept-flake-config \ --command -- cowsay 'Hello, world!' ``` ### Using Docker ```bash docker run -v nix-store:/nix --rm nixos/nix nix \ --extra-experimental-features 'nix-command flakes' \ --option build-users-group "" \ develop 'https://nixomatic.com/?p=cowsay' \ --accept-flake-config \ --command -- cowsay 'Hello, world!' ``` Pipe data into a tool inside the environment: ### Using Nix ```bash echo 'Hello, world!' | \ nix \ --extra-experimental-features 'nix-command flakes' \ develop 'https://nixomatic.com/?p=cowsay' \ --accept-flake-config \ --command -- cowsay ``` ### Using Docker ```bash echo 'Hello, world!' | \ docker run -v nix-store:/nix --rm -i nixos/nix nix \ --extra-experimental-features 'nix-command flakes' \ --option build-users-group "" \ develop 'https://nixomatic.com/?p=cowsay' \ --accept-flake-config \ --command -- cowsay ``` ## Multiple packages Request multiple packages with comma-separated values in an interactive shell: ### Using Nix ```bash nix \ --extra-experimental-features 'nix-command flakes' \ develop 'https://nixomatic.com/?p=rustc,cargo' \ --accept-flake-config ``` ### Using Docker ```bash docker run -v nix-store:/nix --rm -it nixos/nix nix \ --extra-experimental-features 'nix-command flakes' \ --option build-users-group "" \ develop 'https://nixomatic.com/?p=rustc,cargo' \ --accept-flake-config ``` ## Versioning Use `:` to pin a package to a specific nixpkgs revision: ### Using Nix ```bash nix \ --extra-experimental-features 'nix-command flakes' \ develop 'https://nixomatic.com/?p=python3:3b93cf5' \ --accept-flake-config ``` ### Using Docker ```bash docker run -v nix-store:/nix --rm -it nixos/nix nix \ --extra-experimental-features 'nix-command flakes' \ --option build-users-group "" \ develop 'https://nixomatic.com/?p=python3:3b93cf5' \ --accept-flake-config ``` Pin to a specific package version with `@`. Versions are resolved with [nixpkgs-multiverse](https://github.com/fzakaria/nixpkgs-multiverse), which indexes every version of every package nixpkgs ever shipped: ### Using Nix ```bash nix \ --extra-experimental-features 'nix-command flakes' \ develop 'https://nixomatic.com/?p=nodejs@20.11.1' \ --accept-flake-config ``` ### Using Docker ```bash docker run -v nix-store:/nix --rm -it nixos/nix nix \ --extra-experimental-features 'nix-command flakes' \ --option build-users-group "" \ develop 'https://nixomatic.com/?p=nodejs@20.11.1' \ --accept-flake-config ``` If a version is not in the index, `nix develop` tells you which versions of that package do exist. ## Listing available package versions To find out before building, ask `/versions`. It answers from the same index revision the generated flake pins, so every version it lists is a version that flake accepts: ```bash curl 'https://nixomatic.com/versions?p=nodejs' ``` ```json { "nodejs": ["0.10.21", "0.12.7", "…", "24.18.1"] } ``` The answer is keyed by the spec you asked for, whether you asked about one package or ten, so you read every response the same way. Versions come oldest first. Ask for several packages the same way you would anywhere else — comma-separated, or by repeating `p=` — and each gets its own entry: ```bash curl 'https://nixomatic.com/versions?p=nodejs,python3' ``` ```json { "nodejs": ["0.10.21", "0.12.7", "…", "24.18.1"], "python3": ["3.3.2", "3.4.3", "…", "3.14.6"] } ``` ### What a revision ships Add `:` and a revision to ask what version that revision has, rather than every version there is. Each spec keeps its own entry, so several revisions of one package can be compared in a single request: ```bash curl 'https://nixomatic.com/versions?p=python3:3b93cf5&p=python3:afb4584' ``` ```json { "python3:3b93cf5": "3.13.11", "python3:afb4584": "3.14.6" } ``` A revision ships one version of a package, so its entry is that version itself rather than a list of one, and `null` when that revision has no such package. This is evaluated from nixpkgs at that revision rather than looked up in an index, so the first request for a revision takes seconds. ### What is not accepted `@` is refused: a version is what this endpoint returns, not something to ask with. Ask for the package and look through the answer instead. Overrides are refused for the same kind of reason — they do not change what versions exist. A package the index does not cover comes back with no versions rather than an error — an empty list, or `null` when asked at a revision — so an empty answer means either a misspelled package or one that was never indexed. ## Mixed Or mix and match both: ### Using Nix ```bash nix \ --extra-experimental-features 'nix-command flakes' \ develop 'https://nixomatic.com/?p=cowsay:ed142ab,python3:3b93cf5,nodejs@20.11.1' \ --accept-flake-config ``` ### Using Docker ```bash docker run -v nix-store:/nix --rm -it nixos/nix nix \ --extra-experimental-features 'nix-command flakes' \ --option build-users-group "" \ develop 'https://nixomatic.com/?p=cowsay:ed142ab,python3:3b93cf5,nodejs@20.11.1' \ --accept-flake-config ``` --- Source: https://docs.nixomatic.com/github-action.md # GitHub Action The [Nixomatic GitHub Action](https://github.com/marketplace/actions/nixomatic-action) provides reproducible CI/CD environments powered by Nix. It helps you: - Automatically install Nix in your GitHub runners (if needed) - Set up development environments with exactly the packages you need - Pin specific package versions for truly reproducible builds - Run scripts inside a fully configured Nix environment ## Quick Start Add the following step to your `.github/workflows/your-workflow.yml`: ```yaml - uses: curriedsoftware/nixomatic-action@main with: packages: python3 nodejs jq run: | python --version node --version jq --version ``` ## Package Formats You have flexibility in how you specify packages: | Format | Example | Description | |--------|---------|-------------| | Basic | `jq` | Latest version from nixos-unstable | | Versioned | `python3@3.13.11` | Specific version (resolved via [nixpkgs-multiverse](https://github.com/fzakaria/nixpkgs-multiverse)) | | Pinned | `python3:3b93cf5` | Exact nixpkgs commit for full reproducibility | ## Configuration Options | Input | Required | Default | Description | |-------|----------|---------|-------------| | `packages` | Yes | - | Space-separated list of packages to install | | `install-nix` | No | `true` | Whether to install Nix (skip if already available) | | `run` | No | - | Script to execute in the Nix environment | ## Example A complete workflow that tests a Python project with pinned Python and Node.js versions: ```yaml name: CI on: [push, pull_request] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: curriedsoftware/nixomatic-action@main with: packages: python3@3.13.11 nodejs@24.13.0 jq run: | pip install -r requirements.txt python -m pytest npm test ``` For more details, see the [Nixomatic Action on GitHub Marketplace](https://github.com/marketplace/actions/nixomatic-action). --- Source: https://docs.nixomatic.com/agent-skill.md # Agent Skill The [Nixomatic Agent Skill](https://github.com/curriedsoftware/nixomatic-skill) enables AI coding agents to automatically set up reproducible development environments powered by Nix. It works with agents supporting the skills convention, such as [Claude Code](https://code.claude.com/) and [Codex](https://openai.com/codex/). It helps you: - Automatically detect required packages from project dependency files - Execute commands within a fully configured Nix environment - Retry with missing packages when runtime errors occur - Document the working environment configuration in your project README ## Quick Start ### Per-Project Setup ```bash # For Claude Code mkdir -p .claude/skills ln -s /path/to/nixomatic-skill/nixomatic .claude/skills/nixomatic # For Codex mkdir -p .codex/skills ln -s /path/to/nixomatic-skill/nixomatic .codex/skills/nixomatic ``` ### Global Setup ```bash # For Claude Code (available across all projects) ln -s /path/to/nixomatic-skill/nixomatic ~/.claude/skills/nixomatic # For Codex (available across all projects) ln -s /path/to/nixomatic-skill/nixomatic ~/.codex/skills/nixomatic ``` ## How It Works Once installed, the skill activates when you ask the agent to build, test, run, or set up a project. It follows this workflow: 1. **Project analysis** — Scans dependency files (`package.json`, `Cargo.toml`, `go.mod`, etc.) to identify required packages 2. **Environment construction** — Generates a nixomatic URL with the detected packages 3. **Command execution** — Runs commands inside a `nix develop` environment 4. **Error recovery** — If a command fails due to a missing tool, it adds the package and retries 5. **Documentation** — Updates the project README with the finalized nixomatic URL ## Detected Languages and Tools The skill automatically maps project files to Nix packages: | File | Package(s) | |------|------------| | `package.json` | `nodejs` | | `Cargo.toml` | `rustc`, `cargo` | | `go.mod` | `go` | | `requirements.txt`, `pyproject.toml` | `python3` | | `Gemfile` | `ruby` | | `pom.xml`, `build.gradle` | `jdk` | | `mix.exs` | `elixir` | | `composer.json` | `php` | | `.csproj`, `.fsproj` | `dotnet-sdk` | | `Package.swift` | `swift` | | `stack.yaml`, `.cabal` | `ghc`, `cabal-install` | | `pubspec.yaml` | `dart` | | `build.zig`, `zig.zon` | `zig` | Build tools are also detected: | File | Package | |------|---------| | `Makefile` | `gnumake` | | `CMakeLists.txt` | `cmake` | | `meson.build` | `meson` | | `Justfile` | `just` | | `Taskfile.yml` | `go-task` | ## Requirements The skill requires one of the following runtimes on the system: - **Nix** (with flakes support) — used natively - **Docker** — falls back to the `nixos/nix` image ## Package Formats The skill constructs nixomatic URLs using the same package formats available everywhere in Nix O'matic: | Format | Example | Description | |--------|---------|-------------| | Basic | `nodejs` | Latest version from nixos-unstable | | Versioned | `nodejs@20.11.1` | Specific version (resolved via [nixpkgs-multiverse](https://github.com/fzakaria/nixpkgs-multiverse)) | | Pinned | `python3:3b93cf5` | Exact nixpkgs commit for full reproducibility | For more details, see the [Nixomatic Agent Skill on GitHub](https://github.com/curriedsoftware/nixomatic-skill). --- Source: https://docs.nixomatic.com/ssh-accounts.md # SSH Accounts Everything on `nixomatic.com` works without an account. `into.nixomatic.com` is where an account comes from: an SSH server that hands you one and shows you what it will hold. There is nothing to install and no password — the SSH key you already have is the credential. ## Creating an account Connect with an empty username, so SSH does not send your local login name, on port 2003 — the year Nix was created: ```bash ssh -l '' -p 2003 into.nixomatic.com ``` The server creates an account, prints its id — a UUID — along with the two ways back into it, and closes the connection. The account id is worth keeping, but it is not a secret to guard: the key that created the account is what holds it, and the id alone opens nothing. ## Coming back Two ways, and both land on the same account: - **Anonymously again.** `ssh -l '' -p 2003 into.nixomatic.com` looks up the key you present. If it already holds an account, you get that account and its id back rather than a second one — connecting twice never leaves you with two accounts. - **By id.** `ssh -p 2003 @into.nixomatic.com` opens the interactive interface, and `ssh -T -p 2003 @into.nixomatic.com ` runs a single command and exits. Naming an account only works from the key that created it. A connection presenting a different key closes without an explanation — that feedback would be for whoever is guessing, not for you. An id that belongs to no account is told how to create one. Only public-key authentication is accepted; password and keyboard-interactive attempts are refused. The username must be either empty or an account id, so a stray local login name is rejected outright rather than quietly creating something. ## What an account holds The interactive interface lists four sections — substituters, packages, flake settings, and domains — navigated with `j`/`k` (or `Ctrl-n`/`Ctrl-p`), `Ctrl-a`/`Ctrl-e` for first and last, and `q` to quit. The same four are subcommands of the non-interactive CLI, which takes `--json` for machine-readable output: ```bash ssh -T -p 2003 @into.nixomatic.com packages list --json ``` ```json {"forced":[],"defaults":[]} ``` **These four sections are a preview of what an account will configure, not settings that take effect yet.** Nothing said to them is stored: a `packages add` reports the package it was given and forgets it, and a list always comes back empty. Flakes served from `nixomatic.com` are identical whether or not you have an account. What is real today is the account itself — its id, and the key that holds it. ## Coming soon Personalising what you are served is what comes next. An account will apply what it holds to the flakes it answers with — substituters to fetch from, packages present in every shell, flake settings layered on top — so a shell comes out configured without any of it repeated on the command line. Domains are how that reaches past a single account. A domain added to an account and pointed at nixomatic with a `CNAME` is served by nixomatic, and some of what the account holds will apply to that whole domain rather than to you alone: a request arriving through that name is answered with the domain's configuration, whoever made it. That is the point — a domain is how a team or a project shares one configuration — but it also means adding a domain is a decision on behalf of everyone who uses it. All of this is work in progress. Adding a domain and configuring it correctly changes nothing about what is served today; the sections are there so the shape is visible before the behaviour is. Coming soon. ## What is recorded Two things are counted for each account, alongside the pageviews the websites count: `account_created` when a key that held no account gets one, and `account_accessed` each time an existing account is reached (with `identified_by` saying whether the connection was recognised by its key alone or named the account id). Both carry the account id, the SSH key fingerprint, and the address connected from. Neither is sent anywhere else, and analytics failing is never allowed to fail a connection.