summaryrefslogtreecommitdiffstats
path: root/README.md
blob: a409fc24e3b38f442798141ada3f947834d10368 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
<!-- markdownlint-disable MD033 MD041 -->

<div id="doc-begin" align="center">
  <h1 id="header">
    <pre>Hjem [ˈjɛmˀ]</pre>
  </h1>
  <p>
    A streamlined way to manage your <code>$HOME</code> with Nix.
  </p>
  <br/>
  <a href="#what-is-this">Synopsis</a><br/>
  <a href="#features">Features</a> | <a href="#module-interface">Interface</a><br/>
  <a href="#things-to-do">Future Plans</a>
  <br/>
</div>

## What is this?

[systemd-tmpfiles]: https://www.freedesktop.org/software/systemd/man/latest/systemd-tmpfiles-setup.service.html
[smfh]: https://github.com/feel-co/smfh

**Hjem** ("home" in Danish) is a module system that implements a simple and
streamlined way to manage files in your `$HOME`, such as but not limited to
files in your `~/.config`. Hjem aims to approach as an alternative,
easy-to-grasp utility for managing your `$HOME` purely and safely.

### Features

We have learned from the mistakes made in the ecosystem.

1. Powerful `$HOME` management functionality and potential
2. Small and simple codebase with minimal abstraction
3. Robust, safe and _manifest based_ file handling with [smfh]
4. Multi-user by design, works with any number of users
5. Designed for ease of extensibility and integration

No compromises, only comfort.

### How to use

Refer to our documentation at <https://hjem.feel-co.org>.

### Standalone CLI

Hjem ships a standalone CLI, `hjem`, for non-NixOS and mixed setups.

The standalone entrypoint evaluates a Hjem manifest and applies it directly to
the current user. `switch` and `build` accept exactly one manifest source:

1. `--manifest` for a pre-generated manifest
2. `--config` for a `hjem.nix` file
3. `--flake` for a flake output

Examples:

```sh
# Evaluate a local hjem.nix and apply it.
$ hjem standalone switch --config ./hjem.nix

# Evaluate a flake with the default attr:
# hjemConfigurations."<USER>".manifest.
$ hjem standalone switch --flake .

# Evaluate a custom flake attribute explicitly.
$ hjem standalone switch \
  --flake . \
  --flake-attr 'hjemConfigurations."alice@laptop".manifest'
```

`hjem.nix` may evaluate to either a manifest directly or to an attribute set
with a `manifest` attribute:

```nix
{
  version = 3;
  files = [
    {
      type = "symlink";
      source = ./dotfiles/example;
      target = "/home/alice/.config/example";
    }
  ];
}
```

Other standalone lifecycle commands:

```sh
# Build-only: evaluate and validate the manifest without applying it.
$ hjem standalone build --config ./hjem.nix

# List stored generations.
$ hjem standalone generations

# Roll back to the previous generation.
$ hjem standalone rollback

# Roll back to a specific generation id.
$ hjem standalone rollback --generation generation-1780000000-123456789

# Remove old generations by timestamp, while preserving the current generation.
$ hjem standalone expire-generations '-30 days'

# Keep only the newest N generations, while preserving the current generation.
$ hjem standalone expire-generations --keep-last 10

# Remove explicit generation ids. The current generation cannot be removed.
$ hjem standalone remove-generations generation-1780000000-123456789
```

Standalone state lives in `$XDG_STATE_HOME/hjem/standalone`, or
`~/.local/state/hjem/standalone` when `XDG_STATE_HOME` is unset. Use
`--state-dir` on standalone commands to override that location.

### Implementation

Hjem exposes a streamlined interface with multi-tenant capabilities, which you
may use to manage individual users' homes by leveraging the module system.

```nix
{ inputs, lib, pkgs, ... }:
{
  /*
    other NixOS configuration here...
  */

  hjem = {
    users = {
      alice = {
        enable = true;

        files = {
          # Write a text file in `/home/alice/.foo`
          # with the contents bar
          ".foo".text = "bar";

          # Alternatively, create the file source using a writer.
          # This can be used to generate config files with various
          # formats expected by different programs.
          ".bar".source = pkgs.writeText "file-foo" "file contents";

          # You can also use generators to transform Nix values
          ".baz" = {
            # Works with `pkgs.formats` too!
            generator = lib.generators.toJSON { };
            value = {
              some = "contents";
            };
          };
        };

        # this will write into `/home/alice/.config/test/bar.json`
        xdg.config.files."test/bar.json" = {
          generator = lib.generators.toJSON { };
          value = {
            foo = 1;
            bar = "Hello world!";
            baz = false;
          };
          # overwrite existing unmanaged file, if present
          clobber = true;
        };
      };
    };
  };
}
```

> [!NOTE]
> Each attribute under `hjem.users`, e.g., `hjem.users.alice` or
> `hjem.users.jane` represent a user managed via `users.users` in NixOS. If a
> user does not exist, then Hjem will refuse to manage their `$HOME` by
> filtering non-existent users in file creation.

## Module Interface

[already does!]: https://github.com/snugnug/hjem-rum

The interface for the `hjem` module is conceptually very similar to prior art
(e.g., Home Manager), but it does not act as a collection of modules like Home
Manager. Instead, we implement minimal features, and leave application-specific
abstractions to the user to do as they see fit. This, of course, does not mean
that a module collection cannot exist. In fact, one [already does!]

Below is a live implementation of the module.

<!--markdownlint-disable MD013-->

```sh
$ nix eval .#nixosConfigurations.test.config.hjem.users.alice.files.'".foo"' --json | jq
{
  "clobber": false,
  "enable": true,
  "executable": false,
  "generator": null,
  "relativeTo": "/home/alice",
  "source": "/nix/store/22yfhzhk0w5mgaq6c943vimsg6qlr1sh-foo",
  "target": "/home/alice/.foo",
  "text": "bar",
  "value": null
}
```

<!--markdownlint-enable MD013-->

### Linker Implementation

Hjem relies on our home-baked tool [smfh], an atomic and reliable file creation
tool designed by [Gerg-l]. We utilize smfh and Systemd services [^1] to
correctly link files into place.

[^1]: Which is preferable to hacky activation scripts that may or may not break.
    Systemd services allow for ordered dependency management across all
    services, and easy monitoring of Hjem-related services from the central
    `systemctl` interface.

### Environment Management

Hjem does **not** manage user environments as one might expect, but it provides
a convenient `environment.sessionVariables` option that you can use to store
your variables. This script will be used to store your environment variables in
a POSIX-compliant script generated by Hjem, which you can source in your shell
configurations.

## Usage without flakes

We support usage without flakes. Specifically, you can use the following shell
commands:

| With flakes        | Without flakes               |
| ------------------ | ---------------------------- |
| `nix flake check`  | `nix-build -A checks`        |
| `nix develop`      | `nix-shell -A shell`         |
| `nix build .#hjem` | `nix-build -A packages.hjem` |
| `nix fmt`          | `nix run -f . formatter`     |

You can also `import` the root of the repo and get all of the same attributes as
the flake (without `system`).

## Things to do

Hjem is _mostly_ feature-complete, in the sense that it is a clean
implementation of `home.files` in Home Manager: it was never a goal to dive into
abstracting files into modules.

### Alternative or/and configurable file linking mechanisms

[Gerg-l]: https://github.com/gerg-l
[`hjem.linker`]: https://hjem.feel-co.org/options.html#option-hjem-linker

Hjem previously utilized [systemd-tmpfiles] to ensure files are linked in place.
This served us well for the short duration that we relied on them, but we have
ultimately decided to go with our in-house file linker developed by [Gerg-l].
The new linker is, of course, infinitely more powerful and while we are _not_
looking back, we understand that some users might be interested in alternative
linking mechanisms that they can customize as they prefer. You can set the
[`hjem.linker`] option to use a custom linker if desired.

## Attributions / Prior Art

[Nixpkgs]: https://github.com/nixOS/nixpkgs
[Home Manager]: https://github.com/nix-community/home-manager
[Hjem Rum]: https://github.com/snugnug/hjem-rum
[@Lunarnovaa]: https://github.com/lunarnovaa
[@nezia1]: https://github.com/nezia1

Special thanks to [Nixpkgs] and [Home Manager]. The interface of the
`hjem.users` module is inspired by Home Manager's `home.file` and Nixpkgs'
`users.users` modules. What is now Hjem started as an experimental module
addition to Nixpkgs' `users.users`. Hjem would not be possible without any of
those projects, thank you!

A project worthy of note is [Hjem Rum], by [@Lunarnovaa] and [@nezia1], which
establishes a Home Manager-like module system for users less comfortable with
manually linking files in place. If you wish to utilize the power of Hjem, but
want an easier interface, we encourage you to take a look at Hjem Rum.

Last but not least, our sincerest thanks to everyone who has used, contributed
to or just talked about Hjem in public spaces. Thank you for the support!

## License

This project is made available under Mozilla Public License (MPL) version 2.0.
See [LICENSE](LICENSE) for more details on the exact conditions. An online copy
is [provided here](https://www.mozilla.org/en-US/MPL/2.0/).

<div align="right">
  <a href="#doc-begin">Back to the Top</a>
  <br/>
</div>