RepoPilotOpen in app →

nickel-lang/nickel

Better configuration for less

Healthy

Healthy across the board

weakest axis
Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 3d ago
  • 9 active contributors
  • Distributed ownership (top contributor 25% of recent commits)
Show all 6 evidence items →
  • MIT licensed
  • CI configured
  • Tests present

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/nickel-lang/nickel)](https://repopilot.app/r/nickel-lang/nickel)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/nickel-lang/nickel on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: nickel-lang/nickel

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/nickel-lang/nickel shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across the board

  • Last commit 3d ago
  • 9 active contributors
  • Distributed ownership (top contributor 25% of recent commits)
  • MIT licensed
  • CI configured
  • Tests present

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live nickel-lang/nickel repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/nickel-lang/nickel.

What it runs against: a local clone of nickel-lang/nickel — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in nickel-lang/nickel | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 33 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>nickel-lang/nickel</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of nickel-lang/nickel. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/nickel-lang/nickel.git
#   cd nickel
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of nickel-lang/nickel and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "nickel-lang/nickel(\\.git)?\\b" \\
  && ok "origin remote is nickel-lang/nickel" \\
  || miss "origin remote is not nickel-lang/nickel (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "Cargo.toml" \\
  && ok "Cargo.toml" \\
  || miss "missing critical file: Cargo.toml"
test -f "cli/src/main.rs" \\
  && ok "cli/src/main.rs" \\
  || miss "missing critical file: cli/src/main.rs"
test -f "core/src/lib.rs" \\
  && ok "core/src/lib.rs" \\
  || miss "missing critical file: core/src/lib.rs"
test -f "parser/src/lib.rs" \\
  && ok "parser/src/lib.rs" \\
  || miss "missing critical file: parser/src/lib.rs"
test -f "cli/src/eval.rs" \\
  && ok "cli/src/eval.rs" \\
  || miss "missing critical file: cli/src/eval.rs"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 33 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~3d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/nickel-lang/nickel"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Nickel is a typed configuration language that compiles to JSON/YAML/XML, designed to eliminate boilerplate and enable safe, composable infrastructure configuration. It combines static type checking with runtime contracts and merge operators to manage configuration templates at scale, solving the problem of 'JSON with functions' done right through a sound gradual type system. Workspace monorepo: core/ (evaluation engine + type system), parser/ (Nickel syntax), cli/ (command-line interface with eval/export/format subcommands), nls/ (LSP server), lsp-harness/ (testing), package/ and git/ (standard library modules), wasm-repl/ (browser REPL). Each crate published independently via Cargo workspace.

👥Who it's for

Infrastructure engineers, DevOps teams, and configuration management specialists who write complex Nix expressions, Terraform, or Kubernetes manifests and want type safety, composability, and less repetition. Also attractive to teams maintaining large configuration repositories (Tweag clients, Kubernetes adopters, NixOS contributors).

🌱Maturity & risk

Actively developed but pre-1.0: version 1.16.0 with comprehensive CI/CD (benchmark, release, and update workflows), extensive test suites in cli/tests/integration/, and lively GitHub activity. Production-ready for non-critical configs; some users in the wild but breaking changes still possible (gradual typing system evolving).

Moderate risk: single organization (Tweag) drives development; monorepo has 13 interdependent crates (core, parser, cli, lsp, etc.) with tight coupling; Rust 1.89 MSRV requirement may lag; ecosystem smaller than Terraform/Nix so community libraries limited. Breaking changes between 1.x releases documented in RELEASES.md.

Active areas of work

Active development on gradual typing refinements, LSP improvements (lsp/nls/), standard library expansion (flock, git, vector crates), and benchmarking infrastructure (.github/workflows/benchmark-*.yaml). Release pipeline automated; flake.nix pinned but regularly updated (update-flake-lock.yml). Python bindings in py-nickel/ suggest growing polyglot adoption.

🚀Get running

git clone https://github.com/nickel-lang/nickel
cd nickel
cargo build --release
./target/release/nicl --help
# Run examples: ./target/release/nicl eval examples/merging/records.ncl

Daily commands: Development: cargo build (debug) or cargo build --release. Run REPL: cargo run -p cli -- repl. Evaluate file: cargo run -p cli -- eval <file.ncl>. Test suite: cargo test --workspace. Benchmark: cargo bench -p core. Format: cargo run -p cli -- format <file.ncl>.

🗺️Map of the codebase

  • Cargo.toml — Workspace root defining all member crates (cli, core, parser, etc.) and shared dependencies—essential for understanding the entire project structure.
  • cli/src/main.rs — Entry point for the Nickel CLI tool; demonstrates how the language is invoked and processed end-to-end.
  • core/src/lib.rs — Core interpreter library that houses the evaluation engine, type system, and runtime semantics of the Nickel language.
  • parser/src/lib.rs — Parser module responsible for converting Nickel source text into the AST; foundational for all compilation.
  • cli/src/eval.rs — CLI evaluation handler that orchestrates file loading, type checking, and evaluation—bridges CLI and core interpreter.
  • README.md — Project overview explaining Nickel's purpose (configuration templating language), design philosophy, and core features.
  • HACKING.md — Developer guide with build instructions, architecture overview, and contribution conventions specific to this codebase.

🛠️How to make changes

Add a new built-in function

  1. Define the function signature and docstring in core/src/builtins.rs with contract annotations (core/src/builtins.rs)
  2. Implement evaluation logic in the eval match statement (core/src/eval.rs)
  3. Add type signature to core/src/stdlib.rs for static type checking (core/src/stdlib.rs)
  4. Write integration tests in cli/tests/integration/main.rs validating the function with various inputs (cli/tests/integration/main.rs)

Add a new CLI subcommand

  1. Define the command struct and arguments in cli/src/cli.rs using clap derive macros (cli/src/cli.rs)
  2. Create a handler module (e.g., cli/src/mycommand.rs) implementing the subcommand logic (cli/src/mycommand.rs)
  3. Add a match arm in cli/src/main.rs to dispatch the new command (cli/src/main.rs)
  4. Add snapshot tests in cli/tests/snapshot/inputs/mycommand/ with .ncl input files (cli/tests/snapshot/inputs/mycommand)

Add a new language feature (expression type)

  1. Add the AST node variant to parser/src/ast.rs (parser/src/ast.rs)
  2. Implement parsing logic in parser/src/parser.rs (parser/src/parser.rs)
  3. Add evaluation case in core/src/eval.rs to handle the new expression (core/src/eval.rs)
  4. Add type inference rules in core/src/typecheck.rs (core/src/typecheck.rs)
  5. Write test files in cli/tests/snapshot/inputs/ demonstrating the feature (cli/tests/snapshot/inputs/features)

Enhance contract validation

  1. Define new contract type or validator in core/src/contract.rs (core/src/contract.rs)
  2. Implement runtime checking logic in core/src/eval.rs where contracts are applied (core/src/eval.rs)
  3. Add contract annotation syntax examples in cli/tests/snapshot/inputs/errors/ test files (cli/tests/snapshot/inputs/errors)

🔧Why these technologies

  • Rust — Systems language enabling lightweight embedding, strong memory safety guarantees, and cross-platform compilation; aligns with Nickel's goal of being embeddable in many environments.
  • Cargo/Workspace — Rust package manager supporting modular architecture across 13 crates (cli, core, parser, lsp, etc.) with clear separation of concerns and dependency management.
  • LSP (Language Server Protocol) — Standard protocol for editor integration; enables IDE support (autocomplete, diagnostics) across VSCode, Vim, Emacs without reimplementation.
  • Snapshot Testing — CLI snapshot tests in cli/tests/snapshot/ enable regression detection for error messages and output formatting; critical for language usability.
  • clap (CLI framework) — Declarative command-line argument parsing with derive macros; simplifies CLI extension and maintainability.

⚖️Trade-offs already made

  • Single-pass evaluation vs. multi-pass compilation

    • Why: Nickel evaluates directly from AST without bytecode compilation; simplifies implementation and embedding but may sacrifice performance for large configurations.
    • Consequence: Faster interpreter startup and simpler code, but slower evaluation for complex recursive computations.
  • Contract checking at runtime vs. compile-time

    • Why: Contracts are validated during evaluation; provides flexibility for dynamic data but cannot catch contract violations before runtime.
    • Consequence: Configuration errors discovered late; easier gradual typing adoption but requires defensive evaluation patterns.
  • Snapshot testing over unit tests for CLI

    • Why: Output-focused testing matches Nickel's use case (static file generation); captures exact error messages and formatting.
    • Consequence: Snapshot updates required on intentional message changes; comprehensive but brittle to formatting changes.
  • Immutable term representation during evaluation

    • Why: Values are immutable once created; guarantees no side effects and safe parallel evaluation.
    • Consequence: Memory overhead and potential performance cost for large data structures vs. in-place updates.

🚫Non-goals (don't propose these)

  • Does not handle asynchronous or real-time computation—Nickel is synchronous and declarative
  • Not a package manager—uses external package/module resolution (flock crate) but does not manage binary dependencies
  • Not Turing-complete—intentionally limited to configuration generation (no loops, explicit recursion only)
  • Does not provide network I/O—configuration must be materialized locally
  • Not a configuration database or versioning system—static

🪤Traps & gotchas

Nix flake pinning: wasm-bindgen version in Cargo.lock requires corresponding hash in flake.nix; mismatch breaks nix build. Rust edition: Cargo.toml specifies edition = '2024' (unstable); may require nightly toolchain depending on features. Module resolution: nickel/ directory is the standard library root; import paths resolve relative to workspace root, not file location. Type contexts: gradual type checking maintains TypeEnv state across merges; contract ordering matters. LSP harness: lsp/lsp-harness/ is a test framework, not the actual LSP server (server is lsp/nls/); common confusion point.

🏗️Architecture

💡Concepts to learn

  • Gradual typing — Nickel's core differentiator: mix static type checking with dynamic validation; understand this to grasp why Nickel isn't Rust or TypeScript
  • Design by contract — Contracts are Nickel's validation mechanism (not static types); you attach predicates to values and enforce them at runtime—critical for config schemas
  • Eager evaluation with lazy records — Nickel uses eager evaluation for most terms but records remain lazy (fields computed on access); this hybrid approach enables efficient config templating without full laziness
  • Record merging semantics — Core feature for composable config; multiple records merge with metadata (defaults, type annotations, docs) preserved; requires understanding merge priorities
  • Module resolution and import semantics — Nickel has a package/module system (nickel/std, cache coherence); understanding how imports resolve and how stdlib discovery works is key to stdlib development
  • AST visitor pattern — core/src/term.rs uses visitor patterns extensively for traversal (typecheck, eval, transform); new features require implementing visitor methods
  • LSP (Language Server Protocol) — Nickel has full LSP support (lsp/nls/); editor integration requires understanding diagnostics, completion, and hover message protocol
  • NixOS/nix — Nix language is a direct inspiration and competitor for configuration templating; Nickel aims to solve problems Nix has (simpler syntax, gradual typing)
  • kubernetes/kubernetes — Nickel is frequently used to generate Kubernetes manifests as an alternative to Helm or Kustomize; big use-case driver
  • hashicorp/terraform — Terraform HCL is another configuration DSL in the same problem space; Nickel can generate TF configurations via JSON export
  • tweag/flakes — Tweag maintains both Nickel and Nix flakes infrastructure; ecosystem companion for reproducible builds
  • tweag/topiary — Tweag-maintained universal code formatter; Nickel's formatter (cli/src/format.rs) follows similar principles of language-agnostic pretty-printing

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add integration tests for CLI convert subcommand with all supported formats

The cli/tests/integration/inputs directory contains mixed.json, mixed.ncl, and mixed.toml test files, but there's no comprehensive integration test suite validating the nickel convert command across JSON, YAML, TOML, and XML formats. The cli/src/convert.rs file exists but lacks end-to-end test coverage for format conversions. This would catch regressions when format handling logic changes.

  • [ ] Review cli/src/convert.rs to understand supported output formats
  • [ ] Create cli/tests/integration/convert.rs with test cases for each format pair (JSON→YAML, TOML→JSON, etc.)
  • [ ] Add test fixtures in cli/tests/integration/inputs/convert/ for edge cases (nested structures, unicode, special characters)
  • [ ] Integrate into ci/tests/snapshot testing framework documented in cli/tests/snapshot/README.md
  • [ ] Ensure tests run in the continuous-integration.yml workflow

Add GitHub Actions workflow for Python package testing and distribution

The workspace includes a py-nickel member and release-python.yml workflow exists, but there's no dedicated CI workflow for running Python unit tests on PRs. This gap means Python binding changes could break without immediate feedback. Adding a parallel test job for Python alongside the Rust CI would catch issues early.

  • [ ] Examine release-python.yml to understand the Python build process
  • [ ] Create .github/workflows/python-ci.yml that runs on all PRs (not just releases)
  • [ ] Add steps to: install Python dependencies, run pytest on py-nickel/tests/, lint with ruff/black
  • [ ] Ensure the workflow tests against multiple Python versions (3.9, 3.10, 3.11, 3.12) using matrix strategy
  • [ ] Link workflow status badge to README.md for visibility

Add documentation for the LSP server setup and configuration in CONTRIBUTING.md

The repo contains an LSP implementation (lsp/nls and lsp/lsp-harness in workspace) with .vscode/launch.json configuration, but CONTRIBUTING.md and HACKING.md don't document how to set up the Language Server for development or how to test it. New contributors working on language features need this guidance to debug editor integration.

  • [ ] Review .vscode/launch.json and lsp/nls/src structure to understand the LSP architecture
  • [ ] Add a new section 'Setting up the Language Server' to HACKING.md with: build instructions, launch configuration, and testing steps
  • [ ] Document the relationship between lsp-harness (testing framework) and nls (actual server implementation)
  • [ ] Include examples of testing LSP features (hover, completion, diagnostics) using the test harness
  • [ ] Link to relevant crates in Cargo.toml and explain the workspace member dependencies

🌿Good first issues

  • Add integration tests for cli/src/export.rs covering YAML and XML backends; currently only JSON heavily tested (cli/tests/integration/ exists but is sparse for export variations)
  • Document the contract system with runnable examples in nickel/std/; contracts are powerful but lack in-repo tutorial (RATIONALE.md mentions contracts but no beginner-friendly guide)
  • Implement missing stdlib functions: audit nickel/std/*.ncl for TODO comments or compare against Nix builtins to find low-hanging stdlib additions (vector crate hints at array operations needing work)

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 802cdb6 — Merge pull request #2606 from gominimal/program-builder (yannham)
  • 8083df7 — Refactor Program to use the builder pattern for construction (Tom)
  • 3a39923 — Merge pull request #2603 from nickel-lang/jneem/unpin-wasm (jneem)
  • bd4a802 — Merge pull request #2605 from L0r3m1p5um/typecheck-err-completion (yannham)
  • 8a2796c — Create Analysis even when typechecking fails in nls (L0r3m1p5um)
  • 45da06d — Merge pull request #2518 from nickel-lang/public-api-pending-contracts (jneem)
  • d839946 — Review comments (jneem)
  • 217db2d — Unpin the wasm-bindgen version in Cargo.toml, but check it in the flake (Joe Neeman)
  • 156d030 — Merge pull request #2390 from mkatychev/chore/typos-cli-lint (yannham)
  • 44b394d — Merge pull request #2602 from nickel-lang/dependabot/cargo/rustls-webpki-0.103.13 (yannham)

🔒Security observations

The Nickel codebase shows a reasonable security posture with no critical vulnerabilities detected in the visible configuration. The Rust-based implementation reduces common vulnerability classes (memory safety, injection attacks). However, several areas need attention: (1) Docker image hardening (non-root user, minimal base image considerations), (2) binary integrity verification in the release process, (3) incomplete visibility of all dependencies for full audit, (4) lack of container image signing and provenance attestation. The project would benefit from implementing supply chain security practices including dependency auditing, signed releases, and secure build attestation.

  • Medium · Dockerfile Uses 'scratch' Base Image Without Verification — Dockerfile. The Dockerfile uses 'FROM scratch' which creates a minimal container with only the copied binaries. While this reduces attack surface, there is no verification of binary integrity (no checksums or signatures validated). Binaries could be tampered with during the build process. Fix: Add checksum verification or GPG signature validation of the nickel and nls binaries before COPY. Consider using a minimal verified base image instead of scratch, or implement build attestation.
  • Low · Missing HEALTHCHECK in Docker Image — Dockerfile. The Dockerfile lacks a HEALTHCHECK instruction, making it difficult for container orchestrators to determine if the service is healthy. This is a best practice for production Docker images. Fix: Add a HEALTHCHECK instruction that verifies the binary's availability or functionality, e.g., 'HEALTHCHECK CMD /bin/nickel --version || exit 1'
  • Low · No Non-Root User Defined in Docker Image — Dockerfile. The Dockerfile does not explicitly create or specify a non-root user. When using 'FROM scratch', containers will run as root by default, which is a security risk. Fix: Create a non-root user in the Dockerfile and ensure the binary runs with minimal privileges. Note: 'scratch' images cannot use RUN commands, so consider a minimal base image like 'alpine' or use a multi-stage build.
  • Low · Incomplete Dependency Information — Cargo.toml. The Cargo.toml excerpt appears truncated (ends at 'gi' in dependencies), making it impossible to fully audit all dependencies. Several dependencies are listed but the complete list is not visible, potentially hiding vulnerable or unmaintained packages. Fix: Ensure complete dependency audit by reviewing the full Cargo.toml file. Regularly run 'cargo audit' to check for known vulnerabilities in dependencies. Consider using tools like 'cargo-deny' for supply chain security.
  • Low · Workspace Contains Multiple Member Crates — Cargo.toml (workspace members). The workspace includes 12 member crates with varying purposes (py-nickel, wasm-repl, etc.). Each increases the attack surface and maintenance burden. Some members like 'py-nickel' and 'wasm-repl' introduce language bindings and web contexts with distinct security considerations. Fix: Conduct separate security audits for each workspace member, especially those with external language bindings (py-nickel) or web exposure (wasm-repl). Isolate and version them independently if they have different security profiles.
  • Low · No Container Image Signature or Attestation — .github/workflows/release-artifacts.yaml, Dockerfile. The Docker image build process and release artifacts lack visible signatures, attestations, or provenance verification mechanisms. This makes it difficult for users to verify the authenticity of distributed binaries. Fix: Implement container image signing (e.g., cosign), SLSA provenance attestation, and publish signatures alongside releases. Document verification instructions for users.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · nickel-lang/nickel — RepoPilot