Compare commits

..
Author SHA1 Message Date
marthsincemelee 2f88d5567e feat: MC widget and Foundry Description 2026-10-05 14:20:07 +02:00
marthsincemeleeandClaude Opus 5.5 b725bb37c2 feat(homepage): add Gaming section with FoundryVTT servers
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 14:14:00 +02:00
finn.markwitz f7196c0c86 chore: Flake Update 2026-10-04 18:39:52 +02:00
finn.markwitz 20c2b43ae5 Merge pull request 'Feat/hermes webpage port' (#17) from feat/hermes-webpage-port into main
Reviewed-on: #17
2026-10-04 18:37:36 +02:00
finn.markwitz eecb7fa2b2 Merge pull request 'Feat/jupiter seerr rename' (#16) from feat/jupiter-seerr-rename into feat/hermes-webpage-port
Reviewed-on: #16
2026-10-04 18:36:35 +02:00
finn.markwitzandClaude Sonnet 5 84ada68069 fix(mibook): disable hermes-agent's built-in self-update GitHub polling
Its self-updater was independently polling GitHub for the same repo the
flake input tracks, and stacked with a runaway crash-restart loop this
exhausted the GitHub rate limit, causing unrelated flake fetches to 429.
The Nix flake input is already the source of truth for hermes's version.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F9ge2kVMD55sLJExx3v2G3
2026-09-29 17:36:18 +02:00
finn.markwitz 07a1d8ee62 feat(mibook): open port 47823 for hermes ad-hoc webpage hosting
Distinct from the existing 9119 dashboard port — this lets the agent
serve one-off pages to devices on the local network.
2026-09-26 08:15:58 +02:00
finn.markwitzandClaude Sonnet 5 565ec2bf39 feat(jupiter): rename jellyseerr profile to seerr
Jellyseerr was rebranded upstream to Seerr (seerr-team/seerr), and
nixpkgs now aliases services.jellyseerr to services.seerr with an
identical state directory, so this is a same-data rename. Also fixes
systemd.services.jellyseerr.after, which was a silent no-op since the
underlying unit has always been named seerr.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019MLWL7mWHCV6UGfzmhnfqN
2026-09-22 11:51:02 +02:00
finn.markwitz 34a55841eb chore: Flake Update 2026-09-21 16:12:45 +02:00
finn.markwitzandClaude Sonnet 5 e110cb6b87 fix(homepage): replace GitLab links with self-hosted Gitea
Migrated from gitlab.smoothcloud.de to git.rechberg.online; drop the
now-obsolete bookmark and repoint the Services tile.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QD5x9KR8cM7EPPsxKATHfQ
2026-09-21 16:01:50 +02:00
finn.markwitzandClaude Sonnet 5 33ac72aaed fix(home-assistant): disable otbr-agent, ZBT-2 antenna not connected
otbr-agent can't reach the Thread radio without the antenna attached
and crash-loops on every switch, failing the rebuild.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QD5x9KR8cM7EPPsxKATHfQ
2026-09-21 15:55:20 +02:00
finn.markwitzandClaude Sonnet 5 30b7f177c5 feat(immich): upgrade to 3.x via unstable overlay
nixos-26.05 pins immich at 2.7.5; pull 3.2.0 from pkgs.unstable
instead. The machine-learning service picks up the matching version
automatically via the package's passthru. Verified jupiter's toplevel
still builds; pgvecto.rs->vectorchord migration was already in place
so no DB migration is needed for the bump itself.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DDyhS2N9XEeMq4GisBrqyf
2026-09-21 15:42:31 +02:00
finn.markwitz c1fc8e2a05 Merge pull request 'fix(homepage): merge service groups by name to stop manual entries being dropped' (#14) from fix/homepage-duplicate-service-groups into main
Reviewed-on: #14
2026-09-21 15:29:59 +02:00
finn.markwitzandClaude Sonnet 5 202eca2d03 fix(homepage): merge service groups by name to stop manual entries being dropped
homepage-dashboard resolves services.yaml groups by name using first-match
lookup, so the module-contributed "Services" group and manual-services.nix's
"Services" group (two separate top-level YAML list entries) caused the
second one to be silently discarded. Merge by group name before handing the
list to services.homepage-dashboard.services.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JbLevsLozTCcCWe1SoUGe1
2026-09-21 15:27:07 +02:00
finn.markwitz 2ff3042cd9 Merge pull request 'feat(mibook): add swapfile and nodejs dev tooling' (#13) from feat/mibook-swapfile into main
Reviewed-on: #13
2026-09-21 15:21:22 +02:00
finn.markwitzandClaude Sonnet 5 d219f2b61c feat(mibook): add swapfile and nodejs dev tooling
Add an 8G swapfile for headroom during nix builds (7.7G RAM, no prior
swap) and bring nodejs (bundles npm) into the development profile.
Also picks up latest flake.lock input updates.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C5fRUDLRzDhoKhEqa69cyR
2026-09-21 15:13:03 +02:00
finn.markwitz 5a2a649244 feat: Sops for Jupiter Setup 2026-09-19 18:48:53 +02:00
finn.markwitz 4691eb1aa4 Merge pull request 'Feat/sops nix' (#12) from feat/sops-nix into main
Reviewed-on: #12
2026-09-14 13:06:45 +02:00
finn.markwitz 9dbd6ff71d Merge branch 'main' into feat/sops-nix 2026-09-14 13:06:33 +02:00
finn.markwitzandClaude Sonnet 5 807eea7e4f feat(homepage): add Athena Dashboard link to jupiter's homepage
Hermes Agent's dashboard runs on mibook, but the homepage-dashboard
service only runs on jupiter, so wire it in as a manual cross-host
entry rather than via my.homepage.services (which is scoped per-host
and would be inert on mibook).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sux8hmeb2qadqPqbJ1zNzL
2026-09-10 11:09:48 +02:00
finn.markwitz b96d30edd7 config: Futher Poweroptions to deny hibernate 2026-09-03 08:19:07 +02:00
finn.markwitz a7ffcc4648 feat: Enable Claude on Jupiter 2026-09-03 08:18:39 +02:00
finn.markwitz 652630cfe4 config: Jupiter Domain 2026-08-13 17:22:58 +02:00
finn.markwitz abe2431dbb config: Local DNS for Homepage Dashboard 2026-08-13 17:21:08 +02:00
18 changed files with 376 additions and 146 deletions
+7 -5
View File
@@ -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
View File
@@ -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 -1
View File
@@ -49,11 +49,22 @@
# Try fix wifi disconnect # Try fix wifi disconnect
networking.networkmanager.wifi.powersave = false; networking.networkmanager.wifi.powersave = false;
# Disable hibernate completely # Disable hibernate and suspend completely - this is a headless server.
# The board exposes a phantom ACPI lid switch (PNP0C0D) that fires a
# "closed" event when the HDMI cable is unplugged, which used to trigger
# a real suspend via logind's default HandleLidSwitch=suspend.
powerManagement.enable = true; powerManagement.enable = true;
systemd.targets."hibernate".enable = false; systemd.targets."hibernate".enable = false;
systemd.targets."hybrid-sleep".enable = false; systemd.targets."hybrid-sleep".enable = false;
systemd.targets."suspend-then-hibernate".enable = false; systemd.targets."suspend-then-hibernate".enable = false;
systemd.targets."suspend".enable = false;
systemd.targets."sleep".enable = false;
services.logind.settings.Login = {
HandleLidSwitch = "ignore";
HandleLidSwitchExternalPower = "ignore";
HandleLidSwitchDocked = "ignore";
};
# Optional: kernel parameter to fully disable hibernation # Optional: kernel parameter to fully disable hibernation
boot.kernelParams = [ "nohibernate" ]; boot.kernelParams = [ "nohibernate" ];
+2 -1
View File
@@ -10,13 +10,14 @@ _: {
}; };
actual.enable = false; actual.enable = false;
audiobookshelf.enable = true; audiobookshelf.enable = true;
claude-code.enable = true;
kde-desktop.enable = false; kde-desktop.enable = false;
radarr.enable = true; radarr.enable = true;
docker.enable = true; docker.enable = true;
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;
+1 -1
View File
@@ -4,7 +4,7 @@ _: {
]; ];
networking = { networking = {
domain = "jupiter.solar.internal"; domain = "jupiter";
search = [ "jupiter.solar.internal" ]; search = [ "jupiter.solar.internal" ];
}; };
} }
+7
View File
@@ -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";
+1
View File
@@ -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
]; ];
} }
+1 -1
View File
@@ -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 -14
View File
@@ -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/";
} }
]; ];
+81 -65
View File
@@ -12,91 +12,107 @@ 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";
}; };
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
networking.firewall.allowedTCPPorts = [ dashboardPort ];
services.homepage-dashboard = { services.homepage-dashboard = {
enable = true; enable = true;
listenPort = dashboardPort; listenPort = dashboardPort;
allowedHosts = "${dashboardHost}:${toString dashboardPort},localhost:${toString dashboardPort},127.0.0.1:${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;
}; };
@@ -2,6 +2,13 @@
# Example: # Example:
{ {
"Services" = [ "Services" = [
{
"Athena Dashboard" = {
href = "http://mibook:9119";
description = "Hermes Agent messaging gateway";
icon = "mdi-robot-outline";
};
}
{ {
"Tesla - Dashboard" = { "Tesla - Dashboard" = {
href = "https://grafana.smoothcloud.de"; href = "https://grafana.smoothcloud.de";
@@ -10,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";
}; };
} }
{ {
@@ -25,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" }; }
] ]
+2
View File
@@ -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;
@@ -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" ];
}; };
}; };