Compare commits
21
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2e93c57b37 | ||
|
|
3f48c0400b | ||
|
|
4de92dcbe8 | ||
|
|
2f88d5567e | ||
|
|
b725bb37c2 | ||
|
|
f7196c0c86 | ||
|
|
20c2b43ae5 | ||
|
|
eecb7fa2b2 | ||
|
|
84ada68069 | ||
|
|
07a1d8ee62 | ||
|
|
565ec2bf39 | ||
|
|
34a55841eb | ||
|
|
e110cb6b87 | ||
|
|
33ac72aaed | ||
|
|
30b7f177c5 | ||
|
|
c1fc8e2a05 | ||
|
|
202eca2d03 | ||
|
|
2ff3042cd9 | ||
|
|
d219f2b61c | ||
|
|
5a2a649244 | ||
|
|
4691eb1aa4 |
+7
-5
@@ -1,7 +1,7 @@
|
|||||||
keys:
|
keys:
|
||||||
- &admin_finn age1a0v442ct2qfjcdhyktn25spw02yq4fl08plrrvuradwwxzsle4mq8thln4
|
- &admin_finn age1a0v442ct2qfjcdhyktn25spw02yq4fl08plrrvuradwwxzsle4mq8thln4
|
||||||
- &host_mibook age1n3uqtee5ymykrls6k04dznq50cwmj99hw7ny83yxjndt4y2ncf5qhjwa2p
|
- &host_mibook age1n3uqtee5ymykrls6k04dznq50cwmj99hw7ny83yxjndt4y2ncf5qhjwa2p
|
||||||
# - &host_jupiter age1... # TODO: Phase 9, see docs/secrets.md
|
- &host_jupiter age15uxuaxhn2hr4ypmgll36fwnkdkvv6gynvlxuc2p8ek0enmxmr5rsvlq0r2
|
||||||
|
|
||||||
creation_rules:
|
creation_rules:
|
||||||
- path_regex: ^secrets/mibook\.yaml$
|
- path_regex: ^secrets/mibook\.yaml$
|
||||||
@@ -9,9 +9,11 @@ creation_rules:
|
|||||||
- age:
|
- age:
|
||||||
- *admin_finn
|
- *admin_finn
|
||||||
- *host_mibook
|
- *host_mibook
|
||||||
# - path_regex: ^secrets/jupiter\.yaml$ # TODO: Phase 9
|
- path_regex: ^secrets/jupiter\.yaml$
|
||||||
# key_groups:
|
key_groups:
|
||||||
# - age: [ *admin_finn, *host_jupiter ]
|
- age:
|
||||||
# - path_regex: ^secrets/common\.yaml$ # TODO: Phase 9
|
- *admin_finn
|
||||||
|
- *host_jupiter
|
||||||
|
# - path_regex: ^secrets/common\.yaml$ # TODO: only if/when a secret needs to be shared across both hosts
|
||||||
# key_groups:
|
# key_groups:
|
||||||
# - age: [ *admin_finn, *host_mibook, *host_jupiter ]
|
# - age: [ *admin_finn, *host_mibook, *host_jupiter ]
|
||||||
|
|||||||
@@ -0,0 +1,164 @@
|
|||||||
|
# Homepage Widgets Implementation Plan
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||||
|
|
||||||
|
**Goal:** Add a `my.homepage.widgets` NixOS option so widgets can be declared in the homepage module and contributed from other modules, mirroring how `my.homepage.services` works today.
|
||||||
|
|
||||||
|
**Architecture:** Add a `my.homepage.widgets` option (typed `listOf attrs` since widget shapes vary by type) to the homepage module, import a `manual-widgets.nix` for ad-hoc definitions, merge both and pass to `services.homepage-dashboard.widgets`. Add starter widgets in `machines/jupiter/environments.nix` to confirm the wiring works end-to-end.
|
||||||
|
|
||||||
|
**Tech Stack:** Nix, NixOS module system, gethomepage.dev (`services.homepage-dashboard`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## File Map
|
||||||
|
|
||||||
|
| Action | File | Responsibility |
|
||||||
|
|--------|------|----------------|
|
||||||
|
| Modify | `modules/environments/homepage/default.nix` | Add `my.homepage.widgets` option + wire to dashboard |
|
||||||
|
| Create | `modules/environments/homepage/manual-widgets.nix` | Empty list for ad-hoc widgets (parallel to `manual-services.nix`) |
|
||||||
|
| Modify | `machines/jupiter/environments.nix` | Declare starter widgets to verify the feature end-to-end |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 1: Add `my.homepage.widgets` option to the homepage module
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `modules/environments/homepage/default.nix`
|
||||||
|
- Create: `modules/environments/homepage/manual-widgets.nix`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Create `manual-widgets.nix`** — empty list, same pattern as `manual-services.nix`
|
||||||
|
|
||||||
|
```nix
|
||||||
|
# modules/environments/homepage/manual-widgets.nix
|
||||||
|
[ ]
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Add `manualWidgets` import in the `let` block of `default.nix`**
|
||||||
|
|
||||||
|
Current `let` block (lines 7–42) ends with `homepageServices`. Add one line after `manualServices`:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
manualServices = import ./manual-services.nix;
|
||||||
|
manualWidgets = import ./manual-widgets.nix;
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: Add the `my.homepage.widgets` option**
|
||||||
|
|
||||||
|
After the closing brace of `options.my.homepage.services` (line 80), add:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
options.my.homepage.widgets = with lib; mkOption {
|
||||||
|
type = types.listOf types.attrs;
|
||||||
|
default = [ ];
|
||||||
|
description = "Widget definitions passed directly to services.homepage-dashboard.widgets. Each entry is an attrset like { resources = { cpu = true; memory = true; }; }.";
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 4: Wire widgets to the dashboard in the `config` block**
|
||||||
|
|
||||||
|
The `config` block currently sets `services = homepageServices ++ manualServices;`. Add `widgets`:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
services.homepage-dashboard = {
|
||||||
|
enable = true;
|
||||||
|
listenPort = dashboardPort;
|
||||||
|
allowedHosts = "${dashboardHost}:${toString dashboardPort},localhost:${toString dashboardPort},127.0.0.1:${toString dashboardPort},jupiter.solar.internal:${toString dashboardPort}";
|
||||||
|
bookmarks = import ./bookmarks.nix;
|
||||||
|
services = homepageServices ++ manualServices;
|
||||||
|
widgets = config.my.homepage.widgets ++ manualWidgets;
|
||||||
|
};
|
||||||
|
# ... rest of config unchanged
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 5: Build to check for eval errors (no switch yet)**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nixos-rebuild build --flake /Users/finnmarkwitz/development/nixos#jupiter 2>&1 | tail -20
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: build succeeds with no errors (widgets list is empty, so no visible change yet).
|
||||||
|
|
||||||
|
- [ ] **Step 6: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /Users/finnmarkwitz/development/nixos
|
||||||
|
git add modules/environments/homepage/default.nix modules/environments/homepage/manual-widgets.nix
|
||||||
|
git commit -m "feat: add my.homepage.widgets option to homepage module"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 2: Add starter widgets in `environments.nix`
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `machines/jupiter/environments.nix`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Add `my.homepage.widgets` to `environments.nix`**
|
||||||
|
|
||||||
|
Add the following after the `my.profiles` block (e.g. after line 39, before the `my.hardware` block):
|
||||||
|
|
||||||
|
```nix
|
||||||
|
my.homepage.widgets = [
|
||||||
|
{
|
||||||
|
search = {
|
||||||
|
provider = "google";
|
||||||
|
target = "_blank";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
resources = {
|
||||||
|
cpu = true;
|
||||||
|
memory = true;
|
||||||
|
disk = "/";
|
||||||
|
cacheInterval = 5000;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
datetime = {
|
||||||
|
text_size = "xl";
|
||||||
|
format = {
|
||||||
|
timeStyle = "short";
|
||||||
|
dateStyle = "short";
|
||||||
|
hour12 = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Build to confirm eval**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nixos-rebuild build --flake /Users/finnmarkwitz/development/nixos#jupiter 2>&1 | tail -20
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: build succeeds.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Switch and verify visually**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo nixos-rebuild switch --flake /Users/finnmarkwitz/development/nixos#jupiter
|
||||||
|
```
|
||||||
|
|
||||||
|
Open `http://jupiter.solar.internal:8082` (or `http://localhost:8082`) in a browser.
|
||||||
|
|
||||||
|
Expected: search bar, CPU/memory/disk resource monitor, and date/time widget appear at the top of the dashboard.
|
||||||
|
|
||||||
|
- [ ] **Step 4: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /Users/finnmarkwitz/development/nixos
|
||||||
|
git add machines/jupiter/environments.nix
|
||||||
|
git commit -m "feat: add starter homepage widgets (search, resources, datetime)"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verification Checklist
|
||||||
|
|
||||||
|
- [ ] `nixos-rebuild build` passes with no eval errors
|
||||||
|
- [ ] Dashboard at `:8082` shows widgets at top of page
|
||||||
|
- [ ] Existing services and bookmarks are unchanged
|
||||||
|
- [ ] Other modules can now contribute widgets via `my.homepage.widgets = [ ... ];` in their `config` block
|
||||||
Generated
+40
-40
@@ -21,11 +21,11 @@
|
|||||||
"nixpkgs-lib": "nixpkgs-lib"
|
"nixpkgs-lib": "nixpkgs-lib"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1785627969,
|
"lastModified": 1790898470,
|
||||||
"narHash": "sha256-4dtXQk/NMePegK/nWp5NSeuZKLATItOq61lpEvmXqGw=",
|
"narHash": "sha256-zTwuwezD0w3hpga6a6P8emidzAZFyWqlNeRBlpWOOl8=",
|
||||||
"owner": "hercules-ci",
|
"owner": "hercules-ci",
|
||||||
"repo": "flake-parts",
|
"repo": "flake-parts",
|
||||||
"rev": "427bf4bd9435fdf21321c8cc628c24efc14c0f7a",
|
"rev": "024633cd702b10285db5cb19b40ad48d2399ba60",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -63,11 +63,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1782949081,
|
"lastModified": 1788450739,
|
||||||
"narHash": "sha256-vp6Y/Grm98ESt6ceOkWiHWyZRDV3J1RID4w+6NWK9yA=",
|
"narHash": "sha256-glZLQlzIn1fXH6PazR2iUmTo7kzzyYSshrWhLS9TqCU=",
|
||||||
"owner": "hercules-ci",
|
"owner": "hercules-ci",
|
||||||
"repo": "flake-parts",
|
"repo": "flake-parts",
|
||||||
"rev": "17c9d6cdfc60c64f4ee8d306f9bc0b4ccb51481e",
|
"rev": "31729ca8cbdb4fa927b34e5f4353e6a83f39e993",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -87,11 +87,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1783008725,
|
"lastModified": 1788267358,
|
||||||
"narHash": "sha256-jGiy6+sxjNWXSjp25uoJuNfyH9zBK1PEDY0lVoL4ibQ=",
|
"narHash": "sha256-nt+lUqYVpc9Y6JeMd2WmXzCDojasdadKo0mWcluvY2Y=",
|
||||||
"owner": "cachix",
|
"owner": "cachix",
|
||||||
"repo": "git-hooks.nix",
|
"repo": "git-hooks.nix",
|
||||||
"rev": "bca82caa46d5ec0f5d422c61fb1e30bc51313cbe",
|
"rev": "27555e2624241fb116b49095df4caaee85a25691",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -113,11 +113,11 @@
|
|||||||
"uv2nix": "uv2nix"
|
"uv2nix": "uv2nix"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1788877844,
|
"lastModified": 1791121781,
|
||||||
"narHash": "sha256-9Ik9egIxYhW/IDw1mz/dYN0IqLTP3bEe+LdEFtP9FWM=",
|
"narHash": "sha256-39vzOiYTAwECDMfJAv/b+OxpHPXHfJle0Gx5x+WjPW0=",
|
||||||
"owner": "NousResearch",
|
"owner": "NousResearch",
|
||||||
"repo": "hermes-agent",
|
"repo": "hermes-agent",
|
||||||
"rev": "c8aa5608c24e3636e77c267650c0f1f52e44adb0",
|
"rev": "af90026aa09949579bd423d24def3d38f743cde0",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -157,11 +157,11 @@
|
|||||||
"nixpkgs-regression": "nixpkgs-regression"
|
"nixpkgs-regression": "nixpkgs-regression"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1787274306,
|
"lastModified": 1791067591,
|
||||||
"narHash": "sha256-Qg9f9td5iphUWSQS6zmvyZWO1F+D7j8Z3U6dGyUTg08=",
|
"narHash": "sha256-SGcfVVSS3DLO+ES4J+SrLxKGP11yvTWXgiAqku1L+Sk=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nix",
|
"repo": "nix",
|
||||||
"rev": "649e823fb24ed118d72e613be35fa8ea1b64afe7",
|
"rev": "e8280775f307a94ca82cea193cfcc14c0d56232a",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -211,11 +211,11 @@
|
|||||||
"nixpkgs": "nixpkgs_2"
|
"nixpkgs": "nixpkgs_2"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1787144466,
|
"lastModified": 1791128201,
|
||||||
"narHash": "sha256-HHfv2/HkNSKbbSyU9iD/g8lbP6r4tl33sSw1W4rXCk0=",
|
"narHash": "sha256-rlsYY/Dg/LhbIj51Aa6TLvRpZeb3KZgUTd7llQ5XcJE=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixos-hardware",
|
"repo": "nixos-hardware",
|
||||||
"rev": "0471accf8d0a8210b31d947497d179ecc99e0021",
|
"rev": "31cc5f4d9b9ba601071e8b8504601b9b176e2756",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -226,11 +226,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1783148766,
|
"lastModified": 1789344334,
|
||||||
"narHash": "sha256-H9+N+GFtsbVC8ZniHliChM7ndizxtqVZs6bnGOLM3WQ=",
|
"narHash": "sha256-it+7kNGnOOHBCEnl4SfZ7QtfGziH3EryzHqwvJpjAfg=",
|
||||||
"rev": "a50de1b7d8a586adc18d2395c19de7d6058e6030",
|
"rev": "c3eea5b2156db11c7eeeada3dc737711255b253e",
|
||||||
"type": "tarball",
|
"type": "tarball",
|
||||||
"url": "https://releases.nixos.org/nixos/26.05/nixos-26.05.4193.a50de1b7d8a5/nixexprs.tar.xz"
|
"url": "https://releases.nixos.org/nixos/26.05/nixos-26.05.9729.c3eea5b2156d/nixexprs.tar.xz"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"type": "tarball",
|
"type": "tarball",
|
||||||
@@ -255,11 +255,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs-lib": {
|
"nixpkgs-lib": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1785031560,
|
"lastModified": 1790477367,
|
||||||
"narHash": "sha256-OmshNvn2vupOFpYinLUu+1Dnpu4n7Q5N3ggGVNHpkUI=",
|
"narHash": "sha256-oujbxmVKDhci2E4EM3KyAbRUgp5/IsCoiA/LfEF7OOk=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "nixpkgs.lib",
|
"repo": "nixpkgs.lib",
|
||||||
"rev": "0e79af5e3d4dcfcd676ab5ba3f95d2e3352e078c",
|
"rev": "f7cd230690d9fc982d06129f9189b101fddcfa3b",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -286,11 +286,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs-unstable": {
|
"nixpkgs-unstable": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1787135253,
|
"lastModified": 1791048980,
|
||||||
"narHash": "sha256-M5/r2v++FjVhdsxXYMb4BDJ5YLAdCWFt3aZotcshocA=",
|
"narHash": "sha256-u3KCLxsnf1622GdFccg8hmkEIutOZ1h4pvia5ERjIuI=",
|
||||||
"rev": "ffb3c9b700e759be2ef13237c9d8f953b32a1e46",
|
"rev": "a7868a727837f3c09cee2ce0ca671c76b1589fed",
|
||||||
"type": "tarball",
|
"type": "tarball",
|
||||||
"url": "https://releases.nixos.org/nixos/unstable/nixos-26.11pre1058091.ffb3c9b700e7/nixexprs.tar.xz"
|
"url": "https://releases.nixos.org/nixos/unstable/nixos-26.11pre1084968.a7868a727837/nixexprs.tar.zst"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"id": "nixpkgs",
|
"id": "nixpkgs",
|
||||||
@@ -300,11 +300,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1767892417,
|
"lastModified": 1789546076,
|
||||||
"narHash": "sha256-8bW3q88CEg2u4hSP66Vf4lpbLonHz7hqDNBMcCY7E9U=",
|
"narHash": "sha256-vWkSk5bbfTqdtMoSgD9FshACO8JCvXTFi+3cqEp0mH0=",
|
||||||
"rev": "3497aa5c9457a9d88d71fa93a4a8368816fbeeba",
|
"rev": "b1b875982b17dabde9b4a37f3e229e74913e6db3",
|
||||||
"type": "tarball",
|
"type": "tarball",
|
||||||
"url": "https://releases.nixos.org/nixos/unstable/nixos-26.05pre924538.3497aa5c9457/nixexprs.tar.xz"
|
"url": "https://releases.nixos.org/nixos/unstable/nixos-26.11pre1074753.b1b875982b17/nixexprs.tar.xz"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"type": "tarball",
|
"type": "tarball",
|
||||||
@@ -313,11 +313,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs_3": {
|
"nixpkgs_3": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1787101114,
|
"lastModified": 1791031588,
|
||||||
"narHash": "sha256-BA7sSNjLDuPGSOYBGpr6WQjke1MQ8AZpJ8GlYZM/mOc=",
|
"narHash": "sha256-4XF6NXFWmQPM0xHuxTw+iQEA6mUtmDQNJoVd4u9GkLw=",
|
||||||
"rev": "b18a4b905f8d028dc4476412e6d6891728695379",
|
"rev": "825e2028c29b702a4a5f085f08095d12099784f2",
|
||||||
"type": "tarball",
|
"type": "tarball",
|
||||||
"url": "https://releases.nixos.org/nixos/26.05/nixos-26.05.8045.b18a4b905f8d/nixexprs.tar.xz"
|
"url": "https://releases.nixos.org/nixos/26.05/nixos-26.05.11150.825e2028c29b/nixexprs.tar.zst"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"id": "nixpkgs",
|
"id": "nixpkgs",
|
||||||
@@ -415,11 +415,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1788337237,
|
"lastModified": 1791103873,
|
||||||
"narHash": "sha256-gkSH8VUtCo6hnysNmb9DbTuDepH2t5pv+QWjP75xKAk=",
|
"narHash": "sha256-nFxM+pKoZ8LJAEnUXARyCaOAloWgaW9kZQOSjWzKcTE=",
|
||||||
"owner": "Mic92",
|
"owner": "Mic92",
|
||||||
"repo": "sops-nix",
|
"repo": "sops-nix",
|
||||||
"rev": "fbf759290e0cb0a98dfc813a4eb7d53ad1dacb57",
|
"rev": "dcd241ba97088c22569d1573286e1b9daad340c0",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
@@ -12,6 +12,13 @@
|
|||||||
|
|
||||||
settings = {
|
settings = {
|
||||||
auto-optimise-store = true;
|
auto-optimise-store = true;
|
||||||
|
# Without these, gc sweeps away eval-time-only sources (flake inputs,
|
||||||
|
# their build deps) since they're not part of the runtime closure.
|
||||||
|
# The next evaluation then cold-refetches everything from GitHub,
|
||||||
|
# which is enough on its own to trip GitHub's unauthenticated rate
|
||||||
|
# limit for large dependency trees (e.g. hermes-agent's).
|
||||||
|
keep-outputs = true;
|
||||||
|
keep-derivations = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
gc = {
|
gc = {
|
||||||
|
|||||||
@@ -72,6 +72,9 @@
|
|||||||
|
|
||||||
system = {
|
system = {
|
||||||
stateVersion = "23.05";
|
stateVersion = "23.05";
|
||||||
autoUpgrade.enable = true;
|
# Was silently failing daily (legacy channel path, no --flake set) without
|
||||||
|
# ever reaching the network. Disabled rather than fixed: rebuilds should
|
||||||
|
# only happen when triggered manually.
|
||||||
|
autoUpgrade.enable = false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ _: {
|
|||||||
readarr.enable = true;
|
readarr.enable = true;
|
||||||
sonarr.enable = true;
|
sonarr.enable = true;
|
||||||
jellyfin.enable = true;
|
jellyfin.enable = true;
|
||||||
jellyseerr.enable = true;
|
seerr.enable = true;
|
||||||
immich.enable = true;
|
immich.enable = true;
|
||||||
development.enable = true;
|
development.enable = true;
|
||||||
home-assistant.enable = true;
|
home-assistant.enable = true;
|
||||||
|
|||||||
@@ -16,6 +16,13 @@
|
|||||||
];
|
];
|
||||||
|
|
||||||
networking.hostName = "mibook";
|
networking.hostName = "mibook";
|
||||||
|
|
||||||
|
swapDevices = [
|
||||||
|
{
|
||||||
|
device = "/var/lib/swapfile";
|
||||||
|
size = 8 * 1024; # 8G, headroom for nix builds (7.7G RAM, no prior swap)
|
||||||
|
}
|
||||||
|
];
|
||||||
boot.loader.grub = {
|
boot.loader.grub = {
|
||||||
enable = true;
|
enable = true;
|
||||||
device = "/dev/nvme0n1";
|
device = "/dev/nvme0n1";
|
||||||
@@ -54,6 +61,9 @@
|
|||||||
|
|
||||||
system = {
|
system = {
|
||||||
stateVersion = "23.05";
|
stateVersion = "23.05";
|
||||||
autoUpgrade.enable = true;
|
# Was silently failing daily (legacy channel path, no --flake set) without
|
||||||
|
# ever reaching the network. Disabled rather than fixed: rebuilds should
|
||||||
|
# only happen when triggered manually.
|
||||||
|
autoUpgrade.enable = false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,5 +4,6 @@ _: {
|
|||||||
# firewall otherwise blocks inbound connections from other devices.
|
# firewall otherwise blocks inbound connections from other devices.
|
||||||
networking.firewall.allowedTCPPorts = [
|
networking.firewall.allowedTCPPorts = [
|
||||||
9119 # athena hermes dashboard
|
9119 # athena hermes dashboard
|
||||||
|
47823 # hermes agent ad-hoc webpage server
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
./readarr
|
./readarr
|
||||||
./sonarr
|
./sonarr
|
||||||
./jellyfin
|
./jellyfin
|
||||||
./jellyseerr
|
./seerr
|
||||||
./immich
|
./immich
|
||||||
./hermes-agent
|
./hermes-agent
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ in
|
|||||||
neovim
|
neovim
|
||||||
# jetbrains.idea-ultimate
|
# jetbrains.idea-ultimate
|
||||||
go
|
go
|
||||||
|
nodejs # bundles npm
|
||||||
(python3.withPackages (
|
(python3.withPackages (
|
||||||
ps: with ps; [
|
ps: with ps; [
|
||||||
jupyter # notebooks
|
jupyter # notebooks
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ in
|
|||||||
enable = true;
|
enable = true;
|
||||||
# Deliberate pin, matches the approved design — bump on purpose, not by drift.
|
# Deliberate pin, matches the approved design — bump on purpose, not by drift.
|
||||||
settings.model.default = "anthropic/claude-sonnet-4-5";
|
settings.model.default = "anthropic/claude-sonnet-4-5";
|
||||||
|
# The Nix flake input is the source of truth for hermes's version here; its
|
||||||
|
# built-in self-updater polling GitHub independently just burns API quota.
|
||||||
|
settings.updates.check = false;
|
||||||
environmentFiles = [ config.sops.secrets."hermes-env".path ];
|
environmentFiles = [ config.sops.secrets."hermes-env".path ];
|
||||||
addToSystemPackages = true;
|
addToSystemPackages = true;
|
||||||
|
|
||||||
|
|||||||
@@ -54,14 +54,16 @@ in
|
|||||||
"f /var/lib/hass/scenes.yaml 0644 hass hass - []"
|
"f /var/lib/hass/scenes.yaml 0644 hass hass - []"
|
||||||
];
|
];
|
||||||
|
|
||||||
services.openthread-border-router = {
|
# Disabled: ZBT-2 antenna isn't connected, so otbr-agent can't reach the
|
||||||
enable = true;
|
# radio and just crash-loops on every switch.
|
||||||
package = pkgs.unstable.openthread-border-router;
|
# services.openthread-border-router = {
|
||||||
openFirewall = true;
|
# enable = true;
|
||||||
backboneInterfaces = [ "enp3s0" ];
|
# package = pkgs.unstable.openthread-border-router;
|
||||||
radio.device = "/dev/serial/by-id/usb-Nabu_Casa_ZBT-2_DCB4D9149C7C-if00";
|
# openFirewall = true;
|
||||||
radio.baudRate = 460800;
|
# backboneInterfaces = [ "enp3s0" ];
|
||||||
};
|
# radio.device = "/dev/serial/by-id/usb-Nabu_Casa_ZBT-2_DCB4D9149C7C-if00";
|
||||||
|
# radio.baudRate = 460800;
|
||||||
|
# };
|
||||||
|
|
||||||
my.homepage.services = [
|
my.homepage.services = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,16 +1,4 @@
|
|||||||
[
|
[
|
||||||
{
|
|
||||||
Developer = [
|
|
||||||
{
|
|
||||||
Github = [
|
|
||||||
{
|
|
||||||
abbr = "GitLab - Smoothcloud";
|
|
||||||
href = "https://gitlab.smoothcloud.de/";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
Social = [
|
Social = [
|
||||||
{
|
{
|
||||||
@@ -18,7 +6,6 @@
|
|||||||
{
|
{
|
||||||
icon = "reddit.png";
|
icon = "reddit.png";
|
||||||
href = "https://reddit.com/";
|
href = "https://reddit.com/";
|
||||||
description = "The front page of the internet";
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -29,7 +16,7 @@
|
|||||||
{
|
{
|
||||||
YouTube = [
|
YouTube = [
|
||||||
{
|
{
|
||||||
abbr = "YT";
|
icon = "youtube.png";
|
||||||
href = "https://youtube.com/";
|
href = "https://youtube.com/";
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -12,79 +12,93 @@ let
|
|||||||
manualServices = import ./manual-services.nix;
|
manualServices = import ./manual-services.nix;
|
||||||
manualWidgets = import ./manual-widgets.nix;
|
manualWidgets = import ./manual-widgets.nix;
|
||||||
|
|
||||||
groupedServices =
|
groupedServices = lib.foldl' (
|
||||||
lib.foldl'
|
acc: entry:
|
||||||
(
|
acc
|
||||||
acc: entry:
|
// {
|
||||||
acc
|
${entry.group} = (acc.${entry.group} or [ ]) ++ [ entry ];
|
||||||
// {
|
|
||||||
${entry.group} = (acc.${entry.group} or [ ]) ++ [ entry ];
|
|
||||||
}
|
|
||||||
)
|
|
||||||
{ }
|
|
||||||
config.my.homepage.services;
|
|
||||||
|
|
||||||
homepageServices = lib.mapAttrsToList (
|
|
||||||
group: entries:
|
|
||||||
{
|
|
||||||
${group} = map (
|
|
||||||
entry:
|
|
||||||
let
|
|
||||||
service = builtins.removeAttrs entry [
|
|
||||||
"group"
|
|
||||||
"name"
|
|
||||||
];
|
|
||||||
in
|
|
||||||
{
|
|
||||||
${entry.name} = lib.filterAttrs (_: value: value != null) service;
|
|
||||||
}
|
|
||||||
) entries;
|
|
||||||
}
|
}
|
||||||
) groupedServices;
|
) { } config.my.homepage.services;
|
||||||
|
|
||||||
|
homepageServices = lib.mapAttrsToList (group: entries: {
|
||||||
|
${group} = map (
|
||||||
|
entry:
|
||||||
|
let
|
||||||
|
service = builtins.removeAttrs entry [
|
||||||
|
"group"
|
||||||
|
"name"
|
||||||
|
];
|
||||||
|
in
|
||||||
|
{
|
||||||
|
${entry.name} = lib.filterAttrs (_: value: value != null) service;
|
||||||
|
}
|
||||||
|
) entries;
|
||||||
|
}) groupedServices;
|
||||||
|
|
||||||
|
# homepage-dashboard keeps only the first services.yaml list entry with a
|
||||||
|
# given group name (first match wins), so module-contributed and manual
|
||||||
|
# groups sharing a name (e.g. "Services") must be merged here rather than
|
||||||
|
# simply concatenated, or the later ones are silently dropped.
|
||||||
|
mergeGroups =
|
||||||
|
lists:
|
||||||
|
let
|
||||||
|
merged = lib.foldl' (
|
||||||
|
acc: groupAttrs:
|
||||||
|
let
|
||||||
|
groupName = builtins.head (builtins.attrNames groupAttrs);
|
||||||
|
in
|
||||||
|
acc // { ${groupName} = (acc.${groupName} or [ ]) ++ groupAttrs.${groupName}; }
|
||||||
|
) { } lists;
|
||||||
|
in
|
||||||
|
lib.mapAttrsToList (name: entries: { ${name} = entries; }) merged;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
|
||||||
options.my.homepage.services = with lib; mkOption {
|
options.my.homepage.services =
|
||||||
type = types.listOf (
|
with lib;
|
||||||
types.submodule {
|
mkOption {
|
||||||
options = {
|
type = types.listOf (
|
||||||
group = mkOption {
|
types.submodule {
|
||||||
type = types.str;
|
options = {
|
||||||
description = "Homepage service group";
|
group = mkOption {
|
||||||
};
|
type = types.str;
|
||||||
|
description = "Homepage service group";
|
||||||
|
};
|
||||||
|
|
||||||
name = mkOption {
|
name = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
description = "Homepage service name";
|
description = "Homepage service name";
|
||||||
};
|
};
|
||||||
|
|
||||||
description = mkOption {
|
description = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
description = "Homepage service description";
|
description = "Homepage service description";
|
||||||
};
|
};
|
||||||
|
|
||||||
href = mkOption {
|
href = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
description = "Homepage service URL";
|
description = "Homepage service URL";
|
||||||
};
|
};
|
||||||
|
|
||||||
icon = mkOption {
|
icon = mkOption {
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
default = null;
|
default = null;
|
||||||
description = "Optional Homepage service icon";
|
description = "Optional Homepage service icon";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
}
|
);
|
||||||
);
|
default = [ ];
|
||||||
default = [ ];
|
description = "Merged homepage service metadata contributed by repo modules.";
|
||||||
description = "Merged homepage service metadata contributed by repo modules.";
|
};
|
||||||
};
|
|
||||||
|
|
||||||
options.my.homepage.widgets = with lib; mkOption {
|
options.my.homepage.widgets =
|
||||||
type = types.listOf types.attrs;
|
with lib;
|
||||||
default = [ ];
|
mkOption {
|
||||||
description = "Widget definitions passed directly to services.homepage-dashboard.widgets. Each entry is an attrset like { resources = { cpu = true; memory = true; }; }.";
|
type = types.listOf types.attrs;
|
||||||
};
|
default = [ ];
|
||||||
|
description = "Widget definitions passed directly to services.homepage-dashboard.widgets. Each entry is an attrset like { resources = { cpu = true; memory = true; }; }.";
|
||||||
|
};
|
||||||
|
|
||||||
options.my.profiles.homepage = with lib; {
|
options.my.profiles.homepage = with lib; {
|
||||||
enable = mkEnableOption "getHomepage.dev Dashboard";
|
enable = mkEnableOption "getHomepage.dev Dashboard";
|
||||||
@@ -98,7 +112,7 @@ in
|
|||||||
listenPort = dashboardPort;
|
listenPort = dashboardPort;
|
||||||
allowedHosts = "${dashboardHost}:${toString dashboardPort},192.168.178.65:${toString dashboardPort},localhost:${toString dashboardPort},127.0.0.1:${toString dashboardPort},jupiter:${toString dashboardPort},jupiter.solar.internal:${toString dashboardPort}";
|
allowedHosts = "${dashboardHost}:${toString dashboardPort},192.168.178.65:${toString dashboardPort},localhost:${toString dashboardPort},127.0.0.1:${toString dashboardPort},jupiter:${toString dashboardPort},jupiter.solar.internal:${toString dashboardPort}";
|
||||||
bookmarks = import ./bookmarks.nix;
|
bookmarks = import ./bookmarks.nix;
|
||||||
services = homepageServices ++ manualServices;
|
services = mergeGroups (homepageServices ++ manualServices);
|
||||||
widgets = config.my.homepage.widgets ++ manualWidgets;
|
widgets = config.my.homepage.widgets ++ manualWidgets;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -17,10 +17,10 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
"GitLab" = {
|
"Gitea" = {
|
||||||
href = "https://gitlab.smoothcloud.de";
|
href = "https://git.rechberg.online";
|
||||||
description = "Selfhosted GitLab";
|
description = "Selfhosted Gitea";
|
||||||
icon = "gitlab.png";
|
icon = "gitea.png";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@@ -32,4 +32,29 @@
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
"Gaming" = [
|
||||||
|
{
|
||||||
|
"Talon" = {
|
||||||
|
href = "https://ethraldos.online";
|
||||||
|
description = "Kunst der Täuschung";
|
||||||
|
icon = "foundry-vtt.png";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"Tyranny of Dragons" = {
|
||||||
|
href = "https://hotdq.smoothcloud.de";
|
||||||
|
description = "Tyranny of Dragons (D&D)";
|
||||||
|
icon = "foundry-vtt.png";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"Beholder D&D" = {
|
||||||
|
href = "https://beholder.ethraldos.online";
|
||||||
|
description = "Andrey FoundryVTT Server";
|
||||||
|
icon = "foundry-vtt.png";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -3,4 +3,5 @@
|
|||||||
{ resources = { cpu = true; memory = true; disk = "/"; }; }
|
{ resources = { cpu = true; memory = true; disk = "/"; }; }
|
||||||
{ datetime = { text_size = "xl"; format = { timeStyle = "short"; }; }; }
|
{ datetime = { text_size = "xl"; format = { timeStyle = "short"; }; }; }
|
||||||
{ search = {provider = "google"; focus = true; target = "_blank"; }; }
|
{ search = {provider = "google"; focus = true; target = "_blank"; }; }
|
||||||
|
{ minecraft = { url = "udp://rechberg.online:25565" }; }
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ in
|
|||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
services.immich = {
|
services.immich = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
# nixos-26.05 pins immich 2.7.5; pull 3.x from the unstable overlay instead.
|
||||||
|
package = pkgs.unstable.immich;
|
||||||
host = "0.0.0.0";
|
host = "0.0.0.0";
|
||||||
inherit port;
|
inherit port;
|
||||||
openFirewall = true;
|
openFirewall = true;
|
||||||
|
|||||||
+6
-6
@@ -1,17 +1,17 @@
|
|||||||
# manages and downloads films
|
# manages and downloads films
|
||||||
{ config, lib, ... }:
|
{ config, lib, ... }:
|
||||||
let
|
let
|
||||||
cfg = config.my.profiles.jellyseerr;
|
cfg = config.my.profiles.seerr;
|
||||||
hostName = config.networking.hostName;
|
hostName = config.networking.hostName;
|
||||||
port = 5055;
|
port = 5055;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.my.profiles.jellyseerr = with lib; {
|
options.my.profiles.seerr = with lib; {
|
||||||
enable = mkEnableOption "JellySeerr Media Service";
|
enable = mkEnableOption "Seerr Media Service";
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
services.jellyseerr = {
|
services.seerr = {
|
||||||
enable = true;
|
enable = true;
|
||||||
openFirewall = true;
|
openFirewall = true;
|
||||||
};
|
};
|
||||||
@@ -19,14 +19,14 @@ in
|
|||||||
my.homepage.services = [
|
my.homepage.services = [
|
||||||
{
|
{
|
||||||
group = "Media";
|
group = "Media";
|
||||||
name = "Jellyseerr";
|
name = "Seerr";
|
||||||
description = "Media requests";
|
description = "Media requests";
|
||||||
href = "http://${hostName}:${toString port}";
|
href = "http://${hostName}:${toString port}";
|
||||||
icon = "mdi-television-guide";
|
icon = "mdi-television-guide";
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
systemd.services.jellyseerr = {
|
systemd.services.seerr = {
|
||||||
after = [ "network-online.target" ];
|
after = [ "network-online.target" ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
Reference in New Issue
Block a user