Introduction
This repository is a Nix Flakes-based dotfiles and system configuration, managing NixOS systems and Home Manager user environments across multiple machines.
It uses flake-parts with autowire (from jig) for automatic module discovery and composition.
Repository Structure
flake.nix # Entry point, declares all inputs
→ flake/*.nix # Flake-level glue (configs, formatter, activation)
→ packs/{home,nixos}/ # Autowired packs (common, host, container, gui)
→ mixins/{home,nixos}/ # Opt-in configs (manually imported by configurations)
→ home/*.nix # Per-user base Home Manager configurations
→ nixos/{hosts,containers} # Per-host/container NixOS configurations
packs/— Autowired collections — import a pack, get everything in itmixins/— Opt-in configuration pieces (services, hardware, versions)home/— Base Home Manager configs (yjpark.nix,yj.nix)nixos/— Per-host and per-container NixOS configssecrets/— SOPS-encrypted secrets (age keys, per-host)private/— Host-specific private configs (gitignored, present on deployed machines)
Architecture
Autowiring Pattern
Pack roots use wireImportsRecursively to auto-discover all .nix files recursively:
{flake, ...}: flake.inputs.autowire.wireImportsRecursively ./.
Subdirectories with a custom default.nix are treated as opaque — their default.nix is imported instead of recursing further. Adding a new .nix file to a pack directory automatically includes it.
Layered Composition
Configuration is built up in layers:
flake.nix— Declares all inputs; outputs generated viaflake-partsflake/*.nix— Flake-level glue (configs, formatter, activation). Each.nixfile is aflake-partsmodule imported byflake.nixpacks/{home,nixos}/— Autowired packs (common, host, container, gui). Import a pack, get everything in itmixins/{home,nixos}/— Opt-in configuration pieces (services, hardware, versions), manually imported by host configshome/*.nix— Per-user base Home Manager configurationsnixos/{hosts,containers}/— Per-host and per-container NixOS configurations
Custom Options
packs/home/common/options.nix defines the me option set used throughout Home Manager modules:
me.usernameme.fullnameme.email
These are set in each user’s base config (e.g., home/yjpark.nix).
Key Commands
Tasks are defined in mise.toml. Use mise tasks to list all available tasks.
Daily Use
# Home Manager activation (applies user-level config)
mise run _activate-home
# Build NixOS config for current host (builds without switching by default)
mise run build-host
# Switch NixOS config (applies system-level config, requires sudo)
mise run _switch-host
Flake Maintenance
# Update all flake inputs
mise run flake-update
# Update specific inputs
mise run flake-update nixpkgs home-manager
# Show flake outputs
mise run show
# Format Nix files (uses nixpkgs-fmt)
nix fmt
Documentation
# Serve docs locally (hot-reload)
mise run docs-serve
# Build static docs site
mise run docs-build
Nix Directly
# Activate Home Manager (same as mise run _activate-home)
nix run
# Build a specific package
nix build .#docs
Home Manager
User Profiles
Two user profiles exist in this configuration:
| Username | Used On | Base Config | State Version |
|---|---|---|---|
yjpark | Physical hosts | home/yjpark.nix | 25.05 |
yj | Containers | home/yj.nix | 26.05 |
Host and Container Mixins
Host-specific configurations live in:
mixins/home/hosts/— One.nixfile per physical hostmixins/home/containers/— One.nixfile per container
Adding a .nix file to either directory automatically registers a new host or container — no manual imports needed.
Activation Logic
flake/activate-home.nix defines how mise run _activate-home resolves the correct Home Manager configuration:
- Matches current hostname against known hosts → activates
yjpark@<host> - Matches current hostname against known containers → activates
yj@<host> - Falls back to bare
<username>for unknown hosts
Configuration Generation
flake/home-configs.nix generates username@host entries for each host/container mixin, plus a bare username fallback (without host suffix). This populates homeConfigurations in the flake outputs.
Secrets
Secrets are managed with SOPS-nix using age encryption.
Setup
- Each host has its own age key
- Encrypted secret files live in
secrets/directories and any files matchingsecret.* - The
.sops.yamlfile at the repo root defines which age keys can decrypt which secrets
Usage
Encrypted files are automatically decrypted at activation time by sops-nix and made available to NixOS/Home Manager modules as paths under /run/secrets/.
Refer to the sops-nix documentation for creating and editing secrets.
Flake Inputs
All inputs are declared in flake.nix. This page documents the purpose of each.
Core / Framework
| Input | Purpose |
|---|---|
nixpkgs | nixos-unstable — the primary package set |
home-manager | User environment management |
flake-parts | Flake composition framework |
jig | github:edger-dev/jig — provides autowire lib for auto-discovering and composing .nix files |
Software
| Input | Purpose |
|---|---|
sops-nix | Declarative secret management with SOPS + age |
nixvim | Neovim configured via Nix |
nixos-vscode-server | VS Code remote server support on NixOS |
solaar | Logitech device manager |
llm-agents | LLM agent tools |
Desktop / UI
| Input | Purpose |
|---|---|
claude-desktop | Claude desktop application |
niri | Wayland compositor |
xremap-flake | Key remapper for Wayland/X11 |
antigravity | (UI tool) |
jjui | TUI for the jj (Jujutsu) VCS |
Active Tasks
In Progress
No tasks
Todo
Install latest beans via nix flake (flakes-6ne0)
Task · normal
Install Zeroclaw (flakes-kj17)
Task · normal
Container-first infrastructure (flakes-qbvb)
Epic · normal · (6/7 done)
- ✓ Migrate container IPs to new scheme (flakes-cjao)
- ✓ Drop nixos-unified, use raw flake-parts (flakes-dght)
- ○ Declarative incus fleet management (flakes-ihxf)
- ✓ Fix CA cert injection to be declarative (flakes-krtw)
- ✓ Containerize OneCLI (flakes-t9u2)
- ✓ Setup SearXNG search for agents (flakes-woco)
- ✓ Container-to-host network isolation (flakes-x821)
Done (4)
Unify incus container image build tasks (flakes-p8hf)
Task · normal
All Tasks
Epics
- Container-first infrastructure (flakes-qbvb) — Todo
- Migrate container IPs to new scheme (flakes-cjao) — Done
- Drop nixos-unified, use raw flake-parts (flakes-dght) — Done
- Declarative incus fleet management (flakes-ihxf) — Todo
- Fix CA cert injection to be declarative (flakes-krtw) — Done
- Containerize OneCLI (flakes-t9u2) — Done
- Setup SearXNG search for agents (flakes-woco) — Done
- Container-to-host network isolation (flakes-x821) — Done
Features
- Project-wise pane configuration in Zellij (flakes-1zlj) — Done ·
archived - Deploy OneCLI as credential proxy for yolo container (flakes-2aqm) — Done ·
archived - Host Caddy LAN proxy for Incus container services (flakes-68h7) — Done ·
archived - Incus container ingress auto-discovery (flakes-7ckd) — Done ·
archived - Ingress hub page: service dashboard with iframe embedding (flakes-bti9) — Done ·
archived - Extract ingress hub scripts for Ubuntu compatibility (flakes-d4np) — Done ·
archived - Change Zellij pane background color based on project path (flakes-dkc4) — Done ·
archived - Declarative incus fleet management (flakes-ihxf) — Todo
- Zellij WASM plugin for dynamic tab naming (flakes-je55) — Draft
- Niri config: declarative host-based mixin (flakes-p2qs) — Done ·
archived - Add mdBook documentation site (flakes-px5o) — Done ·
archived - Fish functions for jj workspace management (flakes-rhqy) — Done ·
archived - Zellij per-project auto-layouts on cd (flakes-u0yw) — Done ·
archived - Setup SearXNG search for agents (flakes-woco) — Done
- Add git worktree support to workspace commands (flakes-y87y) — Done ·
archived
Tasks
- Disable terminal bell sound (flakes-0u0f) — Done ·
archived - Create mise-run-or-just fish function (flakes-0ycg) — Done ·
archived - Enhance tv-mise-tasks to handle tasks with arguments (flakes-14he) — Done ·
archived - Make j abbreviation expand conditionally to mise run or just (flakes-1cc9) — Done ·
archived - Convert onecli-reseed to a manually-invoked script (flakes-2ey6) — Done
- Tidy up the shell title when running zellij (flakes-2fpy) — Done ·
archived - Remove stateVersion mixin pattern, use defaults instead (flakes-5pbu) — Done ·
archived - Restructure home config host/container registration (flakes-6n5b) — Done ·
archived - Install latest beans via nix flake (flakes-6ne0) — Todo
- Resolve username from host/container dir in activate-home.nix (flakes-7aac) — Done ·
archived - Setup markdown-oxide (flakes-7ih3) — Done ·
archived - Automate OneCLI CA push to containers on boot (flakes-aurl) — Done ·
archived - Set up Incus across machines (flakes-bxl7) — Done ·
archived - Auto-trigger tab completion after j abbr expands to mise run _ (flakes-c03b) — Done ·
archived - Migrate container IPs to new scheme (flakes-cjao) — Done
- Drop nixos-unified, use raw flake-parts (flakes-dght) — Done
- Unify terminal theme to Tokyo Night (flakes-hncv) — Done ·
archived - Replace autowire.nix with jig lib (flakes-iymi) — Done ·
archived - Set up firewalld as NixOS service and migrate existing firewall rules (flakes-jvmx) — Done ·
archived - Setup quartz to preview and publish oxide projects (flakes-k391) — Todo
- Check MCPVault, to see whether it’s a better option for the markdowns (flakes-k3pr) — Todo
- Install Zeroclaw (flakes-kj17) — Todo
- Fix CA cert injection to be declarative (flakes-krtw) — Done
- Update CLAUDE.md to reflect current state (flakes-nyvs) — Done ·
archived - Setup colima with incus (flakes-o04s) — Done ·
archived - Add edit-in-place script (flakes-oh4v) — Done ·
archived - Add GitHub token via OneCLI + container git config (flakes-oi2x) — Done ·
archived - Refactor ai.nix into ai/ directory (flakes-ojyn) — Done ·
archived - Configure jjui theme for readability with Pencil Dark terminal theme (flakes-p7hc) — Done ·
archived - Unify incus container image build tasks (flakes-p8hf) — Done
- Setup OpenCode and Claude for spacebot container (flakes-pr3i) — Done
- Integrate Home Manager as a NixOS module (flakes-rg27) — Done ·
archived - Migrate from just to mise for task running (flakes-rg2j) — Done ·
archived - Full jjui theme with terminal-independent hex colors (flakes-sk2r) — Done ·
archived - Containerize OneCLI (flakes-t9u2) — Done
- Inhibit idle/sleep during audio/video playback (flakes-va02) — Done ·
archived - Dynamic per-host Home Manager configs via flake module (flakes-vaiq) — Done ·
archived - Container-to-host network isolation (flakes-x821) — Done
- Add rtk-rewrite.sh hook to claude module with home-manager linking (flakes-y887) — Done ·
archived - Replace CopyQ with cliphist (Wayland-native clipboard manager) (flakes-yyox) — Done ·
archived - Add mdbook-beans tasks section to docs (flakes-zvh8) — Done ·
archived
Bugs
- Fix Ctrl+Shift+C in wezterm clobbering zellij clipboard (flakes-5oyz) — Done ·
archived - Auto-restart firewalld when zone config changes (flakes-ja9k) — Todo
- Fix mise.toml var args bug (flakes-m3r8) — Done ·
archived - Fix git push auth inside Incus container via OneCLI proxy (flakes-nz9y) — Done ·
archived - Pass currentSystem to NixOS-integrated home-manager extraSpecialArgs (flakes-sytx) — Done
Drafts
Epics
Container-first infrastructure (flakes-qbvb)
Migrate services to containers, isolate host, restructure Nix config.
IP Scheme
10.100.0.1 host (bridge)
10.100.0.2+ infra containers
.002 onecli
.003 searxng
10.100.0.100+ agent containers
.100 yolo
.101 spacebot
.102 hermes
10.100.0.200+ scratch
.200 ubuntu
Architecture
- Host becomes thin bridge: Caddy ingress, dnsmasq, SOPS secrets, onecli-seeder
- OneCLI moves to its own container
- SearXNG in its own container
- Container→host traffic blocked (except DHCP/DNS) via nftables
- Container↔container unrestricted on bridge
- Secret flow: Host SOPS → seeder calls OneCLI API at .002 → pushes proxy-auth/CA to agent containers
- CA cert injection made declarative via security.pki.certificateFiles
- Drop nixos-unified for raw flake-parts (separate host/container config namespaces)
Features
- Project-wise pane configuration in Zellij (flakes-1zlj) — Done ·
archived - Deploy OneCLI as credential proxy for yolo container (flakes-2aqm) — Done ·
archived - Host Caddy LAN proxy for Incus container services (flakes-68h7) — Done ·
archived - Incus container ingress auto-discovery (flakes-7ckd) — Done ·
archived - Ingress hub page: service dashboard with iframe embedding (flakes-bti9) — Done ·
archived - Extract ingress hub scripts for Ubuntu compatibility (flakes-d4np) — Done ·
archived - Change Zellij pane background color based on project path (flakes-dkc4) — Done ·
archived - Declarative incus fleet management (flakes-ihxf) — Todo
- Zellij WASM plugin for dynamic tab naming (flakes-je55) — Draft
- Niri config: declarative host-based mixin (flakes-p2qs) — Done ·
archived - Add mdBook documentation site (flakes-px5o) — Done ·
archived - Fish functions for jj workspace management (flakes-rhqy) — Done ·
archived - Zellij per-project auto-layouts on cd (flakes-u0yw) — Done ·
archived - Setup SearXNG search for agents (flakes-woco) — Done
- Add git worktree support to workspace commands (flakes-y87y) — Done ·
archived
Project-wise pane configuration in Zellij (flakes-1zlj)
Configure Zellij pane/tab naming to visually identify projects in multi-project sessions.
Design
State Management
- State file:
/tmp/zellij-tab-{ZELLIJ_SESSION_NAME}— one line per pane:{PANE_ID}={project_name} - Session root: Capture
$PWDat shell init asZELLIJ_SESSION_PROJECT— the “home” project for the session - Project name: Git repo root basename (
git rev-parse --show-toplevel | basename), fallback tobasename $PWD
Pane Name Behavior
| Condition | Pane name |
|---|---|
| PWD is within session’s starting project | {command} (current behavior) |
| PWD is in a different project | <{project}> {command} |
| Idle (no running command) | <{project}> or empty (current behavior) |
Updated in fish_preexec (command starts) and on PWD change.
Tab Name Behavior
On every PWD change in any pane:
- Write/update own entry in the state file
- Read all entries, collect unique project names
- If only one unique project:
rename-tab "{project}"(same as today) - If multiple:
rename-tab "{project1} | {project2} | ..."
Cleanup
fish_exitevent: Remove own pane entry from state file, rebuild tab name- Shell init: Prune entries whose pane IDs are no longer in the state file
Tasks
- Add helper to resolve project name (git root basename, fallback to basename PWD)
- Capture session project on shell init ($ZELLIJ_SESSION_PROJECT)
- Implement state file writes (per-pane project tracking)
- Update pane name logic: <project> command format when outside session project
- Update tab name logic: aggregate unique projects from state file
- Add cleanup on fish_exit
- Add stale entry pruning on shell init (simplified: natural overwrite on pane ID reuse)
Summary of Changes
Implemented in modules/home/programs/fish/init/zellij.fish:
zellij_project_name: resolves git repo root basename, fallback to basename PWDZELLIJ_SESSION_PROJECT: captured at shell init to detect foreign projects- State file (
/tmp/zellij-tab-{SESSION}): per-pane project tracking, scoped by session name - Pane names:
<project> commandwhen in foreign project, justcommandotherwise - Tab names: aggregated unique projects in pane order, joined with
| - Cleanup on
fish_exitremoves pane entry and rebuilds tab name
Deploy OneCLI as credential proxy for yolo container (flakes-2aqm)
Set up OneCLI (MITM proxy) on edger host to inject API keys for agents running in the yolo Incus LXC container. Agents get placeholder keys; OneCLI injects real credentials at the network layer.
Tasks
- Create mixins/nixos/services/onecli.nix (OCI containers + seeder service)
- Create mixins/nixos/services/secrets/onecli-secrets.txt (sops-encrypted)
- Modify configurations/nixos/edger/imports.nix (enable onecli)
- Modify mixins/home/ai/tools/claude-mcp-add-context7.bash (use placeholder key)
- Modify mixins/home/host/linux/scripts/incus/incus-launch-yolo.bash (push CA cert)
context7 Rule Fix
- Update seeder to use per-secret config (hostPattern + headerName + valuePrefix)
- Add CONTEXT7_API_KEY entry targeting context7.com with Authorization: Bearer injection
Proxy Auth & CA Trust Fixes
- Use agent token (aoc_ prefix) instead of user API key (oc_ prefix) for proxy auth
- Set /etc/onecli-proxy-auth to mode 644 so non-root users can read it
- Append OneCLI CA to existing CA bundles (handles Nix store symlinks)
- Add fish shell proxy config via Home Manager shellInit
- Guard onecli-seed-secrets in mise tasks for hosts without OneCLI
- Add verbose diagnostics to onecli-check-proxy script
Summary of Changes
Fixed three root causes preventing OneCLI proxy injection in containers:
- Wrong API key type — gateway expects agent tokens (aoc_), not user keys (oc_)
- CA trust — appended OneCLI CA directly to active CA bundles instead of using security.pki (which fails at Nix build time)
- Fish shell — profile.d scripts aren’t sourced by fish; moved proxy var setup to Home Manager’s programs.fish.shellInit
Host Caddy LAN proxy for Incus container services (flakes-68h7)
Add host-level Caddy reverse proxy to expose Incus container services to ZeroTier LAN via *.hostname.yjpark.org with Let’s Encrypt certs (Cloudflare DNS-01). Domain pattern: yolo-8080.edger.yjpark.org → http://10.100.0.100:8080.
Summary of Changes
Modified mixins/nixos/host/incus-ingress.nix:
- Added
pkgs.caddy.withPluginswith the Cloudflare DNS plugin (hash pinned tosha256-bL1cpMvDogD/...) - Added Caddyfile generation: HTTPS + HTTP fallback blocks, per-container
host_regexpmatchers - Added
sops.secrets."cloudflare-caddy-env"declaration pointing to./secrets/cloudflare-caddy.txt - Added
systemd.services.caddy.serviceConfig.EnvironmentFilefor the SOPS secret path - Added
services.firewalld.zones.public.services = ["http" "https"]
Pending user action: create mixins/nixos/host/secrets/cloudflare-caddy.txt as a SOPS-encrypted dotenv file containing CLOUDFLARE_API_TOKEN=<token>.
Incus container ingress auto-discovery (flakes-7ckd)
Caddy reverse proxy inside container that auto-discovers listening ports and serves them via hostname routing (e.g. https://3000.yolo.incus). Includes ingress and ingress-sync shell commands.
Ingress hub page: service dashboard with iframe embedding (flakes-bti9)
A hub web page served inside each container that auto-discovers running services and presents them as a navigable list with iframe embedding. Built on existing Caddy + ingress-sync infrastructure.
Design
Overview
Single hub page per container at hub.<hostname>.incus — left sidebar lists discovered services, right pane shows selected service in an iframe.
Service Discovery
Extend existing generate-ingress-config script to also produce /var/lib/ingress/services.json:
ss -tlnp→ port + PID + process name (existing logic)readlink /proc/<pid>/cwd→ working directory (new)- Shorten cwd (strip home prefix, show last 1-2 path segments)
- Output format:
[{"port": 3000, "process": "node", "cwd": "my-app", "url": "https://3000.hostname.incus"}] - Hub port excluded from the list (avoid self-reference)
Hub Page (Caddy Templates)
- Static HTML file with embedded CSS/JS, served by Caddy
templatesdirective - JS fetches
services.jsonat load time - Left sidebar: service list showing
<short_path> <process> :<port> - Right pane: iframe loading selected service URL
- Iframe failure detection → fallback “open in new tab” link
Caddy Config Changes
- New route:
hub.<hostname>.incusserving the hub HTML +services.json - Strip
X-Frame-Optionsand rewriteContent-Security-Policyheaders on all proxied routes (enables iframe embedding) - Internal TLS unchanged
Nix Integration
- All changes in
mixins/nixos/container/ingress.nix - Hub HTML as a Nix file/package
ingress-syncregenerates both Caddy config andservices.jsoningresscommand unchanged
Tasks
- Extend
generate-ingress-configto read/proc/<pid>/cwdand writeservices.json - Create hub HTML template (sidebar + iframe layout, JS service loader, iframe error fallback)
- Add Caddy route for
hub.<hostname>.incusserving hub page + services.json - Strip X-Frame-Options/CSP headers on proxied routes
- Test with multiple running services
Not in v1
- Manual label overrides
- Cross-container aggregation (host-level hub)
- Auto-refresh on service change (manual page reload for now)
- Service grouping/categorization
Summary of Changes
Implemented ingress hub page for container service dashboard:
- Hub page served at
hub.<hostname>.incus(internal) and<container>-hub.<host>.yjpark.org(external) - Service discovery via
ss -tlnpwith process name and working directory from/proc/<pid>/cwd - Sidebar + iframe layout with resizable sidebar, compact mode (icon toolbar), and service list sorted by port
- Smart URL routing: uses
https://<container>-<port>.<host>.yjpark.org(real LE certs) when accessed externally,http://<port>.<hostname>.incusinternally - Sync button triggers
generate-ingress-configvia Python API, showsingressstatus output in dismissable modal - Favicon proxy at
/api/icon/<port>fetches favicons from services (tries/favicon.icothen parses HTML<link rel=icon>), falls back to colored letter icons - Header stripping: removes
X-Frame-OptionsandContent-Security-Policyon proxied routes for iframe embedding - Host ingress: added
<container>-hubroute toincus-ingress.nixfor external access
Files changed:
mixins/nixos/container/ingress.nix— hub HTML, sync API, enhanced generate-ingress-configmixins/nixos/services/incus-ingress.nix— hub route for host-level Caddy
Extract ingress hub scripts for Ubuntu compatibility (flakes-d4np)
Extract scripts from mixins/nixos/container/ingress.nix into standalone files under mixins/home/container/ingress/, refactor NixOS module to reference them, and add ubuntu-setup-ingress.bash for Ubuntu container support.
Tasks
- Extract hub-index.html from ingress.nix
- Extract generate-ingress-config.bash
- Extract ingress-sync-api.py
- Extract ingress.bash (status script)
- Extract ingress-sync.bash
- Create mixins/home/container/ingress/default.nix (Nix packages)
- Refactor mixins/nixos/container/ingress.nix to use shared scripts
- Create ubuntu-setup-ingress.bash
Summary of Changes
Extracted inline scripts from the NixOS module into standalone files:
- Scripts live in
mixins/home/container/ingress/(source of truth) - Copies in
mixins/nixos/container/ingress-scripts/(needed due to Nix flake autowire boundaries) - NixOS module refactored to use
builtins.readFileon local copies - Home Manager module adds scripts to PATH via
home.packages ubuntu-setup-ingress.bashhandles apt packages, systemd units, dnsmasq, resolved, sudo rules- All three configs (yolo, yolo-lima, home/yj) evaluate successfully
Change Zellij pane background color based on project path (flakes-dkc4)
Visually distinguish panes belonging to different projects by assigning each project a unique background color in Zellij. Builds on the project-wise pane naming from flakes-1zlj.
Design
Palette
8 subtle Gruvbox-adjacent background tints (base bg is #282828):
| Index | Hex | Tint |
|---|---|---|
| 0 | #2e1a1a | Red |
| 1 | #1a2e1a | Green |
| 2 | #1a1a2e | Blue |
| 3 | #2e2e1a | Yellow |
| 4 | #2e1a2e | Magenta |
| 5 | #1a2e2e | Cyan |
| 6 | #2e241a | Orange |
| 7 | #1a2e24 | Teal |
Color Assignment
- Hash project name (simple checksum) mod palette size → deterministic color index
- Same project always gets the same color
- Known limitation: hash collisions possible, acceptable for now
Behavior
- Home project (
ZELLIJ_SESSION_PROJECT): no color change, stays at terminal default - Foreign project: apply palette color via
zellij action set-pane-color --bg - On return to home project:
zellij action set-pane-color --reset - Applied on PWD change and shell init
Files Changed
modules/home/programs/fish/init/zellij.fish only.
Tasks
- Add color palette array
- Add hash function for project name → palette index
- Add
zellij_update_pane_colorfunction - Integrate into PWD hook and init block
- Reset color when returning to home project
Summary of Changes
Added to modules/home/programs/fish/init/zellij.fish:
ZELLIJ_PANE_COLORS: 8 subtle Gruvbox-adjacent bg tintszellij_project_color_index: djb2-style hash mod palette size, returns stable integer indexzellij_update_pane_color: applies color for foreign projects, resets for home project- Called from PWD hook and init block alongside existing pane/tab name updates
Declarative incus fleet management (flakes-ihxf)
NixOS module to declare containers (image, IP, devices, ACLs) and have them rebuild/restart on _switch-host. Long-term goal.
Zellij WASM plugin for dynamic tab naming (flakes-je55)
Background
We implemented project-aware tab naming in Zellij via fish shell hooks. After extensive iteration, the current approach uses zellij action dump-layout to parse pane names in visual order and compose tab names (e.g., flakes | litmus).
What works well (current fish implementation)
- Project detection via git root basename (
zellij_project_name) - Pane naming with
<project>prefix (zellij_update_panename) - Deterministic pane background colors per project (
zellij_update_pane_color) - Tab name composed from unique project names in visual order (
zellij_visual_projects) dump-layoutparsing gives correct visual order and avoids state file race conditions
Remaining trigger limitations (fish shell can’t solve)
- Pane moves between tabs: no fish event fires when a pane is moved — tab name only updates on next
cd - Pane detach/reattach: splitting a pane into a new tab doesn’t trigger any shell hook
- Non-shell panes: panes running editors, Claude, or other long-running processes never return to fish prompt
- All-tab updates: when a pane moves, both source and destination tabs need updating — fish can only rename the current tab
Why a WASM plugin is the right approach
- Zellij plugins receive native events:
TabUpdate,PaneUpdate,ModeUpdate - A plugin can react to pane moves, tab changes, and layout changes in real-time
- It can update ALL tab names (not just the focused tab) via
rename_tab - No shell hooks needed for tab naming — the plugin handles it entirely
- Fish hooks can focus solely on pane-level concerns (pane name, pane color)
Design considerations
- Research Zellij plugin API for tab/pane events
- Determine how to detect pane project (read pane name set by fish, or query cwd?)
- Prototype plugin that listens to layout changes and renames tabs
- Decide whether to keep fish-based pane naming or move everything to the plugin
- Package the plugin with Nix
Reference
- Zellij plugin docs: https://zellij.dev/documentation/plugins
- Current fish implementation:
modules/home/programs/fish/init/zellij.fish - Tab bar plugin already in use:
~/.config/zellij/plugins/tab-bar.wasm
Niri config: declarative host-based mixin (flakes-p2qs)
Make niri KDL config fully declarative by moving host-specific extras into per-host mixins, eliminating the manual apply-extras step.
Summary of Changes
- Added
me.niri.extraConfigoption tomodules/home/options.nix - Updated
modules/flake/home-configs.nixto support directory-based host mixins (falls back to/{host}.nixif no directory exists) - Created
mixins/home/hosts/a13/andmixins/home/hosts/edger/withdefault.nix+niri.extras.kdl - Rewrote niri config module to concatenate
config.common.kdl+config.me.niri.extraConfig - Deleted
extras.a13.kdl,extras.edger.kdl, andniri.justfilefrom old location
Add mdBook documentation site (flakes-px5o)
Create a docs/ folder using mdBook to maintain documentation about the flakes configuration. Seed initial content from CLAUDE.md, integrate with Nix flake (packages.docs, apps.docs-serve), and add mise tasks (docs-build, docs-serve).
Summary of Changes
- Created with mdBook structure (book.toml + 6 content pages seeded from CLAUDE.md)
- Added with (nix build) and
- Added and mise tasks
- Added to
Fish functions for jj workspace management (flakes-rhqy)
Convention-based jj workspace management via fish shell functions. All workspaces at ~/workspaces/
Functions
| Abbr | Full name | Behavior |
|---|---|---|
| wl | workspace-list | List all workspaces across all projects with bookmark + dirty/conflict status |
| w | workspace-cd | cd to a workspace + show brief status. Tab-completes |
| wc | workspace-create | From inside a repo, create ~/workspaces/ |
| workspace-delete | (no abbr) | Forget + remove a workspace |
Design Details
Convention
- All workspaces at ~/workspaces/
/ = basename of the main repo root - Default workspace = the main repo itself
Registry (~/.config/workspaces.conf)
- Maps project name to main repo path (e.g. llm-triage=/home/yj/code/llm-triage)
- Auto-populated by wc on first use
- Needed to discover default workspace / run jj commands from the right root
workspace-list (wl)
- Iterates all registered projects
- For each: runs jj workspace list from main repo, then for each workspace shows:
- Workspace name (default or feature name)
- Path (main repo or ~/workspaces/
/ ) - Bookmark name (or ‘no bookmark’)
- Change-id (short)
- Status: clean / dirty / conflicts
- Grouped by project
workspace-cd (w)
- w
/ → cd to workspace path + print one-line status (bookmark, change-id, dirty/conflicts) - w
/default → cd to main repo root - Tab completion for all
/ combos - w with no args → do nothing
workspace-create (wc)
- Must be run from inside a jj repo
- wc
→ jj workspace add ~/workspaces/ / - Auto-registers project in ~/.config/workspaces.conf if not present
- cd to the new workspace after creation
workspace-delete
- workspace-delete
/ → jj workspace forget (from main repo) + rm -rf the directory - No abbreviation (destructive operation)
- Tab completion same as w
Tasks
- Create workspace-list.fish function
- Create workspace-cd.fish function with completions
- Create workspace-create.fish function
- Create workspace-delete.fish function
- Add abbrs (wl, w, wc) to abbrs.nix
- Wire functions into fish module via nix (autowired automatically)
Zellij per-project auto-layouts on cd (flakes-u0yw)
Spec
When cd’ing to a project directory inside Zellij, automatically open a new tab with a layout matching the project’s configuration.
Preset Layout Files
Location: modules/home/programs/zellij/layouts/ → deployed to ~/.config/zellij/layouts/
claude_terminal.kdl — claude on left (50%), terminal on right (50%)
claude_beans-terminal.kdl — claude on left (50%), right side split: beans-serve --cors-origin "*" on top, stacked terminals below
Presets have no cwd — the fish hook passes --cwd at open time, keeping presets project-agnostic.
Layout Resolution Order
.zellij-layout.kdlfile in project root (inline layout, highest priority)ZELLIJ_LAYOUT_{USERNAME}env var (e.g.,ZELLIJ_LAYOUT_yj=claude_beans-terminal) — only if$USERmatchesZELLIJ_LAYOUTenv var — generic fallback- Neither → do nothing
Env vars are set via .envrc (direnv), e.g.:
export ZELLIJ_LAYOUT=claude_terminal
export ZELLIJ_LAYOUT_yj=claude_beans-terminal
export ZELLIJ_LAYOUT_yjpark=claude_terminal
Fish Hook Logic
Extend existing PWD hook in modules/home/programs/fish/init/zellij.fish:
- Not in Zellij? → skip
- Resolve project root (existing git root detection)
- Determine layout (resolution order above)
- Guard: check
__zellij_opened_layoutsfish global var — if project root already in list → skip zellij action new-tab --layout {layout_file} --cwd {project_root}- Add project root to
__zellij_opened_layouts
State resets when fish session ends. Re-opening after terminal restart is acceptable.
Relationship to existing bean
Related to flakes-kxju (predefined layout files) — this is the broader feature that subsumes it.
Tasks
- Create
claude_terminal.kdlpreset layout - Create
claude_beans-terminal.kdlpreset layout - Extend
zellij.fishPWD hook with layout resolution and auto-open logic - Test: cd to project with
ZELLIJ_LAYOUTset →zzapplies layout to current tab - Test: stacked layout, tab/status bars, clear buffer all working
- Test:
ZELLIJ_LAYOUT_yjoverridesZELLIJ_LAYOUTfor useryj - Test:
.zellij-layout.kdlin project root takes priority (not yet tested)
Setup SearXNG search for agents (flakes-woco)
Deploy SearXNG as a self-hosted meta-search engine to provide web search capabilities for agents (spacebot, hermes, etc.).
- https://github.com/searxng/searxng
Goals
- Run SearXNG as a service accessible to agent containers over the LAN
- Provide a search API endpoint agents can call (JSON format) without external API keys
- Keep configuration declarative via Nix
Open Questions
- Run as NixOS system service in a dedicated incus container at 10.100.0.3
- Which search engines to enable by default?
- Authentication/rate-limiting for the API endpoint?
- Integration method: MCP server, direct HTTP API, or tool wrapper?
Summary of Changes
- Created
nixos/containers/searxng/NixOS container config:- Static IP 10.100.0.3, services.searxng with JSON format enabled
- Engines: google, bing, duckduckgo, wikipedia, github
- Listens on 0.0.0.0:8080; no auth needed (LAN-only)
- Uses full container pack (ingress.nix auto-discovers port 8080)
- Registered “searxng” in
flake/nixos-configs.nix - Added searxng to
incus-ingress.nixingressContainers (10.100.0.3) - Added
incus-launch-searxng.bash - JSON API: http://10.100.0.3:8080/search?q=<query>&format=json
- Caddy: searxng-8080.<host>.yjpark.org → http://10.100.0.3:8080
Add git worktree support to workspace commands (flakes-y87y)
Extend workspace-create, workspace-list, workspace-cd, workspace-delete, and completions to support git worktree in addition to jj workspaces. Runtime VCS detection (jj priority over git). Git worktrees create new branches by default.
Summary of Changes
Added git worktree support to all workspace commands:
- workspace-create: detects jj vs git, uses git worktree add -b for git repos
- workspace-list: shows (jj)/(git) indicator per project, git worktrees show branch/hash/status
- workspace-cd: shows git branch/hash/status when navigating to git worktrees
- workspace-delete: uses git worktree remove for git repos
- completions: lists git worktrees alongside jj workspaces
- New helper __workspace_list_git_entry.fish for git worktree display formatting
Tasks
- Disable terminal bell sound (flakes-0u0f) — Done ·
archived - Create mise-run-or-just fish function (flakes-0ycg) — Done ·
archived - Enhance tv-mise-tasks to handle tasks with arguments (flakes-14he) — Done ·
archived - Make j abbreviation expand conditionally to mise run or just (flakes-1cc9) — Done ·
archived - Convert onecli-reseed to a manually-invoked script (flakes-2ey6) — Done
- Tidy up the shell title when running zellij (flakes-2fpy) — Done ·
archived - Remove stateVersion mixin pattern, use defaults instead (flakes-5pbu) — Done ·
archived - Restructure home config host/container registration (flakes-6n5b) — Done ·
archived - Install latest beans via nix flake (flakes-6ne0) — Todo
- Resolve username from host/container dir in activate-home.nix (flakes-7aac) — Done ·
archived - Setup markdown-oxide (flakes-7ih3) — Done ·
archived - Automate OneCLI CA push to containers on boot (flakes-aurl) — Done ·
archived - Set up Incus across machines (flakes-bxl7) — Done ·
archived - Auto-trigger tab completion after j abbr expands to mise run _ (flakes-c03b) — Done ·
archived - Migrate container IPs to new scheme (flakes-cjao) — Done
- Drop nixos-unified, use raw flake-parts (flakes-dght) — Done
- Unify terminal theme to Tokyo Night (flakes-hncv) — Done ·
archived - Replace autowire.nix with jig lib (flakes-iymi) — Done ·
archived - Set up firewalld as NixOS service and migrate existing firewall rules (flakes-jvmx) — Done ·
archived - Setup quartz to preview and publish oxide projects (flakes-k391) — Todo
- Check MCPVault, to see whether it’s a better option for the markdowns (flakes-k3pr) — Todo
- Install Zeroclaw (flakes-kj17) — Todo
- Fix CA cert injection to be declarative (flakes-krtw) — Done
- Update CLAUDE.md to reflect current state (flakes-nyvs) — Done ·
archived - Setup colima with incus (flakes-o04s) — Done ·
archived - Add edit-in-place script (flakes-oh4v) — Done ·
archived - Add GitHub token via OneCLI + container git config (flakes-oi2x) — Done ·
archived - Refactor ai.nix into ai/ directory (flakes-ojyn) — Done ·
archived - Configure jjui theme for readability with Pencil Dark terminal theme (flakes-p7hc) — Done ·
archived - Unify incus container image build tasks (flakes-p8hf) — Done
- Setup OpenCode and Claude for spacebot container (flakes-pr3i) — Done
- Integrate Home Manager as a NixOS module (flakes-rg27) — Done ·
archived - Migrate from just to mise for task running (flakes-rg2j) — Done ·
archived - Full jjui theme with terminal-independent hex colors (flakes-sk2r) — Done ·
archived - Containerize OneCLI (flakes-t9u2) — Done
- Inhibit idle/sleep during audio/video playback (flakes-va02) — Done ·
archived - Dynamic per-host Home Manager configs via flake module (flakes-vaiq) — Done ·
archived - Container-to-host network isolation (flakes-x821) — Done
- Add rtk-rewrite.sh hook to claude module with home-manager linking (flakes-y887) — Done ·
archived - Replace CopyQ with cliphist (Wayland-native clipboard manager) (flakes-yyox) — Done ·
archived - Add mdbook-beans tasks section to docs (flakes-zvh8) — Done ·
archived
Disable terminal bell sound (flakes-0u0f)
Disable audible bell in kitty and wezterm to prevent loud alert sounds during terminal work.
Summary of Changes
- kitty: set
enable_audio_bell = no - wezterm: set
audible_bell = 'Disabled'
Create mise-run-or-just fish function (flakes-0ycg)
Create a fish wrapper function that auto-detects whether to use mise run or just based on whether mise is configured in the current directory. Update the j abbr to use it.
Summary of Changes
- Created : wrapper that checks [ { “path”: “/home/yj/agents/flakes/mise.toml”, “tools”: [] } ] output; if non-empty array, uses , otherwise falls back to
- Updated line 21: →
Enhance tv-mise-tasks to handle tasks with arguments (flakes-14he)
Update tv-mise-tasks fish function to detect required args via ‘mise tasks info –json | jq’ and either run directly or pre-fill command line.
Make j abbreviation expand conditionally to mise run or just (flakes-1cc9)
Update fish config to use abbr –function for j so it expands inline to ‘mise run’ or ‘just’ based on current directory
Convert onecli-reseed to a manually-invoked script (flakes-2ey6)
Remove the systemd service for onecli-init-ca-and-secrets and replace with a plain onecli-reseed command. Launch is manual so systemd wantedBy/autostart causes more trouble than it’s worth.
Summary of Changes
- Renamed
initScript→reseedScriptwith binary nameonecli-reseed - Added
reseedScripttoenvironment.systemPackagesdirectly - Removed
systemd.services.onecli-init-ca-and-secretsblock entirely - Deleted
onecli-init-ca-and-secrets.bash(was justsudo systemctl start ...) - Removed auto-start block from
mise run _switch-host - Updated
mise run restart-oneclito callsudo onecli-reseeddirectly
Tidy up the shell title when running zellij (flakes-2fpy)
Objective
Configure zellij so the terminal emulator’s tab title (kitty/wezterm tab bar) shows the zellij session name instead of the verbose <cwd> | <last command with args> format zellij currently sets.
Context
When zellij runs inside a kitty or wezterm tab, it overwrites the terminal’s tab title with its own format: <current directory> | <last command with arguments>. This is too long for a tab bar and makes tabs hard to distinguish.
Fish shell’s fish_title is already configured to show just the current directory or last command name, and works correctly when zellij is not running. The problem is specifically that zellij overrides the terminal title with its own verbose format.
Requirements
- Configure zellij to set the terminal tab title to its session name (e.g. “main”, “dev”)
- Do not modify fish_title or other shell-level title configuration
- Zellij’s internal pane/tab titles (within zellij’s own UI) are out of scope and can remain as-is
Acceptance Criteria
- When zellij is running in a kitty or wezterm tab, the tab bar shows the zellij session name
- When zellij is not running, fish_title continues to work as before (current directory or last command name)
- No regressions in zellij’s internal tab/pane display
Summary of Changes
- : Return empty string when inside zellij — zellij’s
make_terminal_titlealready shows just the session name, so an empty pane title avoids duplication (was: echo $ZELLIJ_SESSION_NAME which produced.skills | .skills) - : Removed
zellij_update_tabname_pwd(PWD event hook) andzellij_update_panename_cmd(preexec event hook) — these were driving zellij’s verbose<cwd> | <command>terminal title format. Keptzellij_update_tabnamecall at startup only, which sets the zellij internal tab name to the initial directory once.
Revision: New Approach (2026-03-17)
Previous approach (empty fish_title inside zellij) broke zellij’s internal tab/pane renaming.
New approach: revert fish/zellij files to original, configure kitty and wezterm to extract just the session name (before ’ | ’) from the terminal title for display.
- Revert fish_title.fish to original
- Revert zellij.fish to original
- Update kitty tab_title_template to use partition(’ | ’)[0]
- Add wezterm format-tab-title event handler
Summary of Revised Changes
- Reverted to original (no ZELLIJ_SESSION_NAME check)
- Reverted to original (restored and hooks)
- Updated kitty to use — strips suffix, showing only the session name
- Added wezterm event handler that extracts text before using Lua pattern matching
Remove stateVersion mixin pattern, use defaults instead (flakes-5pbu)
Set default stateVersion in base configs, delete nearly-empty mixin files, fix fallback key mismatch in activate-home.nix
Summary of Changes
- Added
home.stateVersion = "25.05"toconfigurations/home/yjpark.nix - Added
home.stateVersion = "26.05"toconfigurations/home/yj.nix - Deleted nearly-empty host mixin files: alienware-13.nix, edger.nix, hp-g1.nix, pc.nix, and containers/yolo.nix
- Restored
mixins/home/containers/.gitkeepfor future use - Simplified
mixins/home/hosts/gpd-p2.nix: removed version import, kept only incus/edger.nix import - No change needed to activate-home.nix (the trailing
@on fallback key is required by nixos-unified; home-configs.nix omits it correctly as nixos-unified adds it internally)
Restructure home config host/container registration (flakes-6n5b)
Move host/container registration to mixins/home/hosts/ and mixins/home/containers/, update home-configs.nix and activate-home.nix accordingly
Summary of Changes
- Created files for alienware-13, edger, hp-g1, pc (each imports 25.05 version mixin)
- Updated to add 25.05 version import
- Created importing 26.05 version mixin
- Deleted
- Rewrote : removed
configDirparam,mixinDirnow serves both roles - Rewrote : reads host names from hosts/ and containers/ dirs; fixed fallback key (removed trailing @)
- Removed version imports from
configurations/home/yjpark.nixandconfigurations/home/yj.nix
Verified: nix eval .#homeConfigurations --apply 'x: builtins.attrNames x' returns expected keys.
Install latest beans via nix flake (flakes-6ne0)
Add beans (edger-dev/beans) as a flake input and install it as a home-manager package, replacing or supplementing the current beans installation.
Resolve username from host/container dir in activate-home.nix (flakes-7aac)
Replace flat knownHosts list with separate hosts/containers lists so activate-home.nix determines username (yjpark vs yj) from which dir the hostname is found in, rather than using $(id -un). Also update home-configs.nix fallback key to use ‘username@’ format.
Summary of Changes
- : replaced flat
knownHostswith separatehostsandcontainerslists; shell script now checks hosts first (→yjpark@$_host), then containers (→yj@$_host), falling back to$(id -un)@only when hostname is unknown home-configs.nix: updated fallback key from${username}to"${username}@"to match new shell script format
Setup markdown-oxide (flakes-7ih3)
For neovim, zed, vscode
Automate OneCLI CA push to containers on boot (flakes-aurl)
OneCLI CA cert gets wiped from container CA bundles on reboot/rebuild. Extend onecli-seed-secrets to also push the CA, and add wantedBy=multi-user.target + after=incus.service so it runs on every boot.
Design
Problem: init-ingress-ca on yolo copies system CAs to /var/lib/ingress/ca-bundle.crt on boot, wiping the OneCLI CA that was previously appended by onecli-push-ca. This breaks all HTTPS through the OneCLI MITM proxy (nix downloads, curl, git, etc.) until someone manually runs onecli-push-ca yolo.
Solution: Extend onecli-seed-secrets on edger (host) to:
- Fetch OneCLI CA from
http://10.100.0.1:10254/api/gateway/ca - Push to each running agent container via
incus file push - Append to CA bundles inside the container (handling Nix store symlinks + idempotency)
Also update the systemd service:
- Add
wantedBy = ["multi-user.target"]— runs on every boot - Add
after = [..., "incus.service"]— ensures incus is up
Files to modify:
mixins/nixos/services/onecli.nix— extend seeder script + service config
Known gap: Container-side nixos-rebuild switch resets CA bundles. User must re-run sudo systemctl start onecli-seed-secrets on host. Acceptable since container rebuilds are manual.
Tasks
- Add CA push logic to seeder script in onecli.nix
- Rename
onecli-seed-secretsservice toonecli-init-ca-and-secrets(systemd service + script name) - Add
wantedByandafterincus.service to systemd service - Add
onecli-init-ca-and-secretsshell script on host (starts the systemd service via sudo) for easy manual use - Update
onecli-check-proxy.basherror messages to suggest runningonecli-init-ca-and-secretson the host - Add CA bundle verification to check script: detect broken TLS (e.g. curl to github.com fails but
--noproxyworks) and surface a clear diagnosis - Update
_switch-hostin mise.toml to reference new service name - Verify build with
mise run build-host
Summary of Changes
mixins/nixos/services/onecli.nix— Renamed serviceonecli-seed-secrets→onecli-init-ca-and-secrets. Added CA push logic (fetch from API, push to containers, append to CA bundles with symlink handling + idempotency). AddedwantedBy = ["multi-user.target"]andafter = ["incus.service"]so it runs on every boot.mise.toml— Updated_switch-hostandrestart-oneclitasks to reference new service name.mixins/home/host/linux/scripts/incus/onecli-init-ca-and-secrets.bash— New host script for easy manual triggering.mixins/home/container/scripts/onecli-check-proxy.bash— Updated error messages to point toonecli-init-ca-and-secrets. Added TLS verification check that detects “proxy works but TLS fails” scenario and surfaces clear fix instructions.
Set up Incus across machines (flakes-bxl7)
Set up Incus (container/VM manager) across all machines.
Tasks
- Create
mixins/nixos/services/incus.nix— Incus daemon with KVM, directory storage pool, NAT networking - Create
modules/home/packages/incus.nix— Incus client package + fish completions - Create
mixins/home/settings/incus/edger.nix— sample remote config for edger.yjpark.org - Include mixin in at least one NixOS host to test (edger)
Decisions
- No multi-host clustering
- Both containers and VMs (KVM enabled)
- Directory-based storage pool
- No shell abbreviations for now
- macOS colima setup is a separate future task
Reference
See clarified/2026-03-15_setup-incus.md for full clarification notes.
Summary of Changes
- : Enables incus daemon with NAT bridge network (incusbr0), directory storage pool, KVM kernel modules, and adds yjpark to the incus-admin group
- : Installs incus client and sources fish completions via shellInit
- : Home activation script that registers edger.yjpark.org as an incus remote (idempotent, skips if already present; manual cert trust still needed)
- : Added incus service mixin to edger host
Auto-trigger tab completion after j abbr expands to mise run _ (flakes-c03b)
Replace _j_abbr function with _j_expand fish function that handles expansion and triggers completion automatically when in a mise directory. Bind Space to _j_expand.
Summary of Changes
- Removed abbreviation entry from (was using function)
- Replaced function with in : detects when command line is exactly , expands to + triggers completion in mise dirs, or otherwise; falls through to normal space + abbr expansion for any other input
- Added to bind Space to (both normal and insert/vi mode)
Migrate container IPs to new scheme (flakes-cjao)
Update static IPs: spacebot .102→.101, hermes .103→.102, ubuntu .101→.200. Update incus-ingress.nix, launch scripts, and dnsmasq config.
Summary of Changes
- Updated : spacebot .102→.101, hermes .103→.102
- Updated @onecli static block to point to 10.100.0.2 (anticipating OneCLI containerization)
- Note: ubuntu container IP (.101→.200) is managed imperatively via
incus config device override ubuntu eth0 ipv4.address=10.100.0.200
Drop nixos-unified, use raw flake-parts (flakes-dght)
Replace nixos-unified.lib.mkFlake with flake-parts.lib.mkFlake. Separate host and container config namespaces. Rewrite home-configs.nix and activate-home.nix to own the logic directly. Keep autowire (from jig) for module discovery.
Plan
- Move host configs: configurations/nixos/{edger,a13,g1,p2,pc} → configurations/nixos/hosts/
- Move container configs: configurations/nixos/{yolo,spacebot,hermes} → configurations/nixos/containers/
- Rewrite flake.nix: use flake-parts.lib.mkFlake with explicit imports
- Rewrite modules/flake/toplevel.nix: remove nixos-unified imports
- Create modules/flake/nixos-configs.nix: explicit nixosConfigurations + nixosModules.default + homeModules.default + overlays
- Rewrite modules/flake/home-configs.nix: use home-manager.lib.homeManagerConfiguration directly
- Rewrite modules/flake/activate-home.nix: use home-manager switch –flake directly
- Remove nixos-unified from flake inputs
- Update mise.toml build tasks — no changes needed, output names unchanged
- Test: nix flake check (passes — niri hash mismatch is pre-existing, unrelated)
- Test: mise run build-host (on edger) — blocked by pre-existing niri hash issue
Summary of Changes
Completed in two commits:
-
fee9eea - Drop nixos-unified, use raw flake-parts
- Replaced nixos-unified.lib.mkFlake with flake-parts.lib.mkFlake
- Separated host/container configs into configurations/nixos/hosts/ and containers/
- Rewrote home-configs.nix, activate-home.nix to own the logic directly
- Removed nixos-unified flake input
-
f69f1fd - Restructure into packs/ with wireImportsRecursively
- Introduced packs/ directory with autowired module collections
- Added wireImportsRecursively to jig (1f1b27c)
- Removed 28 boilerplate default.nix files
- Merged modules/ and relevant mixins/ into packs/
- Retained mixins/ for opt-in pieces (services, versions, storage, lan)
- Deduplicated shared config (ai/, removed pass-through files)
Unify terminal theme to Tokyo Night (flakes-hncv)
Switch wezterm from Gruvbox Dark to Tokyo Night theme, and update Zellij pane background color palette from Gruvbox-adjacent tints to Tokyo Night-adjacent tints. Kitty already uses tokyo_night_night.
Summary of Changes
- wezterm: Changed
color_schemefromGruvbox Dark (Gogh)toTokyo Nightinmixins/home/gui/linux/wezterm/wezterm.lua - Zellij pane colors: Updated palette in
modules/home/programs/fish/init/zellij.fishfrom Gruvbox-adjacent tints (base#282828) to Tokyo Night-adjacent tints (base#1a1b26)
All terminal themes now unified on Tokyo Night: kitty (tokyo_night_night), wezterm (Tokyo Night), Zellij (tokyo-night-dark), and pane background tints.
Replace autowire.nix with jig lib (flakes-iymi)
Migrate from standalone autowire.nix flake input to jig’s lib.autowire. Add shim in flake.nix, rename default→wireImports, fix generic gatherFiles calls, update docs.
Summary of Changes
- Replaced
autowire.url = "github:yjpark/autowire.nix"withjig.url = "github:edger-dev/jig"in flake.nix - Added shim:
inputs = inputs // { autowire = inputs.jig.lib.autowire; }so all existingflake.inputs.autowire.*references keep working - Renamed
autowire.default→autowire.wireImportsin 48 default.nix files - Updated 3 files using generic
gatherFiles→gatherFiles_(pre-applied variant) - Updated CLAUDE.md and docs/src/architecture.md
- Verified with
nix flake show— evaluates cleanly
Set up firewalld as NixOS service and migrate existing firewall rules (flakes-jvmx)
Objective
Replace NixOS’s built-in networking.firewall with firewalld across all hosts, enabling zone-based firewall management that integrates natively with incus.
Context
The repo currently uses NixOS’s networking.firewall — a simple declarative wrapper around iptables/nftables. This works for basic port allowlisting but doesn’t support zone-based policies. With incus now in the stack (mixins/nixos/services/incus.nix), zone-based rules are a better fit:
- Incus has built-in firewalld support — it can automatically manage zones for bridge interfaces (
incusbr0), so containers/VMs get proper network isolation without manual rules. - Already on nftables —
networking.nftables.enable = trueis set in the incus mixin. firewalld uses nftables as its default backend, so there’s no backend conflict. - Current LAN rules use raw iptables — the
extraCommandsinmixins/nixos/lan/*/firewall.nixinject iptables rules directly, which won’t work under firewalld’s managed ruleset. - Zone-based model is cleaner — instead of scattering port ranges across files, interfaces get assigned to zones with appropriate policies.
Requirements
1. Enable firewalld as a NixOS service
- Set
services.firewalld.enable = truein an appropriate NixOS module - This automatically disables
networking.firewall— both cannot be active simultaneously
2. Migrate all existing networking.firewall usages
The following files need migration:
| File | Current rules | Migration approach |
|---|---|---|
mixins/nixos/lan/my/firewall.nix | Open ports 1000-65535 for 10.0.0.0/8 (iptables) | Create a zone (e.g., “lan”) with these rules, assign LAN interface |
mixins/nixos/lan/cn/firewall.nix | Same as above | Same zone approach |
mixins/nixos/dev/ports.nix | TCP ranges 3000-3999, 8000-8999, 29000-29999 | Add port ranges to appropriate zone |
modules/nixos/services/airplay.nix | TCP 7000,7001,7100 + UDP 6000,6001,7011 | firewalld service definition or rich rules |
modules/nixos/services/clash-verge.nix | TCP ports for clash | firewalld service or zone rules |
modules/nixos/services/zerotierone.nix | UDP port for zerotier | firewalld service or zone rules |
mixins/nixos/ext4/k3s.ext4.nix | k3s TCP ports + ranges | firewalld zone for k3s |
mixins/nixos/zfs/k3s.zfs.nix | k3s TCP ports + ranges | firewalld zone for k3s |
configurations/nixos/alienware-13/ports.nix | TCP 2342 (photoprism) | firewalld service or zone rule |
3. Configure incus integration
- Ensure
incusbr0bridge interface is assigned to an appropriate firewalld zone - Verify incus can manage its own firewall rules through firewalld without manual intervention
4. Design the zone layout
Decide on zones — at minimum:
- public (default) — external-facing interface, restrictive
- trusted or custom lan zone — for
10.0.0.0/8traffic with broader access - incus zone — for
incusbr0, managed by incus
Acceptance Criteria
-
services.firewalldis enabled andnetworking.firewallis no longer used - All previously open ports/ranges remain accessible in the correct contexts
- LAN-scoped rules (
10.0.0.0/8broad access) work via firewalld zones instead of raw iptables - Incus containers/VMs have working network access through
incusbr0 - No regressions — services (airplay, clash-verge, zerotier, k3s, photoprism) remain reachable
-
nix fmtpasses on all changed files
Dependencies
- Depends on incus being configured (already done in
mixins/nixos/services/incus.nix) - Hosts not using incus should still work with firewalld (zone config just won’t include incus zone)
Setup quartz to preview and publish oxide projects (flakes-k391)
Check MCPVault, to see whether it’s a better option for the markdowns (flakes-k3pr)
Install Zeroclaw (flakes-kj17)
Install Zeroclaw (https://github.com/zeroclaw-labs/zeroclaw) — evaluate and set up in the environment.
Fix CA cert injection to be declarative (flakes-krtw)
Replace manual /etc/ssl/certs mutation with security.pki.certificateFiles. Seeder pushes CA to a known path, NixOS handles cert bundle integration.
Summary of Changes
packs/nixos/container/onecli-proxy.nix: added/var/lib/onecli/tmpfiles dir,onecli-ca-bundle.service(oneshot, rebuilds bundle idempotently from system certs + CA), andonecli-ca-bundle.path(watches/var/lib/onecli/ca.crt, re-triggers on every push/rotation). UpdatedNODE_EXTRA_CA_CERTSto point to the new stable path.mixins/nixos/services/onecli.nix: seeder now writes CA to/var/lib/onecli/ca.crtonly — no more in-container symlink replacement or bundle appending.packs/home/host/linux/scripts/incus/onecli-push-ca.bash: same simplification.
Update CLAUDE.md to reflect current state (flakes-nyvs)
Fix outdated command names, module descriptions, overlays, flake inputs, and add Home Manager activation subsection
Summary of Changes
- Fixed → On branch dev
Changes not staged for commit:
(use “git add
…” to update what will be committed) (use “git restore …” to discard changes in working directory) modified: CLAUDE.md modified: flake.lock
Untracked files:
(use “git add
no changes added to commit (use “git add” and/or “git commit -a”)
- Fixed build-host description: “dry run” → “builds without switching”
- Simplified modules/ description (removed stale subdirectory list)
- Simplified mixins/ description (removed specific version numbers)
- Simplified configurations/ description (removed stale “plus version and platform mixins”)
- Fixed overlays/default.nix description: autowires from
./not./packages/ - Added Desktop/UI flake inputs group: claude-desktop, niri, xremap-flake, antigravity, jjui
- Added Home Manager Activation subsection covering yjpark/yj profiles, host/container mixin dirs, activate-home.nix logic, and home-configs.nix structure
Setup colima with incus (flakes-o04s)
Add edit-in-place script (flakes-oh4v)
Create modules/home/scripts/edit-in-place.bash to back up and replace home-manager managed symlinks with writable copies for local testing
Summary of Changes
Created modules/home/scripts/edit-in-place.bash — autowired automatically. Script backs up the symlink to .bak, removes the symlink, copies .bak back as a regular file, and sets 644 permissions.
Add GitHub token via OneCLI + container git config (flakes-oi2x)
Add GitHub fine-grained token to OneCLI for transparent auth injection into yolo container. Add container-specific git config to rewrite SSH URLs to HTTPS.
Summary of Changes
mixins/nixos/services/onecli.nix— AddedGITHUB_TOKENsecret config with*.github.comhost pattern andAuthorization: token {value}injectionmixins/home/container/git.nix— New file: rewrites SSH GitHub URLs to HTTPS (routes through OneCLI proxy) and setsGIT_TERMINAL_PROMPT=0mixins/nixos/services/secrets/onecli-secrets.txt— User needs to add real token viasops
Refactor ai.nix into ai/ directory (flakes-ojyn)
Convert mixins/home/host/common/ai.nix into a folder (ai/), moving scripts/installs/ under ai/installs/ and extracting inline scripts into bash files.
Summary of Changes
- Converted
mixins/home/host/common/ai.nix→ai/directory ai/default.nix: autowire pattern for extensibilityai/ai.nix: package declarations (bun, nodejs_25)ai/installs/default.nix: gatherScriptPackages_bash- Moved
scripts/installs/install-claude-mcp-context7.bashandinstall-claude-mcp-verena.bash→ai/installs/ - Extracted inline clone-beans and install-ccline scripts into
ai/installs/ - Removed
scripts/installs/directory (now empty)
Configure jjui theme for readability with Pencil Dark terminal theme (flakes-p7hc)
Add settings.ui.colors overrides to programs.jjui in modules/home/programs/jujutsu.nix to fix readability issues with the Pencil Dark (Gogh) WezTerm color scheme. The default dark theme uses ‘bright black’ for dimmed text and selected backgrounds, which is too dark/invisible in Pencil Dark.
Summary of Changes
Added settings.ui.colors overrides to programs.jjui block in modules/home/programs/jujutsu.nix. Key fixes:
dimmed:"bright black"→"#808080"(mid-gray, readable in Pencil Dark)selected/revisions details selectedbg:"bright black"→"#3a3a3a"revset completionbg:"black"→"#1a1a1a"revset completion dimmed: same fix asdimmed
Config verified at ~/.config/jjui/config.toml after just activate-home.
Unify incus container image build tasks (flakes-p8hf)
Replace per-container build-image/build-metadata/build-and-import tasks with a single parameterized task that builds image+metadata and imports directly without staging in images/
Summary of Changes
Replaced 9 per-container tasks (build-yolo-image, build-yolo-metadata, build-and-import-yolo, and equivalents for spacebot/hermes) with a single mise run build-container <name> task.
- Uses
usagefield with KDLchoicesfor shell auto-complete (covers all 5 containers) - Builds metadata + image sequentially, resolves nix store paths directly from
resultsymlink - Pipes both tarballs straight to
incus image import— noimages/staging directory needed - Removed
images/directory entirely
Setup OpenCode and Claude for spacebot container (flakes-pr3i)
Configure OpenCode with the claude-code-plugin (github:unixfox/opencode-claude-code-plugin) in the spacebot incus container, enabling Claude as a coding assistant within spacebot’s environment.
Summary of Changes
- Added
opencode-claude-code-pluginflake input (github:unixfox/opencode-claude-code-plugin, flake=false) - Updated
mixins/home/containers/spacebot.nix:- Added
llm-agents.opencodeandllm-agents.claude-codeto packages - Added
xdg.configFile."opencode/plugins/claude-code"pointing to plugin source
- Added
- Plugin placed at
~/.config/opencode/plugins/claude-codefor OpenCode to load - Also fixed minor bug in spacebot-restart (was calling spacebot-restart instead of spacebot-status)
Integrate Home Manager as a NixOS module (flakes-rg27)
Create modules/nixos/settings/home-manager.nix to import home-manager as a NixOS module so nixos-rebuild switch handles both system and home config in one command.
Summary of Changes
Created modules/nixos/settings/home-manager.nix which:
- Imports
home-manager.nixosModules.home-manager - Sets
useGlobalPkgs = trueanduseUserPackages = true - Passes
extraSpecialArgswith theflakeargument so home modules get their expected{flake, ...}argument - Wires
home-manager.users.yjparkto importconfigurations/home/yjpark.nixplus any host-specific mixin frommixins/home/hosts/<hostname>.nix
The module is auto-included in all NixOS hosts via the autowired modules/nixos/settings/ directory. Verified with nix flake check and just build-host — home-manager generation is now built as part of the NixOS system build.
Migrate from just to mise for task running (flakes-rg2j)
Add mise.toml files and shell abbreviations to migrate task running from just to mise. Keep justfiles intact during transition.
Summary of Changes
- Created at repo root with all 12 tasks from the main justfile
- Created with task
- Created with 4 preset tasks (update-presets + 3 individual)
- Added and abbreviations to fish () and nushell ()
- Justified files remain intact for the transition period
- All tasks verified working via
mise tasksandmise run vcs-status
Full jjui theme with terminal-independent hex colors (flakes-sk2r)
Replace the partial Pencil Dark fix with a complete theme using only hex/ANSI256 colors (no ANSI 0-15) so it looks good on any dark terminal.
Summary of Changes
Replaced partial Pencil Dark fix with a complete One Dark-inspired theme in modules/home/programs/jujutsu.nix. Covers all 60+ color keys: core, flash, confirmation, help, revisions list/details, revset/completion, status, menu, picker, oplog, evolog, rebase/squash/duplicate/revert/set_parents, input, choose. All colors use explicit hex values — no ANSI 0-15 — so the theme is terminal-agnostic.
Containerize OneCLI (flakes-t9u2)
Move OneCLI + postgres from podman-on-host to a dedicated incus container at 10.100.0.2. Update seeder to target container IP. Convert to NixOS service with local postgres (no more podman-in-podman).
Summary of Changes
- Created
nixos/containers/onecli/with NixOS config:- Static IP 10.100.0.2, native postgresql, podman onecli image with –network=host
- Selective imports (skips ingress.nix and onecli-proxy.nix)
- Registered “onecli” in
flake/nixos-configs.nix - Updated
mixins/nixos/services/onecli.nix: removed podman setup, now just the seeder pointing to 10.100.0.2 - Updated
packs/nixos/container/onecli-proxy.nix: reference 10.100.0.2 - Updated all launch/utility scripts: spacebot .102→.101, hermes .103→.102, ubuntu .101→.200, onecli scripts 10.100.0.1→10.100.0.2
- Rewrote
onecli-reset-db.bashto use incus exec instead of podman - Added
incus-launch-onecli.bash
Inhibit idle/sleep during audio/video playback (flakes-va02)
Add sway-audio-idle-inhibit to prevent hypridle from powering off monitors when audio is playing (e.g. YouTube, Netflix in Chrome). Changes: add package to hypridle.nix and spawn at niri startup.
Summary of Changes
- Added
sway-audio-idle-inhibitpackage tomixins/home/gui/linux/services/hypridle.nix - Added
spawn-at-startup "sway-audio-idle-inhibit"to niri config (config.common.kdl)
The daemon monitors PipeWire/PulseAudio for active audio streams and sends a Wayland idle inhibit signal, preventing hypridle from powering off monitors during video/audio playback.
Dynamic per-host Home Manager configs via flake module (flakes-vaiq)
Create home-hosts.nix flake module to auto-generate homeConfigurations for all NixOS hosts, with optional host mixins. Delete per-host config files.
Summary of Changes
- Created
modules/flake/home-hosts.nix: dynamically generates homeConfigurations for all NixOS hosts by readingconfigurations/nixos/dirs, with optional per-host mixins frommixins/home/hosts/<host>.nix - Created
mixins/home/hosts/gpd-p2.nix: imports incus/edger mixin only for gpd-p2 - Updated
modules/flake/activate-home.nix: adds fallback to plainyjparkconfig when hostname isn’t in known NixOS hosts - Deleted all per-host
configurations/home/yjpark@<host>.nixfiles (pc, edger, alienware-13, hp-g1, gpd-p2) - Key fix: used
lib.mkForceon wholelegacyPackagesattrset (not just homeConfigurations sub-key) to override autoWire’s perSystem definition
Container-to-host network isolation (flakes-x821)
Add nftables INPUT rules on incusbr0 to block container→host traffic except DHCP (67/68) and DNS (53/5354). Container↔container traffic via FORWARD chain stays unrestricted.
Summary of Changes
- Updated
packs/nixos/host/incus.nix: removedtarget = "ACCEPT"from incus firewalld zone - Added explicit services: “dhcp” (UDP 67) and “dns” (TCP/UDP 53) for container→host DHCP/DNS
- Added ports 5354 TCP/UDP for custom dnsmasq DNS
- Container↔container traffic via FORWARD chain is unaffected (bridge forwarding)
Add rtk-rewrite.sh hook to claude module with home-manager linking (flakes-y887)
Add the rtk-rewrite.sh hook file to modules/home/programs/claude/hooks/ and set up home.file linking to ~/.claude/hooks/rtk-rewrite.sh
Summary of Changes
- Created
modules/home/programs/claude/hooks/rtk-rewrite.sh(copied from~/.claude/hooks/rtk-rewrite.sh) - Created
modules/home/programs/claude/hooks/default.nixlinking it to~/.claude/hooks/rtk-rewrite.shwith executable=true - Autowire in
claude/default.nixpicks up the new hooks/ subdirectory automatically — no other files changed
Replace CopyQ with cliphist (Wayland-native clipboard manager) (flakes-yyox)
Replace CopyQ (XWayland) with cliphist for Wayland-native clipboard history. Adds fuzzel picker keybinding, television cable channel, and fish function.
Summary of Changes
- Deleted
mixins/home/gui/linux/services/copyq.nix(removed CopyQ with forceXWayland) - Created
mixins/home/gui/linux/services/cliphist.nix(enables cliphist service) - Added
Mod+Vkeybinding in niri config to open fuzzel clipboard history picker - Added
xdg.configFilefor television cable channel inmodules/home/programs/television.nix - Created
modules/home/programs/fish/functions/clip.fishfor tv-based clipboard selection - Added
tcabbreviation inmodules/home/programs/fish/abbrs.nix
Add mdbook-beans tasks section to docs (flakes-zvh8)
Integrate mdbook-beans preprocessor into the flakes documentation, mirroring the litmus project setup. Adds kanban and all-tasks pages.
Summary of Changes
- Added
mdbook-beansflake input toflake.nix - Updated
docs/book.tomlwith beans preprocessor config and sidebar CSS - Created
docs/src/beans/tasks.md(all tasks) anddocs/src/beans/kanban.md(active tasks) - Copied
docs/src/beans-sidebar.cssfrom litmus for bean styling - Updated
docs/src/SUMMARY.mdwith Kanban and All Tasks links - Updated
modules/flake/docs.nixto include mdbook-beans and .beans data in build - Updated
mise.tomldocs tasks to use nix (ensuring mdbook-beans is available)
Bugs
- Fix Ctrl+Shift+C in wezterm clobbering zellij clipboard (flakes-5oyz) — Done ·
archived - Auto-restart firewalld when zone config changes (flakes-ja9k) — Todo
- Fix mise.toml var args bug (flakes-m3r8) — Done ·
archived - Fix git push auth inside Incus container via OneCLI proxy (flakes-nz9y) — Done ·
archived - Pass currentSystem to NixOS-integrated home-manager extraSpecialArgs (flakes-sytx) — Done
Fix Ctrl+Shift+C in wezterm clobbering zellij clipboard (flakes-5oyz)
Copy (to system clipboard) doesn’t work when using wezterm → incus shell → zellij. Root cause: Ctrl+Shift+C runs CopyTo(‘Clipboard’) which copies empty terminal selection, overwriting what zellij put in clipboard via OSC 52. Fix: only copy when there’s an actual selection.
Summary of Changes
Changed binding in from a direct action to a callback that first checks if there’s an actual terminal selection. Only copies when selection is non-empty, matching kitty’s behavior and preventing the clipboard from being clobbered when zellij has already set it via OSC 52.
Auto-restart firewalld when zone config changes (flakes-ja9k)
NixOS services.firewalld module doesn’t restart/reload the firewalld service when zone config changes, so switch-host applies new XML but the running daemon keeps old rules until manually restarted.
Context
Discovered while debugging ICMP/ping access (commits 84638b0, 235381f). After running mise run _switch-host with new services.firewalld.zones.lan settings (added protocols = ["icmp"] and extra source range), the active runtime config from firewall-cmd --zone=lan --list-all still showed the old rules. Manual sudo systemctl restart firewalld was required.
Investigation
- Confirm root cause: check whether nixpkgs
services.firewalldmodule setsrestartTriggers/reloadTriggerson the systemd unit when zone XML or settings change - Decide between restart vs reload (
firewall-cmd --reloadis non-disruptive and is likely what we want) - Check if upstream nixpkgs already has an open issue/PR
Implementation
- Add a fix in
packs/nixos/common/settings/firewalld.nix— likely asystemd.services.firewalld.reloadTriggersreferencing the generated zone config files, or a small activation script that runsfirewall-cmd --reloadwhen config changes - Test by editing a zone (e.g. add a port), running
_switch-host, and verifyingfirewall-cmd --zone=… --list-allreflects the change without manual intervention - If a clean fix exists, consider upstreaming to nixpkgs
Fix mise.toml var args bug (flakes-m3r8)
Remove unused args and fix the var=true arg to be optional (default=‘’) in mise.toml
Summary of Changes
- : removed unused — task never needed extra args
- : changed to so it’s optional
- : removed unused trailing
- : removed unused trailing
Fix git push auth inside Incus container via OneCLI proxy (flakes-nz9y)
git push inside the container failed with ‘could not read Username for https://github.com: terminal prompts disabled’. Two root causes were identified and fixed.
Summary of Changes
Problem
git push inside the Incus container failed with:
fatal: could not read Username for 'https://github.com': terminal prompts disabled
The OneCLI MITM proxy was correctly configured and the proxy was being used, but two issues prevented authentication from working.
Root Cause 1: gh credential helper override
Home Manager’s programs.gh module auto-registers gh auth git-credential as a git credential helper for github.com. The lib.mkForce "" in git.nix cleared the helper list, but gh re-added its helper after the clear. Git would call gh auth git-credential, which tried the placeholder GH_TOKEN=onecli-managed, failed, then fell back to terminal prompt.
Fix: programs.gh.gitCredentialHelper.enable = false in mixins/home/container/git.nix
Root Cause 2: Wrong auth format for GitHub’s git HTTP endpoint
OneCLI was injecting Authorization: token <PAT> which works for GitHub’s REST API (api.github.com) but NOT for GitHub’s git smart HTTP endpoint (github.com). The git endpoint requires Basic auth: Authorization: Basic base64(x-access-token:<PAT>).
Fix: Added encoding = "basic-auth" field to GITHUB_TOKEN secret config in mixins/nixos/services/onecli.nix. The seeder script base64-encodes x-access-token:<value> when this encoding is set, and the valueFormat was changed to Basic {value}.
Key diagnostic commands
GIT_CURL_VERBOSE=1 git push— revealed git wasn’t sendingProxy-Authorization(fixed byhttp.proxyAuthMethod = basic)- OneCLI gateway logs (
podman logs onecli) — confirmed MITM + injection was happening but GitHub returned 401 - Certificate issuer in TLS handshake — confirmed OneCLI CA vs real cert (MITM vs tunnel)
Files modified
mixins/home/container/git.nix— disabled gh credential helper, removed extraHeader workaround, addedproxyAuthMethod = basicmixins/nixos/services/onecli.nix— changed GITHUB_TOKEN to Basic auth format with base64 encoding at seed time
Pass currentSystem to NixOS-integrated home-manager extraSpecialArgs (flakes-sytx)
nixos-rebuild on g1 fails with infinite recursion in packs/home/host because the NixOS-integrated home-manager module (packs/nixos/common/settings/home-manager.nix) doesn’t pass currentSystem via extraSpecialArgs. Standalone home configurations get it via flake/home-configs.nix but NixOS hosts that use home-manager.users.* don’t.
Summary of Changes
Updated packs/nixos/common/settings/home-manager.nix to:
- Take
pkgsas module argument - Pass
currentSystem = pkgs.stdenv.hostPlatform.systemviaextraSpecialArgs
This mirrors what flake/home-configs.nix already does for standalone home configurations. The integrated home-manager NixOS module evaluates packs/home/host (via home/yjpark.nix imported through packs/nixos/host/yjpark.nix), and that module reads currentSystem in its imports to conditionally include the linux subdirectory.
Verified: g1 evaluation now progresses past the recursion point (fails only on an unrelated network fetch of Smithay/smithay.git).
Drafts
Zellij WASM plugin for dynamic tab naming (flakes-je55)
Background
We implemented project-aware tab naming in Zellij via fish shell hooks. After extensive iteration, the current approach uses zellij action dump-layout to parse pane names in visual order and compose tab names (e.g., flakes | litmus).
What works well (current fish implementation)
- Project detection via git root basename (
zellij_project_name) - Pane naming with
<project>prefix (zellij_update_panename) - Deterministic pane background colors per project (
zellij_update_pane_color) - Tab name composed from unique project names in visual order (
zellij_visual_projects) dump-layoutparsing gives correct visual order and avoids state file race conditions
Remaining trigger limitations (fish shell can’t solve)
- Pane moves between tabs: no fish event fires when a pane is moved — tab name only updates on next
cd - Pane detach/reattach: splitting a pane into a new tab doesn’t trigger any shell hook
- Non-shell panes: panes running editors, Claude, or other long-running processes never return to fish prompt
- All-tab updates: when a pane moves, both source and destination tabs need updating — fish can only rename the current tab
Why a WASM plugin is the right approach
- Zellij plugins receive native events:
TabUpdate,PaneUpdate,ModeUpdate - A plugin can react to pane moves, tab changes, and layout changes in real-time
- It can update ALL tab names (not just the focused tab) via
rename_tab - No shell hooks needed for tab naming — the plugin handles it entirely
- Fish hooks can focus solely on pane-level concerns (pane name, pane color)
Design considerations
- Research Zellij plugin API for tab/pane events
- Determine how to detect pane project (read pane name set by fish, or query cwd?)
- Prototype plugin that listens to layout changes and renames tabs
- Decide whether to keep fish-based pane naming or move everything to the plugin
- Package the plugin with Nix
Reference
- Zellij plugin docs: https://zellij.dev/documentation/plugins
- Current fish implementation:
modules/home/programs/fish/init/zellij.fish - Tab bar plugin already in use:
~/.config/zellij/plugins/tab-bar.wasm