Compare commits

..

63 Commits

Author SHA1 Message Date
aner e36767b625 azos-core bump: fix over-eager AZOS_AGENT_SHELL_SESSION guard on SessionStart hook 2026-10-13 10:55:53 +03:00
aner 2585a0e9d3 Rename claude backend toggles to the new agent-memory/agent-skills shape
Mirrors the azos-core change: azos.claude.enable now sets
azos.agent-memory.backends.claude.enable and
azos.agent-skills.backends.claude.enable instead of the old
azos.claude-memory.enable/azos.claude-skills.enable. The new agent-shell
memory backend needs no wiring here -- it's bundled directly in
azos-core's editor/emacs module, alongside wherever agent-shell itself
gets installed.
2026-10-13 10:51:22 +03:00
aner ac6c15f931 Set real mail accounts and tie presence check to the yubikey toggle
Mirrors the azos-core change: features/mail/default.nix now just sets
accounts.email.accounts (the three real addresses, with the existing
default_account_params/default_gmail_params convenience merging kept
here since it's personal boilerplate, not mechanism) and
azos.mail.presenceCheckCommand, wired to azos-card-present only when
azos.encryption.yubikey.enable is true.
2026-10-13 10:03:48 +03:00
aner b880a194ba Set real values for genericized git-config/encryption/send-alert/printing
Mirrors the azos-core change: drops the now-fully-migrated
features/{git-config,encryption,printing}, rewrites features/homey-alert
down to just the azos-homey-ntfy-alert overlay package (the ntfy-specific
remote-notification command plugged into azos.send-alert.remoteCommand),
and sets every real personal value (name/email/signing key, GPG key id,
YubiKey/browserpass/gpg-ssh toggles and keygrip/pubkey, printing username)
directly in home-manager/home.nix and nixos/configuration.nix, same place
the other personal values (azos.name, azos.headphones.devices) already
live.
2026-10-13 09:50:44 +03:00
aner 8b633f598c Move hfsprogs into azos-core's desktop suite as a NixOS module
Mirrors the azos-core change -- nixos.desktop already imported in
nixos/configuration.nix, so no new import line needed, just drops the
old homeManager.hfsprogs import.
2026-10-13 09:29:02 +03:00
aner da5df102cd Move audio/binfmt/bluetooth/headphones/chess/kubernetes/virtualization into azos-core suites
Mirrors the azos-core change: removes the now-relocated standalone
features from azos/features, and updates both import lists
(home-manager/home.nix, nixos/configuration.nix) to pull the nixos.desktop
and nixos.dev suite modules instead of the old per-feature ones.
2026-10-13 09:19:31 +03:00
aner 5ec9f2c528 azos-core bump: restore exwm's azos-emacs-desktop dependency 2026-10-13 09:05:25 +03:00
aner 80420198e8 Rename azos-core station suite to desktop; move discord out to azos/features
Mirrors the azos-core change: station is renamed desktop (its apps are
generically useful on any machine, work included), discord moves to its
own standalone azos/features/discord (personal-only, so it lives in the
azos project rather than azos-core), and azos-emacs-station becomes
azos-emacs-desktop in lauretta's emacs config to match.
2026-10-13 08:54:39 +03:00
aner 53976751cd Rename azos-core features/ to suites/; fold claude-memory/claude-skills into base
Bumps the azos-core submodule and updates docs/imports to match: AGENTS.md
now documents the suite-grouping convention (no bare top-level modules),
and claude-memory/claude-skills no longer need their own entries in
home-manager/home.nix since they're folded into the base suite.
2026-10-13 08:42:49 +03:00
aner b3380c6ce4 Bugfix 2026-10-11 23:15:45 +03:00
aner 97fdb926ac Auto-notify on long Bash commands; homey-alert local fallback; nextcloud mount fix
- homey-alert: add a global PreToolUse hook that transparently times every
  Bash command Claude runs and fires a notification once a command crosses
  the configured threshold (default 5 min), without needing the skill to
  be invoked manually. Also makes homey-alert always fire a local
  notify-send alongside the ntfy push, since the ntfy server isn't always
  reachable.
- nextcloud: fix sleep crash-loop under the restricted systemd PATH
  (bin/sleep -> coreutils store path).
- azos-core bump (adds ncdu to the base suite).
2026-10-11 23:14:15 +03:00
aner 04427ddcda Nextcloud sync, also zapzap 2026-10-11 09:22:42 +03:00
aner 0ea6d168fd azos-core bump 2026-10-11 00:23:30 +03:00
aner b6f3eee1b1 pcap mode and auto load hook azos-core bump 2026-10-10 23:53:14 +03:00
aner 1d661943cf Add YubiKey U2F login/sudo auth; disable unused features by default
pam_u2f is set up as a sufficient factor ahead of password for sudo and
login (which greetd/tuigreet substacks), so touching the key logs in
without typing a password while leaving password as fallback.
Fingerprint was investigated too but lauretta's reader is an unsupported
match-on-chip sensor, documented in the feature instead of wired up.

Also flip kubectl, qutebrowser-config, and snx-rs to disabled by default
since they're unused.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-09 14:08:33 +03:00
aner d9fbf95ead Mail facelift 2026-10-09 00:01:24 +03:00
aner 0a3a1746cb New mail notifications 2026-10-08 13:21:32 +03:00
aner f079a39cbc Make elfeed-protocol Nextcloud password fetch retriable
A failed pass/gpg fetch (e.g. YubiKey not plugged in yet) used to pass
process output straight to string-trim, which signals instead of
returning nil on empty output, aborting the sentinel before
elfeed-feeds or elfeed-protocol-enable ran. That left elfeed-feeds nil
for the rest of the session with no visible error beyond a *Messages*
line, and every later elfeed-update silently had nothing to fetch.

Wrap the fetch in azos/elfeed-protocol-init-feeds so a failed attempt
can be retried interactively instead of requiring a full reload of the
elfeed-protocol feature.
2026-10-08 13:14:14 +03:00
aner edd18bafdd Remove unused lieer, add silent periodic mbsync timer; bump azos-core
lieer was declared (programs/services.lieer.enable) but had zero real
footprint — mu4e actually fetches via mbsync (mu4e-get-mail-command is
literally "mbsync -a") and sends via msmtp; lieer never had an auth/sync
state file anywhere. Drop it to stop the config suggesting a sync path
that isn't actually in use.

Add a systemd user timer that runs mbsync every 5 minutes. mbsync's
PassCmd shells out to `pass`, which needs the GPG smartcard; on a blind
timer a missing card would otherwise surface as a pinentry "please
insert card" prompt every run. The wrapper script gates the sync behind
`gpg --card-status`, which only queries the reader without invoking
pinentry either way, so a missing card is now a silent no-op instead of
a nag.

Bump azos-core for EDNC popup notifications.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-08 13:14:08 +03:00
aner c1cb2490ed Bump azos-core: pre-approve org-roam search_nodes/create_node MCP tools
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-06 10:29:17 +03:00
aner 2f4f4257a3 Fix GPG smartcard pinentry routing to Emacs; bump azos-core
The gpg-agent systemd Environment=INSIDE_EMACS=1 hack never worked:
gpg-agent calls gnupg_unsetenv("INSIDE_EMACS") on itself at startup by
design, expecting the variable per-connection from the client instead.
Move it to home.sessionVariables so git/gpg invocations themselves carry
it and forward it to gpg-agent via "OPTION putenv=...", which is what
actually routes a pinentry request to Emacs instead of failing on
curses with no tty.

Bump azos-core for the project-brain-aligned todo/workplate/work-history
skills and the global org-roam Read/Edit permission rules.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-06 10:26:29 +03:00
aner cdb8e15060 Whoops 2026-10-06 09:41:36 +03:00
aner 3b389a5f2a pinentry fixees, exwm gated 2026-10-06 09:40:41 +03:00
aner b20a67fdc6 Bump azos-core: resolve node paths via search_nodes, not content calls 2026-10-06 09:22:02 +03:00
aner 858f68f9c6 Lazily retry lichess token fetch; demand-load lichess package
gpg-agent may not have a cached passphrase yet when the top-level setq
runs at Emacs startup, so a cold agent makes 'pass' fail silently
(stderr redirected) and leaves lichess-token permanently empty for the
session. Retry the fetch right before each use instead of only once
at startup.
2026-10-06 00:30:30 +03:00
aner 8578e23114 Bump azos-core: org-roam-resync hook, no-Emacs-dependency 2026-10-06 00:30:00 +03:00
aner 98b2f461cd Leetcode and chess overhaul 2026-10-05 11:31:04 +03:00
aner f80ed5863e Yay fixes and stuff 2026-10-05 09:33:01 +03:00
aner 1d9784877b Better chess, cuda maintainers fix, elfeed update 2026-09-29 10:45:24 +03:00
aner e5455f35f9 Bugfix 2026-09-09 10:06:13 +03:00
aner fc41d9aef3 agent-shell-math-render update 2026-09-09 09:35:18 +03:00
aner d6916a3fa3 Maildir shortcuts, maildir fix 2026-09-07 07:04:05 +03:00
aner a9b5cd2847 Bump 2026-09-06 17:26:12 +03:00
aner 177963b64e Fixes! 2026-09-06 14:40:40 +03:00
aner e5cc25eb49 Fixy 2026-09-06 13:54:15 +03:00
aner 8fde1cd5fe FIx 2026-09-06 13:47:09 +03:00
aner 21be2b0c87 Version bump 2026-09-06 13:29:20 +03:00
aner e27b7cb777 Fixy fix 2026-09-06 13:24:45 +03:00
aner f4923cbcad Experimental features bump 2026-09-06 11:59:39 +03:00
aner 630054fb8d azos-core bump 2026-09-06 11:57:29 +03:00
aner 9909fb411b Pinentry update 2026-09-06 11:55:47 +03:00
aner 9c64e1513e Remote run skill, mu4e change 2026-09-06 11:49:54 +03:00
aner 943498ce52 Homey alert! 2026-09-03 11:37:12 +03:00
aner df97c76527 Added 8bitdo 2026-08-26 20:25:27 +03:00
aner 8be92183bb Headphone mechanism change 2026-08-20 10:18:57 +03:00
aner 4ea2421734 Beacon updated 2026-07-26 10:51:18 +03:00
aner fa2c62e2f4 azos-core bump 2026-07-26 01:20:47 +03:00
aner a6ff616c2d azos-core version bump 2026-07-26 00:53:03 +03:00
aner 6e0f938e65 New beacon config, redone passwords 2026-07-25 11:45:17 +03:00
aner 59c05832b1 New encryption key 2026-07-25 00:00:39 +03:00
aner b8eb351e6c Interim fix, no gpg key 2026-07-15 20:47:04 +03:00
aner 78afc9e5bf azos-core bump 2026-06-18 22:26:02 +03:00
aner ebdee10fba Bump azos-core, configuration limit. 2026-06-18 21:05:46 +03:00
aner 890f39079b Updated skills and lock and lichess 2026-06-17 07:36:21 +03:00
aner e0a5891cd8 Bump azos-core 2026-06-08 22:01:51 +03:00
aner 7f27339312 Bump azos-core: org-roam-mcp direct SQLite writes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 22:55:40 +03:00
aner bd64633454 Bump azos-core: org-roam-mcp fork with db-sync fix
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 22:47:49 +03:00
aner 7c187d1c3d Updated azos-core and org roam stuff. 2026-06-07 08:01:40 +03:00
aner 1adc0439ea Updated roam backup 2026-06-07 01:27:09 +03:00
aner 2254fd419d Claude as preffered agent, azos-core bump. 2026-06-07 01:18:12 +03:00
aner cf976ae14a Claude memory, second brain, skills 2026-06-07 00:48:20 +03:00
aner c928f5f748 Update lock, more azos-core 2026-06-03 23:49:41 +03:00
aner 8d0f541fbe WTTR 2026-06-02 10:49:52 +03:00
44 changed files with 932 additions and 368 deletions
+148 -62
View File
@@ -22,7 +22,7 @@ nix build .#formatter.x86_64-linux
### Deploying ### Deploying
```bash ```bash
# Rebuild the azos environment for lauretta (this machine) — use this when asked to "rebuild" # Rebuild the azos environment for lauretta (this machine) — use this when asked to "rebuild"
sudo nixos-rebuild switch --flake '.?submodules=1#lauretta' azos-lauretta-update
nix flake update --flake '.?submodules=1' # Update all inputs nix flake update --flake '.?submodules=1' # Update all inputs
nix flake lock --flake '.?submodules=1' --update-input X # Update specific input nix flake lock --flake '.?submodules=1' --update-input X # Update specific input
``` ```
@@ -70,76 +70,119 @@ emacsclient -c -e '(switch-to-buffer (get-buffer-create "test"))'
emacsclient -e '(message "hello")' emacsclient -e '(message "hello")'
``` ```
## Code Style Guidelines ## Repository Structure
### File Organization ```
- **Home-manager modules**: `modules/home-manager/<name>.nix` azos/
- **NixOS modules**: `modules/nixos/<name>.nix` ├── flake.nix # Main flake
- **Imports**: All modules in `modules/home-manager/default.nix` and `modules/nixos/default.nix` (alphabetical order) ├── home-manager/home.nix # Home-manager entry point; manually imports all modules
- **Home config**: `home-manager/home.nix` - main home-manager user config ├── _machines/ # Per-machine NixOS configs (pass suiteModules as specialArgs)
- **Custom packages**: `pkgs/` - custom package definitions ├── nixos/ # NixOS system configs (configuration.nix, configuration-vm.nix, etc.)
- **Overlays**: `overlays/` - package overlays (addpkgs, modifications, unstable-packages) ├── features/ # Machine-specific home-manager features (auto-discovered)
├── overlays/ # Package overlays
├── shells/ # Dev shells
└── azos-core/ # Shared feature library (git submodule)
├── flake.nix
├── suites/ # Suites, each grouping related sub-features (auto-discovered)
├── overlays/ # Core overlays
└── _lib/ # Module schema helpers
```
Features are auto-discovered by `import-tree` — no central imports file. Each feature's
`default.nix` registers itself via `config.flake.modules.homeManager.<name>`. Modules are
then explicitly imported in `home-manager/home.nix` via `suiteModules.homeManager.<name>`.
**Where to put a new feature:**
- Shared / reusable across machines → inside an existing or new suite directory,
`azos-core/suites/<suite>/<name>/default.nix` (registering
`config.flake.modules.homeManager.<suite>`) — never a bare file directly under
`azos-core/suites/`; every azos-core feature belongs to a suite.
- Machine-specific → `azos/features/<name>/default.nix`
## Code Style Guidelines
### Nix Module Template ### Nix Module Template
```nix All features follow this flake-parts registration pattern:
{
lib,
config,
pkgs,
...
}: let
isEnabled =
config.azos.<module-name>.enable;
in {
options.azos.<module-name>.enable = lib.mkOption {
default = true;
example = true;
type = lib.types.bool;
};
config = lib.mkIf isEnabled { ```nix
home.packages = with pkgs; [ pkg1 pkg2 ]; {...}: {
config.flake.modules.homeManager.<name> = {
lib,
config,
pkgs,
...
}: {
options.azos.<name>.enable = lib.mkOption {
default = false;
example = true;
type = lib.types.bool;
};
config = lib.mkIf config.azos.<name>.enable {
home.packages = with pkgs; [pkg1 pkg2];
};
}; };
} }
``` ```
### Naming Conventions ### Naming Conventions
- Option paths: `config.azos.<module-name>.<option>` - Option paths: `azos.<module-name>.<option>`
- Enable option: `enable` (bool), default `true` - Module names: kebab-case (`git-config`, `desktop`)
- Module names: kebab-case (`libreoffice.nix`, `git-config.nix`) - Feature directories: kebab-case, one `default.nix` per feature
- Option names: may differ from filename (e.g., `git.nix` uses `azos.git-config`) - Variables: kebab-case
- Variables: kebab-case (`isEnabled`)
### Formatting ### Formatting
- Indentation: 2 spaces - Indentation: 2 spaces
- Let bindings: multi-line with `isEnabled` on its own line - Packages: `with pkgs; [pkg1 pkg2]` (no trailing semicolon inside list)
- Packages: Use `with pkgs; [ ... ]` syntax
### Imports ### Imports
- Always include `{...}` for module args - Always include `{...}` for the outer module args
- Standard args: `lib, config, pkgs, ...` - Inner module args: `lib, config, pkgs, ...`
- NixOS config args: `inputs, outputs, lib, config, pkgs, ...`
- Use `./relative/path.nix` for local imports
### Option Patterns ### Option Patterns
- Boolean enable: `lib.mkOption { default = true; example = true; type = lib.types.bool; }` - Boolean enable: `lib.mkOption { default = false; example = true; type = lib.types.bool; }`
- Conditional config: `lib.mkIf isEnabled { ... }` - Conditional config: `lib.mkIf config.azos.<name>.enable { ... }`
- User-overridable: `lib.mkDefault` - Auto-enable a dependency: `azos.<dep>.enable = lib.mkDefault true;`
- Force value: `lib.mkForce` (sparingly) - Force value: `lib.mkForce` (sparingly)
### Extensible Options
For options that multiple modules should be able to contribute to, use attrset options:
```nix
options.azos.<name>.things = lib.mkOption {
default = {};
type = lib.types.attrsOf lib.types.path; # or lines, str, etc.
};
```
Any module can then add entries without modifying the owning feature. Examples in use:
- `azos.claude.globalSkills` — attrset of skill name → markdown file path
- `azos.claude.globalMdSections` — attrset of key → markdown string (merged into `~/.claude/CLAUDE.md`)
### Home-Manager vs NixOS ### Home-Manager vs NixOS
- Home-manager: `home.packages`, `home.file`, `programs.<program>` - Home-manager: `home.packages`, `home.file`, `programs.<program>`
- NixOS: `config.services`, `environment.systemPackages` - NixOS: `config.services`, `environment.systemPackages`
### Deploying Files
- Static file: `home.file."dest".source = ./file;`
- Generated text: `home.file."dest".text = "...";`
- Runtime script (e.g. merging JSON at activation): `home.activation.<name> = lib.hm.dag.entryAfter ["writeBoundary"] ''...'';`
### Suites System ### Suites System
Modules are organized into suites (defined in `azos-core/`): Top-level suites group related features (defined in `azos-core/`):
- `azos.suites.base` - Base packages and config - `azos.suites.base` — base packages and config
- `azos.suites.editor` - Editor tools - `azos.suites.editor` — editor tools
- `azos.suites.dev` - Development tools - `azos.suites.dev` — development tools
- `azos.suites.station` - Desktop applications - `azos.suites.desktop` — desktop session plumbing (flameshot, dunst, keyboard layout) plus generally-useful apps (browser, libreoffice, zoom, spotify, gimp, whatsapp). Shared, lives in azos-core — wanted on any GUI machine, work included.
- `azos.suites.exwm` - EXWM window manager - `azos.suites.exwm` — EXWM window manager, depends on `desktop`
- Enable in `home-manager/home.nix` with `azos.suites.<name>.enable = true;`
Machine-specific, personal-only apps (steam, discord) are **not** part of any azos-core
suite — they live as standalone features directly in `azos/features/`, imported only on
machines that want them (e.g. `azos/features/discord`, `azos/features/steam`), since any
such machine already uses the `azos` project rather than a different downstream repo.
The machine suite (`azos.suites.lauretta`) enables the relevant suites for this machine.
### Specializations ### Specializations
NixOS supports specializations for alternative configurations: NixOS supports specializations for alternative configurations:
@@ -158,33 +201,76 @@ specialisation = {
## Adding New Modules ## Adding New Modules
1. Create file in `modules/home-manager/` or `modules/nixos/` 1. Create `features/<name>/default.nix` (machine-specific) or, for shared features,
2. Add import to `modules/<type>/default.nix` (alphabetical) `azos-core/suites/<suite>/<name>/default.nix` inside an existing or new suite
3. Use module template above (registering `config.flake.modules.homeManager.<suite>`, not a standalone module name)
2. Use the module template above
3. Machine-specific: add `suiteModules.homeManager.<name>` to the imports list in
`home-manager/home.nix`. Shared: no change needed if the suite is already imported.
4. Run `nix fmt` 4. Run `nix fmt`
> **Submodule gotcha**: New files in `azos-core/` must be `git add`-ed inside the submodule
> before `nix build` will see them — Nix flakes only evaluate git-tracked files.
> ```bash
> cd azos-core && git add suites/<suite>/<name>/
> ```
## Agent Memory/Skills Integration
Memory (org-roam) and skills (slash commands/CLAUDE.md) are backend-pluggable, not
Claude-specific, even though Claude is currently the only skills backend and one of two
memory backends:
| Feature | Option | What it does |
|---------|--------|--------------|
| `azos-core/suites/base/agent-memory` | `azos.agent-memory.backends.claude.enable` | Registers org-roam-mcp as a global MCP server in `~/.claude.json`; hooks resync org-roam's index on edit and inject project context at session start |
| `azos-core/suites/base/agent-memory` | `azos.agent-memory.backends.agent-shell.enable` | Registers org-roam-mcp via `agent-shell-mcp-servers` and resyncs on `file-write` events — applies regardless of which ACP backend (Claude, Gemini CLI, Codex, ...) a given agent-shell session runs. Also marks Claude sessions agent-shell launches (`AZOS_AGENT_SHELL_SESSION=1`) so the claude backend's own hooks no-op for those sessions instead of double-acting |
| `azos-core/suites/base/agent-skills` | `azos.agent-skills.backends.claude.enable` | Deploys skills to `~/.claude/commands/` and content to `~/.claude/CLAUDE.md` |
| `azos/features/claude` | `azos.claude.enable` | Installs claude-code, auto-enables the claude backend for both of the above |
| `azos-core/suites/editor/emacs` | (bundled, not a separate option) | Installs agent-shell, auto-enables `azos.agent-memory.backends.agent-shell.enable` |
Both agent-memory and agent-skills register `config.flake.modules.homeManager.base`
(they live inside the `base` suite, since that's where agent-shell is introduced) — not
standalone module names, so no separate `suiteModules.homeManager.*` import is needed for
them in `home-manager/home.nix`.
### Adding Claude skills or standing instructions
From any module — no need to touch azos-core:
```nix
azos.claude.globalSkills.my-skill = ./skills/my-skill.md;
azos.claude.globalMdSections.my-rule = ''
# My Rule
Always do X when Y.
'';
```
`globalSkills`/`globalMdSections` stay Claude-specific (`~/.claude/commands/`,
`~/.claude/CLAUDE.md`) deliberately — no other backend has a uniform equivalent yet. See
`azos-core/suites/base/agent-skills/README.md` for full documentation.
## Key Files ## Key Files
| File | Purpose | | File | Purpose |
|------|---------| |------|---------|
| `flake.nix` | Main flake, defines systems, overlays | | `flake.nix` | Main flake, defines systems and overlays |
| `modules/home-manager/default.nix` | Home-manager imports | | `home-manager/home.nix` | Home-manager entry point, imports all modules |
| `modules/nixos/default.nix` | NixOS imports | | `_machines/lauretta.nix` | Lauretta machine config, passes `suiteModules` as specialArgs |
| `home-manager/home.nix` | User home-manager config, enables suites | | `nixos/configuration.nix` | Lauretta NixOS system config |
| `nixos/configuration.nix` | Lauretta laptop config |
| `nixos/configuration-vm.nix` | Test VM config | | `nixos/configuration-vm.nix` | Test VM config |
| `overlays/` | Custom package overlays | | `overlays/` | Package overlays |
| `pkgs/` | Custom packages | | `azos-core/` | Shared feature library (git submodule) |
| `azos-core/` | Shared modules (submodule) | | `azos-core/suites/` | Suites, each grouping related shared sub-features (auto-discovered by import-tree) |
| `features/` | Machine-specific features (auto-discovered by import-tree) |
| `azos-core/suites/editor/emacs/config.org` | Literate Emacs config |
| `azos-core/suites/base/claude-skills/README.md` | Claude skills extensibility docs |
## Common Tasks ## Common Tasks
**Add system package**: Edit NixOS module, add to `environment.systemPackages = with pkgs; [ pkg ]` **Add system package**: Edit a NixOS feature, add to `environment.systemPackages = with pkgs; [ pkg ]`
**Add home-manager package**: Edit module, add to `home.packages = with pkgs; [ pkg ]` **Add home-manager package**: Edit a feature's config block, add to `home.packages = with pkgs; [ pkg ]`
**Add system service**: Edit NixOS module, add under `services.<service>` **Add system service**: Edit a NixOS feature, add under `services.<service>`
**Add custom package**: Create file in `pkgs/`, add to `pkgs/default.nix`, use via overlay **Add custom package**: Add to `azos-core/overlays/` via `config.flake.overlayPkgs.<name>`, then use as `pkgs.<name>`
**Access unstable packages**: Use `pkgs.unstable.<package>` (via unstable-packages overlay) **Access unstable packages**: Use `pkgs.unstable.<package>` (via unstable-packages overlay)
Symlink
+1
View File
@@ -0,0 +1 @@
AGENTS.md
+17
View File
@@ -0,0 +1,17 @@
{
config,
inputs,
...
}: {
config.flake.nixosConfigurations.beacon-wsl = inputs.nixpkgs.lib.nixosSystem {
specialArgs = {
inherit inputs;
outputs = config.flake;
suiteModules = config.flake.modules;
};
modules = [../nixos/configuration-beacon-wsl.nix];
};
config.flake.packages.x86_64-linux.beacon-wsl-tarball =
config.flake.nixosConfigurations.beacon-wsl.config.system.build.tarballBuilder;
}
-41
View File
@@ -1,41 +0,0 @@
{...}: {
config.flake.modules.homeManager.audio = {
lib,
config,
...
}: {
options.azos.home-audio.enable = lib.mkOption {
default = true;
type = lib.types.bool;
};
config = lib.mkIf config.azos.home-audio.enable {};
};
config.flake.modules.nixos.audio = {
lib,
config,
pkgs,
...
}: {
options.azos.hardware-audio.enable = lib.mkOption {
default = true;
type = lib.types.bool;
};
config = lib.mkIf config.azos.hardware-audio.enable {
services = {
pipewire = {
enable = true;
audio.enable = true;
pulse.enable = true;
alsa = {
enable = true;
support32Bit = true;
};
jack.enable = true;
};
};
environment.systemPackages = with pkgs; [pavucontrol];
musnix.enable = true;
};
};
}
-15
View File
@@ -1,15 +0,0 @@
{...}: {
config.flake.modules.nixos.binfmt = {
lib,
config,
...
}: {
options.azos.binfmt.enable = lib.mkOption {
default = true;
type = lib.types.bool;
};
config = lib.mkIf config.azos.binfmt.enable {
boot.binfmt.emulatedSystems = ["aarch64-linux"];
};
};
}
-16
View File
@@ -1,16 +0,0 @@
{...}: {
config.flake.modules.nixos.bluetooth = {
lib,
config,
...
}: {
options.azos.bluetooth.enable = lib.mkOption {
default = true;
type = lib.types.bool;
};
config = lib.mkIf config.azos.bluetooth.enable {
services.blueman.enable = true;
hardware.bluetooth.enable = true;
};
};
}
+2
View File
@@ -11,6 +11,8 @@
}; };
config = lib.mkIf config.azos.claude.enable { config = lib.mkIf config.azos.claude.enable {
home.packages = with pkgs; [claude-code claude-agent-acp]; home.packages = with pkgs; [claude-code claude-agent-acp];
azos.agent-memory.backends.claude.enable = lib.mkDefault true;
azos.agent-skills.backends.claude.enable = lib.mkDefault true;
}; };
}; };
} }
+16
View File
@@ -0,0 +1,16 @@
{...}: {
config.flake.modules.homeManager.discord = {
lib,
config,
pkgs,
...
}: {
options.azos.discord.enable = lib.mkOption {
default = true;
type = lib.types.bool;
};
config = lib.mkIf config.azos.discord.enable {
home.packages = with pkgs; [discord];
};
};
}
-37
View File
@@ -1,37 +0,0 @@
{...}: {
config.flake.modules.homeManager.encryption = {
lib,
config,
pkgs,
...
}: {
options.azos.encryption.enable = lib.mkOption {
default = true;
type = lib.types.bool;
};
config = lib.mkIf config.azos.encryption.enable {
programs.password-store = {
enable = true;
settings = {
PASSWORD_STORE_KEY = "076AA297579A0064";
};
};
home.packages = with pkgs; [
yubikey-personalization
pinentry-gtk2
];
programs.gpg = {
enable = true;
};
services.gpg-agent = {
enable = true;
enableSshSupport = true;
grabKeyboardAndMouse = false;
pinentry.package = pkgs.pinentry-gtk2;
};
home.file.".ssh/config".source = ./ssh-config;
home.file.".ssh/gpg-as-ssh.pub".source = ./gpg-as-ssh.pub;
home.file.".gnupg/sshcontrol".source = ./sshcontrol;
};
};
}
-1
View File
@@ -1 +0,0 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDBFZRqiTsOCAJPMqUyMeLd2MbyjdGoyqDVq5/Inhb6EOaM1NUGG4b6FPmYgFLyJIm5LC9BOo6M7npiaiOs/zMqp+hoGLNQUNwm5/G0uy1bjkEfKdUTdGnJ2+M9rkxrR1c+KXrjkiqECqTbnPE4mJbGyVxBW2MwMeP5w8c0DB5KO528PetvHMPPQuEdXyZzDI4kKtVpMlJoPIrIGlNFX0G/wrgXcM4zU1snOTuYGqZnWW++4kBsgIlRKpf/bLJyUMTp30eLVr0fQ6OMBtj1tzUUBaaowU6VGYQQDU/rIh/NpkA2cEVPXZegM4OohkAqrJBFPIAg90WD9Z/SyQlz0Jn8PpAloP0Cuq2vVRr+QLEwxqGiFq91YQ2VtwksMHwJGVrXRCNegpxTZQijWMEd+o0FD2cEd7Ftw6v2L6g12GJ3QGX/q0d/u0GongLLa9fPXl4VoAu7AL+cUcbX/SS7RCG8kYAR3DwOazVbK0NWEdwvWdoSU4lZ3j2at1xqMGjHjyLiTeUqZBjm+Sl5MJWIYNg+8hnONljvggg4SzDFDAkgVLZtOCaZibsMA1ucGR7VRCM09uoaEI4/ZS5pCBtYcp8X67Bv67Og8s2NFf5sUfYBPPKpdBSs+dEPycNVff6JlmzfNiyzLawacGKIDWYSgkOl43N/5ehtpsL3HMZ+5SVNIw== (none)
-1
View File
@@ -1 +0,0 @@
IdentityAgent ${XDG_RUNTIME_DIR}/gnupg/S.gpg-agent.ssh
-1
View File
@@ -1 +0,0 @@
61D809B46CEE2A0AF799C4C2FADB0F61A19EEABD
-32
View File
@@ -1,32 +0,0 @@
{...}: {
config.flake.modules.homeManager.git-config = {
lib,
config,
pkgs,
...
}: {
options.azos.git-config.enable = lib.mkOption {
default = true;
type = lib.types.bool;
};
config = lib.mkIf config.azos.git-config.enable {
home.packages = with pkgs; [pass-git-helper unzip];
programs.git = {
enable = true;
signing = {
key = "6D17E295C70E2674";
signByDefault = true;
};
settings = {
credential.helper = "!pass-git-helper $@";
user = {
name = "Aner Zakobar";
email = "aner@zakobar.com";
};
};
};
home.file.".config/pass-git-helper/git-pass-mapping.ini".source =
./pass-git-mapping.ini;
};
};
}
-2
View File
@@ -1,2 +0,0 @@
[*git.zakobar.com*]
target=zakobar.com/users/aner
+52
View File
@@ -0,0 +1,52 @@
{...}: {
config.flake.modules.nixos.hardware-auth = {
lib,
config,
pkgs,
...
}: {
options.azos.hardware-auth.enable = lib.mkOption {
default = false;
example = true;
type = lib.types.bool;
description = ''
Enables YubiKey (U2F/FIDO2) as a "sufficient" PAM factor ahead of
the password, for both sudo and login (which greetd/tuigreet
substacks) -- touch the key to auth, or just type your password as
normal if it's not plugged in.
After enabling and rebuilding, enroll each key on the new machine
(per-user, not machine-wide state, so this must be redone per
machine):
mkdir -p ~/.config/Yubico
pamu2fcfg > ~/.config/Yubico/u2f_keys
To add a second/backup key without overwriting the first:
pamu2fcfg -n >> ~/.config/Yubico/u2f_keys
Test with `sudo true` (touching the key) before trusting it on the
greeter -- a login lockout is harder to recover from than a failed
sudo in an already-open session.
'';
};
config = lib.mkIf config.azos.hardware-auth.enable {
# Default NixOS PAM rule ordering already tries u2f before pam_unix
# (password), both "sufficient" -- so YubiKey touch wins first,
# password always remains as fallback.
#
# Fingerprint (fprintd) is deliberately not wired up here: lauretta's
# reader is a Synaptics Metallica MIS (06cb:009a), a match-on-chip
# sensor unsupported by upstream libfprint. The only known fix is an
# unofficial python-validity + open-fprintd stack, not packaged in
# nixpkgs and fragile enough (suspend/resume, PAM lockout risk) to not
# be worth it for now.
security.pam.u2f = {
enable = true;
settings.cue = true;
};
};
};
}
-20
View File
@@ -1,20 +0,0 @@
{...}: {
config.flake.modules.homeManager.headphones = {
lib,
config,
pkgs,
...
}: {
options.azos.headphones-whmx4000.enable = lib.mkOption {
default = true;
type = lib.types.bool;
};
config = lib.mkIf config.azos.headphones-whmx4000.enable {
home.packages = [
(pkgs.writeShellScriptBin
"azos-connect-headphones-whmx4000"
"echo \"connect AC:80:0A:AF:E1:C2\" | bluetoothctl")
];
};
};
}
-16
View File
@@ -1,16 +0,0 @@
{...}: {
config.flake.modules.homeManager.hfsprogs = {
lib,
config,
pkgs,
...
}: {
options.azos.hfsprogs.enable = lib.mkOption {
default = true;
type = lib.types.bool;
};
config = lib.mkIf config.azos.hfsprogs.enable {
home.packages = with pkgs; [hfsprogs];
};
};
}
+28
View File
@@ -0,0 +1,28 @@
{...}: {
config.flake.overlayPkgs.azos-homey-ntfy-alert = pkgs:
pkgs.writeShellApplication {
name = "azos-homey-ntfy-alert";
runtimeInputs = with pkgs; [curl pass];
text = ''
TOKEN="$(pass zakobar-homecenter/ntfy-token)"
CMD=(
curl -sf
-H "Authorization: Bearer $TOKEN"
-H "Priority: ''${PRIORITY:-default}"
)
[[ -n "''${TITLE:-}" ]] && CMD+=(-H "Title: $TITLE")
[[ -n "''${TAGS:-}" ]] && CMD+=(-H "Tags: $TAGS")
CMD+=(-d "''${MESSAGE:-}" https://ntfy.zakobar.com/alerts)
if [[ -n "''${AZOS_SEND_ALERT_PRINT_REMOTE:-}" ]]; then
# Shell-quote each element so the output is safe to embed in SSH commands --
# the token is already resolved above, so the remote host only needs curl.
printf '%q ' "''${CMD[@]}"
printf '\n'
else
"''${CMD[@]}"
fi
'';
};
}
-16
View File
@@ -1,16 +0,0 @@
{...}: {
config.flake.modules.homeManager.kubernetes = {
lib,
config,
pkgs,
...
}: {
options.azos.kubectl.enable = lib.mkOption {
default = true;
type = lib.types.bool;
};
config = lib.mkIf config.azos.kubectl.enable {
home.packages = with pkgs; [kubectl kubernetes-helm velero];
};
};
}
+3 -1
View File
@@ -12,9 +12,11 @@ orgTrivialBuild {
pkgs.azos-emacs-dev pkgs.azos-emacs-dev
pkgs.azos-emacs-editor pkgs.azos-emacs-editor
pkgs.azos-emacs-exwm pkgs.azos-emacs-exwm
pkgs.azos-emacs-station pkgs.azos-emacs-desktop
agent-shell agent-shell
elfeed-protocol
org-caldav org-caldav
pinentry
]; ];
} }
+239 -7
View File
@@ -9,11 +9,17 @@
(require 'azos-emacs-dev) (require 'azos-emacs-dev)
(require 'azos-emacs-editor) (require 'azos-emacs-editor)
(require 'azos-emacs-exwm) (require 'azos-emacs-exwm)
(require 'azos-emacs-station) (require 'azos-emacs-desktop)
#+end_src #+end_src
* Lauretta specific * Lauretta specific
** Weather
#+begin_src emacs-lisp
(setq wttrin-default-cities '("Meitar, Israel"))
#+end_src
** LLM ** LLM
#+begin_src emacs-lisp #+begin_src emacs-lisp
@@ -28,19 +34,46 @@
:models '(openai/gpt-oss-120b))) :models '(openai/gpt-oss-120b)))
#+end_src #+end_src
** GPG Pinentry
gpg-agent is configured with =pinentry.package = pkgs.pinentry-emacs=, which
needs a running Emacs-side pinentry service to hand it prompts over a
loopback socket. Without =pinentry-start=, the pinentry-emacs binary can't
reach Emacs and falls back to the curses pinentry (visible as a TUI prompt
when committing from vterm) or hangs entirely (as seen from Magit).
#+begin_src emacs-lisp
(require 'pinentry)
(pinentry-start)
#+end_src
** Agent Shell ** Agent Shell
#+begin_src emacs-lisp #+begin_src emacs-lisp
(setq agent-shell-opencode-default-model-id "opencode/big-pickle") (setq agent-shell-preferred-agent-config 'claude-code)
;; (setq agent-shell-preferred-agent-config (agent-shell-opencode-make-agent-config))
#+end_src #+end_src
** Headphones ** Headphones
#+begin_src emacs-lisp #+begin_src emacs-lisp
(defun azos/connect-headphones () (defun azos/connect-headphones (&optional arg)
(interactive) "Connect to headphones via bluetoothctl.
(start-process-shell-command "connect-headphones" nil "azos-connect-headphones-whmx4000")) Without prefix ARG, connects to the first device in the list.
With prefix ARG, prompts to choose from all configured devices."
(interactive "P")
(if (not arg)
(start-process-shell-command "connect-headphones" nil "azos-connect-headphones")
(let* ((raw (shell-command-to-string "azos-connect-headphones --list"))
(lines (split-string (string-trim raw) "\n" t))
(choices (mapcar (lambda (line)
(let ((space (string-match " " line)))
(cons (substring line (1+ space))
(substring line 0 space))))
lines))
(name (completing-read "Connect headphones: " (mapcar #'car choices) nil t))
(mac (cdr (assoc name choices))))
(start-process-shell-command "connect-headphones" nil
(concat "azos-connect-headphones --mac " mac)))))
(define-key azos/global-minor-mode/open-keymap (define-key azos/global-minor-mode/open-keymap
(kbd "h") 'azos/connect-headphones) (kbd "h") 'azos/connect-headphones)
@@ -147,7 +180,7 @@
(interactive) (interactive)
(let* ((password (string-trim (let* ((password (string-trim
(shell-command-to-string (shell-command-to-string
(format "pass zakobar.com/users/%s" azos/lauretta/nextcloud-user)))) "pass zakobar.com | head -1")))
(url-http-real-basic-auth-storage (url-http-real-basic-auth-storage
(list (list "nextcloud.zakobar.com:443" (list (list "nextcloud.zakobar.com:443"
(cons azos/lauretta/nextcloud-user password))))) (cons azos/lauretta/nextcloud-user password)))))
@@ -157,6 +190,149 @@
(kbd "C") 'azos/caldav-sync) (kbd "C") 'azos/caldav-sync)
#+end_src #+end_src
** Elfeed Nextcloud News Sync
[[https://github.com/fasheng/elfeed-protocol][elfeed-protocol]] adds an =owncloud+= protocol that speaks the
ownCloud News API, which the Nextcloud News app also implements, so
it syncs elfeed's feed list and read/unread state with the Nextcloud
News app instead of just reading a local feed list one-way.
Reuses the same =zakobar.com= pass entry as the CalDAV sync above,
since it's the same Nextcloud account.
As of elfeed-protocol 1.0.0 (paired with elfeed >= 4.0.0), the
credentials go directly on =elfeed-feeds= — the older
=elfeed-protocol-feeds= variable is dead: setting it only logs a
deprecation warning, and =elfeed-feeds= ends up with the bare URL
and no =:password=, so requests silently authenticate with an empty
password and nothing ever lands in the db.
Fetching the password with =shell-command-to-string= used to
deadlock Emacs whenever the GPG PIN cache had expired: that call
blocks Emacs's single thread on the =pass|gpg= subprocess, but
=pinentry-emacs= (see the GPG Pinentry section above) needs Emacs's
command loop running to answer its loopback prompt — so Emacs waits
on gpg-agent while gpg-agent waits on Emacs. Fetching the password
with =make-process= instead keeps the command loop alive, so
=pinentry-emacs= can prompt normally; =elfeed-feeds= and
=elfeed-protocol-enable= are only set once the process sentinel
fires. Same stderr-redirect reasoning as before, to keep a stray
gpg/pass warning off the captured password.
The fetch is wrapped in a named, interactive function rather than
inlined in =:config= so a failed attempt (e.g. =pass= produced no
output because the YubiKey wasn't plugged in yet) can be retried
with =M-x azos/elfeed-protocol-init-feeds= — re-running =:config=
itself would require reloading the =elfeed-protocol= feature
entirely. An earlier version passed =(process-get proc 'output)=
straight to =string-trim=, which signals (not just returns nil) when
no output was ever read, aborting the sentinel before =elfeed-feeds=
or =elfeed-protocol-enable= ran — so a failed first attempt left
=elfeed-feeds= permanently =nil= for the rest of the session with no
visible error beyond a =*Messages*= line, and every subsequent
=elfeed-update= silently had nothing to fetch.
#+begin_src emacs-lisp
(defun azos/elfeed-protocol-init-feeds ()
"Fetch the Nextcloud password and (re)enable elfeed-protocol sync.
Unlike the one-shot `use-package' :config form this is called from,
safe to call again (e.g. via \\[azos/elfeed-protocol-init-feeds]) if
a previous attempt failed, such as the YubiKey not being plugged in
yet — it re-spawns the `pass' process and re-prompts for the PIN."
(interactive)
(make-process
:name "elfeed-protocol-pass"
:command '("sh" "-c" "pass zakobar.com 2>/dev/null | head -1")
:noquery t
:filter (lambda (proc chunk)
(process-put proc 'output (concat (or (process-get proc 'output) "") chunk)))
:sentinel (lambda (proc _event)
(let ((password (string-trim (or (process-get proc 'output) ""))))
(if (string-empty-p password)
(message "elfeed-protocol: `pass zakobar.com' produced no output; retry with M-x azos/elfeed-protocol-init-feeds")
(setq elfeed-feeds
`(("owncloud+https://aner@nextcloud.zakobar.com"
:password ,password)))
(elfeed-protocol-enable)
(elfeed-update))))))
(use-package elfeed-protocol
:after elfeed
:config
(setq elfeed-protocol-enabled-protocols '(owncloud))
(azos/elfeed-protocol-init-feeds))
#+end_src
** Elfeed Full Article Fetch
Many feeds only publish a short excerpt. elfeed >= 4.0 has built-in
commands for this — =f= (=elfeed-show-fetch-link=) fetches the
linked page and appends it to the show buffer, =R=
(=elfeed-show-readable=) strips the fetched page down to
article text via eww's readability scorer — and both can run
automatically via =elfeed-show-update-hook=, gated on a feed's
=:fetch-link=/=:readable= metadata.
That gating keys off an exact match on the feed's URL/id in
=elfeed-feeds=, which breaks for ownCloud/Nextcloud subfeeds:
elfeed-protocol synthesizes a per-subfeed id of the form
=<host-url>::<subfeed-url>= that never appears in =elfeed-feeds=
(only the bare host URL does), so the metadata lookup always misses
and the stock hooks never fire. Replacing them with unconditional
versions makes full-text + readable-mode the default for every
entry instead.
#+begin_src emacs-lisp
(defun azos/elfeed-show-auto-readable ()
"Like `elfeed-show-auto-readable', but unconditional."
(unless (local-variable-p 'elfeed-transform-html-functions)
(let ((inhibit-message t))
(elfeed-show-readable))))
(defun azos/elfeed-show-auto-fetch-link ()
"Like `elfeed-show-auto-fetch-link', but unconditional."
(elfeed-show-fetch-link))
(setq elfeed-show-update-hook
(list #'azos/elfeed-show-auto-readable #'azos/elfeed-show-auto-fetch-link))
#+end_src
** Lichess
=lichess.org= in pass already holds the website login password, and
lichess.el's =auth-source-pass= lookup resolves by bare hostname, so
the API token can't live under that same entry without colliding.
Store it separately under =lichess.org/token= (=pass insert
lichess.org/token=) and set the =lichess-token= variable directly —
=lichess-token= (the function) checks this variable before falling
back to =auth-source=, so this takes precedence without disturbing
the existing =lichess.org= entry or its consumers (e.g. browserpass).
=shell-command-to-string= merges stderr into its return value, so any
gpg/pass warning on stderr (e.g. an unsafe-permissions notice) would
otherwise get concatenated onto the token and break auth silently.
Redirect stderr away so only the token itself is ever captured.
#+begin_src emacs-lisp
(setq lichess-token
(string-trim (shell-command-to-string "pass lichess.org/token 2>/dev/null | head -1")))
#+end_src
=gpg-agent= may not have a cached passphrase yet when the =setq= above
runs at Emacs startup, in which case =pass= fails silently (stderr is
redirected away) and =lichess-token= is left as =""=. Retry the fetch
lazily right before each actual use, so a cold agent at startup
doesn't permanently wedge the token for the rest of the session.
#+begin_src emacs-lisp
(with-eval-after-load 'lichess
(advice-add 'lichess-token :before
(lambda ()
(when (string-empty-p lichess-token)
(setq lichess-token
(string-trim (shell-command-to-string "pass lichess.org/token 2>/dev/null | head -1")))))))
#+end_src
** Beacon Remote Jobs ** Beacon Remote Jobs
#+begin_src emacs-lisp #+begin_src emacs-lisp
@@ -317,6 +493,62 @@ With prefix ARG, prompt for a pattern then select from matches."
(define-key azos/beacon/keymap (kbd "t") #'azos/beacon/tail-log) (define-key azos/beacon/keymap (kbd "t") #'azos/beacon/tail-log)
#+end_src #+end_src
** Roam Backup
=roam-backup= signs its commit with gpg, which can prompt for the YubiKey PIN
via pinentry. =async-shell-command= spawns the process with =TERM=dumb= and
no real controlling tty, so pinentry's curses fallback fails with
\"Inappropriate ioctl for device\" whenever the PIN cache has expired. Run it
in a =vterm= instead, which gives pinentry a real pty to prompt on.
#+begin_src emacs-lisp
(defun azos/roam/backup ()
"Commit and push ~/roam to the remote git repo."
(interactive)
(let ((vterm-buffer-name "*roam-backup*"))
(with-current-buffer (vterm-other-window)
(vterm-send-string "roam-backup")
(vterm-send-return))))
(define-key azos/roam-keymap (kbd "B") #'azos/roam/backup)
#+end_src
** Printing
#+begin_src emacs-lisp
(defun azos/print-buffer (&optional arg)
"Print the current buffer.
For image/PDF/doc buffers, sends the file path to lp directly.
For text buffers, uses lpr-buffer.
With C-u, interactively prompt for scaling, B&W, and orientation options."
(interactive "P")
(let* ((image-p (derived-mode-p 'image-mode 'pdf-view-mode 'doc-view-mode))
(scale (when arg (y-or-n-p "Fit to page? ")))
(bw (when arg (y-or-n-p "Black and white? ")))
(landscape (when (and arg image-p) (y-or-n-p "Landscape? ")))
(lp-opts (concat
(when scale " -o fit-to-page")
(when bw " -o print-color-mode=monochrome")
(when landscape " -o landscape"))))
(if image-p
(if buffer-file-name
(progn
(shell-command
(concat "lp" lp-opts " " (shell-quote-argument buffer-file-name)))
(message "Sent %s to printer%s%s%s."
(file-name-nondirectory buffer-file-name)
(if scale " [scaled]" "")
(if bw " [B&W]" "")
(if landscape " [landscape]" "")))
(error "Buffer has no associated file"))
(let ((lpr-switches
(append lpr-switches
(when bw '("-o print-color-mode=monochrome")))))
(lpr-buffer)))))
(define-key azos/global-minor-mode/open-keymap (kbd "P") #'azos/print-buffer)
#+end_src
* Provide * Provide
#+begin_src emacs-lisp #+begin_src emacs-lisp
+19
View File
@@ -0,0 +1,19 @@
{...}: {
config.flake.modules.homeManager.leetcode = {
lib,
config,
pkgs,
...
}: {
options.azos.leetcode.enable = lib.mkOption {
default = false;
example = true;
type = lib.types.bool;
};
config = lib.mkIf config.azos.leetcode.enable {
azos.emacs.pkgs = [pkgs.azos-emacs-leetcode];
azos.emacs.enabledSuites = ["azos-emacs-leetcode"];
};
};
}
+14
View File
@@ -0,0 +1,14 @@
{
orgTrivialBuild,
epkgs,
pkgs,
}:
orgTrivialBuild {
pname = "azos-emacs-leetcode";
version = "0.1.0";
src = ./config.org;
packageRequires = with epkgs; [
pkgs.azos-emacs-base
leetcode
];
}
+29
View File
@@ -0,0 +1,29 @@
#+title: Aner's Emacs Leetcode Configuration
#+property: header-args :results silent
* Base setup
** Require
#+begin_src emacs-lisp
(require 'azos-emacs-base)
#+end_src
* Leetcode
#+begin_src emacs-lisp
(use-package leetcode
:init
(defun azos/leetcode/open ()
"Open leetcode in its dedicated \"leetcode\" tab."
(interactive)
(azos/tab-bar/open-singleton-tab "leetcode" #'leetcode))
:bind
(:map azos/global-minor-mode/open-keymap
("L" . azos/leetcode/open)))
#+end_src
* Provide
#+begin_src emacs-lisp
(provide 'azos-emacs-leetcode)
#+end_src
+3
View File
@@ -0,0 +1,3 @@
{...}: {
config.flake.overlayPkgs.azos-emacs-leetcode = pkgs: pkgs.localEmacsPkg ./_pkg.nix;
}
+16 -20
View File
@@ -2,15 +2,18 @@
config.flake.modules.homeManager.mail = { config.flake.modules.homeManager.mail = {
lib, lib,
config, config,
pkgs,
... ...
}: let }: let
default_account_params = { default_account_params = {
realName = "Aner Zakobar"; realName = "Aner Zakobar";
notmuch.enable = true;
mbsync = { mbsync = {
enable = true; enable = true;
create = "maildir"; create = "maildir";
remove = "both";
expunge = "both";
}; };
msmtp.enable = true;
}; };
default_gmail_params = default_gmail_params =
default_account_params default_account_params
@@ -20,45 +23,38 @@
default_smtp = { default_smtp = {
tls = { tls = {
enable = true; enable = true;
useStartTls = true;
certificatesFile = "/etc/ssl/certs/ca-certificates.crt"; certificatesFile = "/etc/ssl/certs/ca-certificates.crt";
}; };
}; };
in { in {
options.azos.mail.enable = lib.mkOption { config = {
default = true; azos.mail.enable = true;
type = lib.types.bool;
}; # mbsync's PassCmd shells out to `pass`, which needs the GPG smartcard to
config = lib.mkIf config.azos.mail.enable { # decrypt -- only meaningful to gate on when the smartcard/YubiKey setup
programs = { # is actually in play.
notmuch = { azos.mail.presenceCheckCommand = lib.mkIf config.azos.encryption.yubikey.enable "${pkgs.azos-card-present}/bin/azos-card-present";
enable = true;
hooks = {preNew = "mbsync -a";};
};
mbsync.enable = true;
msmtp.enable = true;
lieer.enable = true;
};
services.lieer.enable = true;
accounts.email.accounts = { accounts.email.accounts = {
gmail = gmail =
default_gmail_params default_gmail_params
// { // {
address = "anerisgreat@gmail.com"; address = "anerisgreat@gmail.com";
userName = "anerisgreat"; userName = "anerisgreat";
passwordCommand = "pass gmail.com/mbsync-anerisgreat"; passwordCommand = "pass mbsync/anerisgreat@gmail.com | head -1";
}; };
bgu = bgu =
default_gmail_params default_gmail_params
// { // {
address = "anerz@post.bgu.ac.il"; address = "anerz@post.bgu.ac.il";
userName = "anerz@post.bgu.ac.il"; userName = "anerz@post.bgu.ac.il";
passwordCommand = "pass post.bgu.ac.il/mbsync-anerz"; passwordCommand = "pass mbsync/anerz@post.bgu.ac.il | head -1";
}; };
zakobar = zakobar =
default_account_params default_account_params
// { // {
address = "aner@zakobar.com"; address = "aner@zakobar.com";
msmtp.enable = true;
primary = true; primary = true;
userName = "aner@zakobar.com"; userName = "aner@zakobar.com";
imap = {host = "mail.privateemail.com";}; imap = {host = "mail.privateemail.com";};
@@ -68,7 +64,7 @@
port = 587; port = 587;
host = "mail.privateemail.com"; host = "mail.privateemail.com";
}; };
passwordCommand = "pass zakobar.com/mail/aner"; passwordCommand = "pass privateemail.com | head -1";
}; };
}; };
}; };
+64 -7
View File
@@ -4,17 +4,74 @@
config, config,
pkgs, pkgs,
... ...
}: { }: let
mountDir = "synced-docs";
remoteSubfolder = "synced-docs";
remoteName = "ncsynceddocs";
remoteNameEnv = lib.toUpper remoteName;
# rclone's webdav backend needs the account's Nextcloud *user ID*, not
# its login name, in the /dav/files/<uid>/ path -- the two differ on
# this server. The login name ("aner") still goes in the `user` field
# for Basic Auth. Both the uid and password come from `pass` at service
# start, same as mbsync in features/mail, so neither lands in the Nix
# store.
#
# Shares the azos-card-present silent presence check (overlays/default.nix)
# with the mail sync timer: loop quietly until the YubiKey is plugged in
# (no pinentry prompt either way), then exec rclone in the foreground.
# Restart=always means unplugging/replugging the key remounts naturally.
nextcloudMountSafe = pkgs.writeShellScript "nextcloud-mount-safe" ''
set -eu
mountpoint="$HOME/${mountDir}"
${pkgs.coreutils}/bin/mkdir -p "$mountpoint"
while ! ${pkgs.azos-card-present}/bin/azos-card-present; do
${pkgs.coreutils}/bin/sleep 10
done
password=$(${pkgs.pass}/bin/pass zakobar.com | ${pkgs.coreutils}/bin/head -1)
uid=$(${pkgs.pass}/bin/pass nextcloud-username/aner | ${pkgs.coreutils}/bin/head -1)
export RCLONE_CONFIG_${remoteNameEnv}_TYPE=webdav
export RCLONE_CONFIG_${remoteNameEnv}_URL="https://nextcloud.zakobar.com/remote.php/dav/files/$uid/"
export RCLONE_CONFIG_${remoteNameEnv}_VENDOR=nextcloud
export RCLONE_CONFIG_${remoteNameEnv}_USER=aner
export RCLONE_CONFIG_${remoteNameEnv}_PASS="$(${pkgs.rclone}/bin/rclone obscure "$password")"
exec ${pkgs.rclone}/bin/rclone mount ${remoteName}:${remoteSubfolder} "$mountpoint" \
--vfs-cache-mode writes
'';
in {
options.azos.nextcloud-client.enable = lib.mkOption { options.azos.nextcloud-client.enable = lib.mkOption {
default = true; default = true;
type = lib.types.bool; type = lib.types.bool;
}; };
config = lib.mkIf config.azos.nextcloud-client.enable { options.azos.nextcloud-mount.enable = lib.mkOption {
home.packages = with pkgs; [nextcloud-client]; default = true;
services.nextcloud-client = { type = lib.types.bool;
enable = true;
startInBackground = false;
};
}; };
config = lib.mkMerge [
(lib.mkIf config.azos.nextcloud-client.enable {
home.packages = with pkgs; [nextcloud-client];
services.nextcloud-client = {
enable = true;
startInBackground = false;
};
})
(lib.mkIf config.azos.nextcloud-mount.enable {
home.packages = with pkgs; [rclone];
# default.target, not graphical-session.target: the latter never
# activates under EXWM in this setup (nothing explicitly starts it),
# which is why nextcloud-client itself silently never autostarts.
systemd.user.services.nextcloud-mount = {
Unit.Description = "Mount Nextcloud ${remoteSubfolder} via rclone (waits silently for YubiKey)";
Service = {
Type = "simple";
Environment = "PATH=/run/wrappers/bin:${pkgs.fuse3}/bin:${pkgs.fuse}/bin";
ExecStart = "${nextcloudMountSafe}";
ExecStop = "/run/wrappers/bin/fusermount3 -u %h/${mountDir}";
Restart = "always";
RestartSec = "10s";
};
Install.WantedBy = ["default.target"];
};
})
];
}; };
} }
+3
View File
@@ -58,3 +58,6 @@ c.fonts.hints = "bold 13px 'LiberationMono'"
#Set highdpi #Set highdpi
c.qt.highdpi = True c.qt.highdpi = True
c.zoom.default = 70 c.zoom.default = 70
c.qt.args = ['--disable-gpu']
c.qt.environ = {'QT_XCB_GL_INTEGRATION': 'none', 'LIBGL_ALWAYS_SOFTWARE': '1'}
+1 -1
View File
@@ -5,7 +5,7 @@
... ...
}: { }: {
options.azos.qutebrowser-config.enable = lib.mkOption { options.azos.qutebrowser-config.enable = lib.mkOption {
default = true; default = false;
type = lib.types.bool; type = lib.types.bool;
}; };
config = lib.mkIf config.azos.qutebrowser-config.enable { config = lib.mkIf config.azos.qutebrowser-config.enable {
+30
View File
@@ -0,0 +1,30 @@
{...}: {
config.flake.modules.homeManager.roam-backup = {
lib,
config,
pkgs,
...
}: {
options.azos.roam-backup.enable = lib.mkOption {
default = false;
example = true;
type = lib.types.bool;
};
config = lib.mkIf config.azos.roam-backup.enable {
home.packages = [
(pkgs.writeShellScriptBin "roam-backup" ''
set -e
cd "$HOME/roam"
git add -A
if git diff --cached --quiet; then
echo "Nothing to commit."
else
git commit -m "backup: $(date '+%Y-%m-%d %H:%M')"
fi
git push --set-upstream origin HEAD
'')
];
};
};
}
+1 -1
View File
@@ -9,7 +9,7 @@
in { in {
options.azos.snx-rs = { options.azos.snx-rs = {
enable = lib.mkOption { enable = lib.mkOption {
default = true; default = false;
type = lib.types.bool; type = lib.types.bool;
}; };
server = lib.mkOption { server = lib.mkOption {
+8
View File
@@ -10,6 +10,14 @@
}; };
config = lib.mkIf config.azos.steam.enable { config = lib.mkIf config.azos.steam.enable {
programs.steam.enable = true; programs.steam.enable = true;
# HORI STICK A fight stick (0f0d:0040) is missing from Steam's bundled
# 60-steam-input.rules, so Steam can't open its hidraw node for Steam
# Input and falls back to a generic joystick mapping that drops BTN_C
# (Circle). Grant the same uaccess the other HORI devices get.
services.udev.extraRules = ''
KERNEL=="hidraw*", ATTRS{idVendor}=="0f0d", ATTRS{idProduct}=="0040", MODE="0660", TAG+="uaccess"
'';
}; };
}; };
} }
-30
View File
@@ -1,30 +0,0 @@
{...}: {
config.flake.modules.nixos.virtualization = {
lib,
config,
pkgs,
...
}: {
options.azos.virtualization.enable = lib.mkOption {
default = true;
type = lib.types.bool;
};
config = lib.mkIf config.azos.virtualization.enable {
virtualisation.libvirtd = {
enable = true;
qemu = {
swtpm.enable = true;
};
};
environment.systemPackages = with pkgs; [
qemu_kvm
libvirt
virt-manager
virt-viewer
];
services.spice-vdagentd.enable = true;
networking.firewall.allowedTCPPorts = [5900 5901];
networking.firewall.allowedUDPPorts = [5900 5901];
};
};
}
Generated
+76 -22
View File
@@ -56,6 +56,22 @@
"type": "github" "type": "github"
} }
}, },
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1767039857,
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-parts": { "flake-parts": {
"inputs": { "inputs": {
"nixpkgs-lib": "nixpkgs-lib" "nixpkgs-lib": "nixpkgs-lib"
@@ -79,11 +95,11 @@
"nixpkgs-lib": "nixpkgs-lib_2" "nixpkgs-lib": "nixpkgs-lib_2"
}, },
"locked": { "locked": {
"lastModified": 1778716662, "lastModified": 1788450739,
"narHash": "sha256-m1Yf0wZ8j1OHjTc2UwHwyQRSnNeSgLJOd7q5Y45hzi4=", "narHash": "sha256-glZLQlzIn1fXH6PazR2iUmTo7kzzyYSshrWhLS9TqCU=",
"owner": "hercules-ci", "owner": "hercules-ci",
"repo": "flake-parts", "repo": "flake-parts",
"rev": "f7c1a2d347e4c52d5fb8d10cb4d94b5884e546fb", "rev": "31729ca8cbdb4fa927b34e5f4353e6a83f39e993",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -139,11 +155,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1779969295, "lastModified": 1788651960,
"narHash": "sha256-HwIJ3tOcwSMiV75L7KqJXciXR9UfT+d7rwOZMX7cTnA=", "narHash": "sha256-v9wJd32eZ2bvhBzVOd7TIjLQd011P7nwOhjKtWlci5I=",
"owner": "nix-community", "owner": "nix-community",
"repo": "home-manager", "repo": "home-manager",
"rev": "61e2c9659324181e0f0ed911958c536333b1d4f6", "rev": "2c0350c759688177331b8f5242311fae8877bdb3",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -170,11 +186,11 @@
}, },
"import-tree_2": { "import-tree_2": {
"locked": { "locked": {
"lastModified": 1778781969, "lastModified": 1788467110,
"narHash": "sha256-Jjuz5CmSkur8KvLDoGa+vylEp+RkQtv4mt/qcMznpH0=", "narHash": "sha256-ljEMTXP/rH0tOvDzc9gzwww6KcHRPRnEHzd9lK48V7s=",
"owner": "vic", "owner": "vic",
"repo": "import-tree", "repo": "import-tree",
"rev": "d321337efd0f23a9eb14a42adb7b2c29313ab274", "rev": "eb1b52eaecc57f7c136d07ae8a93e724dfecac46",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -202,12 +218,15 @@
} }
}, },
"nixos-hardware": { "nixos-hardware": {
"inputs": {
"nixpkgs": "nixpkgs_4"
},
"locked": { "locked": {
"lastModified": 1779826373, "lastModified": 1788335262,
"narHash": "sha256-3sRzgLX86qV5NlhWUAufLmHwkyP03tmL3VdZIM13dEo=", "narHash": "sha256-3jBEq8avfzlrsY4UpW4d5TOmm7ocseZfnitEJhqauyc=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixos-hardware", "repo": "nixos-hardware",
"rev": "ef4efb84766a166c906bd55759574676bf91267c", "rev": "44d95795ee2d475b3d687325e26dcf4ca9104557",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -217,6 +236,27 @@
"type": "github" "type": "github"
} }
}, },
"nixos-wsl": {
"inputs": {
"flake-compat": "flake-compat",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1784642409,
"narHash": "sha256-hcbDqFuySAJawljt5r0sKBCJKYnbtGD0T/ZIozH1Dq0=",
"owner": "nix-community",
"repo": "nixos-wsl",
"rev": "eaeb18da90024448a60eb1ec7132eafa4003404e",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nixos-wsl",
"type": "github"
}
},
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1769421245, "lastModified": 1769421245,
@@ -248,11 +288,11 @@
}, },
"nixpkgs-lib_2": { "nixpkgs-lib_2": {
"locked": { "locked": {
"lastModified": 1777168982, "lastModified": 1788057806,
"narHash": "sha256-GOkGPcboWE9BmGCRMLX3worL4EMnsnG8MyKmXNeYuhQ=", "narHash": "sha256-DTQSMxzDWmT0zhguthvegnVkn7CFqGCv4IHCzk5ZUpM=",
"owner": "nix-community", "owner": "nix-community",
"repo": "nixpkgs.lib", "repo": "nixpkgs.lib",
"rev": "f5901329dade4a6ea039af1433fb087bd9c1fe14", "rev": "596e2e3940e09b2abbeb03f75fa1828c57fcd72c",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -263,11 +303,11 @@
}, },
"nixpkgs-unstable": { "nixpkgs-unstable": {
"locked": { "locked": {
"lastModified": 1779560665, "lastModified": 1788614874,
"narHash": "sha256-tpyBcxPpcQb8ukyNF7DoCwfSY3VPsxHoYwj00Cayv5o=", "narHash": "sha256-7QYjT2vHLuX9Z1pdxHXDKCbh1CR3D/2rywB9Tx0MPRg=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "64c08a7ca051951c8eae34e3e3cb1e202fe36786", "rev": "c043004d1c6985732bcc1cbc5a9c9aecbbb4e0f0",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -311,11 +351,24 @@
}, },
"nixpkgs_4": { "nixpkgs_4": {
"locked": { "locked": {
"lastModified": 1779877693, "lastModified": 1767892417,
"narHash": "sha256-NOF9NAREhxr50bbBfVcVOq+ArCMSoe8dP79Pk2uyARk=", "narHash": "sha256-8bW3q88CEg2u4hSP66Vf4lpbLonHz7hqDNBMcCY7E9U=",
"rev": "3497aa5c9457a9d88d71fa93a4a8368816fbeeba",
"type": "tarball",
"url": "https://releases.nixos.org/nixos/unstable/nixos-26.05pre924538.3497aa5c9457/nixexprs.tar.xz"
},
"original": {
"type": "tarball",
"url": "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz"
}
},
"nixpkgs_5": {
"locked": {
"lastModified": 1788549839,
"narHash": "sha256-kOrCcSIA6w9J1hX5DqHy2k9pDTJymExTsbV74U9UtCA=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "4100e830e085863741bc69b156ec4ccd53ab5be0", "rev": "17de0b976395537756f30a3e78f2f06e5cec89ed",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -333,7 +386,8 @@
"import-tree": "import-tree_2", "import-tree": "import-tree_2",
"musnix": "musnix", "musnix": "musnix",
"nixos-hardware": "nixos-hardware", "nixos-hardware": "nixos-hardware",
"nixpkgs": "nixpkgs_4", "nixos-wsl": "nixos-wsl",
"nixpkgs": "nixpkgs_5",
"nixpkgs-unstable": "nixpkgs-unstable" "nixpkgs-unstable": "nixpkgs-unstable"
} }
}, },
+6
View File
@@ -21,6 +21,11 @@
flake = true; flake = true;
}; };
nixos-wsl = {
url = "github:nix-community/nixos-wsl";
inputs.nixpkgs.follows = "nixpkgs";
};
flake-parts.url = "github:hercules-ci/flake-parts"; flake-parts.url = "github:hercules-ci/flake-parts";
import-tree.url = "github:vic/import-tree"; import-tree.url = "github:vic/import-tree";
}; };
@@ -34,6 +39,7 @@
./_machines/lauretta.nix ./_machines/lauretta.nix
./_machines/vm.nix ./_machines/vm.nix
./_machines/beacon.nix ./_machines/beacon.nix
./_machines/beacon-wsl.nix
]; ];
systems = [ systems = [
+43 -7
View File
@@ -11,17 +11,12 @@
suiteModules.homeManager.base suiteModules.homeManager.base
suiteModules.homeManager.dev suiteModules.homeManager.dev
suiteModules.homeManager.editor suiteModules.homeManager.editor
suiteModules.homeManager.station suiteModules.homeManager.desktop
suiteModules.homeManager.discord
suiteModules.homeManager.exwm suiteModules.homeManager.exwm
suiteModules.homeManager.lauretta suiteModules.homeManager.lauretta
suiteModules.homeManager.audio
suiteModules.homeManager.claude suiteModules.homeManager.claude
suiteModules.homeManager.encryption
suiteModules.homeManager.git-config
suiteModules.homeManager.hfsprogs
suiteModules.homeManager.headphones
suiteModules.homeManager.hyprland suiteModules.homeManager.hyprland
suiteModules.homeManager.kubernetes
suiteModules.homeManager.mail suiteModules.homeManager.mail
suiteModules.homeManager.mpris-proxy suiteModules.homeManager.mpris-proxy
suiteModules.homeManager.nextcloud suiteModules.homeManager.nextcloud
@@ -29,14 +24,55 @@
suiteModules.homeManager.qutebrowser suiteModules.homeManager.qutebrowser
suiteModules.homeManager.reaper suiteModules.homeManager.reaper
suiteModules.homeManager.snx-rs suiteModules.homeManager.snx-rs
suiteModules.homeManager.roam-backup
suiteModules.homeManager.ytdl suiteModules.homeManager.ytdl
suiteModules.homeManager.leetcode
]; ];
programs.home-manager.enable = true; programs.home-manager.enable = true;
azos.suites.lauretta.enable = true; azos.suites.lauretta.enable = true;
azos.chess.enable = true;
azos.leetcode.enable = true;
azos.name = "Aner Zakobar"; azos.name = "Aner Zakobar";
azos.headphones.enable = true;
azos.headphones.devices = [
{
mac = "AC:80:0A:AF:E1:C2";
name = "Aner's Headphones";
}
{
mac = "AC:80:0A:A1:5F:53";
name = "Chen's Headphones";
}
{
mac = "E4:17:D8:29:9B:16";
name = "8bitdo";
}
];
azos.roam-backup.enable = true;
azos.send-alert.enable = true;
azos.send-alert.remoteCommand = "${pkgs.azos-homey-ntfy-alert}/bin/azos-homey-ntfy-alert";
azos.git-config.userName = "Aner Zakobar";
azos.git-config.userEmail = "aner@zakobar.com";
azos.git-config.signing.enable = true;
azos.git-config.signing.key = "BB141234A3DD953D";
azos.git-config.passCredentialHelper.enable = true;
azos.git-config.passCredentialHelper.mapping = ''
[*git.zakobar.com*]
target=zakobar.com
'';
azos.encryption.passwordStore.gpgKeyId = "26B851F81F8F7C55";
azos.encryption.yubikey.enable = true;
azos.encryption.browserpass.enable = true;
azos.encryption.gpgSsh.enable = true;
azos.encryption.gpgSsh.keygrip = "37710BAB5F6DC9878A450CDA8A4661D932C04ACB";
azos.encryption.gpgSsh.publicKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDMdozJewuuqG4VuwGhI5Uw2xDIUrkQwyPGQ2q3tvnPq/VoV+zfdnou42I6XYEfOGd6xfLR0byOGCk1Ia1F/picBsxADEaJFBnTny5MWNA5MxwJIYUPW5+kFN1TmxdNGmj0WJ8qZeKkS3ffixdHlHTVu4Rzrlu8qDdw8TmgcvD7sHpNaBB+hwG9B/s5BAozfXvyXtW51lLLrEZdmUXJxAP51ubVgysZ985PA89o4G7LUE20IKAj3rgylLwq+Lz2PoGmVCptPTknLLzGlxTy2mU/tESJtS4iUvshSYiKak73BSen88xLWL/eZGFzOLW4TNem/qT0ykqK1s1BaGWCcQiDWN+Lpa3XqTbFN054MfhLdEMp+NjrdsCbZORzp9p2ZPDqi5jI1Hy7IN/8VzzB+T13MX6YhW7CBBqUZaivGhVQGsNjrFusPGhCaZrzNJ1l4qssLAlOh9qdaYzqDe+BIHsty55vw4Ph+Axou82babpLoiQzkCol2TWjPr7JSfHFkm6CmoTQ7mK8m7jRCodmxF+BEe4Usr+HrTKDc9fr5P4mdfL0O+ZPrlkPuG1zBTMal9MPxeCk4emzOZf7vBMNzb0aKHbOtSdVk/IcjatlDd2EIo34e5A6anLRMAdxb7901mnCAcjvCn6+ArNV8nr+NBk1+UvumZ+Q59LTrAkgRt3rBw== openpgp:0x13E0C25D";
home = { home = {
username = "aner"; username = "aner";
homeDirectory = "/home/aner"; homeDirectory = "/home/aner";
+78
View File
@@ -0,0 +1,78 @@
{
lib,
config,
pkgs,
inputs,
suiteModules,
...
}: {
imports = [
inputs.nixos-wsl.nixosModules.default
suiteModules.nixos.attic
];
wsl.enable = true;
wsl.defaultUser = "aner";
nixpkgs.hostPlatform = "x86_64-linux";
nixpkgs.config.allowUnfree = true;
nix.settings = {
experimental-features = ["nix-command" "flakes"];
auto-optimise-store = true;
substituters = [
"https://cache.nixos.org"
"https://cuda-maintainers.cachix.org"
];
trusted-public-keys = [
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
"cuda-maintainers.cachix.org-1:0dq3bujKpuEPMCX6U4WylrUDZ9JyUG0VpVZa7CNfq5E="
];
};
security.sudo.wheelNeedsPassword = false;
networking.hostName = "beacon";
networking.firewall.allowedTCPPorts = [ 22 ];
programs.nix-ld.enable = true;
time.timeZone = "Asia/Jerusalem";
# GPU is exposed through WSL2 paravirtualization; no Linux NVIDIA KM needed
hardware.graphics.enable = true;
services.openssh = {
enable = true;
settings = {
PermitRootLogin = "no";
PasswordAuthentication = false;
};
};
users.users.aner = {
isNormalUser = true;
extraGroups = ["wheel" "video"];
openssh.authorizedKeys.keys = [
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDMdozJewuuqG4VuwGhI5Uw2xDIUrkQwyPGQ2q3tvnPq/VoV+zfdnou42I6XYEfOGd6xfLR0byOGCk1Ia1F/picBsxADEaJFBnTny5MWNA5MxwJIYUPW5+kFN1TmxdNGmj0WJ8qZeKkS3ffixdHlHTVu4Rzrlu8qDdw8TmgcvD7sHpNaBB+hwG9B/s5BAozfXvyXtW51lLLrEZdmUXJxAP51ubVgysZ985PA89o4G7LUE20IKAj3rgylLwq+Lz2PoGmVCptPTknLLzGlxTy2mU/tESJtS4iUvshSYiKak73BSen88xLWL/eZGFzOLW4TNem/qT0ykqK1s1BaGWCcQiDWN+Lpa3XqTbFN054MfhLdEMp+NjrdsCbZORzp9p2ZPDqi5jI1Hy7IN/8VzzB+T13MX6YhW7CBBqUZaivGhVQGsNjrFusPGhCaZrzNJ1l4qssLAlOh9qdaYzqDe+BIHsty55vw4Ph+Axou82babpLoiQzkCol2TWjPr7JSfHFkm6CmoTQ7mK8m7jRCodmxF+BEe4Usr+HrTKDc9fr5P4mdfL0O+ZPrlkPuG1zBTMal9MPxeCk4emzOZf7vBMNzb0aKHbOtSdVk/IcjatlDd2EIo34e5A6anLRMAdxb7901mnCAcjvCn6+ArNV8nr+NBk1+UvumZ+Q59LTrAkgRt3rBw== cardno:29_109_265"
];
};
environment.systemPackages = with pkgs; [
git
rsync
tmux
vim
wget
rclone
pciutils
nvtopPackages.nvidia
cudaPackages.cudatoolkit
cudaPackages.cudnn
cudaPackages.nccl
python3
direnv
];
azos.attic.enable = true;
system.stateVersion = "25.11";
}
+1 -1
View File
@@ -28,7 +28,7 @@
nixpkgs.config.cudaSupport = true; nixpkgs.config.cudaSupport = true;
nix.settings = { nix.settings = {
experimental-features = "nix-command flakes"; experimental-features = ["nix-command" "flakes"];
auto-optimise-store = true; auto-optimise-store = true;
substituters = [ substituters = [
"https://cache.nixos.org" "https://cache.nixos.org"
+1 -1
View File
@@ -47,7 +47,7 @@
config.nix.registry; config.nix.registry;
nix.settings = { nix.settings = {
experimental-features = "nix-command flakes"; experimental-features = ["nix-command" "flakes"];
auto-optimise-store = true; auto-optimise-store = true;
}; };
+20 -6
View File
@@ -14,18 +14,18 @@
inputs.home-manager.nixosModules.home-manager inputs.home-manager.nixosModules.home-manager
suiteModules.nixos.base suiteModules.nixos.base
suiteModules.nixos.exwm suiteModules.nixos.exwm
suiteModules.nixos.audio suiteModules.nixos.desktop
suiteModules.nixos.bluetooth suiteModules.nixos.dev
suiteModules.nixos.steam suiteModules.nixos.steam
suiteModules.nixos.virtualization
suiteModules.nixos.binfmt
suiteModules.nixos.attic suiteModules.nixos.attic
suiteModules.nixos.hardware-auth
]; ];
boot.loader.grub = { boot.loader.grub = {
enable = true; enable = true;
efiSupport = true; efiSupport = true;
device = "nodev"; device = "nodev";
configurationLimit = 5;
}; };
boot.loader.efi.canTouchEfiVariables = true; boot.loader.efi.canTouchEfiVariables = true;
@@ -80,12 +80,26 @@
}; };
nix.settings = { nix.settings = {
experimental-features = "nix-command flakes"; experimental-features = ["nix-command" "flakes"];
auto-optimise-store = true; auto-optimise-store = true;
substituters = [
"https://cache.nixos.org"
];
trusted-public-keys = [
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
];
}; };
azos.suites.exwm.enable = true; azos.suites.exwm.enable = true;
azos.attic.enable = true; azos.attic.enable = true;
azos.printing.enable = true;
azos.printing.username = "aner";
azos.hardware-auth.enable = true;
# Needed for unprivileged FUSE mounts (e.g. rclone mount) -- without this,
# fusermount3 has no setuid wrapper and mounting fails with
# "Operation not permitted" even though /dev/fuse itself is world-writable.
programs.fuse.enable = true;
home-manager = { home-manager = {
extraSpecialArgs = {inherit inputs outputs suiteModules pkgs;}; extraSpecialArgs = {inherit inputs outputs suiteModules pkgs;};
@@ -108,7 +122,7 @@
services.greetd.settings = lib.mkForce { services.greetd.settings = lib.mkForce {
terminal.vt = 1; terminal.vt = 1;
default_session = { default_session = {
command = "${pkgs.tuigreet}/bin/tuigreet --time --user-menu --cmd '/home/aner/.login.sh'"; command = "${pkgs.tuigreet}/bin/tuigreet --time --user-menu --user-menu-min-uid 1000 --user-menu-max-uid 29999 --cmd '/home/aner/.login.sh'";
user = "greeter"; user = "greeter";
}; };
initial_session = { initial_session = {
+10
View File
@@ -11,4 +11,14 @@
config.allowUnfree = true; config.allowUnfree = true;
}; };
}; };
# Shared silent presence check for the GPG smartcard (the YubiKey's OpenPGP
# applet): `gpg --card-status` only queries the reader, never invoking
# pinentry, so it's safe to poll without ever producing a "please insert
# card" prompt. Used by both the mail sync timer and the Nextcloud mount
# service to gate on `pass` being decryptable.
config.flake.overlayPkgs.azos-card-present = pkgs:
pkgs.writeShellScriptBin "azos-card-present" ''
exec ${pkgs.gnupg}/bin/gpg --card-status >/dev/null 2>&1
'';
} }
-2
View File
@@ -1,5 +1,3 @@
{pkgs} @ args: { {pkgs} @ args: {
#TODO since I do not pass along packages, this cannot work
# debugTex = import ./debugTex args;
default = import ./defaultShell.nix args; default = import ./defaultShell.nix args;
} }
+2 -1
View File
@@ -2,9 +2,10 @@
pkgs.mkShell { pkgs.mkShell {
buildInputs = with pkgs; [ buildInputs = with pkgs; [
alejandra alejandra
nh
(pkgs.writeShellScriptBin (pkgs.writeShellScriptBin
"azos-lauretta-update" "azos-lauretta-update"
"sudo nixos-rebuild switch --flake '.?submodules=1#lauretta'") "nh os switch '.?submodules=1#lauretta'")
(pkgs.writeShellScriptBin (pkgs.writeShellScriptBin
"azos-update-azos-core" "azos-update-azos-core"
"nix flake update --flake '.?submodules=1' azos-core") "nix flake update --flake '.?submodules=1' azos-core")