Commit graph

292 commits

Author SHA1 Message Date
082529dac9 phantom-ship + vps-relay: declare bon service + vhost (port 8091)
bon — receipt scanner Mini App. Snap a receipt with the device camera,
upload, list. MVP only captures + stores; OCR/categorization later.

phantom-ship.nix
  - systemd.services.bon on port 8091, binds :: for ZT
  - 8091 added to zt+ allowedTCPPorts
  - tmpfiles for /home/danny/.local/share/bon/{,images}
  - python env adds python-multipart (form upload) + pillow (image
    validate + downscale to 2400px JPEG)

vps-relay.nix
  - Caddy vhost bon.dannydannydanny.me → ZT [::]:8091
2026-05-07 22:12:03 +02:00
DannyDannyDanny
73d4225f9b sunken-ship: grant mulbo-server read on navidrome.db
mulbo-server's /folders endpoint reads navidrome.db directly because
the Subsonic API's path field is tag-virtual (not real fs paths).

Three pieces:
- services.navidrome UMask = 0027 (force) so future DB writes are
  group-readable; default was 0077.
- tmpfiles z-rules to chmod 0640 the existing navidrome.db, -wal, -shm
  (created under the old umask).
- mulbo-server gets SupplementaryGroups=[navidrome] so the unit's
  process can read those files.

Trade-off: couples mulbo-server to Navidrome's schema (specifically
media_file.id + media_file.path). Acceptable given Navidrome 0.61.1
has been stable on these columns; we'll catch breakage at the /health
navidrome_db_readable probe.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 15:06:51 +02:00
DannyDannyDanny
4debab6f69 sunken-ship: mulbo-server creds via EnvironmentFile + MULBO_MUSIC_ROOT
Adds:
- MULBO_MUSIC_ROOT=/srv/music (for the /folders fs walk)
- EnvironmentFile=/home/danny/.secrets/mulbo-server-navidrome (creds
  for Subsonic API calls — file is mode 600, owned by danny, not in
  source control)

Required for the new /folders endpoint and the upcoming POST /tracks
which needs to call search3.view + startScan.view.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 21:22:37 +02:00
DannyDannyDanny
1744d776e2 sunken-ship: mulbo-server systemd service + pull timer + ZT port 8091
Phase 5 of the mulbo Navidrome-pivot — companion HTTP service co-
located with Navidrome that owns uploads + the dedup index + the
real on-disk folder layout (which Navidrome's tag-virtual API can't
expose). Wire spec lives in the mulbo repo at 20_mulbo/SERVER_API.md.

Runs as `danny` so writes pass through to /home/danny/music/mulbo-
uploads via the existing /srv/music ro bind-mount — no mount changes
needed. Bound to [::]:8091 (8090 was taken by escape-hormuz on
phantom-ship); firewall scopes it to the ZT mesh, same trick bbbot
uses on 8080.

Pulls the python-projects repo via SSH using sunken-ship's id_ed25519
(registered as a read-only deploy key on the repo). Auto-pull timer
runs every 15 min, offset from fitness-bot-pull and dotfiles-rebuild.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 21:11:05 +02:00
Hara
3de1747e92 hara-heartbeat: strip markdown asterisks/underscores via sed before sending 2026-05-05 14:22:26 +02:00
Hara
7f8badf1d1 hara-heartbeat: plain text only prompt — no markdown asterisks in Telegram output 2026-05-05 14:11:03 +02:00
4e01e62cc0 phantom-ship: dedupe escape-hormuz tmpfiles + service block (rebase artifact) 2026-05-05 09:41:17 +02:00
8a91f3db88 phantom-ship + vps-relay: declare escape-hormuz service + vhost
Hara (openclaw) shipped escape_hormuz imperatively — service runs but
firewall + Caddy vhost weren't declared, so the public URL didn't
resolve and the firewall rule would've been wiped on next
dotfiles-rebuild. Bring it under nix:

phantom-ship.nix
  - systemd.services.escape-hormuz on port 8090, binds :: for ZT
  - 8090 added to zt+ allowedTCPPorts
  - tmpfiles entry for /home/danny/.local/share/escape_hormuz

vps-relay.nix
  - Caddy vhost escapehormuz.dannydannydanny.me → ZT [::]:8090
2026-05-05 09:40:11 +02:00
Hara
4600a8e5ca escape-hormuz: add service (port 8090) + escapehormuz.dannydannydanny.me vhost 2026-05-04 23:25:00 +02:00
DannyDannyDanny
d0e9b3f907 phantom-ship + vps-relay: Forgejo on git.dannydannydanny.me
Phase 1 of the de-platform-from-GitHub roadmap (vimwiki/diary/2026-05-03.md).

- phantom-ship: services.forgejo bound to 0.0.0.0:3000, sqlite, lfs on,
  registration disabled, sign-in required.
- phantom-ship: add :3000 to the existing zt+ allowedTCPPorts list
  (joins shelfish/scuttle — never exposed on WAN/Wi-Fi).
- vps-relay: Caddy vhost git.dannydannydanny.me reverse-proxies over
  ZT to phantom-ship:3000.

Manual steps before reachable:
1. GoDaddy A record git.dannydannydanny.me -> 89.167.39.251
2. clan machines update phantom-ship && clan machines update vps-relay
3. On phantom-ship: bootstrap admin (registration is disabled)
2026-05-04 21:35:03 +02:00
Hara
a9bb775b7d hara-heartbeat: check all 3 Gmail accounts (add wildstylewarrior) 2026-05-04 18:56:38 +02:00
Hara
e952667623 hara-heartbeat: shift schedule to 06/10/14/18 Copenhagen 2026-05-04 18:28:00 +02:00
Hara
c04b463ad0 hara-heartbeat: fix OnCalendar timezone syntax, fire every 4h (08/12/16/20) 2026-05-04 18:27:01 +02:00
9ad8d71f61 phantom-ship: set SHIPYARD_OWNER_ID for owner-only /admin commands 2026-05-04 18:26:20 +02:00
Hara
69d982d0fa hara: add morning heartbeat systemd service + timer
Daily 08:07 CEST oneshot: runs claude -p with Gmail MCP to check email,
sends a morning Telegram ping via Bot API. Persistent timer survives reboots.
2026-05-04 12:51:33 +02:00
Danny
3604c08650 phantom-ship: scuttle gets SC_TILES_DIR + tmpfiles for OSM tile cache 2026-05-03 19:22:28 +02:00
Danny
f419fed7eb phantom-ship + vps-relay: KomTolk service + vhost (was translate-platform)
KomTolk is the rebranded translate-platform — same Copenhagen
translation gigs Mini App, new name. Service on port 8080, mirrors
shelfish/scuttle/banana setup. New tmpfiles dir + zt+ firewall
opening + caddy vhost.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 18:56:52 +02:00
Danny
08495161ae phantom-ship + vps-relay: add bananasimulator service + vhost
bananasimulator.service mirrors shelfish/scuttle (fastapi + uvicorn
+ httpx + python-telegram-bot). Port 8083. ENV BS_RIPE_MIN_PER_STAGE=2
in prod (30 min total banana lifetime); preview uses 0.5 for fast
testing.

vps-relay gets a fifth vhost (bananasimulator.dannydannydanny.me)
reverse-proxying to phantom-ship over ZeroTier. The shipyard manifest
has been pointing at this URL as a placeholder since day one — now
it's actually live.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 07:58:12 +02:00
Danny
6d9ccf5d4e phantom-ship + vps-relay: add scuttle service + vhost
scuttle.service mirrors shelfish — fastapi/uvicorn/httpx/python-telegram-bot
plus websockets, runs uvicorn --host :: --port 8082, DB at
~/.local/share/scuttle/scuttle.db (tmpfiles rule + zt+ firewall port
added alongside shelfish's).

vps-relay gets a fourth virtualHost (scuttle.dannydannydanny.me)
reverse-proxying to phantom-ship over ZeroTier. WebSocket upgrade is
transparent under Caddy's reverse_proxy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 07:26:17 +02:00
Hara
4d2e40455d hara-gmail-mcp: add mark_read and archive tools (v0.2.0)
Adds two write-capable IMAP tools:
- gmail_mark_read: sets \Seen flag on a message
- gmail_archive: copies to [Gmail]/All Mail and removes from INBOX

The IMAP connection already used SELECT (read-write mode); this just
exposes the mutation surface through MCP.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 07:14:42 +02:00
Danny
8056e510c5 phantom-ship: bind shelfish to '::' so it listens on both IPv4 and IPv6
ZT mesh addresses are IPv6; uvicorn on 0.0.0.0 only listens on IPv4
so vps-relay's caddy got 'connection refused' over the mesh.
2026-05-03 06:41:04 +02:00
Danny
f599a76aba phantom-ship: open shelfish (:8081) on ZT iface, bind 0.0.0.0
shelfish was only listening on 127.0.0.1 — vps-relay's Caddy
couldn't reach it over the ZT mesh. Bind 0.0.0.0 and allow 8081
inbound on \`zt+\` interfaces (not the global firewall — same
pattern sunken-ship uses for bbbot).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 06:39:57 +02:00
Danny
0b20c375b5 vps-relay: add shelfish.dannydannydanny.me vhost → phantom-ship ZT 2026-05-03 06:30:07 +02:00
Danny
2aec4d4d5e shelfish: front via vps-relay (don't expose phantom-ship public IP)
Original commit added Caddy directly on phantom-ship and opened
ports 80/443 — that would have exposed the home connection's
public IP via DNS. Reverting that and using the existing relay
pattern instead: vps-relay (Hetzner) terminates public TLS and
reverse-proxies over ZeroTier to phantom-ship's ZT IPv6 on 8081.

phantom-ship now just runs shelfish.service bound to 127.0.0.1:8081;
it accepts connections only from the ZT mesh interface (since
caddy/firewall changes are gone, the only listeners are the
existing trusted-interface ones plus this loopback).

vps-relay gets a third virtualHost alongside navidrome and bbbot.

DNS: shelfish.dannydannydanny.me → 89.167.39.251 (vps-relay public IP),
NOT phantom-ship's home IP.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 06:29:48 +02:00
Danny
d787b0ea48 phantom-ship: merge shelfish data dir into existing tmpfiles rules
Fixes nixos-rebuild error: systemd.tmpfiles.rules was set twice.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 06:27:21 +02:00
Danny
a7dd6284d8 phantom-ship: add Caddy + shelfish FastAPI service
Caddy fronts 80/443 with auto-Let's-Encrypt; reverse-proxies
shelfish.dannydannydanny.me to the local shelfish service on
127.0.0.1:8081. ACME issues the cert once the subdomain A-records
to this host's static IP.

Shelfish service mirrors shipyard's pattern: nix-built python env,
SHIPYARD_BOT_TOKEN_FILE pointed at the existing secret, DB stored
outside the rsynced code dir at ~/.local/share/shelfish/ so deploys
don't clobber state.

Code itself is rsync'd from ~/python-projects/27_shelfish/ to
/home/danny/shelfish/ (same convention as shipyard).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 06:25:54 +02:00
DannyDannyDanny
af9f735abc feat(phantom-ship): hara-gmail-mcp server (path 1, IMAP+SMTP) 📬
Adds an MCP server exposing read tools (list_inbox, search, read_email)
across three personal Gmail accounts using existing app passwords in
/etc/openclaw/. Wired into claude-channels via --mcp-config. Slated for
replacement by an OAuth2 Gmail+Calendar server in path 2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 14:15:10 +02:00
DannyDannyDanny
771cc58076 feat: vps fail2ban + shared server-debug-tools module 🛡️
VPS public SSH: enable fail2ban with bantime-increment so brute-force
probers get evicted with exponential backoff (1h → 4h → 16h → 2.7d →
10.7d, capped at 30d). Default jail covers sshd; maxretry=5 in 10m.

server-debug-tools: htop, tcpdump, dnsutils, jq, curl. Imported by
sunken-ship + phantom-ship via flake.nixosModules.server-debug-tools.
These are the practical bits we'd otherwise pick up by enabling
clan.core.enableRecommendedDefaults — but the full clan defaults flip
systemd-networkd/resolved on, which broke dnsmasq + navidrome's resolv
.conf bind-mount on the homelab servers, so we cherry-pick instead.
2026-04-25 13:51:19 +02:00
DannyDannyDanny
b8bc17f385 feat(servers): declare SSH authorizedKeys + root mac admin trust 🔑
Move the imperative SSH-key-related scars accumulated during the
clan/VPS rollout into nix config so future installs and rebuilds
reproduce the same state:

- danny@sunken-ship + danny@phantom-ship: trust the mac admin key
  (id_ed25519_<host> on Daniel-Macbook-Air) and the host's own
  self-loopback key (used by clan ssh-ng:// nix-copy-closure back
  to the same host during `clan machines update`).
- root@sunken-ship + root@phantom-ship: trust the mac admin key so
  `clan machines update` can run its SOPS-key upload step that
  SSHes to root@<host> to write /var/lib/sops-nix/key.txt.

Existing key files (~/.ssh/id_ed25519 on each host) stay where they
are; the keypair was generated once during initial bootstrap and the
public side is now declared above. Reinstalls would regenerate and
need the pubkey re-pinned here.
2026-04-25 13:30:40 +02:00
DannyDannyDanny
644420481e fix(sunken-ship): bbbot 8080 only allowed on ZT interface 🔐 2026-04-25 13:26:37 +02:00
DannyDannyDanny
3b5288a48c feat(sunken-ship): bbbot bind dual-stack so VPS Caddy reaches it via ZT IPv6 🪢 2026-04-25 13:17:27 +02:00
DannyDannyDanny
bce34985eb feat(sunken-ship): open firewall :8080 for bbbot via vps-relay 🔓 2026-04-25 13:15:59 +02:00
DannyDannyDanny
ba277b3f49 fix(vps-relay): grub config force-override to resolve dup in mirroredBoots 🐞 2026-04-24 17:43:00 +02:00
DannyDannyDanny
244988d52d fix(vps-relay): switch to GRUB/BIOS — Hetzner Cloud is not UEFI 🧷 2026-04-24 16:05:27 +02:00
DannyDannyDanny
f4738584c3 fix(vps-relay): add virtio modules to initrd so it boots on Hetzner 🛰️ 2026-04-24 14:51:41 +02:00
DannyDannyDanny
914a825587 feat(sunken-ship): trust danny for nix remote builds 🏗️ 2026-04-24 13:47:38 +02:00
DannyDannyDanny
47fc658523 feat(clan): add vps-relay + strip bbbot cloudflared 🚢
Stage 4.5: declare a Hetzner-hosted reverse-proxy VPS as a clan machine.

- nixos/hosts/vps-relay.nix: Debian→NixOS cx23 in hel1. Caddy at public
  80/443 reverse-proxies navidrome.dannydannydanny.me and
  bbbot.dannydannydanny.me over ZT to sunken-ship.
- nixos/disko-cloud.nix: simple GPT + ext4 root, no LUKS — cloud provider
  has physical disk anyway and there's no operator at boot.
- flake-modules/clan.nix: register vps-relay as an inventory machine,
  zerotier peer, internet networking target at its clan-generated ZT
  IPv6, and add vps-relay.clan to clanHostsModule /etc/hosts.
- sunken-ship fitness-bot: drop pkgs.cloudflared from PATH + set
  WEBAPP_URL=https://bbbot.dannydannydanny.me. Paired with the bbbot
  upstream patch (start.py honors env WEBAPP_URL and skips cloudflared
  when set) — once the 15-min fitness-bot-pull timer pulls that change,
  bbbot will stop churning trycloudflare.com URLs.

Vars (zerotier identity/ip + sops machine key) generated on sunken-ship
because clan's hermetic sandbox on macOS fails to run the zerotier
identity generator (same workaround as for data-mesher earlier).

VPS install flow: Hetzner-created Debian box, then `clan machines
install vps-relay --target-host root@<public-ipv4>` reinstalls to
NixOS; subsequent updates go over ZT.
2026-04-24 13:43:21 +02:00
DannyDannyDanny
b0c8664f5c docs: update stale dotfiles/nixos flake paths 📝
Stage 4f cleanup. The flake moved from ~/dotfiles/nixos/ to ~/dotfiles/
in 88c5139; docs and install scripts hadn't been refreshed. Point all
rebuild / flake references at the new root:

- AGENTS.md, README.md, server-quickstart.md, docs/server-installer-usb.md,
  docs/sunken-ship-wifi.md, nixos/readme.md — rebuild command paths.
- scripts/nixos-server-install.sh — auto-detect now looks for flake.nix
  at repo root (was nixos/flake.nix).
- scripts/post-install-provision.sh — first-rebuild hint path.

`nixos/hosts/<host>-hardware.nix` and friends stay where they are —
host-specific NixOS modules still live under nixos/; only the flake
entry-points + sops/ + vars/ + lib/ + modules/ + flake-modules/ moved.

nixos/readme.md rewritten to reflect the split (flake at root, per-host
modules under nixos/).
2026-04-20 20:28:05 +02:00
DannyDannyDanny
754cb0d274 chore(flake): bump clan-community fork (dm-send-deploy narHash skip) 🔖 2026-04-20 20:06:08 +02:00
DannyDannyDanny
0cd4947282 feat(sunken-ship): retire Cloudflare Tunnel for navidrome ☁️💥
Stage 4d of the clan migration. Navidrome is now reachable only over
the ZeroTier mesh (port 4533 on sunken-ship's ZT IPv6 address, or via
the sunken-ship-zt SSH alias). Dropped:

- systemd.services.cloudflare-tunnel
- clan.core.vars.generators.cloudflare-tunnel
- cloudflared from environment.systemPackages
- vars/per-machine/sunken-ship/cloudflare-tunnel/

Manual follow-ups still needed on sunken-ship:
- rm /home/danny/.secrets/cloudflare-tunnel-token  (old unmanaged token)
- delete the tunnel itself in the Cloudflare Zero Trust dashboard
- unlink the DNS record music.dannydannydanny.me if it was separate
2026-04-20 10:36:15 +02:00
DannyDannyDanny
b66dd1d30c fix(ssh): phantom-ship-zt needs the dedicated identity key 🔑 2026-04-20 10:28:34 +02:00
DannyDannyDanny
84da9ed8f5 feat(ssh): add zerotier host aliases on mac 🕸️
Home-manager now writes a drop-in at ~/.ssh/config.d/zerotier with
sunken-ship-zt and phantom-ship-zt aliases pointing at the ZT IPv6
addresses. Useful when off the LAN — the aliases route over the
ZeroTier mesh. Requires a one-time \`Include ~/.ssh/config.d/*\` at
the top of ~/.ssh/config.
2026-04-19 21:07:02 +02:00
DannyDannyDanny
7d3fd2d8cf feat(sunken-ship): migrate cloudflare-tunnel-token to clan vars 🔐
Declare a clan.core.vars.generators.cloudflare-tunnel generator that
prompts for the tunnel token on first run and stores it SOPS-encrypted
under vars/per-machine/sunken-ship/cloudflare-tunnel/tunnel-token.
systemd.services.cloudflare-tunnel ExecStart now reads the decrypted
secret at runtime from \${config.clan.core.vars...path} (lives at
/run/secrets/vars/...) instead of the unmanaged
/home/danny/.secrets/cloudflare-tunnel-token file.

Stage 4c of the clan migration. The tunnel itself is slated for
retirement in 4d — ZeroTier-only access after that. Cloudflare token
was rotated during this migration; old value no longer valid.
2026-04-19 21:07:02 +02:00
DannyDannyDanny
88c51399d0 refactor(nix): move flake to repo root 🚚
clan-cli silently ignores the `?dir=` URL parameter when resolving a
flake source, so with the flake at nixos/flake.nix `clan machines
update` fails with "flake.nix does not exist". Move the flake tree up
so the repo root contains flake.nix, flake.lock, flake-modules/, lib/,
modules/, sops/, and vars/. Host-specific NixOS modules stay in
nixos/{hosts,home,fish.nix,neovim.nix,…}; flake-module paths updated
accordingly.

- dotfiles-rebuild flakeRef is now "${dotfilesDir}#<host>" (was
  "${dotfilesDir}/nixos#<host>").
- CLAUDE.md build commands + clan section updated. nixupdate fish alias
  updated. sunken-ship hostsfile comment updated.
- Existing /etc/dotfiles checkouts on the servers will pick up the new
  layout on the next `dotfiles-rebuild` timer tick; the rebuild service
  was pre-updated via rsync so its flakeRef matches before the pull.

Also includes 4b follow-through: zerotier identities are now live on
both servers (sunken-ship=d553a2de33 controller, phantom-ship=6c048abbdc
peer) and IPv6 ping across the ZT mesh works.
2026-04-19 15:19:59 +02:00
DannyDannyDanny
9921a7f9f1 feat(nix): zerotier overlay via clan inventory + mac ZT client 🕸️
Stage 4b of the clan migration. Declares a clan.inventory.instances.zerotier
instance with sunken-ship as controller and phantom-ship as peer (controller
is also listed as a peer so it joins its own network). Generates the network
ID, controller identity, and per-peer identities via `clan vars generate`;
all secrets are SOPS-encrypted to the user's age key and the per-machine
age keys.

- nixos/sops/ — clan-managed SOPS state (user + per-machine age keys).
- nixos/vars/ — shared + per-machine zerotier vars; *-identity-secret
  files are SOPS-encrypted, *.value files are plain public data.
- clan.core.networking.{targetHost,buildHost} = "danny@<host>" on both
  servers so `clan machines update` knows where to push and build.
- mac gets `zerotier-one` installed as a homebrew cask; authorization
  on the controller happens manually by node-ID in a follow-up step.

Known rough edges (to chase in later stages):
- zerotier-inventory-autoaccept.service races zerotierone.service on
  first activation (connection refused against the local API). Retrying
  the unit succeeds; clan upstream bug.
- Deployment must go through `clan machines update`, not plain
  nixos-rebuild, or the per-host SOPS age key isn't uploaded and
  zerotier-one can't decrypt its identity.
2026-04-19 14:43:29 +02:00
DannyDannyDanny
29ff1c9be7 feat(nix): bootstrap clan-core for sunken-ship + phantom-ship 🏴‍☠️
Stage 4a of the dendritic + clan migration. Both servers now live under
clan.machines (via nixos/flake-modules/clan.nix) and clan-core generates
their nixosConfigurations for us; the previous per-host flake-modules
are removed.

Notes:
- clan.core.enableRecommendedDefaults = false on both machines so we
  keep the existing dhcpcd / non-networkd / non-resolved stack. Services
  like dnsmasq, navidrome, and the existing wireless setup break with
  the clan defaults on.
- dotfiles-rebuild timer is untouched (safety net). Replacing it with
  clan machines update / dm-pull-deploy comes in 4e.
- mac stays outside the clan as admin only.

Verified: `clan machines list --flake path:…/nixos` returns both hosts;
both servers rebuild cleanly and all services (navidrome, cloudflare-
tunnel, fitness-bot, dnsmasq, openclaw-gateway, sshd) stay active.
2026-04-19 13:54:44 +02:00
DannyDannyDanny
663be7872a fix(neovim): set withRuby and withPython3 explicitly to false 🔇 2026-04-19 13:48:25 +02:00
DannyDannyDanny
c3742db32e feat(phantom-ship): add shipyard systemd service 🚢
Telegram bot hub that lists mini-apps and collects feedback via ForceReply.
Code deployed via rsync to /home/danny/shipyard/; token at
~danny/.secrets/telegram-bot-token-shipyard.
2026-04-19 13:20:27 +02:00
Hara
14e60ca839 phantom-ship: add openai-whisper + ffmpeg for voice transcription 2026-04-18 23:05:24 +02:00
DannyDannyDanny
9566986ade fix: move permission bypass to settings.json to avoid warning dialog 🔧 2026-04-18 22:47:21 +02:00