Personal configuration files managed with KCL and dotter.
- Shell: Zsh (Oh My Zsh), Nushell, Fish
- Terminal: Ghostty
- Multiplexer: Tmux with theme support
- Editor: Neovim with LSP, plugins, and profile variants (default/work/personal)
- CLI Tools: Starship, Atuin, Carapace, Zoxide, Jujutsu, iamb
- AI Assistants: OpenCode, Claude Code, Kiro (MCP server configs, commands, skills)
- Window Management: AeroSpace (macOS), Hyprland (Linux)
- Package Managers: Homebrew (macOS), pnpm, npm
git clone https://github.com/zenibako/dotfiles.git
cd dotfiles
cp local.toml.example .dotter/local.tomlEdit .dotter/local.toml to set your name, email, profile, platform, and theme.
sh init.shThis installs dependencies, generates configs from KCL, and deploys via dotter.
./deploy.sh # KCL generation + dotter deploy
./deploy.sh -f # Force overwrite changed targetsAlways use ./deploy.sh rather than bare dotter deploy — KCL must regenerate global.toml before dotter reads it.
Select ONE profile, ONE platform, ONE theme in .dotter/local.toml:
packages = ["work", "mac", "monokai"]- work / personal — both inherit from default via
depends - Themes: monokai, nightowl, tokyonight
Secret injection is split in two:
- Seeding (explicit):
scripts/secrets/seed-secrets.shbuilds a local cache from Proton Pass (pass-cli, parallel fetches) or macOS Keychain. Run it on a fresh machine, after rotating a secret, or when a deploy warns the cache is stale (>72h).--forcerebuilds,--statusshows freshness. - Injection (every deploy):
post_deploy.shconsumes whichever cache exists and injects values into deployed configs. It never builds the cache inline — deploys stay fast and never block on vault prompts. (Exception: an interactive deploy with no cache at all seeds once automatically.)
Never commit secrets to local.k/local.toml.
security add-generic-password -s KEY_NAME -a dotfiles -w SECRET_VALUE -U login.keychainsrc/ # Source of truth (KCL package root; contains kcl.mod)
├── kcl.mod # KCL package manifest (makes `import local` resolve to local.k)
├── main.k # KCL entrypoint — imports every app module and assembles config
├── profiles.k # Profile/package definitions + dotter file→target mappings
├── local.k # Per-machine overrides (gitignored; created from local.k.example)
├── local.k.example # Template for local.k
├── packages.k # Shared top-level modules live flat at src root:
├── themes.k # packages, themes, env, completions, profiles.
├── env.k # (Not apps — imported as `import <name> as <name>_mod`.)
├── completions.k #
├── _shared/ # Reusable KCL schemas, MCP helpers, templates
│
│ # ── Apps: one folder per tool, each with a config.k ──
├── atuin/config.k # Every app follows the same shape:
├── ghostty/config.k # src/<app>/config.k defines a top-level `<app> = …`
├── jj/config.k # binding, and main.k pulls it in with
├── tmux/config.k # `import <app> as <app>_mod`. Non-KCL assets for the
├── zsh/config.k # app (scripts, READMEs, templates like zsh/zshrc,
├── kiro/config.k # ghostty/shaders) sit alongside config.k in the folder.
├── opencode/config.k #
├── claude/ # Nested app: two sub-apps, each its own config.k
│ ├── code/config.k # → `import claude.code as claude_code`
│ └── desktop/config.k# → `import claude.desktop as claude`
├── nvim/ # Neovim configs (default/work/personal profiles)
├── gnupg/ # GPG agent config (template; no config.k)
└── ... # aerospace, iamb, gitlogue, pnpm, starship, gitconfig, …
scripts/ # Deploy pipeline scripts
├── pre_deploy.sh # KCL generation + validation (dotter hook)
├── post_deploy.sh # Secret injection + post-deploy checks (dotter hook)
└── dotter/ # Shared helpers and validators
├── lib.sh # Common functions (resolve_python, run_with_timeout, etc.)
├── generate_from_kcl.py # Converts KCL JSON output to dotter global.toml + configs
├── validate_*.py # Config validation scripts
└── validate_schema.sh
.dotter/ # Generated output (gitignored)
├── global.toml # Generated by KCL pipeline
├── local.toml # Per-machine config (user creates)
├── pre_deploy.sh # Symlink → ../scripts/pre_deploy.sh
└── post_deploy.sh # Symlink → ../scripts/post_deploy.sh
out/ # Generated config files (gitignored, written by KCL)
deploy.sh # Deploy wrapper (creates .dotter/, runs pipeline)
init.sh # First-time machine setup
- KCL (
src/main.k) evaluates profiles, variables, and templates into JSON - Python (
scripts/dotter/generate_from_kcl.py) converts JSON into.dotter/global.toml+out/configs - Dotter reads
global.toml+local.toml, deploys files to~/.config/etc. - Post-deploy injects secrets from Keychain, validates Lua/LSP/schemas
- macOS: Full support (Homebrew, AeroSpace, Ghostty)
- Linux: Fedora (dnf), Arch (pacman), Debian/Ubuntu (apt), openSUSE (zypper), Alpine (apk)
Personal configurations — use at your own discretion.