star × nix
planned — this whole page is design, tracked in FUTURE-NIX.md. Nothing here is implemented yet, and the decisions below are proposals to validate, not settled fact.
star’s star.toml deliberately overlaps in purpose with nix flake templates outputs. The plan
is to meet in the middle, in three layers of increasing ambition. The invariant across all of
them: ordinary star.toml templates and ordinary flake templates are always supported on
their own. star.nix is additive; it never becomes required.
Layer 1 — discovering flake templates
A repository whose root exposes a flake templates output becomes a template source, no changes
required on the repository side. For each templates.<name> attrset, star registers the name
(qualified namespace#name, exactly like star.toml templates) and the description. Author and
init-message have no flake-native equivalent, so defaults apply.
These flow into the same discovery registry star.toml produces, so resolution,
disambiguation, and materialization are unchanged. A directory with both a star.toml and a
flake templates output keeps one identity: the star.toml wins — it is strictly more
expressive. templates.<name>.path is treated as advisory; content is the declaring directory,
consistent with star.toml semantics.
Layer 2 — star.nix
Repositories that want full metadata declare templates in a star.nix at the repo root:
# star.nix — evaluated by star (and importable by the repo's flake)
{ lib, ... }:
{
templates = {
rust-cli = {
# star.toml-equivalent metadata, fully typed
directory = "templates/rust-cli"; # template root, relative to repo
author = "jingus";
description = "clap + color-eyre + tracing + tokio, built by crane";
init-message = ''
Hope you enjoy my template! Use `nix develop` to enter the dev shell!
God bless!
'';
ignore = [ "target" "*.log" ];
};
};
}
Design decisions that matter:
-
star.nixis evaluated with a fixed, minimal eval context —nix eval --jsonon an expression star controls, never coupled to the repo’s flake inputs. The file must be evaluable with onlylibin scope. -
A flake input exposes the module system for declaring inside your flake instead:
inputs.star.url = "git+https://git.jingus.dev/star/star"; # in outputs: templates = inputs.star.lib.mkStarTemplates ./star.nix;mkStarTemplatesconverts the star declaration into a conventional flaketemplatesoutput, so the same repository remains 100% usable bynix flake init -t. The round-trip is the core promise: star metadata is the source of truth, the flake output is derived, and plain nix users lose nothing. -
Mixed repos are fine during migration: when both exist,
star.nixwins for directories it claims;star.tomlin unclaimed directories still works. -
Schema versioning gates incompatible changes the same way
[star] versiondoes.
Layer 3 — what else the module can expose
checks— per-template validation as flake checks: manifest parses,directoryexists, ignore globs compile, nostar.tomlinside a claimed directory.devShells.template-author— a shell with star itself plus git fixtures for testing templates end-to-end.- Generated index/docs — render the repo’s template catalog into a README section, so the catalog is never stale.
- Passthru metadata — future star features (post-init hooks, prompts, variable substitution) get a declaration point here first.
Open questions
- Eval trust & cost —
nix evalexecutes arbitrary nix from the cloned repo. Timeouts,--option eval-cache, and opt-in vs graceful-failure defaults need deciding. - Where flake templates live — root
templatesoutput only, or subdirectory flakes too? (Start root-only.) - URL-qualified flake refs — should
star use github:owner/repo#tever parse? The#grammar must not grow ambiguities. - Lockfiles — flake-sourced templates probably should materialize their
flake.lock(it is part of the committed tree); the ignore pipeline can exclude it per-template if authors disagree.