Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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 the nixos-unified framework with autowire for automatic module discovery and composition.

Repository Structure

flake.nix                          # Entry point, declares all inputs
  → modules/flake/toplevel.nix     # Flake-level glue (formatter, packages)
  → modules/{home,nixos}/          # Reusable modules (autowired)
  → mixins/{home,nixos}/           # Platform/version-specific configs
  → configurations/{home,nixos}/   # Per-host final configurations
  • modules/ — Core reusable NixOS/Home Manager modules
  • mixins/ — Platform-specific (linux/darwin) and version-specific configuration layers
  • configurations/ — Per-host configs that compose modules + mixins
  • overlays/ — Nixpkgs overlays and custom packages
  • secrets/ — SOPS-encrypted secrets (age keys, per-host)
  • private/ — Host-specific private configs (gitignored, present on deployed machines)

Architecture

Autowiring Pattern

Most default.nix files contain a single line:

{flake, ...}: flake.inputs.autowire.default ./.

This auto-discovers and composes all .nix files in the same directory into a merged NixOS/Home Manager module. Adding a new .nix file to an autowired directory automatically includes it — no manual imports needed.

Layered Composition

Configuration is built up in layers:

  1. flake.nix — Declares all inputs; outputs are generated via nixos-unified
  2. modules/flake/ — Flake-level glue (formatter, packages, apps). Each .nix file here is a flake-parts module auto-included by the framework
  3. modules/{home,nixos}/ — Reusable Home Manager / NixOS modules, autowired
  4. mixins/{home,nixos}/ — Platform-specific layers (linux, darwin) and host/container-specific config
  5. configurations/{home,nixos}/ — Per-host final configurations that compose modules + mixins

Custom Options

modules/home/options.nix defines the me option set used throughout Home Manager modules:

  • me.username
  • me.fullname
  • me.email

These are set in each host’s configuration file (e.g., configurations/home/yjpark.nix).

Overlays and Custom Packages

overlays/default.nix autowires from ./, picking up packages.nix in the overlays directory. Custom packages are automatically available as nixpkgs overlays throughout the configuration.

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:

UsernameUsed OnBase ConfigState Version
yjparkPhysical hostsconfigurations/home/yjpark.nix25.05
yjContainersconfigurations/home/yj.nix26.05

Host and Container Mixins

Host-specific configurations live in:

  • mixins/home/hosts/ — One .nix file per physical host
  • mixins/home/containers/ — One .nix file per container

Adding a .nix file to either directory automatically registers a new host or container via the autowire pattern — no manual imports needed.

Activation Logic

modules/flake/activate-home.nix defines how mise run _activate-home resolves the correct Home Manager configuration:

  1. Matches current hostname against known hosts → activates yjpark@<host>
  2. Matches current hostname against known containers → activates yj@<host>
  3. Falls back to <username>@ for unknown hosts (the trailing @ is required by nixos-unified for bare username fallback configs)

Configuration Generation

modules/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 matching secret.*
  • The .sops.yaml file 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

InputPurpose
nixpkgsnixos-unstable — the primary package set
home-managerUser environment management
flake-partsFlake composition framework
nixos-unifiedOpinionated wrapper around flake-parts for NixOS + HM
autowireCustom fork (github:yjpark/autowire.nix) — auto-discovers and composes .nix files in a directory

Software

InputPurpose
sops-nixDeclarative secret management with SOPS + age
nixvimNeovim configured via Nix
floxDeveloper environments
nixidyKubernetes GitOps (k8s manifest generation)
nixos-vscode-serverVS Code remote server support on NixOS
solaarLogitech device manager
llm-agentsLLM agent tools

Desktop / UI

InputPurpose
claude-desktopClaude desktop application
niriWayland compositor
xremap-flakeKey remapper for Wayland/X11
antigravity(UI tool)
jjuiTUI for the jj (Jujutsu) VCS

Active Tasks

In Progress

Todo

Done (24)

All Tasks

Features

Tasks

Bugs

Drafts

Features

Project-wise pane configuration in Zellij (flakes-1zlj)

StatusDone
TypeFeature
Prioritynormal

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 $PWD at shell init as ZELLIJ_SESSION_PROJECT — the “home” project for the session
  • Project name: Git repo root basename (git rev-parse --show-toplevel | basename), fallback to basename $PWD

Pane Name Behavior

ConditionPane 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:

  1. Write/update own entry in the state file
  2. Read all entries, collect unique project names
  3. If only one unique project: rename-tab "{project}" (same as today)
  4. If multiple: rename-tab "{project1} | {project2} | ..."

Cleanup

  • fish_exit event: 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 PWD
  • ZELLIJ_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> command when in foreign project, just command otherwise
  • Tab names: aggregated unique projects in pane order, joined with |
  • Cleanup on fish_exit removes pane entry and rebuilds tab name

Deploy OneCLI as credential proxy for yolo container (flakes-2aqm)

StatusDone
TypeFeature
Prioritynormal

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:

  1. Wrong API key type — gateway expects agent tokens (aoc_), not user keys (oc_)
  2. CA trust — appended OneCLI CA directly to active CA bundles instead of using security.pki (which fails at Nix build time)
  3. 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)

StatusDone
TypeFeature
Prioritynormal

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.withPlugins with the Cloudflare DNS plugin (hash pinned to sha256-bL1cpMvDogD/...)
  • Added Caddyfile generation: HTTPS + HTTP fallback blocks, per-container host_regexp matchers
  • Added sops.secrets."cloudflare-caddy-env" declaration pointing to ./secrets/cloudflare-caddy.txt
  • Added systemd.services.caddy.serviceConfig.EnvironmentFile for 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)

StatusDone
TypeFeature
Prioritynormal

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)

StatusDone
TypeFeature
Prioritynormal

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 templates directive
  • JS fetches services.json at 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>.incus serving the hub HTML + services.json
  • Strip X-Frame-Options and rewrite Content-Security-Policy headers 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-sync regenerates both Caddy config and services.json
  • ingress command unchanged

Tasks

  • Extend generate-ingress-config to read /proc/<pid>/cwd and write services.json
  • Create hub HTML template (sidebar + iframe layout, JS service loader, iframe error fallback)
  • Add Caddy route for hub.<hostname>.incus serving 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 -tlnp with 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>.incus internally
  • Sync button triggers generate-ingress-config via Python API, shows ingress status output in dismissable modal
  • Favicon proxy at /api/icon/<port> fetches favicons from services (tries /favicon.ico then parses HTML <link rel=icon>), falls back to colored letter icons
  • Header stripping: removes X-Frame-Options and Content-Security-Policy on proxied routes for iframe embedding
  • Host ingress: added <container>-hub route to incus-ingress.nix for external access

Files changed:

  • mixins/nixos/container/ingress.nix — hub HTML, sync API, enhanced generate-ingress-config
  • mixins/nixos/services/incus-ingress.nix — hub route for host-level Caddy

Change Zellij pane background color based on project path (flakes-dkc4)

StatusDone
TypeFeature
Prioritynormal

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):

IndexHexTint
0#2e1a1aRed
1#1a2e1aGreen
2#1a1a2eBlue
3#2e2e1aYellow
4#2e1a2eMagenta
5#1a2e2eCyan
6#2e241aOrange
7#1a2e24Teal

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_color function
  • 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 tints
  • zellij_project_color_index: djb2-style hash mod palette size, returns stable integer index
  • zellij_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

Zellij WASM plugin for dynamic tab naming (flakes-je55)

StatusDraft
TypeFeature
Prioritynormal

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-layout parsing 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)

StatusArchived
TypeFeature
Prioritynormal

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.extraConfig option to modules/home/options.nix
  • Updated modules/flake/home-configs.nix to support directory-based host mixins (falls back to /{host}.nix if no directory exists)
  • Created mixins/home/hosts/a13/ and mixins/home/hosts/edger/ with default.nix + niri.extras.kdl
  • Rewrote niri config module to concatenate config.common.kdl + config.me.niri.extraConfig
  • Deleted extras.a13.kdl, extras.edger.kdl, and niri.justfile from old location

Add mdBook documentation site (flakes-px5o)

StatusDone
TypeFeature
Prioritynormal

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

Zellij per-project auto-layouts on cd (flakes-u0yw)

StatusDone
TypeFeature
Prioritynormal

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

  1. .zellij-layout.kdl file in project root (inline layout, highest priority)
  2. ZELLIJ_LAYOUT_{USERNAME} env var (e.g., ZELLIJ_LAYOUT_yj=claude_beans-terminal) — only if $USER matches
  3. ZELLIJ_LAYOUT env var — generic fallback
  4. 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:

  1. Not in Zellij? → skip
  2. Resolve project root (existing git root detection)
  3. Determine layout (resolution order above)
  4. Guard: check __zellij_opened_layouts fish global var — if project root already in list → skip
  5. zellij action new-tab --layout {layout_file} --cwd {project_root}
  6. 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.kdl preset layout
  • Create claude_beans-terminal.kdl preset layout
  • Extend zellij.fish PWD hook with layout resolution and auto-open logic
  • Test: cd to project with ZELLIJ_LAYOUT set → zz applies layout to current tab
  • Test: stacked layout, tab/status bars, clear buffer all working
  • Test: ZELLIJ_LAYOUT_yj overrides ZELLIJ_LAYOUT for user yj
  • Test: .zellij-layout.kdl in project root takes priority (not yet tested)

Tasks

Disable terminal bell sound (flakes-0u0f)

StatusDone
TypeTask
Prioritynormal

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)

StatusDone
TypeTask
Prioritynormal

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)

StatusDone
TypeTask
Prioritynormal

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)

StatusDone
TypeTask
Prioritynormal

Update fish config to use abbr –function for j so it expands inline to ‘mise run’ or ‘just’ based on current directory

Tidy up the shell title when running zellij (flakes-2fpy)

StatusArchived
TypeTask
Prioritynormal
Tagstweaks

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_title already 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) and zellij_update_panename_cmd (preexec event hook) — these were driving zellij’s verbose <cwd> | <command> terminal title format. Kept zellij_update_tabname call 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)

StatusArchived
TypeTask
Prioritynormal

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" to configurations/home/yjpark.nix
  • Added home.stateVersion = "26.05" to configurations/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/.gitkeep for 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)

StatusArchived
TypeTask
Prioritynormal

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 configDir param, mixinDir now serves both roles
  • Rewrote : reads host names from hosts/ and containers/ dirs; fixed fallback key (removed trailing @)
  • Removed version imports from configurations/home/yjpark.nix and configurations/home/yj.nix

Verified: nix eval .#homeConfigurations --apply 'x: builtins.attrNames x' returns expected keys.

Setup code on incus (flakes-6zwu)

StatusIn Progress
TypeTask
Prioritynormal
Tagstools, security
  • https://github.com/mensfeld/code-on-incus

Resolve username from host/container dir in activate-home.nix (flakes-7aac)

StatusArchived
TypeTask
Prioritynormal

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 knownHosts with separate hosts and containers lists; 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)

StatusArchived
TypeTask
Priorityhigh
Tagstools

For neovim, zed, vscode

Automate OneCLI CA push to containers on boot (flakes-aurl)

StatusDone
TypeTask
Prioritynormal

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:

  1. Fetch OneCLI CA from http://10.100.0.1:10254/api/gateway/ca
  2. Push to each running agent container via incus file push
  3. 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-secrets service to onecli-init-ca-and-secrets (systemd service + script name)
  • Add wantedBy and after incus.service to systemd service
  • Add onecli-init-ca-and-secrets shell script on host (starts the systemd service via sudo) for easy manual use
  • Update onecli-check-proxy.bash error messages to suggest running onecli-init-ca-and-secrets on the host
  • Add CA bundle verification to check script: detect broken TLS (e.g. curl to github.com fails but --noproxy works) and surface a clear diagnosis
  • Update _switch-host in mise.toml to reference new service name
  • Verify build with mise run build-host

Summary of Changes

  1. mixins/nixos/services/onecli.nix — Renamed service onecli-seed-secretsonecli-init-ca-and-secrets. Added CA push logic (fetch from API, push to containers, append to CA bundles with symlink handling + idempotency). Added wantedBy = ["multi-user.target"] and after = ["incus.service"] so it runs on every boot.
  2. mise.toml — Updated _switch-host and restart-onecli tasks to reference new service name.
  3. mixins/home/host/linux/scripts/incus/onecli-init-ca-and-secrets.bash — New host script for easy manual triggering.
  4. mixins/home/container/scripts/onecli-check-proxy.bash — Updated error messages to point to onecli-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)

StatusArchived
TypeTask
Prioritynormal

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)

StatusDone
TypeTask
Prioritynormal

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)

Unify terminal theme to Tokyo Night (flakes-hncv)

StatusDone
TypeTask
Prioritynormal

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_scheme from Gruvbox Dark (Gogh) to Tokyo Night in mixins/home/gui/linux/wezterm/wezterm.lua
  • Zellij pane colors: Updated palette in modules/home/programs/fish/init/zellij.fish from 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.

Set up firewalld as NixOS service and migrate existing firewall rules (flakes-jvmx)

StatusArchived
TypeTask
Prioritynormal

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 nftablesnetworking.nftables.enable = true is 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 extraCommands in mixins/nixos/lan/*/firewall.nix inject 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 = true in 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:

FileCurrent rulesMigration approach
mixins/nixos/lan/my/firewall.nixOpen 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.nixSame as aboveSame zone approach
mixins/nixos/dev/ports.nixTCP ranges 3000-3999, 8000-8999, 29000-29999Add port ranges to appropriate zone
modules/nixos/services/airplay.nixTCP 7000,7001,7100 + UDP 6000,6001,7011firewalld service definition or rich rules
modules/nixos/services/clash-verge.nixTCP ports for clashfirewalld service or zone rules
modules/nixos/services/zerotierone.nixUDP port for zerotierfirewalld service or zone rules
mixins/nixos/ext4/k3s.ext4.nixk3s TCP ports + rangesfirewalld zone for k3s
mixins/nixos/zfs/k3s.zfs.nixk3s TCP ports + rangesfirewalld zone for k3s
configurations/nixos/alienware-13/ports.nixTCP 2342 (photoprism)firewalld service or zone rule

3. Configure incus integration

  • Ensure incusbr0 bridge 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/8 traffic with broader access
  • incus zone — for incusbr0, managed by incus

Acceptance Criteria

  • services.firewalld is enabled and networking.firewall is no longer used
  • All previously open ports/ranges remain accessible in the correct contexts
  • LAN-scoped rules (10.0.0.0/8 broad 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 fmt passes 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)

StatusTodo
TypeTask
Prioritynormal
Tagstools

Check MCPVault, to see whether it’s a better option for the markdowns (flakes-k3pr)

StatusTodo
TypeTask
Prioritynormal

Update CLAUDE.md to reflect current state (flakes-nyvs)

StatusArchived
TypeTask
Prioritynormal

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 …” to include in what will be committed) .beans/flakes-nyvs–update-claudemd-to-reflect-current-state.md

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)

StatusArchived
TypeTask
Priorityhigh
Tagstools

Add edit-in-place script (flakes-oh4v)

StatusDone
TypeTask
Prioritynormal

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)

StatusDone
TypeTask
Prioritynormal

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

  1. mixins/nixos/services/onecli.nix — Added GITHUB_TOKEN secret config with *.github.com host pattern and Authorization: token {value} injection
  2. mixins/home/container/git.nix — New file: rewrites SSH GitHub URLs to HTTPS (routes through OneCLI proxy) and sets GIT_TERMINAL_PROMPT=0
  3. mixins/nixos/services/secrets/onecli-secrets.txt — User needs to add real token via sops

Refactor ai.nix into ai/ directory (flakes-ojyn)

StatusDone
TypeTask
Prioritynormal

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.nixai/ directory
  • ai/default.nix: autowire pattern for extensibility
  • ai/ai.nix: package declarations (bun, nodejs_25)
  • ai/installs/default.nix: gatherScriptPackages_bash
  • Moved scripts/installs/install-claude-mcp-context7.bash and install-claude-mcp-verena.bashai/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)

StatusDone
TypeTask
Prioritynormal

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 selected bg: "bright black""#3a3a3a"
  • revset completion bg: "black""#1a1a1a"
  • revset completion dimmed: same fix as dimmed

Config verified at ~/.config/jjui/config.toml after just activate-home.

Integrate Home Manager as a NixOS module (flakes-rg27)

StatusArchived
TypeTask
Prioritynormal

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 = true and useUserPackages = true
  • Passes extraSpecialArgs with the flake argument so home modules get their expected {flake, ...} argument
  • Wires home-manager.users.yjpark to import configurations/home/yjpark.nix plus any host-specific mixin from mixins/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)

StatusArchived
TypeTask
Prioritynormal

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 tasks and mise run vcs-status

Full jjui theme with terminal-independent hex colors (flakes-sk2r)

StatusDone
TypeTask
Prioritynormal

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.

Inhibit idle/sleep during audio/video playback (flakes-va02)

StatusDone
TypeTask
Prioritynormal

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-inhibit package to mixins/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)

StatusArchived
TypeTask
Prioritynormal

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 reading configurations/nixos/ dirs, with optional per-host mixins from mixins/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 plain yjpark config when hostname isn’t in known NixOS hosts
  • Deleted all per-host configurations/home/yjpark@<host>.nix files (pc, edger, alienware-13, hp-g1, gpd-p2)
  • Key fix: used lib.mkForce on whole legacyPackages attrset (not just homeConfigurations sub-key) to override autoWire’s perSystem definition

Add rtk-rewrite.sh hook to claude module with home-manager linking (flakes-y887)

StatusDone
TypeTask
Prioritynormal

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.nix linking it to ~/.claude/hooks/rtk-rewrite.sh with executable=true
  • Autowire in claude/default.nix picks up the new hooks/ subdirectory automatically — no other files changed

Replace CopyQ with cliphist (Wayland-native clipboard manager) (flakes-yyox)

StatusArchived
TypeTask
Prioritynormal

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+V keybinding in niri config to open fuzzel clipboard history picker
  • Added xdg.configFile for television cable channel in modules/home/programs/television.nix
  • Created modules/home/programs/fish/functions/clip.fish for tv-based clipboard selection
  • Added tc abbreviation in modules/home/programs/fish/abbrs.nix

Add mdbook-beans tasks section to docs (flakes-zvh8)

StatusDone
TypeTask
Prioritynormal

Integrate mdbook-beans preprocessor into the flakes documentation, mirroring the litmus project setup. Adds kanban and all-tasks pages.

Summary of Changes

  • Added mdbook-beans flake input to flake.nix
  • Updated docs/book.toml with beans preprocessor config and sidebar CSS
  • Created docs/src/beans/tasks.md (all tasks) and docs/src/beans/kanban.md (active tasks)
  • Copied docs/src/beans-sidebar.css from litmus for bean styling
  • Updated docs/src/SUMMARY.md with Kanban and All Tasks links
  • Updated modules/flake/docs.nix to include mdbook-beans and .beans data in build
  • Updated mise.toml docs tasks to use nix (ensuring mdbook-beans is available)

Bugs

Fix Ctrl+Shift+C in wezterm clobbering zellij clipboard (flakes-5oyz)

StatusArchived
TypeBug
Prioritynormal

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.

Hub toolbar URL tracking for iframe navigation (flakes-dya3)

StatusTodo
TypeBug
Prioritynormal

The ingress hub page toolbar should display the current URL of the active iframe as the user navigates within it. Current implementation uses same-origin proxy (/s//) + setInterval polling but it’s not working reliably.

Context

The hub page (mixins/nixos/container/ingress.nix) embeds services in iframes. The toolbar at the top should show the current URL of the iframe content.

Current approach (not working)

  1. Caddy proxy routes: handle_path /s/<port>/* in hub config proxies to localhost:<port>, making iframe same-origin
  2. Iframe src uses /s/<port>/ instead of cross-origin http://<port>.yolo.incus
  3. setInterval polls frame.contentWindow.location every 500ms
  4. Translates proxy path back to real service URL for display

Known issues

  • Apps with absolute paths (e.g. <a href="/dashboard">) break under path-based proxy — the iframe navigates to /dashboard on the hub domain instead of /s/<port>/dashboard, which 404s
  • The proxy routes are generated dynamically by generate-ingress-config (needs ingress-sync after rebuild)
  • Needs investigation: may need to verify Caddy config is actually being regenerated with the HUB_ROUTES

Alternative approaches to consider

  • Inject postMessage script via response body rewriting (complex, no native Caddy support)
  • Use a sub-path rewriting middleware or Caddy plugin
  • Accept cross-origin limitation and only show base URL (simplest)
  • Proxy all traffic through the Python sync API server (single-threaded bottleneck)

Files

  • mixins/nixos/container/ingress.nix — hub HTML, Caddy config generation, Python API server

Fix mise.toml var args bug (flakes-m3r8)

StatusArchived
TypeBug
Prioritynormal

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)

StatusDone
TypeBug
Prioritynormal

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 sending Proxy-Authorization (fixed by http.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, added proxyAuthMethod = basic
  • mixins/nixos/services/onecli.nix — changed GITHUB_TOKEN to Basic auth format with base64 encoding at seed time

Drafts

Zellij WASM plugin for dynamic tab naming (flakes-je55)

StatusDraft
TypeFeature
Prioritynormal

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-layout parsing 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