docs: write docs, add README

This commit is contained in:
technofab 2025-12-20 21:27:10 +01:00
parent abe19f9f13
commit a7e20e203c
Signed by: technofab
SSH key fingerprint: SHA256:bV4h88OqS/AxjbPn66uUdvK9JsgIW4tv3vwJQ8tpMqQ
8 changed files with 442 additions and 0 deletions

44
README.md Normal file
View file

@ -0,0 +1,44 @@
# Rensa
Rensa is a powerful and flexible Nix flake framework designed to organize your Nix projects into logical units called "Cells".
It is heavily inspired by [divnix/std](https://github.com/divnix/std) but aims to provide a streamlined experience.
Feel free to check out std's awesome [docs](https://std.divnix.com/reference/std.html) too.
## Features
- **Cells**: Organize your code into functional domains (e.g., `backend`, `frontend`, `devops`).
- **Blocks**: Define types of outputs within a cell (e.g., `packages`, `devShells`, `nixosConfigurations`).
- **Actions**: Integrate with the CLI to run commands defined in your cells.
- **Cell Flakes**: Each cell can be its own flake, allowing for modular dependency management.
## Quick Start
1. **Initialize a Flake**: Create a `flake.nix` that uses `rensa`.
1. **Define Cells**: Create a `cells/` directory.
1. **Add Blocks**: Add `.nix` files in your cells to define outputs.
### Example `flake.nix`
```nix
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
ren.url = "gitlab:rensa-nix/core";
};
outputs = {ren, ...}@inputs: ren.buildWith {
inherit inputs;
cellsFrom = ./cells;
cellBlocks = with ren.blocks; [
(simple "packages")
(simple "devShells")
];
} {
packages = ren.select inputs.self [
["my-cell" "packages"]
];
};
}
```
See the [docs](https://rensa.projects.tf) for more.

View file

@ -31,6 +31,11 @@ in
}; };
nav = [ nav = [
{"Introduction" = "index.md";} {"Introduction" = "index.md";}
{"Concepts" = "concepts.md";}
{"Tutorial" = "tutorial.md";}
{"API Reference" = "api.md";}
{"Related Libraries" = "libraries.md";}
{"Direnv Integration" = "direnv.md";}
]; ];
markdown_extensions = [ markdown_extensions = [
{ {
@ -41,6 +46,7 @@ in
"pymdownx.superfences" "pymdownx.superfences"
"pymdownx.escapeall" "pymdownx.escapeall"
"fenced_code" "fenced_code"
"admonition"
]; ];
}; };
}; };

96
docs/api.md Normal file
View file

@ -0,0 +1,96 @@
# API Reference
## `rensa.buildWith`
The main entry point for creating a Rensa flake.
### Arguments
- `inputs`: The flake inputs.
- `cellsFrom`: Path to the directory containing your cells.
- `cellBlocks`: A list of blocks to load for each cell.
- `transformInputs` (optional): A function to transform inputs before they are passed to cells.
### Returns
A standard Nix flake output set.
## `rensa.build`
The underlying builder function used by `buildWith`. It returns the raw Rensa output structure without the recursive update functor.
### Arguments
- `inputs`: The flake inputs.
- `cellsFrom`: Path to the directory containing your cells.
- `cellBlocks`: A list of blocks to load for each cell.
- `transformInputs` (optional): A function to transform inputs.
### Returns
An attribute set containing:
- `output`: The generated flake outputs.
- `__ren`: Internal metadata about the cells and blocks.
## `rensa.blocks`
Helper functions to define blocks.
### `simple`
```nix
simple "name"
```
Creates a block definition where the type matches the name.
### `dynamic`
```nix
dynamic "name"
```
Creates a block definition for dynamic content. This allows integration of the `std` cli
by passing through actions etc. from a cell.
Currently not really used.
## `rensa.select`
Helper to select specific outputs from the generated flake.
```nix
select inputs.self [
["cellName" "blockName" "outputName"]
]
```
## `rensa.filter`
Filters the generated flake outputs based on a predicate and paths.
```nix
filter predicate inputs.self [
["cellName" "blockName" "outputName"]
]
```
### Arguments
- `predicate`: A function or boolean. If `true`, returns the attribute as is. If a function, it's used to filter the attributes of the target.
- `target`: The flake outputs (usually `inputs.self`).
- `paths`: A list of paths to select. Supports wildcards (`*`).
## `rensa.get`
Retrieves a single attribute from the flake outputs.
```nix
get inputs.self ["cellName" "blockName" "outputName"]
```
### Arguments
- `target`: The flake outputs.
- `path`: The path to the attribute to retrieve.

75
docs/concepts.md Normal file
View file

@ -0,0 +1,75 @@
# Concepts
Rensa is built around a few core concepts that help structure your Nix projects.
## Cells
A **Cell** is the fundamental unit of organization in Rensa.
It represents a functional domain or a component of your system.
For example, you might have cells for:
- `backend`: Your backend services.
- `frontend`: Your frontend applications.
Cells are directories located in the `cellsFrom` directory (usually `cells/` or `nix/`).
### Cell Flakes
A unique feature of Rensa is that each cell can be a self-contained Flake.
If a cell directory contains a `flake.nix`, Rensa will treat it as a flake and pass its outputs to the cell's blocks.
This allows you to manage dependencies at the cell level, keeping your top-level `flake.nix` clean.
!!! success "Advantage"
These nested flakes are also evaluated lazily, so inputs are only fetched if they are actually used.
## Blocks
A **Block** defines a specific type of output within a cell. Blocks are typically defined as `.nix` files within a cell directory.
Rensa provides different block types to handle various use cases.
### Simple Blocks
`rensa.blocks.simple` is the most common block type.
Use it to tell Rensa which blocks you have/it should load.
**Example**:
```nix
blocks = with ren.blocks; [
(simple "hello")
]
```
This will tell Rensa to load any `hello.nix` or `hello/default.nix` in the cells.
It's required to be able to map these to flake outputs (eg. using `ren.select`).
### Dynamic Blocks
`rensa.blocks.dynamic` allows for more complex logic and can generate actions.
## Actions
**Actions** are commands that can be executed via the Std CLI.
They are defined within blocks and allow you to operationalize your Nix code.
For example, a `deploy` action in an `infra` cell could run the necessary commands to deploy your infrastructure.
!!! warning
Actions are also heavily inspired by Std, I added them to Rensa too, but nowadays
I don't see any real use cases for them. If you do, feel free to use and/or extend them :)
## Performance & Best Practices
### Single Instantiation of Nixpkgs
Instantiating `nixpkgs` (e.g., `import inputs.nixpkgs { inherit system; }`) is a computationally expensive operation. In a large project with many cells, doing this repeatedly for every cell or block can significantly slow down evaluation.
The recommended pattern in Rensa is to instantiate `nixpkgs` **once** in your top-level `flake.nix` and pass it down to your cells.
1. **Instantiate in `transformInputs`**: In your `flake.nix`, use the `transformInputs` argument of `buildWith` to add the instantiated `pkgs` to the inputs passed to cells.
1. **Use `i.parent.pkgs`**: In your cell flakes, access this pre-instantiated package set via `inputs.parent.pkgs`.
This ensures that `nixpkgs` is evaluated only once per system, drastically improving performance.
See [Related Libraries](./libraries.md) for examples of this pattern.

37
docs/direnv.md Normal file
View file

@ -0,0 +1,37 @@
# Direnv Integration
Rensa provides a custom `direnv` integration to make your development experience smoother.
It allows you to automatically load development shells defined in your cells.
!!! note
This integration is based on [nix-direnv](https://github.com/nix-community/nix-direnv)
but has been improved and optimized specifically for Rensa usage.
## Setup
1. **Create `.envrc`**: Add the following to your `.envrc` file:
```bash
source $(fetchurl https://gitlab.com/rensa-nix/direnv/-/raw/v0.3.0/direnvrc "sha256-u7+KEz684NnIZ+Vh5x5qLrt8rKdnUNexewBoeTcEVHQ=")
use ren //backend/devShells/default
```
This will automatically load the devShell `default` defined in `cells/backend/devShells.nix`.
1. **Allow Direnv**: Run `direnv allow` to trust the configuration.
## Updating
To update the `direnvrc` to the latest version (or a specific version), you can use `direnv fetchurl`.
1. **Run fetchurl**:
```bash
direnv fetchurl https://gitlab.com/rensa-nix/direnv/-/raw/v0.3.0/direnvrc
```
*Note: Replace `v0.3.0` with the desired version tag.*
1. **Update `.envrc`**: The command above will output a new hash.
Replace the previous version and hash in your `.envrc` with the new values.

View file

@ -1 +1,30 @@
# Rensa Core # Rensa Core
Welcome to the documentation for **Rensa**, a powerful and flexible Nix flake framework.
Rensa is designed to help you organize your Nix projects into logical units called **Cells**,
making your code more modular, maintainable, and scalable.
## Getting Started
If you are new to Rensa, we recommend starting with the [Tutorial](tutorial.md) to build your first project.
## Core Concepts
Understand the philosophy behind Rensa by reading about [Concepts](concepts.md), including:
- **Cells**: Functional domains of your project.
- **Blocks**: Typed outputs within cells.
- **Actions**: CLI commands for your cells.
## API Reference
For detailed information on Rensa's functions and helpers, check the [API Reference](api.md).
## Ecosystem
See [Related Libraries](libraries.md) to see how to extend Rensa with pre-built solutions for development shells, documentation, CI, and more.
## Further Reading
Rensa is inspired by `std`. For more in-depth information on the underlying concepts, you can refer to the [std Reference](https://std.divnix.com/reference/std.html).

47
docs/libraries.md Normal file
View file

@ -0,0 +1,47 @@
# Related Libraries
Rensa has a growing ecosystem of compatible libraries designed to work seamlessly with its cell structure.
These libraries typically expose a `lib` output that accepts `pkgs` as an argument.
## Available Libraries
Here are some common libraries you might want to use:
- [**Rensa Devshell**](https://devshell.rensa.projects.tf): _Minimal devshell implementation using Modules._
- [**Rensa Devtools**](https://devtools.rensa.projects.tf): _Utils and dev tools for the Rensa ecosystem._
- [**Rensa Utils**](https://utils.rensa.projects.tf): _Utilities for NixOS/darwin systems, home & disko configurations etc._
- [**Nix-GitLab-CI**](https://nix-gitlab-ci.projects.tf): _Allows (advanced) configuration of GitLab CI using Nix._
- [**Nixible**](https://nixible.projects.tf): _Ansible but with Nix._
- [**Tofunix**](https://tofunix.projects.tf): _Combining Nix and Terraform for reproducibility and developer experience._
- [**Nixlets**](https://nixlets.projects.tf): _Nixlets - like Helm Charts or Grafana Tanka but instead using Nix._
- [**Nixtest**](https://nixtest.projects.tf): _Test runner for Nix code._
- [**Soonix**](https://soonix.projects.tf): _Auto generated project files from Nix code, with gitignore handling and many generators._
- [**NixMkDocs**](https://nix-mkdocs.projects.tf): _Nix library for easy mkdocs integration into projects._
- [**Torikae**](https://torikae.projects.tf): _Simple CLI to replace versions in files._
## Usage Pattern
When using these libraries within a Cell Flake, you can instantiate them using the `pkgs` passed down from the parent flake.
This follows the "Single Instantiation" best practice.
### Example: `cells/mycell/flake.nix`
```nix
{
inputs = {
# Add the library to your inputs
devshell.url = "gitlab:rensa-nix/devshell?dir=lib";
# ... other inputs
};
outputs = i:
i
// {
# Instantiate the library using the parent's pkgs
dslib = i.devshell.lib { inherit (i.parent) pkgs; };
};
}
```
Now you can use `inputs.dslib` in your blocks!

108
docs/tutorial.md Normal file
View file

@ -0,0 +1,108 @@
# Tutorial
This tutorial will guide you through creating a new project using Rensa.
## Prerequisites
- Nix installed with flakes enabled.
- Optionally `direnv`.
## Step 1: Initialize the Flake
Create a new directory for your project and initialize a `flake.nix`:
```nix title="flake.nix"
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
ren.url = "gitlab:rensa-nix/core";
};
outputs = {ren, self, ...}@inputs: ren.buildWith {
inherit inputs;
cellsFrom = ./nix;
cellBlocks = with ren.blocks; [
(simple "packages")
];
transformInputs = system: inputs: inputs // {
pkgs = import inputs.nixpkgs { inherit system; };
};
} {
packages = ren.select self [
["backend" "packages"]
];
};
}
```
## Step 2: Create a Cell
Create a directory named `nix` and inside it, create a directory for your first cell, e.g., `backend`.
```bash
mkdir -p nix/backend
```
## Step 3: Add a Block
Inside `nix/backend`, create a file named `packages.nix`.
This will correspond to the `packages` block we defined in `flake.nix`.
Since we instantiated `pkgs` in the top-level `flake.nix`, we can access it via `inputs.pkgs`
(because we added it to inputs in `transformInputs`).
```nix
{
inputs,
cell,
}: {
default = inputs.pkgs.hello;
}
```
### Using Cell Flakes (Advanced)
If your cell is a flake (has a `flake.nix`), you can access the parent inputs via `inputs.parent`.
**`nix/backend/flake.nix`**:
```nix
{
inputs.common.url = "github:some/common-lib";
outputs = inputs: inputs // {
# inputs just for the current cell, for example:
common = inputs.common.lib {inherit (inputs.parent) pkgs;};
};
}
```
See [here](./libraries.md) for more information about this syntax.
**`cells/backend/packages.nix`**:
```nix
{
inputs,
cell,
}: {
default = inputs.common.mkPackage { ... };
}
```
## Step 4: Build
Now you can build your package using the standard Nix commands:
```bash
nix build .#backend.packages.default
```
Or, if you mapped it in `flake.nix`:
```bash
nix build .#default
```
## Step 5: Setting up Direnv
Rensa provides a custom `direnv` integration. See the [Direnv Integration](direnv.md) guide for setup instructions.