Merge remote-tracking branch 'origin/master'

# Conflicts:
#	home_config/ghostty/config
#	home_root/.zshrc
This commit is contained in:
2026-07-09 18:04:00 -07:00
27 changed files with 1494 additions and 1051 deletions
+5 -1
View File
@@ -2,4 +2,8 @@
.config/btop
.config/neofetch
/.aider*
__pycache__/
home_config/nvim/lazy-lock.json
__pycache__/
*.bak
# zellij web-pilot auth tokens — credentials, never commit
home_config/zellij/pilot-tokens/
+80
View File
@@ -0,0 +1,80 @@
# dotfiles
Personal dotfiles. Configs are organized by where they get linked:
| Folder | Links into | Examples |
| -------------- | ------------ | --------------------------------- |
| `home_root` | `~` | `.zshrc`, `.wezterm.lua`, `.nanorc` |
| `home_config` | `~/.config` | `nvim`, `zellij`, `ghostty`, `aerospace` |
| `windows` | Windows-only | `windows-terminal/settings.json` |
| `lk-installers`| n/a | helper scripts to install tooling |
## Linux / macOS (GNU stow)
One-shot, host-aware:
```bash
./link-dotfiles # link only (installs stow if missing)
./link-dotfiles --apps # fresh box: install all CLI tools, then link
```
It detects the host (macOS vs Linux), installs [`stow`](https://www.gnu.org/software/stow/)
if missing (Homebrew on macOS; apt/dnf/pacman on Linux), then runs
`stow home_root` and `stow --target=$HOME/.config home_config`. Re-running is
safe — stow is idempotent.
### Installing the tools
The configs assume a handful of CLI tools (`bat`, `fd`, `fzf`, `zoxide`,
`zellij`, `nvim`, `btop`, `htop`, `tldr`, `fastfetch`, plus the `fzf-git.sh`
helper). One host-aware installer covers them:
```bash
./lk-installers/install-apps # macOS -> Homebrew; Linux -> apt + upstream
```
On macOS it bootstraps Homebrew if absent. It's idempotent — re-running only
fills gaps. `./link-dotfiles --apps` just runs this first, then links.
The zsh prompt and plugins (zinit, Powerlevel10k, autosuggestions,
syntax-highlighting, completions, vi-mode, fzf-tab) **self-install** from
`.zshrc` on first shell start, so they're not part of `install-apps`.
## Windows (PowerShell)
`stow` doesn't run natively on Windows, so use the PowerShell equivalent. It
mirrors stow by creating **junctions** for directories and **symlinks/hardlinks**
for files — none of which require administrator rights:
```powershell
pwsh -File .\link-dotfiles.ps1
```
- Re-running is safe: already-correct links are skipped.
- Any real file/dir that would be overwritten is moved aside to `<name>.bak`.
- Preview without changing anything: `pwsh -File .\link-dotfiles.ps1 -DryRun`
The repo stays the source of truth — edit files under `home_root` /
`home_config` and the linked locations update live.
### Windows Terminal
`windows/windows-terminal/settings.json` is linked into the Terminal package
folder (`...\Microsoft.WindowsTerminal_*\LocalState\settings.json`) by
`link-dotfiles.ps1`. Because it's linked, changes you make in the Terminal UI
write straight back into this repo. The settings include the **Australis**
color scheme and the **VictorMono Nerd Font Mono** profile font; install the
font (see below) so glyphs render.
## Prompt
**zsh uses [Powerlevel10k](https://github.com/romkatv/powerlevel10k)** — loaded
through zinit straight from `.zshrc`, with the instant-prompt preamble near the
top for fast startup. The theme config lives at `home_root/.p10k.zsh` (stowed to
`~/.p10k.zsh`); there's no separate installer — zinit fetches it on first shell
start.
PowerShell uses [starship](https://starship.rs/) (configured separately).
Both expect a **Nerd Font v3** (e.g. **VictorMono Nerd Font Mono**) installed and
selected in your terminal for glyphs to render.
+45 -30
View File
@@ -1,38 +1,53 @@
# Font
font-family = VictorMono Nerd Font
font-size = 16
font-style = Regular
font-style-bold = Bold
font-style-italic = Italic
font-style-bold-italic = Bold Italic
adjust-cell-height = 5%
# Ghostty configuration
# Docs: https://ghostty.org/docs/config
# Reload in-app without restarting: Cmd+Shift+,
# --- Font ---------------------------------------------------------------
# VictorMono Nerd Font (installed in ~/Library/Fonts). The "Mono" variant
# keeps glyphs strictly fixed-width, which is what you want in a terminal.
font-family = VictorMono Nerd Font Mono
font-size = 14
# Slightly heavier strokes render nicer on macOS Retina displays.
font-thicken = true
# Theme
# Victor Mono ships a gorgeous cursive italic — make sure it's used.
font-style-italic = Italic
# --- Theme --------------------------------------------------------------
# Australis (Aurora Australis) — a dark theme. Defined in
# ~/.config/ghostty/themes/australis (ported from the upstream WezTerm config).
theme = australis
# Window
window-padding-x = 10
window-padding-y = 10
window-padding-balance = true
background-opacity = 0.95
background-blur-radius = 20
macos-titlebar-style = tabs
# Cursor
cursor-style = bar
cursor-style-blink = true
# Behavior
scrollback-limit = 10000
# --- Cursor -------------------------------------------------------------
cursor-style = block
cursor-style-blink = false
mouse-hide-while-typing = true
copy-on-select = false
confirm-close-surface = false
# Shell integration
# --- Window -------------------------------------------------------------
window-padding-x = 8
window-padding-y = 6
# Keep padding color matched to the background for a clean look.
window-padding-balance = true
# Reopen with the same windows/tabs you left.
window-save-state = always
macos-titlebar-style = tabs
background-opacity = 0.97
# --- Clipboard / selection ---------------------------------------------
copy-on-select = clipboard
clipboard-trim-trailing-spaces = true
# --- macOS / shell behavior --------------------------------------------
# Let the left Option key send Alt (so Alt+f, Alt+b, etc. work in shells/
# editors); keep right Option for composing accented characters.
macos-option-as-alt = left
shell-integration = detect
shell-integration-features = cursor,sudo,title
# ssh-env + ssh-terminfo: on connect, propagate a compatible TERM and
# auto-install Ghostty's terminfo entry on the remote host (v1.2.0+), so
# remote apps render correctly without "unknown terminal type" errors.
shell-integration-features = cursor,sudo,title,ssh-env,ssh-terminfo
# Rendering
bold-is-bright = false
minimum-contrast = 1.1
# --- Misc ---------------------------------------------------------------
# Only prompt to close when a process is still running.
confirm-close-surface = true
scrollback-limit = 10000000
+18
View File
@@ -1,13 +1,22 @@
{
<<<<<<< HEAD
"LazyVim": { "branch": "main", "commit": "3f034d0a7f58031123300309f2efd3bb0356ee21" },
"blink.cmp": { "branch": "main", "commit": "4607923f60029f8cb28e6950a078f93fd33e1288" },
=======
"LazyVim": { "branch": "main", "commit": "ec5981dfb1222c3bf246d9bcaa713d5cfa486fbd" },
"blink.cmp": { "branch": "main", "commit": "49f211fe5d729df53df4c042d7c3464cf47d199e" },
>>>>>>> 00717500056db846954b09bcfac4ebb3f1aa84e6
"bufferline.nvim": { "branch": "main", "commit": "655133c3b4c3e5e05ec549b9f8cc2894ac6f51b3" },
"catppuccin": { "branch": "main", "commit": "5b5e3aef9ad7af84f463d17b5479f06b87d5c429" },
"conform.nvim": { "branch": "master", "commit": "f9ef25a7ef00267b7d13bfc00b0dea22d78702d5" },
"flash.nvim": { "branch": "main", "commit": "3c942666f115e2811e959eabbdd361a025db8b63" },
"friendly-snippets": { "branch": "main", "commit": "efff286dd74c22f731cdec26a70b46e5b203c619" },
"gitsigns.nvim": { "branch": "main", "commit": "7010000889bfb6c26065e0b0f7f1e6aa9163edd9" },
<<<<<<< HEAD
"grug-far.nvim": { "branch": "main", "commit": "2c7ef09353714bd4954f5459d9a7e2579a050dc7" },
=======
"grug-far.nvim": { "branch": "main", "commit": "5da116bc99a03e14be3b824e319f4e49c676af78" },
>>>>>>> 00717500056db846954b09bcfac4ebb3f1aa84e6
"lazy.nvim": { "branch": "main", "commit": "6c3bda4aca61a13a9c63f1c1d1b16b9d3be90d7a" },
"lazydev.nvim": { "branch": "main", "commit": "2367a6c0a01eb9edb0464731cc0fb61ed9ab9d2c" },
"lualine.nvim": { "branch": "master", "commit": "9fef261b53fbe3a2ef01ee9667f6fde064b1ed10" },
@@ -15,12 +24,21 @@
"mason.nvim": { "branch": "main", "commit": "fc98833b6da5de5a9c5b1446ac541577059555be" },
"mini.ai": { "branch": "main", "commit": "978ffc65c6b513fde9ef075326d34d89197f1ea5" },
"mini.icons": { "branch": "main", "commit": "ec61af6e606fc89ee3b1d8f2f20166a3ca917a36" },
<<<<<<< HEAD
"mini.pairs": { "branch": "main", "commit": "cd9d95e33645781f86ca5ffe0a6885a22d59f127" },
"noice.nvim": { "branch": "main", "commit": "0427460c2d7f673ad60eb02b35f5e9926cf67c59" },
"nui.nvim": { "branch": "main", "commit": "8d3bce9764e627b62b07424e0df77f680d47ffdb" },
"nvim-lint": { "branch": "master", "commit": "936197073214c26a347fb933c9459c8766376b23" },
"nvim-lspconfig": { "branch": "master", "commit": "fb733ac734249ccf293e5c8018981d4d8f59fa8f" },
"nvim-treesitter": { "branch": "master", "commit": "d26ce0126694283cf32bf1f4192ef37ef404c037" },
=======
"mini.pairs": { "branch": "main", "commit": "b90e36aa5ca5e0d825e77ad67aac22214a4d9096" },
"noice.nvim": { "branch": "main", "commit": "0427460c2d7f673ad60eb02b35f5e9926cf67c59" },
"nui.nvim": { "branch": "main", "commit": "8d3bce9764e627b62b07424e0df77f680d47ffdb" },
"nvim-lint": { "branch": "master", "commit": "93b8040115c9114dac1047311763bef275e752dc" },
"nvim-lspconfig": { "branch": "master", "commit": "401e50fae626c4707af12114b5ddb7bb9f4236a4" },
"nvim-treesitter": { "branch": "master", "commit": "85168f15808d89b0222313652b9d2777eda3cb08" },
>>>>>>> 00717500056db846954b09bcfac4ebb3f1aa84e6
"nvim-treesitter-textobjects": { "branch": "master", "commit": "9937e5e356e5b227ec56d83d0a9d0a0f6bc9cad4" },
"nvim-ts-autotag": { "branch": "main", "commit": "a1d526af391f6aebb25a8795cbc05351ed3620b5" },
"persistence.nvim": { "branch": "main", "commit": "166a79a55bfa7a4db3e26fc031b4d92af71d0b51" },
-136
View File
@@ -1,136 +0,0 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json
version: 2
final_space: true
console_title_template: "{{ .Shell }} in {{ .Folder }}"
blocks:
- type: prompt
alignment: left
segments:
- type: session
style: diamond
foreground: p:black
background: p:yellow
leading_diamond:
trailing_diamond:
template: " {{ if .SSHSession }}\ueba9 {{ end }}{{ .UserName }} "
- type: path
style: powerline
powerline_symbol:
foreground: p:white
background: p:orange
template: " \uea83 {{ path .Path .Location }} "
properties:
style: folder
- type: git
style: powerline
powerline_symbol:
foreground: p:black
foreground_templates:
- "{{ if or (.Working.Changed) (.Staging.Changed) }}p:black{{ end }}"
- "{{ if and (gt .Ahead 0) (gt .Behind 0) }}p:white{{ end }}"
- "{{ if gt .Ahead 0 }}p:white{{ end }}"
background: p:green
background_templates:
- "{{ if or (.Working.Changed) (.Staging.Changed) }}p:yellow{{ end }}"
- "{{ if and (gt .Ahead 0) (gt .Behind 0) }}p:red{{ end }}"
- "{{ if gt .Ahead 0 }}#49416D{{ end }}"
- "{{ if gt .Behind 0 }}#7A306C{{ end }}"
template: " {{ if .UpstreamURL }}{{ url .UpstreamIcon .UpstreamURL }} {{ end }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \uf044 {{ .Working.String }}{{ end }}{{ if .Staging.Changed }} \uf046 {{ .Staging.String }}{{ end }} "
properties:
branch_max_length: 25
fetch_status: true
fetch_upstream_icon: true
- type: root
style: powerline
powerline_symbol:
foreground: p:white
background: p:yellow
template: " \uf0e7 "
- type: status
style: diamond
foreground: p:white
background: p:blue
background_templates:
- "{{ if gt .Code 0 }}p:red{{ end }}"
leading_diamond: <transparent,background></>
trailing_diamond:
template: " {{ if gt .Code 0 }}\uf00d{{ else }}\uf00c{{ end }} "
properties:
always_enabled: true
- type: rprompt
segments:
- type: node
style: plain
foreground: p:green
background: transparent
template: "\ue718 "
properties:
display_mode: files
fetch_package_manager: false
home_enabled: false
- type: go
style: plain
foreground: p:blue
background: transparent
template: "\ue626 "
properties:
fetch_version: false
- type: python
style: plain
foreground: p:yellow
background: transparent
template: "\ue235 "
properties:
display_mode: files
fetch_version: false
fetch_virtual_env: false
- type: shell
style: plain
foreground: p:white
background: transparent
template: "in <p:blue><b>{{ .Name }}</b></> "
- type: time
style: plain
foreground: p:white
background: transparent
template: at <p:blue><b>{{ .CurrentDate | date "15:04:05" }}</b></>
tooltips:
- type: aws
tips:
- aws
style: diamond
foreground: p:white
background: p:orange
leading_diamond:
trailing_diamond:
template: " \ue7ad {{ .Profile }}{{ if .Region }}@{{ .Region }}{{ end }} "
properties:
display_default: true
- type: az
tips:
- az
style: diamond
foreground: p:white
background: p:blue
leading_diamond:
trailing_diamond:
template: " \uebd8 {{ .Name }} "
properties:
display_default: true
transient_prompt:
foreground: p:black
background: transparent
template: "<p:yellow,transparent>\ue0b6</><,p:yellow> {{ .Folder }} </><p:yellow,transparent>\ue0b0</> "
secondary_prompt:
foreground: p:black
background: transparent
template: "<p:yellow,transparent>\ue0b6</><,p:yellow> > </><p:yellow,transparent>\ue0b0</> "
palette:
black: "#262B44"
blue: "#4B95E9"
green: "#59C9A5"
orange: "#F07623"
red: "#D81E5B"
white: "#E0DEF4"
yellow: "#F3AE35"
-151
View File
@@ -1,151 +0,0 @@
#:schema https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json
console_title_template = '{{if .Root}}(Admin){{end}} {{.PWD}}'
version = 2
[palette]
black = '#222531'
bright_black = '#373b46'
blue = '#6388D8'
bright_blue = '#a4c4ff'
cyan = '#00b1a8'
bright_cyan = '#42dcd1'
green = '#16B866'
bright_green = '#51e08a'
magenta = '#9d78ff'
bright_magenta = '#d8adff'
red = '#ff491a'
bright_red = '#ff854f'
white = '#a9bcc3'
bright_white = '#cce7ec'
yellow = '#e1c631'
bright_yellow = '#FFE14E'
dark_30 = '#414751'
dark_40 = '#565f69'
dark_50 = '#6e7882'
dark_60 = '#86929d'
bright_70 = '#9daeb6'
bright_80 = '#b3cbcf'
bright_90 = '#cce7ec'
[[blocks]]
alignment = 'left'
type = 'prompt'
[[blocks.segments]]
type = 'os'
style = 'plain'
foreground = 'p:cyan'
template = '{{.Icon}} '
[[blocks.segments]]
foreground = 'p:dark_50'
style = 'plain'
template = '{{ .Path }} {{ if not .Writable}}<p:bright_red>󰌾</> {{end}}'
type = 'path'
[blocks.segments.properties]
style = 'agnoster'
[[blocks]]
alignment = 'left'
type = 'prompt'
[[blocks.segments]]
type = 'python'
foreground = 'p:blue'
background = "p:bright_black"
leading_diamond = ""
style = "diamond"
trailing_diamond = " "
template = "  {{ .Venv }} "
[blocks.segments.properties]
display_default = false
[[blocks.segments]]
foreground = 'p:bright_cyan'
background = "p:bright_black"
leading_diamond = ""
style = "diamond"
trailing_diamond = ""
template = " {{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }}<p:yellow>  </>{{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }}  {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }}  {{ .StashCount }}{{ end }} "
type = 'git'
[blocks.segments.properties]
branch_icon = ' '
commit_icon = ' '
merge_icon = ' '
no_commits_icon = ' '
rebase_icon = ' '
revert_icon = ' '
tag_icon = ' '
fetch_stash_count = true
fetch_status = true
fetch_upstream_icon = true
[[blocks]]
type = "prompt"
alignment = "right"
[[blocks.segments]]
foreground = 'p:green'
style = 'plain'
template = '{{ .FormattedMs }}'
type = 'executiontime'
[blocks.segments.properties]
style = 'austin'
[[blocks.segments]]
type = "time"
style = "plain"
foreground = "p:dark_30"
[blocks.segments.properties]
time_format = "3:04:05pm"
[[blocks.segments]]
type = "session"
style = "plain"
foreground = "p:dark_50"
template = "{{.UserName}}"
[[blocks.segments]]
type = "session"
style = "plain"
foreground = "p:cyan"
template = " {{ if .SSHSession }}󰄙 {{ else }}@{{ end }} "
[[blocks.segments]]
type = "session"
style = "plain"
foreground = "p:blue"
template = "{{.HostName}}"
[[blocks]]
type = 'prompt'
alignment = 'left'
newline = true
[[blocks.segments]]
type = 'text'
style = 'plain'
foreground_templates = [
"{{if gt .Code 0}}p:red{{end}}",
"{{if eq .Code 0}}p:bright_green{{end}}",
]
background = 'transparent'
template = ' '
[transient_prompt]
foreground_templates = [
"{{if gt .Code 0}}p:red{{end}}",
"{{if eq .Code 0}}p:bright_green{{end}}",
]
background = 'transparent'
template = ' '
[secondary_prompt]
foreground = 'p:bright_green'
background = 'transparent'
template = '❯❯ '
-26
View File
@@ -1,26 +0,0 @@
# The Fuck settings file
#
# The rules are defined as in the example bellow:
#
# rules = ['cd_parent', 'git_push', 'python_command', 'sudo']
#
# The default values are as follows. Uncomment and change to fit your needs.
# See https://github.com/nvbn/thefuck#settings for more information.
#
# rules = [<const: All rules enabled>]
# exclude_rules = []
# wait_command = 3
# require_confirmation = True
# no_colors = False
# debug = False
# priority = {}
# history_limit = None
# alter_history = True
# wait_slow_command = 15
# slow_commands = ['lein', 'react-native', 'gradle', './gradlew', 'vagrant']
# repeat = False
# instant_mode = False
# num_close_matches = 3
# env = {'LC_ALL': 'C', 'LANG': 'C', 'GIT_TRACE': '1'}
# excluded_search_path_prefixes = []
+131 -136
View File
@@ -1,5 +1,5 @@
//
// THIS FILE WAS AUTOGENERATED BY ZELLIJ, THE PREVIOUS FILE AT THIS LOCATION WAS COPIED TO: /home/lkraven/.config/zellij/config.kdl.bak
// THIS FILE WAS AUTOGENERATED BY ZELLIJ, THE PREVIOUS FILE AT THIS LOCATION WAS COPIED TO: /home/lkraven/.config/zellij/config.kdl.bak.1
//
keybinds clear-defaults=true {
@@ -247,6 +247,126 @@ keybinds clear-defaults=true {
bind "z" { ToggleFocusFullscreen; SwitchToMode "normal"; }
}
}
themes {
australis {
text_unselected {
base 204 231 236
background 65 71 81
emphasis_0 164 196 255
emphasis_1 22 184 102
emphasis_2 99 136 216
emphasis_3 66 220 209
}
text_selected {
base 230 250 255
background 99 136 216
emphasis_0 255 225 78
emphasis_1 22 184 102
emphasis_2 99 136 216
emphasis_3 255 133 79
}
ribbon_selected {
base 65 71 81
background 99 136 216
emphasis_0 81 224 138
emphasis_1 22 184 102
emphasis_2 225 198 49
emphasis_3 255 133 79
}
ribbon_unselected {
base 204 231 236
background 86 95 105
emphasis_0 81 224 138
emphasis_1 22 184 102
emphasis_2 99 136 216
emphasis_3 255 133 79
}
table_title {
base 169 188 195
background 34 37 49
emphasis_0 255 133 79
emphasis_1 22 184 102
emphasis_2 99 136 216
emphasis_3 255 73 26
}
table_cell_selected {
base 204 231 236
background 65 71 81
emphasis_0 255 225 78
emphasis_1 22 184 102
emphasis_2 99 136 216
emphasis_3 255 133 79
}
table_cell_unselected {
base 169 188 195
background 34 37 49
emphasis_0 255 73 26
emphasis_1 22 184 102
emphasis_2 99 136 216
emphasis_3 255 133 79
}
list_selected {
base 204 231 236
background 65 71 81
emphasis_0 255 225 78
emphasis_1 22 184 102
emphasis_2 99 136 216
emphasis_3 255 133 79
}
list_unselected {
base 169 188 195
background 34 37 49
emphasis_0 225 198 49
emphasis_1 22 184 102
emphasis_2 99 136 216
emphasis_3 255 133 79
}
frame_selected {
base 99 136 216
background 34 37 49
emphasis_0 255 73 26
emphasis_1 22 184 102
emphasis_2 225 198 49
emphasis_3 255 133 79
}
frame_highlight {
base 81 224 138
background 34 37 49
emphasis_0 255 133 79
emphasis_1 99 136 216
emphasis_2 225 198 49
emphasis_3 255 73 26
}
exit_code_success {
base 22 184 102
background 0
emphasis_0 255 73 26
emphasis_1 99 136 216
emphasis_2 225 198 49
emphasis_3 255 133 79
}
exit_code_error {
base 255 73 26
background 0
emphasis_0 22 184 102
emphasis_1 99 136 216
emphasis_2 225 198 49
emphasis_3 255 133 79
}
multiplayer_user_colors {
player_1 255 73 26
player_2 255 133 79
player_3 225 198 49
player_4 255 225 78
player_5 157 120 255
player_6 216 173 255
player_7 99 136 216
player_8 0 177 168
player_9 66 220 209
player_10 164 196 255
}
}
}
// Plugin aliases - can be used to change the implementation of Zellij
// changing these requires a restart to take effect
@@ -270,141 +390,9 @@ plugins {
// Plugins to load in the background when a new session starts
// eg. "file:/path/to/my-plugin.wasm"
// eg. "https://example.com/my-plugin.wasm"
themes {
australis {
text_unselected {
base 204 231 236 // #CCE7EC - Bright text
background 65 71 81 // #414751 - Dark 30
emphasis_0 164 196 255 // #A4C4FF - Bright blue
emphasis_1 22 184 102 // #16B866 - Green
emphasis_2 99 136 216 // #6388D8 - Blue
emphasis_3 66 220 209 // #42DCD1 - Bright cyan (was 255 133 79 - Bright red)
}
text_selected {
base 230 250 255 // #E6FAFF - Brighter white (was 204 231 236)
background 99 136 216 // #6388D8 - Blue
emphasis_0 255 225 78 // #FFE14E - Bright yellow
emphasis_1 22 184 102 // #16B866 - Green
emphasis_2 99 136 216 // #6388D8 - Blue
emphasis_3 255 133 79 // #FF854F - Bright red
}
ribbon_unselected {
base 204 231 236 // #CCE7EC - Bright white
background 86 95 105 // #565f69 - Dark 40 (was 65 71 81 - Dark 30)
emphasis_0 81 224 138 // #51E08A - Bright green
emphasis_1 22 184 102 // #16B866 - Green
emphasis_2 99 136 216 // #6388D8 - Blue
emphasis_3 255 133 79 // #FF854F - Bright red
}
ribbon_selected {
base 65 71 81 // #414751 - Dark 30
background 99 136 216 // #6388D8 - Blue
emphasis_0 81 224 138 // #51E08A - Bright green
emphasis_1 22 184 102 // #16B866 - Green
emphasis_2 225 198 49 // #E1C631 - Yellow
emphasis_3 255 133 79 // #FF854F - Bright red
}
table_title {
base 169 188 195 // #A9BCC3 - White
background 34 37 49 // #222531 - Black
emphasis_0 255 133 79 // #FF854F - Bright red
emphasis_1 22 184 102 // #16B866 - Green
emphasis_2 99 136 216 // #6388D8 - Blue
emphasis_3 255 73 26 // #FF491A - Red
}
table_cell_unselected {
base 169 188 195 // #A9BCC3 - White
background 34 37 49 // #222531 - Black
emphasis_0 255 73 26 // #FF491A - Red
emphasis_1 22 184 102 // #16B866 - Green
emphasis_2 99 136 216 // #6388D8 - Blue
emphasis_3 255 133 79 // #FF854F - Bright red
}
table_cell_selected {
base 204 231 236 // #CCE7EC - Bright white
background 65 71 81 // #414751 - Dark 30
emphasis_0 255 225 78 // #FFE14E - Bright yellow
emphasis_1 22 184 102 // #16B866 - Green
emphasis_2 99 136 216 // #6388D8 - Blue
emphasis_3 255 133 79 // #FF854F - Bright red
}
list_unselected {
base 169 188 195 // #A9BCC3 - White
background 34 37 49 // #222531 - Black
emphasis_0 225 198 49 // #E1C631 - Yellow
emphasis_1 22 184 102 // #16B866 - Green
emphasis_2 99 136 216 // #6388D8 - Blue
emphasis_3 255 133 79 // #FF854F - Bright red
}
list_selected {
base 204 231 236 // #CCE7EC - Bright white
background 65 71 81 // #414751 - Dark 30
emphasis_0 255 225 78 // #FFE14E - Bright yellow
emphasis_1 22 184 102 // #16B866 - Green
emphasis_2 99 136 216 // #6388D8 - Blue
emphasis_3 255 133 79 // #FF854F - Bright red
}
frame_selected {
base 99 136 216 // #6388D8 - Blue
background 34 37 49 // #222531 - Black
emphasis_0 255 73 26 // #FF491A - Red
emphasis_1 22 184 102 // #16B866 - Green
emphasis_2 225 198 49 // #E1C631 - Yellow
emphasis_3 255 133 79 // #FF854F - Bright red
}
frame_highlight {
base 81 224 138 // #51E08A - Bright green
background 34 37 49 // #222531 - Black
emphasis_0 255 133 79 // #FF854F - Bright red
emphasis_1 99 136 216 // #6388D8 - Blue
emphasis_2 225 198 49 // #E1C631 - Yellow
emphasis_3 255 73 26 // #FF491A - Red
}
exit_code_success {
base 22 184 102 // #16B866 - Green
emphasis_0 255 73 26 // #FF491A - Red
emphasis_1 99 136 216 // #6388D8 - Blue
emphasis_2 225 198 49 // #E1C631 - Yellow
emphasis_3 255 133 79 // #FF854F - Bright red
}
exit_code_error {
base 255 73 26 // #FF491A - Red
emphasis_0 22 184 102 // #16B866 - Green
emphasis_1 99 136 216 // #6388D8 - Blue
emphasis_2 225 198 49 // #E1C631 - Yellow
emphasis_3 255 133 79 // #FF854F - Bright red
}
multiplayer_user_colors {
player_1 255 73 26 // #FF491A - Red
player_2 255 133 79 // #FF854F - Bright red
player_3 225 198 49 // #E1C631 - Yellow
player_4 255 225 78 // #FFE14E - Bright yellow
player_5 157 120 255 // #9D78FF - Magenta
player_6 216 173 255 // #D8ADFF - Bright magenta
player_7 99 136 216 // #6388D8 - Blue
player_8 0 177 168 // #00B1A8 - Cyan
player_9 66 220 209 // #42DCD1 - Bright cyan
player_10 164 196 255 // #A4C4FF - Bright blue
}
}
}
load_plugins {
}
// Use a simplified UI without special fonts (arrow glyphs)
// Options:
// - true
@@ -414,7 +402,7 @@ load_plugins {
// Choose the theme that is specified in the themes section.
// Default: default
//
theme "australis"
// Choose the base input mode of zellij.
@@ -590,9 +578,16 @@ default_mode "normal"
// Whether to show tips on startup
// Default: true
//
// show_startup_tips false
show_startup_tips false
// Whether to show release notes on first version run
// Default: true
//
// show_release_notes false
// Web-client (zellij web pilot) — force VictorMono Nerd Font for ligatures.
// NOTE: resolves against the CLIENT device's installed fonts (no @font-face
// serving like the ttyd seat); each device needs the font installed.
web_client {
font "VictorMono Nerd Font"
}
-452
View File
@@ -1,452 +0,0 @@
keybinds clear-defaults=true {
locked {
bind "Ctrl g" { SwitchToMode "normal"; }
}
pane {
bind "left" { MoveFocus "left"; }
bind "down" { MoveFocus "down"; }
bind "up" { MoveFocus "up"; }
bind "right" { MoveFocus "right"; }
bind "c" { SwitchToMode "renamepane"; PaneNameInput 0; }
bind "d" { NewPane "down"; SwitchToMode "normal"; }
bind "e" { TogglePaneEmbedOrFloating; SwitchToMode "normal"; }
bind "f" { ToggleFocusFullscreen; SwitchToMode "normal"; }
bind "h" { MoveFocus "left"; }
bind "i" { TogglePanePinned; SwitchToMode "normal"; }
bind "j" { MoveFocus "down"; }
bind "k" { MoveFocus "up"; }
bind "l" { MoveFocus "right"; }
bind "n" { NewPane; SwitchToMode "normal"; }
bind "p" { SwitchFocus; }
bind "Ctrl p" { SwitchToMode "normal"; }
bind "r" { NewPane "right"; SwitchToMode "normal"; }
bind "w" { ToggleFloatingPanes; SwitchToMode "normal"; }
bind "z" { TogglePaneFrames; SwitchToMode "normal"; }
}
tab {
bind "left" { GoToPreviousTab; }
bind "down" { GoToNextTab; }
bind "up" { GoToPreviousTab; }
bind "right" { GoToNextTab; }
bind "1" { GoToTab 1; SwitchToMode "normal"; }
bind "2" { GoToTab 2; SwitchToMode "normal"; }
bind "3" { GoToTab 3; SwitchToMode "normal"; }
bind "4" { GoToTab 4; SwitchToMode "normal"; }
bind "5" { GoToTab 5; SwitchToMode "normal"; }
bind "6" { GoToTab 6; SwitchToMode "normal"; }
bind "7" { GoToTab 7; SwitchToMode "normal"; }
bind "8" { GoToTab 8; SwitchToMode "normal"; }
bind "9" { GoToTab 9; SwitchToMode "normal"; }
bind "[" { BreakPaneLeft; SwitchToMode "normal"; }
bind "]" { BreakPaneRight; SwitchToMode "normal"; }
bind "b" { BreakPane; SwitchToMode "normal"; }
bind "h" { GoToPreviousTab; }
bind "j" { GoToNextTab; }
bind "k" { GoToPreviousTab; }
bind "l" { GoToNextTab; }
bind "n" { NewTab; SwitchToMode "normal"; }
bind "r" { SwitchToMode "renametab"; TabNameInput 0; }
bind "s" { ToggleActiveSyncTab; SwitchToMode "normal"; }
bind "Ctrl t" { SwitchToMode "normal"; }
bind "x" { CloseTab; SwitchToMode "normal"; }
bind "tab" { ToggleTab; }
}
resize {
bind "left" { Resize "Increase left"; }
bind "down" { Resize "Increase down"; }
bind "up" { Resize "Increase up"; }
bind "right" { Resize "Increase right"; }
bind "+" { Resize "Increase"; }
bind "-" { Resize "Decrease"; }
bind "=" { Resize "Increase"; }
bind "H" { Resize "Decrease left"; }
bind "J" { Resize "Decrease down"; }
bind "K" { Resize "Decrease up"; }
bind "L" { Resize "Decrease right"; }
bind "h" { Resize "Increase left"; }
bind "j" { Resize "Increase down"; }
bind "k" { Resize "Increase up"; }
bind "l" { Resize "Increase right"; }
bind "Ctrl n" { SwitchToMode "normal"; }
}
move {
bind "left" { MovePane "left"; }
bind "down" { MovePane "down"; }
bind "up" { MovePane "up"; }
bind "right" { MovePane "right"; }
bind "h" { MovePane "left"; }
bind "Ctrl h" { SwitchToMode "normal"; }
bind "j" { MovePane "down"; }
bind "k" { MovePane "up"; }
bind "l" { MovePane "right"; }
bind "n" { MovePane; }
bind "p" { MovePaneBackwards; }
bind "tab" { MovePane; }
}
scroll {
bind "e" { EditScrollback; SwitchToMode "normal"; }
bind "s" { SwitchToMode "entersearch"; SearchInput 0; }
}
search {
bind "c" { SearchToggleOption "CaseSensitivity"; }
bind "n" { Search "down"; }
bind "o" { SearchToggleOption "WholeWord"; }
bind "p" { Search "up"; }
bind "w" { SearchToggleOption "Wrap"; }
}
session {
bind "a" {
LaunchOrFocusPlugin "zellij:about" {
floating true
move_to_focused_tab true
}
SwitchToMode "normal"
}
bind "c" {
LaunchOrFocusPlugin "configuration" {
floating true
move_to_focused_tab true
}
SwitchToMode "normal"
}
bind "Ctrl o" { SwitchToMode "normal"; }
bind "p" {
LaunchOrFocusPlugin "plugin-manager" {
floating true
move_to_focused_tab true
}
SwitchToMode "normal"
}
bind "w" {
LaunchOrFocusPlugin "session-manager" {
floating true
move_to_focused_tab true
}
SwitchToMode "normal"
}
}
shared_except "locked" {
bind "Alt left" { MoveFocusOrTab "left"; }
bind "Alt down" { MoveFocus "down"; }
bind "Alt up" { MoveFocus "up"; }
bind "Alt right" { MoveFocusOrTab "right"; }
bind "Alt +" { Resize "Increase"; }
bind "Alt -" { Resize "Decrease"; }
bind "Alt =" { Resize "Increase"; }
bind "Alt [" { PreviousSwapLayout; }
bind "Alt ]" { NextSwapLayout; }
bind "Alt f" { ToggleFloatingPanes; }
bind "Ctrl g" { SwitchToMode "locked"; }
bind "Alt h" { MoveFocusOrTab "left"; }
bind "Alt i" { MoveTab "left"; }
bind "Alt j" { MoveFocus "down"; }
bind "Alt k" { MoveFocus "up"; }
bind "Alt l" { MoveFocusOrTab "right"; }
bind "Alt n" { NewPane; }
bind "Alt o" { MoveTab "right"; }
bind "Ctrl q" { Quit; }
}
shared_except "locked" "move" {
bind "Ctrl h" { SwitchToMode "move"; }
}
shared_except "locked" "session" {
bind "Ctrl o" { SwitchToMode "session"; }
}
shared_except "locked" "scroll" "search" "tmux" {
bind "Ctrl b" { SwitchToMode "tmux"; }
}
shared_except "locked" "scroll" "search" {
bind "Ctrl s" { SwitchToMode "scroll"; }
}
shared_except "locked" "tab" {
bind "Ctrl t" { SwitchToMode "tab"; }
}
shared_except "locked" "pane" {
bind "Ctrl p" { SwitchToMode "pane"; }
}
shared_except "locked" "resize" {
bind "Ctrl n" { SwitchToMode "resize"; }
}
shared_except "normal" "locked" "entersearch" {
bind "enter" { SwitchToMode "normal"; }
}
shared_except "normal" "locked" "entersearch" "renametab" "renamepane" {
bind "esc" { SwitchToMode "normal"; }
}
shared_among "pane" "tmux" {
bind "x" { CloseFocus; SwitchToMode "normal"; }
}
shared_among "scroll" "search" {
bind "PageDown" { PageScrollDown; }
bind "PageUp" { PageScrollUp; }
bind "left" { PageScrollUp; }
bind "down" { ScrollDown; }
bind "up" { ScrollUp; }
bind "right" { PageScrollDown; }
bind "Ctrl b" { PageScrollUp; }
bind "Ctrl c" { ScrollToBottom; SwitchToMode "normal"; }
bind "d" { HalfPageScrollDown; }
bind "Ctrl f" { PageScrollDown; }
bind "h" { PageScrollUp; }
bind "j" { ScrollDown; }
bind "k" { ScrollUp; }
bind "l" { PageScrollDown; }
bind "Ctrl s" { SwitchToMode "normal"; }
bind "u" { HalfPageScrollUp; }
}
entersearch {
bind "Ctrl c" { SwitchToMode "scroll"; }
bind "esc" { SwitchToMode "scroll"; }
bind "enter" { SwitchToMode "search"; }
}
renametab {
bind "esc" { UndoRenameTab; SwitchToMode "tab"; }
}
shared_among "renametab" "renamepane" {
bind "Ctrl c" { SwitchToMode "normal"; }
}
renamepane {
bind "esc" { UndoRenamePane; SwitchToMode "pane"; }
}
shared_among "session" "tmux" {
bind "d" { Detach; }
}
tmux {
bind "left" { MoveFocus "left"; SwitchToMode "normal"; }
bind "down" { MoveFocus "down"; SwitchToMode "normal"; }
bind "up" { MoveFocus "up"; SwitchToMode "normal"; }
bind "right" { MoveFocus "right"; SwitchToMode "normal"; }
bind "space" { NextSwapLayout; }
bind "\"" { NewPane "down"; SwitchToMode "normal"; }
bind "%" { NewPane "right"; SwitchToMode "normal"; }
bind "," { SwitchToMode "renametab"; }
bind "[" { SwitchToMode "scroll"; }
bind "Ctrl b" { Write 2; SwitchToMode "normal"; }
bind "c" { NewTab; SwitchToMode "normal"; }
bind "h" { MoveFocus "left"; SwitchToMode "normal"; }
bind "j" { MoveFocus "down"; SwitchToMode "normal"; }
bind "k" { MoveFocus "up"; SwitchToMode "normal"; }
bind "l" { MoveFocus "right"; SwitchToMode "normal"; }
bind "n" { GoToNextTab; SwitchToMode "normal"; }
bind "o" { FocusNextPane; }
bind "p" { GoToPreviousTab; SwitchToMode "normal"; }
bind "z" { ToggleFocusFullscreen; SwitchToMode "normal"; }
}
}
// Plugin aliases - can be used to change the implementation of Zellij
// changing these requires a restart to take effect
plugins {
about location="zellij:about"
compact-bar location="zellij:compact-bar"
configuration location="zellij:configuration"
filepicker location="zellij:strider" {
cwd "/"
}
plugin-manager location="zellij:plugin-manager"
session-manager location="zellij:session-manager"
status-bar location="zellij:status-bar"
strider location="zellij:strider"
tab-bar location="zellij:tab-bar"
welcome-screen location="zellij:session-manager" {
welcome_screen true
}
}
// Plugins to load in the background when a new session starts
// eg. "file:/path/to/my-plugin.wasm"
// eg. "https://example.com/my-plugin.wasm"
load_plugins {
}
// Use a simplified UI without special fonts (arrow glyphs)
// Options:
// - true
// - false (Default)
//
// simplified_ui true
// Choose the theme that is specified in the themes section.
// Default: default
//
// theme "dracula"
// Choose the base input mode of zellij.
// Default: normal
//
// default_mode "locked"
// Choose the path to the default shell that zellij will use for opening new panes
// Default: $SHELL
//
// default_shell "fish"
// Choose the path to override cwd that zellij will use for opening new panes
//
// default_cwd "/tmp"
// The name of the default layout to load on startup
// Default: "default"
//
// default_layout "compact"
// The folder in which Zellij will look for layouts
// (Requires restart)
//
// layout_dir "/tmp"
// The folder in which Zellij will look for themes
// (Requires restart)
//
// theme_dir "/tmp"
// Toggle enabling the mouse mode.
// On certain configurations, or terminals this could
// potentially interfere with copying text.
// Options:
// - true (default)
// - false
//
// mouse_mode false
// Toggle having pane frames around the panes
// Options:
// - true (default, enabled)
// - false
//
// pane_frames false
// When attaching to an existing session with other users,
// should the session be mirrored (true)
// or should each user have their own cursor (false)
// (Requires restart)
// Default: false
//
// mirror_session true
// Choose what to do when zellij receives SIGTERM, SIGINT, SIGQUIT or SIGHUP
// eg. when terminal window with an active zellij session is closed
// (Requires restart)
// Options:
// - detach (Default)
// - quit
//
// on_force_close "quit"
// Configure the scroll back buffer size
// This is the number of lines zellij stores for each pane in the scroll back
// buffer. Excess number of lines are discarded in a FIFO fashion.
// (Requires restart)
// Valid values: positive integers
// Default value: 10000
//
// scroll_buffer_size 10000
// Provide a command to execute when copying text. The text will be piped to
// the stdin of the program to perform the copy. This can be used with
// terminal emulators which do not support the OSC 52 ANSI control sequence
// that will be used by default if this option is not set.
// Examples:
//
// copy_command "xclip -selection clipboard" // x11
// copy_command "wl-copy" // wayland
// copy_command "pbcopy" // osx
//
// copy_command "pbcopy"
// Choose the destination for copied text
// Allows using the primary selection buffer (on x11/wayland) instead of the system clipboard.
// Does not apply when using copy_command.
// Options:
// - system (default)
// - primary
//
// copy_clipboard "primary"
// Enable automatic copying (and clearing) of selection when releasing mouse
// Default: true
//
// copy_on_select true
// Path to the default editor to use to edit pane scrollbuffer
// Default: $EDITOR or $VISUAL
// scrollback_editor "/usr/bin/vim"
// A fixed name to always give the Zellij session.
// Consider also setting `attach_to_session true,`
// otherwise this will error if such a session exists.
// Default: <RANDOM>
//
// session_name "My singleton session"
// When `session_name` is provided, attaches to that session
// if it is already running or creates it otherwise.
// Default: false
//
// attach_to_session true
// Toggle between having Zellij lay out panes according to a predefined set of layouts whenever possible
// Options:
// - true (default)
// - false
//
// auto_layout false
// Whether sessions should be serialized to the cache folder (including their tabs/panes, cwds and running commands) so that they can later be resurrected
// Options:
// - true (default)
// - false
//
// session_serialization false
// Whether pane viewports are serialized along with the session, default is false
// Options:
// - true
// - false (default)
//
// serialize_pane_viewport false
// Scrollback lines to serialize along with the pane viewport when serializing sessions, 0
// defaults to the scrollback size. If this number is higher than the scrollback size, it will
// also default to the scrollback size. This does nothing if `serialize_pane_viewport` is not true.
//
// scrollback_lines_to_serialize 10000
// Enable or disable the rendering of styled and colored underlines (undercurl).
// May need to be disabled for certain unsupported terminals
// (Requires restart)
// Default: true
//
// styled_underlines false
// How often in seconds sessions are serialized
//
// serialization_interval 10000
// Enable or disable writing of session metadata to disk (if disabled, other sessions might not know
// metadata info on this session)
// (Requires restart)
// Default: false
//
// disable_session_metadata false
// Enable or disable support for the enhanced Kitty Keyboard Protocol (the host terminal must also support it)
// (Requires restart)
// Default: true (if the host terminal supports it)
//
// support_kitty_keyboard_protocol false
// Whether to stack panes when resizing beyond a certain size
// Default: true
//
// stacked_resize false
// Whether to show tips on startup
// Default: true
//
// show_startup_tips false
// Whether to show release notes on first version run
// Default: true
//
// show_release_notes false
+736
View File
@@ -0,0 +1,736 @@
# CLAUDE.md — global preferences (lkraven)
Loaded into every Claude Code session regardless of project. Project-
local `CLAUDE.md` files take precedence when they conflict; this file
is the baseline.
## Operator identity
The operator is **Vuong Hoang** (lkraven@lkraven.com), addressed as
"Vuong". Roles across three organizations:
- **Corviduo AI** — Founder, Principal Developer, Chief Systems Architect.
- **PhaseFinal, Inc** — Founder, Principal Developer, Chief Systems Architect.
- **VastBlue AI** — Partner, Chief Systems Architect.
He is the final authority on architectural / material-consequence
calls. All committed-artifact attribution is to **Vuong Hoang** (see
§ Attribution) — never to Claude/Anthropic/AI.
## Core principles
Four principles governing engineering choices across all projects.
Common lodestar: fitness-for-purpose. Each rejects a different
substitute goal that disguises itself as virtue.
1. **Excellence over uniqueness.** Pick the shape that's right for
the problem, not the shape that's new. If uniqueness is a
byproduct of excellence, so be it; do not target it.
2. **Explicit over implicit.** Make load-bearing assumptions,
constraints, and coupling visible. Idiomatic implicitness
(language conventions, well-known protocols) is fine — the rule
targets *invisible* implicitness, not all of it. Cost of
explicitness is verbosity; cost of invisible implicitness is
undetectable coupling. Pay the cost where auditability beats
the tax.
3. **Elegance is a byproduct, not a target.** Excellent engineering
often produces elegant results; targeting elegance directly tends
to produce cleverness, which is a different thing. Review test:
"fit-for-purpose, debuggable, consistent" — not "feels nice."
4. **Action-relevance over thoroughness.** Before investigating,
ask whether the answer would change the action. If both outcomes
lead to the same default, skip the question.
## Operator cognitive-load reduction (core mission)
A core mission: **reduce the operator's cognitive load as he context-
shifts across dozens of projects.** He knows the detailed workings of
each — the job is not to teach, it is to let him re-enter any project
and act without reloading its full context from scratch. Three
standing obligations layered on top of normal work:
1. **Surface every architecture decision that matters to him.**
Material-consequence decisions — module boundaries, naming with
downstream reach, scope direction, anything hard to reverse — go to
him, not a peer, not a silent default. (The operator-owns-
architectural-calls rule, restated as a load-reduction duty.) Do
**not** dumb the decision down — he wants the real substance.
2. **Pair every operator-facing decision with an `/elitk` decision
tree.** When you surface a decision for him to make, accompany the
technical framing with a King-grade (`/elitk`) decision tree:
plain-language, jargon-free, the branches and where each leads, so
he can decide in seconds without reloading the project's context.
The tree is the load-reducer; the technical framing is the
substance — give both, every time. Lead with your recommendation.
3. **Keep a running `/elitk` summary of decisions made on his behalf.**
Every call you take autonomously (agent-discretion: patch bumps,
tie-breaks, routing, sequencing, implementation-level choices) earns
a plain-language line in a decisions summary, so he can audit what
happened in his absence without digging through the work. Offer the
`/elitk` summary unprompted at natural checkpoints and whenever he
asks "what have you decided?"
4. **Always attach the real technical detail — never make him ask for
it.** Every `/elitk` decision tree and every decisions-summary line
carries its actual technical specifics alongside the plain-language,
clearly delineated (parentheses, brackets, an indented technical
note, a `details:` tail — your pick) so it can be read or skipped at
a glance. Plain-language is the fast-scan default; the technical
version rides *with* it, never behind a follow-up request. **He
chooses his own cognitive load by deciding whether to read the
bracketed detail** — the job is to make both present, not to
pre-decide which he needs. Example: "kept the version cadence
conservative `[F03 research work → patch v0.5.4 then v0.5.5; the two
docs-only edits → no bump per the SemVer docs-only skip-rule]`."
This extends the non-technical-breakdown habit (auto-memory
`feedback_non_technical_breakdown_on_findings`) from findings to *all*
decisions, and sharpens it with the decision-tree-for-pending-calls
requirement. `/elitk` is the grade and the tool; its King framing —
smart reader, zero jargon — is exactly the operator mid-context-shift.
## Cross-frontier-model consultation discipline
Consults to non-Claude peer models (Heid = Codex/gpt-5.x oracle;
Eitri-Smithy = Codex-shaped embedded research peer; any future
non-Claude reviewer agent) operate under **two complementary
anti-failure framings**:
1. **Authority-frame**: peers provide **fresh perspective**, not
**superior reasoning**. Different model families have different
priors and different training cutoffs — they catch different
blind spots. That is the load-bearing value, not authority.
2. **Role-frame**: peers are **peer-reviewers, not operator-level
oracles**. Routing operator-level decisions (architectural
choices, scope direction, what-to-build calls with material
consequence) to a peer for an authoritative answer is misuse —
those go to the operator regardless of what the peer says.
Peers can pressure-test, paraphrase, surface ambiguity, and
recommend implementation-level calls; they don't decide.
Together: peers are useful reviewers whose value comes from a
different angle, not better answers; the operator owns the
architectural calls, period.
**Default skepticism, never auto-adopt.** Every cross-frontier reply
gets triaged before any of it lands in a plan, contract, or commit.
Five-category triage:
1. **Genuine add** — peer caught something my framing genuinely
missed. Take it.
2. **Sharpening** — peer reframed something I already had into a
sharper version. Merge into the existing variable; don't
double-count as net-new.
3. **Restatement of settled prior** — peer flagged as "missed" a
thing that is already settled in our findings/contracts/ADRs.
Useful as a coverage checklist; **not** a structural addition.
4. **Out-of-place** — peer's input is correct but belongs at a
different stage (e.g., implementation-stage detail surfaced
during frame-stage). Note and defer.
5. **Wrong-grounding** — peer reasoned from incomplete context and
manufactured a non-issue. Push back; do not adopt.
**Watch for the ignorance-of-context failure mode.** A peer's "you
missed X" claim has two possible sources: (a) genuine fresh insight,
or (b) the peer did not read the artifact where X is settled. Before
treating an omission claim as new, check what the peer actually
read — if your settled artifact wasn't on their reading list, the
"miss" is probably category 3 or 5, not category 1.
**Adoption criterion**: "this improves the outcome on its merits"
— never "the peer said so." Treating Codex (or any non-Claude
oracle) as an all-knowing authority is a category error; treat it
as a wise sounding board whose value is forcing you to defend
your framing against a differently-primed reader.
**Applies hardest to `/heid*` skills.** Those skills' artifact-only
discipline protects the EMITTING side (Heid can't be primed by the
caller); the CONSUMING side rubber-stamp risk is on whoever invokes
the skill. Always triage Heid output before acting on it.
## Althing async-reply monitoring
When you ship an althing message that you expect to come back with a
reply — a consult (`/heid*`), a question to a peer agent, a request
awaiting an answer — and you do **not** already have an althing
monitor running for this session, **always start one**
(`/althing:monitor`). The dispatch and the monitor are one action: you
opened a loop, so arm the thing that closes it.
Why: in an interactive session the inbox banner (📬) only fires on the
*next* user prompt. If the operator steps away after you dispatch an
async consult, the reply can sit unseen indefinitely — the loop you
opened never closes on its own. A monitor actively pings when the
reply lands, so the await-reply promise ("reply will land in your
inbox") is backed by a real notification, not by hoping the operator
prompts again.
Scope: only messages where you're waiting on a response. Pure
fire-and-forget posts (an FYI ping, a post-1.0 downstream-consumer
announcement) don't need a monitor. When the exchange is done, sign
off (`/althing:sign-off`) so monitors don't accumulate — stop a stuck
one with `althing-light-monitor --stop`, never `pkill` (that kills
every agent's monitor, not just yours).
## Development workflow shapes
Two end-to-end shapes for taking a unit of work from idea to landed.
Pick by whether the work will be implemented by an AFK agent
(Sleipnir dispatch) or directly in-session. Both front-load the same
deliberation — heid consult → contract → heid contract review →
contract fixup — so the spec is sound before any code; they diverge
only at the implementation handoff.
Stages are defaults, not a rigid gate. Skip a stage when it would be
ceremony (a trivial bug fix needs no vor pass; a one-liner needs no
contract). The heid consult and review stages follow the cross-
frontier triage discipline above: never auto-adopt.
**Contract-skip is a direct-implementation privilege.** In the direct
shape, low-effort work — surgical test updates, localized bug fixes,
one-liners — runs straight to implementation without a fresh contract,
*provided* any existing contract governing the touched behavior is
updated in the same commit so it stays canonical (skip *authoring* a
contract, never let a live one go stale against the code). This does
not extend to AFK dispatch, which always requires a `prd:`-pinned
contract per § "Issue → AFK dispatch hygiene (Sleipnir)" (hard policy)
— and trivial work is not an AFK candidate in the first place: the
scaffold → contract → review → preflight ritual carries real overhead
that only pays for itself on higher-effort tasks. When in doubt,
low-effort stays direct.
**Graphify the blast radius BEFORE writing the contract** — for ANY
contract that touches existing code (not greenfield). Run a graphify
pass over every symbol the contract will change, delete, or rename
(`graphify explain <symbol>` for callers/neighbors, `graphify path`
for reach) so the contract's scope section enumerates the *true* set
of affected files and call-sites — not an under-count that detonates
mid-implementation. **Cross-check with grep, always.** Graphify is
blind to function-local and DI-injected imports (`from .x import y`
inside a function body, store objects passed through constructors) —
the exact pattern that hides cross-module callers. Graphify confirms
the call structure; grep catches what its AST extraction misses;
neither alone is sufficient (graphify-only under-counts, grep-only
misses transitive reach). Both, before the contract — the scope
section is only as honest as the blast-radius pass behind it. (Lesson:
a contract that names 3 files when the rip touches 6 is a scope miss
the up-front pass would have caught.)
### AFK dispatch shape (Sleipnir)
For work an AFK agent will implement off a contract.
1. Issue created.
2. Heid consult on the issue (`/heid`) — pressure-test the framing.
3. Scaffold the issue for AFK dispatch (`/sleipnir-scaffold <N>`) —
writes the `prd:`-pinned contract frontmatter.
4. Contract generation — the architect writes the contract body.
5. Heid contract review (`/heid-contract-review`).
6. Fixup the contract per triaged findings.
7. Preflight + mark ready-for-agent (`/sleipnir-preflight <N>`) — the
irreversible dispatch authorization. See § "Issue → AFK dispatch
hygiene (Sleipnir)" for the gate's hard requirements.
### Direct implementation shape
For work implemented directly in-session.
1. Issue created.
2. Heid consult on the issue (`/heid`).
3. `/vor` — or `/vor-frame` (ask too shapeless to draft a `/vor`
questionnaire) or `/vor-cross` (cross-frontier peer in the loop) —
if the ask warrants a pre-contract design pass. Skip when the
frame is already crisp.
4. Write the contract.
5. Heid contract review (`/heid-contract-review`).
6. Fixup the contract per triaged findings.
7. TDD implement (`/tdd`) — red-green-refactor against the contract.
8. Heid code review (`/heid-code-review`) — code-vs-contract drift.
9. Fixup the code per triaged findings.
10. Commit if clean.
## Tooling preferences
- **Python: prefer `uv` whenever possible.** Use `uv venv`, `uv pip
install`, `uv run`, `uv tool install`, etc. instead of `python -m
venv`, `pip`, `pipx`, `poetry`. Exception: if the project clearly
uses something else (a `poetry.lock` exists, the README says
`pip-tools`, the Dockerfile already pins `pip install`), follow the
project's tooling — don't fight it just to use uv.
- **Shell: I run interactive `zsh`.** Commands you hand me to paste
must be zsh-safe: quote glob-bearing args (`'pkg[extra]'`, not
`pkg[extra]` — zsh errors `no matches found` on unquoted brackets)
and don't rely on bash-only syntax. Inline `#` comments are fine
(`setopt interactive_comments` is set in `~/.zshrc`). Claude Code's
Bash tool also runs zsh here (it follows `$SHELL`), so the same
applies to tool commands.
## Global tools available
Tools standing ready in the working environment — assume present and use
them without a setup detour. (Most Claude Code sessions run natively on
**nh3-dev** `10.100.10.50`, the dev box; "available" means there unless a
note says otherwise. On other boxes, check first.)
- **Playwright + headless Chromium** — installed **box-wide on nh3-dev**:
the system shared-libs (apt, via `playwright install-deps`), the browser
binaries in shared **`/opt/ms-playwright`** (chromium + headless-shell,
root-owned + world-readable), and
`PLAYWRIGHT_BROWSERS_PATH=/opt/ms-playwright` wired globally
(`/etc/environment` + `/etc/profile.d/`). A project only needs the
`playwright` module (`npm i playwright` — the browser download is
skippable, it resolves the shared binary); **no per-project
`playwright install`**. Use for anything that needs a real browser
engine: true DOM/SVG layout geometry, screenshots, headless rendering,
browser-based tests or scraping. Add a browser / bump via
`ssh infra-ops@10.100.10.50 'sudo env PLAYWRIGHT_BROWSERS_PATH=/opt/ms-playwright npx -y playwright install <browser>'`.
- **Graphify** — open-source knowledge-graph skill for AI coding assistants
(`uv tool install graphifyy`; CLI `graphify`, MCP `graphify-mcp`). Turns a
repo into a queryable graph. The **free, deterministic path** is
`graphify update <path>`: tree-sitter AST extraction + Leiden clustering,
**zero LLM / zero tokens**, ~25s for ~900 files; writes
`graphify-out/{graph.json,GRAPH_REPORT.md}`. Highest-value free output is
the **God Nodes** list (core-abstraction surfacing) plus `graphify explain
<symbol>` / `query` / `affected` / `path` traversals over `EXTRACTED` call
edges. The LLM layer (community **labeling** = low-caliber, and **semantic
extraction** of docs/INFERRED edges = higher-caliber + noisier) is optional
and points at any backend via `~/.graphify/providers.json` — pair labeling
with the cheap LiteLLM/Granite endpoint below; leave deep semantic
extraction off unless needed (its INFERRED/AMBIGUOUS edges fight the
explicit-over-implicit floor). Complements a hand-authored `docs/CODEBASE.md`
(curated geography), doesn't replace it. Pilot-validated on Worldtree
2026-06-10.
- **LiteLLM gateway (Granite 4.1 + friends)** — OpenAI-compatible gateway at
`http://10.250.50.70:4000/v1` (Logs UI `:4000/ui`) fronting vLLM services.
Essentially-**free local compute** for low-caliber, high-volume,
parallelizable LLM work. The **always-available summarizer / classifier
endpoint** is `granite-4.1-8b` — the go-to for summarization, naming/
labeling, classification, and triage (fast, parallelizes well on vLLM):
served FP8 on ana-ml2 GPU 1, production-stable, 131k context (rebalanced
2026-06-13). Treat it as a standing dependency you can reach for any time.
Also behind the gateway: `qwen3.5-9b-fp8` (vision / multimodal — image +
text chat, GPU 1), `qwen3-embedding`, `qwen3-reranker`, and `glm-5.1` /
`glm-4.7` (via z.ai passthrough). The gateway 401s without a **virtual API
key**. **Shared all-agents key** — internal-only gateway, scoped to the *free
local* models only (granite + qwen-vision + embed/rerank, NOT the paid GLM):
`sk-eA_XOdcs6nIkyYXonohtEQ` (alias `all-agents-local`). Use it directly for
the always-available local endpoints — no per-project provisioning needed.
Example: `curl http://10.250.50.70:4000/v1/chat/completions -H "Authorization:
Bearer sk-eA_XOdcs6nIkyYXonohtEQ" -d '{"model":"granite-4.1-8b","messages":[…]}'`.
For the **paid** GLM passthroughs or broader scope, still request a
project-scoped key from infra-ops via althing (the shared key deliberately
can't spend z.ai cost). Rotatable via infra-ops if it leaks. Reach for
this before spending premium API tokens on tasks a small fast local model
handles fine (the LLM-last-resort floor still applies — deterministic first).
## DevOps delegation
For all DevOps work — deployments, infrastructure provisioning,
server administration, credential management, system-level package
installs, network/firewall configuration, service uptime — **prefer
routing to `infra-ops` via althing** rather than handling directly
in a project-dev session.
When infra-ops needs auth keys or access it doesn't already hold,
**it asks the appropriate peer agent directly** rather than blocking
on the operator. Examples:
- Heimdall scopes (Worldtree auth) → ask `worldtree-dev`.
- Gitea API tokens / repo permissions → ask the peer that holds
admin access for the relevant org.
- Vendor / subscription API keys (OpenAI, Anthropic, etc.) → ask
the operator or the peer that owns the consuming service.
- Cloud / hosting credentials → ask the operator.
The principle: infra-ops is self-sufficient on the access-gathering
front. Exhaust peer-agent paths before escalating to the operator.
The operator (Vuong) is the final authority for credentials not in
any agent's possession, but the agent network should resolve
credential routing among itself when possible.
## Attribution
All attributions are to **Vuong Hoang**. Never reference Claude,
Claude Code, Anthropic, "AI-assisted", "Generated with …", or robot
emojis anywhere — git commit messages, PR bodies, README author lines,
LICENSE copyright, `pyproject.toml` authors, file headers, HTML
footers, or any other byline. The user is the author; the assistant
is invisible.
Specifically, never append:
- `Co-Authored-By: Claude …`
- `🤖 Generated with [Claude Code]()`
- "with help from Claude / an AI assistant / etc."
…to any committed artifact.
## SemVer etiquette
**Canonical policy reference:** the formal versioning policy for ALL
projects lives at
`~/development/corviduo-project-template/docs/VERSIONING-POLICY.md`
(canonical, self-pinned as `versioning-policy-v1`). It governs version
format (SemVer 2.0.0), the public-contract declaration each project
must make, pre-1.0 semantics, pre-release staging (`-alpha.N` /
`-beta.N` / `-rc.N`, the same-commit rc discipline), dev/in-progress
labeling per ecosystem, commit conventions, the release process, and
special cases (hotfix, deprecation, breaking security fix, build
metadata). Consult it for any versioning question this section doesn't
answer — especially pre-releases and release staging, which this
section doesn't cover.
This section is Corviduo's **operational cadence layer on top of that
policy**: which commits become releases and at what tier (tier-bar
test, patch-default, operator approval for non-patch). Where the two
differ on cadence or tier choice, this section governs; for format,
contract semantics, pre-release staging, and release mechanics, the
policy governs. Operator ruling (2026-07-02): pre-1.0 **milestone
minors stay legal** — this section's non-breaking milestone-minor
examples override the policy's § 4 strict reading (pre-1.0 minor =
breaking changes only). Settled; do not re-litigate.
Each code-bearing or substantive-artifact commit bumps a version in
the project's `pyproject.toml` (or equivalent), refreshes the
lockfile, gets a `vX.Y.Z` git tag. Establishes a fine-grained
changelog and lets any peer pin against a known-good substrate
state.
**Tier-bar test (the decision tool):**
> *Does this release warrant a release note — or, in the case of a
> post-1.0 release, does it rise to the level of requiring a push
> notification to subscribed downstream consumers? Does this release
> warrant a blog post or a press release?*
The escalation maps to communication metaphors:
| Tier | Question | Communication metaphor |
|---|---|---|
| **Patch** (default) | n/a — patch is the workhorse default | Changelog line |
| **Minor** (pre-1.0) | Does this warrant a **release note**? | Subscribers glance at it |
| **Minor** (post-1.0) | Does this rise to **push-notification to subscribed downstream consumers**? | We actively reach out |
| **Major** | Does this warrant a **blog post or a press release**? | Story worth telling beyond subscribers |
The crucial implicit calibration: **the bar for minor RISES at v1.0.**
Pre-1.0, minor is cheap (would you write a release-note paragraph?);
post-1.0, minor is expensive (would you actually interrupt downstream
consumers about this?). Pre-1.0 is iterative cheap-minors; post-1.0
is stable deliberate-minors. Crossing v1.0 is a discipline-tightening
event, not just a number.
**In Corviduo,** "push notification to subscribed downstream
consumers" maps concretely to: **an althing post to peer-dev handles
announcing the change**. That's the actual mechanism. Operator or
Brokkr pings worldtree-dev / galdrabok-dev / sleipnir-dev / etc.
when a post-1.0 minor lands.
### Operator approval required for any non-patch bump
**Patch bumps are at agent discretion.** Apply them autonomously as
part of the work.
**Minor and major bumps REQUIRE explicit operator approval** before
the bump commit lands. The mechanism:
1. Identify that the work warrants a non-patch bump per the
tier-bar test (release-note / push-notification / blog-post).
2. Surface to the operator with a concrete question:
*"This work appears minor-worthy because <reason>. Approve the
vX.Y.Z → vX.Y+1.0 bump?"*
3. **Wait for explicit approval** before applying the bump.
4. Apply the bump (edit pyproject.toml, run `uv lock`, commit, tag)
only after the operator has said yes.
This guard exists because non-patch bumps in agent-applied autonomy
drifted upward — the operator caught a minor-cadence-too-fast
pathology on 2026-05-25 (three bumps in ~60 min, two of them
minor; would land at v0.4823.2 territory at sustained pace). The
tier-bar test alone wasn't sufficient discipline; explicit
operator-in-the-loop is the corrective.
If the operator pre-authorizes a session-level batch (e.g., "just
ship the next minor when you reach the heid-orchestrator milestone"),
that constitutes approval — but the pre-authorization should be
explicit and bounded to a specific upcoming event, not "all minors
going forward."
This rule applies UNIVERSALLY — even in repos where push is
agent-authorized (like Brokkr-Smithy per its project-local
CLAUDE.md). Push-discretion and bump-discretion are independent
authorizations.
### Patch (`X.Y.Z` → `X.Y.Z+1`) — workhorse default
The default for any code-bearing or substantive-artifact commit.
Includes:
- Bug fixes
- Internal correctness improvements
- Refactors with no public-surface signature change
- New artifacts within an existing family (new R-target finding, new
spec doc, new feedback memory)
- Single-commit features that don't require downstream coordination
- Validator additions, security tightenings, drift-against-spec
corrections
- Skill specs authored (spec drafted; minor fires at implementation
ship)
Patches accumulate routinely. Most commits are patches.
### Minor (`X.Y.Z` → `X.Y+1.0`) — coordinated-release event
Reserved for events where the tier-bar test fires: would you write a
release note (pre-1.0) or send a push notification to downstream
consumers (post-1.0)?
Pre-1.0, the bar is "release-note-worthy paragraph." Post-1.0, it's
the stricter "actually-pinging-consumers." Examples that pass at
either bar:
- **Cross-repo deliverable shipped to a peer agent** (e.g., Brokkr
R10 A01 ContextPromotion intelligence package → worldtree-dev).
Downstream HAS to react.
- **R-target full closure** — multi-finding + action lifecycle
complete; the package is the milestone landmark.
- **Skill IMPLEMENTATION shipped** at the implementation site
(post-spec absorption). Callers must adapt.
- **Methodology charter changes** (e.g., adding noise-floor
cross-check ambient to Brokkr's preregistration discipline).
High-leverage; affects every probe going forward.
- **Pre-v1.x breaking change** — under the no-backward-compatibility
rule, breaking changes ride in minor until v1.0. Breaking changes
are intrinsically release-note-worthy; minor is the right tier.
- **API signature change to publicly-callable surface** post-1.0
that affects fewer callers than a full major (e.g., new optional
parameter, opt-in capability). Still warrants the
push-notification.
Examples that DON'T pass the tier-bar and stay as patches:
- A single new R-target finding (F-ID) within an active R-target's
lifecycle. The closure is the milestone, not each finding.
- A new feedback memory written.
- A spec doc authored (minor fires at implementation, not at spec).
- A new probe artifact added within an existing probe.
- A persistent-memory snapshot.
### Major (`X.Y.Z` → `X+1.0.0`) — blog-post / press-release event
Reserved for v1.0+ release milestones AND post-1.0 events whose
scale warrants telling people beyond your subscriber base.
Pre-v1.x, the no-backward-compat rule means every minor can carry
breakage; major is the milestone-cut signal (v1.0 itself), not a
per-PR concern.
Post-v1.0:
- v1.0 release itself (the discipline-tightening crossover event).
- Substantial breaking changes that would otherwise force most
consumers to adapt at once.
- Architectural restructurings that downstream documentation,
integrations, and conceptual-mental-models depend on.
### Decision rule when ambiguous
**Default to patch.** Minor and major require explicit justification.
If the answer to "does this warrant a release note?" is "maybe, kind
of, I guess?" — that's a patch. Reserve minor for the unambiguous
yes-I'd-write-a-paragraph cases.
**When both minor and patch can be justified, default to patch.**
Tie-breaks go to patch, not minor. The "both could apply" situation
is itself a signal that minor's mandate isn't strong — if minor were
clearly warranted, patch wouldn't also be defensible. Patch is the
workhorse default; let it work. This is a sharper statement of the
same posture above: the bar for non-patch is "patch is NOT defensible
for this commit," not "minor is defensible." Asymmetric default in
favor of the cheaper tier.
The old "two callers react differently" rule remains a useful
internal check: if breaking-vs-keep-working applies to current
callers, it's at least minor. But the tier-bar is the load-bearing
test.
### SKIP the bump entirely for
- CI-only edits
- True docs-only edits (READMEs, comments, formatting)
- ADR commits with no code
- `.contract.md` commits with no code
- Memory-snapshot commits (`memory: snapshot — …`)
- Test-only commits with no production-code change
- WIP / TDD-RED commits where the tree is in a known-broken state
- Brokkr-side template edits with no runtime effect on Brokkr itself
- Worktree-rebuild or env-config changes
- `.claude/` configuration edits
### Cadence
Most commits should be patches. Minor should be rarer than commits —
often 5-15 patches between minors during active development.
A TDD red/green/refactor cycle bumps once or twice (GREEN as patch,
REFACTOR as patch — never three times for the same logical change).
A feature shipped as several incremental green commits bumps each as
patch; the minor that "publishes" the feature can fire at the end of
the arc if it warrants a release-note, OR can be skipped if patches
were sufficient.
If you find yourself bumping minor multiple times per session on the
same project, you're likely over-applying minor. Default back to
patch and ask: does this *specific* commit warrant a release-note
paragraph, or am I just accumulating substantive work?
### Mechanics every bump
0. **If non-patch, get operator approval first** per the § *Operator
approval required for any non-patch bump* rule above. Do not
proceed to step 1 until the operator has explicitly approved the
minor or major bump. (Patch bumps skip this step — apply
autonomously.)
1. Edit `pyproject.toml` (or equivalent project-file) version field.
2. Run `uv lock` (Python) or equivalent so the lockfile records the
new version. Don't hand-edit the lockfile.
3. Stage both files alongside the actual change.
4. Commit with the conventional shape (e.g., `feat(#N): …` /
`fix(#N): …` / `refactor: …`).
5. `git tag vX.Y.Z` after the commit. Lightweight (no `-a`, no
message) is deliberate for per-bump tags: the commit object
carries the rationale, and the tag is just a ref naming the
substrate state.
**Exception — milestone releases** (v1.0, v2.0, future major
cuts) get annotated tags (`git tag -a -m "…"`, or `git tag -s`
when signing). At a milestone the attestation matters separately
from the code change: release notes, tagger identity + date, and
optional GPG signature live in the tag object itself, where
downstream pins and supply-chain verifiers can read them.
6. Push is the operator's call — never push automatically.
(Project-local `CLAUDE.md` may grant push discretion, e.g.,
Brokkr-Smithy; honor those when present.)
### Calibration examples
**Brokkr-Smithy 2026-05-25 session (the recalibration trigger):**
Initially bumped under the pre-amendment rule:
- `v0.1.0 → v0.2.0` (minor) — F02 R06 v2 taxonomy reduction ship
- `v0.2.0 → v0.3.0` (minor) — Heid orchestrator spec set v0.1
- `v0.3.0 → v0.3.1` (patch) — migration runbook revision
Under THIS amended rule:
- F02 ship would be **patch** — single finding within R06 v2's
active lifecycle. R06 v2 closure (multi-finding + action) gets
the minor.
- Heid orchestrator spec set — **patch** strictly (spec authored,
not yet implemented). Galdrabok-dev's skill spec implementation
shipping IS minor (callers adapt).
- Runbook revision — **patch** (correct under both rules).
The session would have ended at roughly v0.1.5 (five patches) with
maybe a v0.2.0 cut when the heid orchestrator's smoke-tests-pass +
galdrabok ship lands as the cohesive milestone.
**Worldtree #185 (2026-05-21):**
- `v0.20.0` (minor) — `ChromaLongTermMemory.store/search/retrieve/
forget` gained required keyword-only `end_user_id`. Pre-v1.x
breaking change; every caller had to be updated. Release-note-
worthy in pre-1.0 framing. **Minor** under both old and new
rules.
- `v0.20.1` (patch) — Heid-flagged drift fixes within the v0.20.0
surface. **Patch** under both rules.
### Retroactive bumps
Don't retroactively bump past commits to align with a tightened
rule. Substrate-state baseline is forward-looking: the bump-cadence
from this point forward reflects the discipline; past versions
record what happened under the previous rule. The pre/post boundary
is the amendment-effective commit, not the rule itself.
## Roadmap discipline — v1 target + parking lot (anti-creep)
Projects sprawl at v0 when features land with **no v1 target to gate
them against** — every good idea, lacking a home, becomes v0 scope by
default, and the project never converges. This is the feature-axis
analog of two disciplines already in force: **value-of-information**
for probes (don't-measure-what-won't-change-behavior) and
**patch-default** for version bumps. Same posture —
*asymmetric default toward not-doing* — applied to features.
**Every project carries a `ROADMAP.md`** (a screenful, not a PRD):
1. **v1 target** — the small, explicit "what must be true to cut
1.0": **37 capabilities**. A big v1 is itself the creep; keep it
tight. This is the done-definition AND the anchor every feature is
gated against.
2. **Parking lot (post-v1 / vNext / spinout)** — every deferred idea,
named, with a home. Creep lands *here* instead of silently
becoming v0 scope. A "feature" that's really its own project is a
**spinout**, not v1 scope.
3. **The gate (the anti-creep mechanism):** a proposed feature → *on
the v1 path? → in; else → parking lot.* **Default = parking lot.**
When both "v1" and "park" are defensible, park it — the same
tie-break-to-the-cheaper-tier asymmetry as the SemVer patch-default.
Applies regardless of who proposed the feature (operator included);
the gate is about v1-path-fit, not provenance.
4. **Creep-check at checkpoints:** when surfacing progress, ask "is
what we're building on the v1 path?" Off-path-but-worth-keeping →
parking lot, surfaced to the operator, never silently into v0.
The per-project `ROADMAP.md` file shape + location is defined in
`corviduo-project-template` as a copied-in **skeleton** (like
`persistent-memory.md` — new projects copy it, then the content
diverges per project), NOT a byte-identical canonical. The skeleton
carries the shape; the discipline itself lives in this rule (loaded
every session), so no byte-sync of content is needed. This mirrors
the SemVer global-rule + per-project-version-file split: the version
*field* is conventional, its *value* diverges per project — nobody
canonical-syncs version values, and likewise nobody syncs roadmap
content. v1.0 is cut when the ROADMAP's v1 target is met — tying
directly into the SemVer "v1.0 = discipline-tightening event."
## Issue → AFK dispatch hygiene (Sleipnir)
Before marking any issue `ready-for-agent` (the label that gates AFK
dispatch via Sleipnir), it MUST have an issue-numbered contract at
`docs/contracts/issues/<N>.contract.md` AND that contract MUST carry
a `prd:` block in its YAML frontmatter pinning it to:
- the issue body (SHA-256, first 16 hex chars)
- the lock-in comment id + content SHA (or `null` if the issue body
alone is the spec)
- a `pinned_at` timestamp
This is hard policy, not a suggestion. Without the contract Sleipnir's
gate refuses dispatch with `blocked-needs-contract`. Without the `prd:`
block PRD-↔-ship drift becomes invisible — the audit infrastructure
that detects it is a no-op.
Verify before applying the label:
- contract file exists at the expected path
- frontmatter has a populated `prd:` block
- `python scripts/contract_drift_check.py --contract <path>` returns
clean (i.e., the pinned hashes match the live issue + comment)
The full convention — frontmatter shape, required fields, reasoning
behind the four drift entry points — lives in
`docs/contracts/CONTRACT-FORMAT.md` (the project that consumes
Sleipnir owns this file). Module-scoped contracts MAY adopt the same
`prd:` block when amended in response to a specific issue; for
issue-scoped contracts it is required.
+25 -20
View File
@@ -105,12 +105,18 @@
# Blue current directory.
typeset -g POWERLEVEL9K_DIR_FOREGROUND=$lightergrey
# Context format when root: user@host. The first part white, the rest grey.
# Context sits just left of the clock and shows the hostname, with the
# session type made obvious at a glance:
# native (local) -> grey hostname
# ssh (remote) -> yellow hostname tagged " ssh"
# root -> user@host, username in white
typeset -g POWERLEVEL9K_CONTEXT_ROOT_TEMPLATE="%F{$white}%n%f%F{$grey}@%m%f"
# Context format when not root: user@host. The whole thing grey.
typeset -g POWERLEVEL9K_CONTEXT_TEMPLATE="%F{$grey}%n@%m%f"
# Don't show context unless root or in SSH.
typeset -g POWERLEVEL9K_CONTEXT_{DEFAULT,SUDO}_CONTENT_EXPANSION=
typeset -g POWERLEVEL9K_CONTEXT_DEFAULT_TEMPLATE="%F{$grey}%m%f"
typeset -g POWERLEVEL9K_CONTEXT_REMOTE_TEMPLATE="%F{$yellow}%m%f%F{$grey} ssh%f"
typeset -g POWERLEVEL9K_CONTEXT_REMOTE_SUDO_TEMPLATE="%F{$white}%n%f%F{$yellow}@%m%f%F{$grey} ssh%f"
# Keep only the local-sudo state quiet (matches Pure); every other state shows.
typeset -g POWERLEVEL9K_CONTEXT_SUDO_CONTENT_EXPANSION=
# Show previous command duration only if it's >= 5s.
typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_THRESHOLD=5
@@ -136,22 +142,21 @@
typeset -g POWERLEVEL9K_VCS_{INCOMING,OUTGOING}_CHANGESFORMAT_FOREGROUND=$cyan
# Don't show remote branch, current tag or stashes.
typeset -g POWERLEVEL9K_VCS_GIT_HOOKS=(vcs-detect-changes git-untracked git-aheadbehind)
# Don't show the branch icon.
typeset -g POWERLEVEL9K_VCS_BRANCH_ICON=
# When in detached HEAD state, show @commit where branch normally goes.
typeset -g POWERLEVEL9K_VCS_COMMIT_ICON='@'
# Don't show staged, unstaged, untracked indicators.
typeset -g POWERLEVEL9K_VCS_{STAGED,UNSTAGED,UNTRACKED}_ICON=
# Show '*' when there are staged, unstaged or untracked files.
typeset -g POWERLEVEL9K_VCS_DIRTY_ICON='*'
# Show '⇣' if local branch is behind remote.
typeset -g POWERLEVEL9K_VCS_INCOMING_CHANGES_ICON=':⇣'
# Show '⇡' if local branch is ahead of remote.
typeset -g POWERLEVEL9K_VCS_OUTGOING_CHANGES_ICON=':⇡'
# Don't show the number of commits next to the ahead/behind arrows.
typeset -g POWERLEVEL9K_VCS_{COMMITS_AHEAD,COMMITS_BEHIND}_MAX_NUM=1
# Remove space between '⇣' and '⇡' and all trailing spaces.
typeset -g POWERLEVEL9K_VCS_CONTENT_EXPANSION='${${${P9K_CONTENT/⇣* :⇡/⇣⇡}// }//:/ }'
# Nerd Font branch glyph () before the branch name.
typeset -g POWERLEVEL9K_VCS_BRANCH_ICON=$' '
# Detached HEAD: git-commit glyph () where the branch name normally goes.
typeset -g POWERLEVEL9K_VCS_COMMIT_ICON=$' '
# Distinct Nerd Font glyphs, each followed by its count, for the working-tree state:
# staged · unstaged (modified, not staged) · untracked.
# A category only renders when its count is non-zero.
typeset -g POWERLEVEL9K_VCS_STAGED_ICON=$' '
typeset -g POWERLEVEL9K_VCS_UNSTAGED_ICON=$' '
typeset -g POWERLEVEL9K_VCS_UNTRACKED_ICON=$' '
# No separate catch-all dirty marker — the three glyphs above are the breakdown.
typeset -g POWERLEVEL9K_VCS_DIRTY_ICON=
# Nerd Font behind/ahead arrows (/), each followed by the commit count.
typeset -g POWERLEVEL9K_VCS_INCOMING_CHANGES_ICON=$' '
typeset -g POWERLEVEL9K_VCS_OUTGOING_CHANGES_ICON=$' '
# Grey current time.
typeset -g POWERLEVEL9K_TIME_FOREGROUND=$grey
-1
View File
@@ -1,5 +1,4 @@
~/.config/tmux/plugins
~/.config/thefuck/__pycache__
~/.config/btop
~/.config/neofetch
~/.config/zinit
+1 -1
View File
@@ -110,7 +110,7 @@ config.colors = {
config.window_decorations = "RESIZE"
config.default_prog = { 'pwsh' }
else
config.window_background_opacity = 0.85
config.window_background_opacity = 0.95
config.macos_window_background_blur = 40
config.enable_tab_bar = false
config.window_decorations = "RESIZE"
+34 -16
View File
@@ -3,9 +3,12 @@ path=(~/bin $path)
path=(~/.local/bin $path)
path=(~/.cache/lk-tools/fzf/bin $path)
# Init OhMyPosh
eval "$(oh-my-posh init zsh --config https://333e8677ac54a1845fe68813017ab7e807c87ab2@gitea.phasefinal.com/vh/dotfiles/raw/branch/master/home_config/ohmyposh/lkraven.toml)"
# Enable Powerlevel10k instant prompt. Should stay close to the top of ~/.zshrc.
# Initialization code that may require console input (password prompts, [y/n]
# confirmations, etc.) must go above this block; everything else may go below.
if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then
source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh"
fi
# Set ZINIT Home
ZINIT_HOME="${HOME}/.config/zinit/zinit.git"
@@ -20,6 +23,10 @@ fi
source "${ZINIT_HOME}/zinit.zsh"
# add zinit
# Powerlevel10k prompt theme (replaces oh-my-posh; instant prompt = fast startup)
zinit ice depth=1
zinit light romkatv/powerlevel10k
zinit light zsh-users/zsh-syntax-highlighting
zinit light zsh-users/zsh-completions
zinit light zsh-users/zsh-autosuggestions
@@ -53,6 +60,10 @@ setopt hist_ignore_dups
setopt hist_find_no_dups
setopt hist_verify
# allow inline `#` comments at the interactive prompt (paste-friendly;
# matches non-interactive/script behavior so pasted commands don't fail)
setopt interactive_comments
# completion styling
zstyle ':completion:*' matcher-list 'm:{a-z}={A-Za-z}'
zstyle ':completion:*' list-colors "${(s.:.)LS_COLORS}"
@@ -62,12 +73,10 @@ zstyle ':fzf-tab:complete:__zoxide_z:*' fzf-preview 'ls --color $realpath'
zstyle ':fzf-tab:*' fzf-command ftb-tmux-popup
# aliases
alias ls='eza'
alias cat='bat'
alias tree='eza --tree'
# To customize prompt, run `p10k configure` or edit ~/.p10k.zsh.
# [[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh
[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh
[ -f ~/.fzf.zsh ] && source ~/.fzf.zsh
export FZF_DEFAULT_COMMAND="fd --hidden --strip-cwd-prefix --exclude .git"
@@ -83,13 +92,13 @@ _fzf_compgen_dir() {
source ~/fzf-git.sh/fzf-git.sh
export FZF_CTRL_T_OPTS="--preview 'bat -n --color=always --line-range :500 {}'"
export FZF_ALT_C_OPTS="--preview 'eza --tree --color=always {} | head -200'"
export FZF_ALT_C_OPTS="--preview 'ls -la {} | head -200'"
_fzf_comprun() {
local command=$1
shift
case "$command" in
cd) fzf --preview 'eza --tree --color=always {} | head -200' "$@" ;;
cd) fzf --preview 'ls -la {} | head -200' "$@" ;;
export|unset) fzf --preview "eval 'echo \$' {}" "$@" ;;
ssh) fzf --preview 'dig {}' "$@" ;;
*) fzf --preview 'bat -n --color=always --line-range :500 {}' "$@" ;;
@@ -99,19 +108,28 @@ export BAT_THEME=Nord
eval "$(zoxide init zsh)"
alias cd='z'
eval $(thefuck --alias)
eval $(thefuck --alias fk)
zinit light Aloxaf/fzf-tab
if [[ $(uname) == "Darwin" ]]; then
source $(brew --prefix)/share/zsh-autosuggestions/zsh-autosuggestions.zsh
elif [[ $(uname) == "Linux" ]]; then
source /usr/share/zsh-autosuggestions/zsh-autosuggestions.zsh
# zsh-autosuggestions is already loaded via zinit above; on Linux, also wire
# the terminfo arrow keys to history search.
if [[ $(uname) == "Linux" ]]; then
bindkey "${terminfo[kcuu1]}" history-search-backward
bindkey "${terminfo[kcud1]}" history-search-forward
fi
export STM32_PRG_PATH=/Applications/STMicroelectronics/STM32Cube/STM32CubeProgrammer/STM32CubeProgrammer.app/Contents/MacOs/bin
export STM32_PRG_PATH=/Applications/STMicroelectronics/STM32Cube/STM32CubeProgrammer/STM32CubeProgrammer.app/Contents/MacOs/bin
# bun completions
[ -s "/home/lkraven/.bun/_bun" ] && source "/home/lkraven/.bun/_bun"
# bun
export BUN_INSTALL="$HOME/.bun"
export PATH="$BUN_INSTALL/bin:$PATH"
# >>> grok installer >>>
export PATH="$HOME/.grok/bin:$PATH"
fpath=(~/.grok/completions/zsh $fpath)
autoload -Uz compinit && compinit -C
# <<< grok installer <<<
+60 -2
View File
@@ -1,3 +1,61 @@
#!/bin/bash
#!/usr/bin/env bash
# One-shot, host-aware dotfile linker for Linux & macOS.
#
# home_root/* -> ~/<name> (e.g. ~/.zshrc) via `stow home_root`
# home_config/* -> ~/.config/<name> (e.g. ~/.config/nvim) via `stow home_config`
#
# Ensures GNU stow is present first (Homebrew on macOS; apt/dnf/pacman on Linux),
# so a fresh box needs nothing pre-installed. Re-running is safe — stow is
# idempotent and refuses to clobber unrelated real files.
#
# Windows / PowerShell: run ./link-dotfiles.ps1 instead (stow has no native
# Windows port; the .ps1 mirrors this with junctions + symlinks).
set -euo pipefail
repo="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$repo"
# `--apps`: install all host CLI tools first, then link. Without it, this only
# links (fast + idempotent). App install is delegated to the host-aware
# lk-installers/install-apps.
if [ "${1:-}" = "--apps" ]; then
echo "Installing apps first (--apps)…"
"$repo/lk-installers/install-apps"
fi
ensure_stow() {
command -v stow >/dev/null 2>&1 && return
echo "GNU stow not found — installing it…"
case "$(uname -s)" in
Darwin)
if ! command -v brew >/dev/null 2>&1; then
echo "error: Homebrew is required on macOS. Run ./lk-installers/install-apps (or ./link-dotfiles --apps) first." >&2
exit 1
fi
brew install stow
;;
Linux)
if command -v apt >/dev/null 2>&1; then sudo apt update && sudo apt install -y stow
elif command -v dnf >/dev/null 2>&1; then sudo dnf install -y stow
elif command -v pacman >/dev/null 2>&1; then sudo pacman -S --noconfirm stow
else
echo "error: no supported package manager (apt/dnf/pacman). Install GNU stow manually." >&2
exit 1
fi
;;
*)
echo "error: unsupported OS '$(uname -s)'. On Windows run ./link-dotfiles.ps1 instead." >&2
exit 1
;;
esac
}
ensure_stow
echo "Linking home_root -> ~"
stow -v home_root
stow -v --target=$HOME/.config/ home_config
echo "Linking home_config -> ~/.config"
stow -v --target="$HOME/.config" home_config
echo "Done."
+116
View File
@@ -0,0 +1,116 @@
#!/usr/bin/env pwsh
<#
.SYNOPSIS
Windows equivalent of ./link-dotfiles (the GNU stow script).
.DESCRIPTION
stow can't run natively on Windows, so this mirrors what it does:
home_root/* -> ~\<name> (e.g. ~\.zshrc)
home_config/* -> ~\.config\<name> (e.g. ~\.config\nvim)
Directories are linked with junctions and files with symlinks/hardlinks,
none of which need administrator rights (junctions and hardlinks never do;
symlinks are attempted first in case Developer Mode is on, then we fall
back). Re-running is safe: correct links are skipped, and any real file or
directory that would be clobbered is moved aside to <name>.bak first.
.EXAMPLE
pwsh -File .\link-dotfiles.ps1
#>
[CmdletBinding()]
param(
# Print what would happen without changing anything.
[switch]$DryRun
)
$ErrorActionPreference = 'Stop'
$repo = $PSScriptRoot
$home_ = $HOME
# stow metadata files we must never link into the home tree.
$skip = @('.stow-local-ignore', '.stow-global-ignore')
function Get-LinkTarget {
param([string]$Path)
$item = Get-Item -LiteralPath $Path -Force -ErrorAction SilentlyContinue
if ($item -and $item.LinkType) { return $item.Target }
return $null
}
function Link-Item {
param(
[string]$Source, # absolute path inside the repo
[string]$Dest # absolute path under the home tree
)
$isDir = (Get-Item -LiteralPath $Source -Force).PSIsContainer
# Already linked to the right place? Nothing to do.
$existingTarget = Get-LinkTarget $Dest
if ($existingTarget -and ($existingTarget -ieq $Source)) {
Write-Host " ok $Dest" -ForegroundColor DarkGray
return
}
if (Test-Path -LiteralPath $Dest) {
if ($existingTarget) {
# A link, but pointing elsewhere -> replace it.
if ($DryRun) { Write-Host " relink $Dest (was -> $existingTarget)" -ForegroundColor Yellow; return }
Remove-Item -LiteralPath $Dest -Force -Recurse
} else {
# A real file/dir -> back it up rather than destroy it.
$bak = "$Dest.bak"
Write-Host " backup $Dest -> $bak" -ForegroundColor Yellow
if (-not $DryRun) { Move-Item -LiteralPath $Dest -Destination $bak -Force }
}
}
if ($DryRun) { Write-Host " link $Dest -> $Source" -ForegroundColor Cyan; return }
$parent = Split-Path $Dest -Parent
if (-not (Test-Path $parent)) { New-Item -ItemType Directory -Path $parent -Force | Out-Null }
if ($isDir) {
New-Item -ItemType Junction -Path $Dest -Target $Source | Out-Null
Write-Host " junc $Dest -> $Source" -ForegroundColor Green
} else {
# Prefer a real symlink (needs admin or Developer Mode); fall back to a
# hardlink (same volume, no admin); finally just copy.
try {
New-Item -ItemType SymbolicLink -Path $Dest -Target $Source -ErrorAction Stop | Out-Null
Write-Host " link $Dest -> $Source" -ForegroundColor Green
} catch {
try {
New-Item -ItemType HardLink -Path $Dest -Target $Source -ErrorAction Stop | Out-Null
Write-Host " hard $Dest -> $Source" -ForegroundColor Green
} catch {
Copy-Item -LiteralPath $Source -Destination $Dest -Force
Write-Host " copy $Dest (could not link; copied)" -ForegroundColor Magenta
}
}
}
}
Write-Host "home_root -> $home_"
Get-ChildItem -LiteralPath (Join-Path $repo 'home_root') -Force |
Where-Object { $skip -notcontains $_.Name } |
ForEach-Object { Link-Item $_.FullName (Join-Path $home_ $_.Name) }
$configDir = Join-Path $home_ '.config'
Write-Host "home_config -> $configDir"
Get-ChildItem -LiteralPath (Join-Path $repo 'home_config') -Force |
Where-Object { $skip -notcontains $_.Name } |
ForEach-Object { Link-Item $_.FullName (Join-Path $configDir $_.Name) }
# Windows Terminal lives in a package folder outside the stow tree, so link its
# settings.json explicitly. Skipped silently if Terminal isn't installed.
$wtPkg = Get-ChildItem (Join-Path $env:LOCALAPPDATA 'Packages') -Filter 'Microsoft.WindowsTerminal_*' -Directory -ErrorAction SilentlyContinue |
Select-Object -First 1
$wtSrc = Join-Path $repo 'windows\windows-terminal\settings.json'
if ($wtPkg -and (Test-Path $wtSrc)) {
$wtDest = Join-Path $wtPkg.FullName 'LocalState\settings.json'
Write-Host "windows-terminal -> $wtDest"
Link-Item $wtSrc $wtDest
}
Write-Host "Done." -ForegroundColor Green
+100
View File
@@ -0,0 +1,100 @@
#!/usr/bin/env bash
# Host-aware installer for every CLI tool the dotfiles assume at runtime.
#
# macOS -> Homebrew (bootstraps Homebrew itself if missing)
# Linux -> apt (Debian/Ubuntu) + upstream installers for tools not in apt
#
# zinit and all zsh plugins (powerlevel10k, zsh-autosuggestions,
# zsh-syntax-highlighting, zsh-completions, zsh-vi-mode, fzf-tab) bootstrap
# themselves from ~/.zshrc on first shell start — they are NOT installed here.
#
# Idempotent: re-running only fills gaps. Pairs with ./link-dotfiles, or run
# `./link-dotfiles --apps` to install then link in one shot.
#
# Consolidates the former macinstaller / install-apt-pkgs / install-tools /
# install-zellij scripts.
set -euo pipefail
# fzf-git.sh is a sourced helper (not a package) — same on every platform.
clone_fzf_git() {
if [ -d "$HOME/fzf-git.sh" ]; then
echo "fzf-git.sh already cloned — skipping"
else
git clone --depth 1 https://github.com/junegunn/fzf-git.sh.git "$HOME/fzf-git.sh"
fi
}
install_macos() {
if ! command -v brew >/dev/null 2>&1; then
echo "Homebrew not found — installing…"
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
if [ -x /opt/homebrew/bin/brew ]; then eval "$(/opt/homebrew/bin/brew shellenv)"
elif [ -x /usr/local/bin/brew ]; then eval "$(/usr/local/bin/brew shellenv)"
fi
fi
echo "Installing CLI tools via Homebrew…"
brew install \
zsh git curl wget stow \
bat fd fzf zoxide \
zellij neovim btop htop fastfetch
# tldr is deprecated upstream — best-effort so a dead formula can't abort the
# run. tlrc is the maintained `tldr` client.
brew install tlrc || brew install tldr || echo "tldr unavailable — skipping"
# fzf key-bindings + completion -> ~/.fzf.zsh (sourced by .zshrc). These flags
# make it non-interactive; --no-update-rc stops it editing .zshrc (the repo
# owns that file).
"$(brew --prefix)/opt/fzf/install" --key-bindings --completion --no-update-rc >/dev/null
clone_fzf_git
}
install_linux() {
if ! command -v apt >/dev/null 2>&1; then
echo "error: Linux app install targets Debian/Ubuntu (apt). Install the tools manually on this distro." >&2
exit 1
fi
echo "Installing base packages via apt…"
sudo apt update
sudo apt install -y --no-install-recommends \
neovim vim-nox btop htop curl wget tldr git zip unzip stow zsh cargo \
zsh-autosuggestions zsh-syntax-highlighting
sudo apt install -y --no-install-recommends rar unrar || true
# fastfetch (modern neofetch); falls back to neofetch on older distros.
sudo apt install -y fastfetch || sudo apt install -y neofetch || echo "fastfetch/neofetch unavailable — skipping"
# fzf (vendored under ~/.cache/lk-tools/fzf; .zshrc adds its bin to PATH)
if [ ! -d "$HOME/.cache/lk-tools/fzf" ]; then
git clone --depth 1 https://github.com/junegunn/fzf.git "$HOME/.cache/lk-tools/fzf"
"$HOME/.cache/lk-tools/fzf/install" --key-bindings --completion --no-update-rc
fi
clone_fzf_git
# zoxide (upstream installer -> ~/.local/bin, already on PATH)
command -v zoxide >/dev/null 2>&1 || \
curl -sS https://raw.githubusercontent.com/ajeetdsouza/zoxide/main/install.sh | sh
# bat + fd: upstream .deb so the binaries are named `bat`/`fd` (Debian ships
# them as `batcat`/`fdfind`). amd64 assumed — adjust the URLs on arm64 boxes.
if ! command -v bat >/dev/null 2>&1; then
wget -qO /tmp/bat.deb https://github.com/sharkdp/bat/releases/download/v0.24.0/bat_0.24.0_amd64.deb
sudo apt install -y /tmp/bat.deb
fi
if ! command -v fd >/dev/null 2>&1; then
wget -qO /tmp/fd.deb https://github.com/sharkdp/fd/releases/download/v10.1.0/fd_10.1.0_amd64.deb
sudo apt install -y /tmp/fd.deb
fi
# zellij: cargo build, fall back to apt
command -v zellij >/dev/null 2>&1 || cargo install zellij || sudo apt install -y zellij
}
case "$(uname -s)" in
Darwin) install_macos ;;
Linux) install_linux ;;
*) echo "error: unsupported OS '$(uname -s)'." >&2; exit 1 ;;
esac
echo "Done. Open a new shell (or 'exec zsh') to pick everything up."
-3
View File
@@ -1,3 +0,0 @@
sudo apt update
sudo apt install neovim vim-nox btop htop neofetch curl wget tldr git zip unzip stow zsh zsh-autosuggestions zsh-syntax-highlighting cargo --no-install-recommends
sudo apt install rar unrar --no-install-recommends
-17
View File
@@ -1,17 +0,0 @@
#!/bin/bash
# Check if Eza is installed
if dpkg-query -Wf'${db:Status-abbrev}' eza; then
sudo apt install -y eza
else
sudo apt update
sudo apt install gpg
sudo mkdir -p /etc/apt/keyrings
wget -qO- https://raw.githubusercontent.com/eza-community/eza/main/deb.asc | sudo gpg --dearmor -o /etc/apt/keyrings/gierens.gpg
echo "deb [signed-by=/etc/apt/keyrings/gierens.gpg] http://deb.gierens.de stable main" | sudo tee /etc/apt/sources.list.d/gierens.list
sudo chmod 644 /etc/apt/keyrings/gierens.gpg /etc/apt/sources.list.d/gierens.list
sudo apt update
sudo apt install -y eza
fi
-1
View File
@@ -1 +0,0 @@
curl -s https://ohmyposh.dev/install.sh | bash -s
-8
View File
@@ -1,8 +0,0 @@
#!/bin/bash
sudo apt update
sudo apt install python3-dev python3-pip python3-setuptools python3-venv
python3 -m venv ~/homebase
source ~/homebase/bin/activate
pip3 install thefuck
mv ~/homebase/bin/fuck ~/.local/bin/
mv ~/homebase/bin/thefuck ~/.local/bin/
-8
View File
@@ -1,8 +0,0 @@
git clone --depth 1 https://github.com/junegunn/fzf.git ~/.cache/lk-tools/fzf
~/.cache/lk-tools/fzf/install
git clone https://github.com/junegunn/fzf-git.sh.git ~/fzf-git.sh
curl -sS https://raw.githubusercontent.com/ajeetdsouza/zoxide/main/install.sh | sh
wget -O /tmp/bat.deb https://github.com/sharkdp/bat/releases/download/v0.24.0/bat_0.24.0_amd64.deb
sudo apt install /tmp/bat.deb
wget -O /tmp/fdfind.deb https://github.com/sharkdp/fd/releases/download/v10.1.0/fd_10.1.0_amd64.deb
sudo apt install /tmp/fdfind.deb
-7
View File
@@ -1,7 +0,0 @@
#!/bin/bash
echo "Installing Zellij via cargo..."
cargo install zellij || {
echo "Cargo failed - trying apt instead"
sudo apt update && sudo apt install -y zellij
}
-35
View File
@@ -1,35 +0,0 @@
#!/bin/bash
# filepath: /Users/vhpfi/dotfiles/lk-installers/macinstaller
# Check if Homebrew is installed
if command -v brew >/dev/null 2>&1; then
echo "Homebrew is already installed. Updating..."
brew update
else
echo "Homebrew not found. Installing Homebrew..."
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Add Homebrew to PATH for the current session
if [[ -f /opt/homebrew/bin/brew ]]; then
# For Apple Silicon Macs
eval "$(/opt/homebrew/bin/brew shellenv)"
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile
echo "Homebrew has been installed and added to your PATH."
elif [[ -f /usr/local/bin/brew ]]; then
# For Intel Macs
eval "$(/usr/local/bin/brew shellenv)"
echo 'eval "$(/usr/local/bin/brew shellenv)"' >> ~/.zprofile
echo "Homebrew has been installed and added to your PATH."
else
echo "Error: Couldn't find the Homebrew binary after installation."
exit 1
fi
fi
echo "Installing packages with Homebrew..."
brew install neovim btop htop neofetch curl wget git zip unzip zsh tldr
brew install zsh-autosuggestions zsh-syntax-highlighting
brew install rustup-init
rustup-init -y
echo "Installation complete!"
+143
View File
@@ -0,0 +1,143 @@
{
"$help": "https://aka.ms/terminal-documentation",
"$schema": "https://aka.ms/terminal-profiles-schema",
"actions":
[
{
"command":
{
"action": "copy",
"singleLine": false
},
"id": "User.copy.644BA8F2"
},
{
"command": "paste",
"id": "User.paste"
},
{
"command":
{
"action": "splitPane",
"split": "auto",
"splitMode": "duplicate"
},
"id": "User.splitPane.A6751878"
},
{
"command": "find",
"id": "User.find"
}
],
"copyFormatting": "none",
"copyOnSelect": false,
"defaultProfile": "{574e775e-4f2a-5b96-ac1e-a2962a402336}",
"keybindings":
[
{
"id": "User.copy.644BA8F2",
"keys": "ctrl+c"
},
{
"id": "User.find",
"keys": "ctrl+shift+f"
},
{
"id": "User.paste",
"keys": "ctrl+v"
},
{
"id": "User.splitPane.A6751878",
"keys": "alt+shift+d"
}
],
"newTabMenu":
[
{
"type": "remainingProfiles"
}
],
"profiles":
{
"defaults":
{
"colorScheme": "Australis",
"font":
{
"face": "VictorMono Nerd Font",
"size": 11,
"features":
{
"calt": 1,
"liga": 1
}
},
"antialiasingMode": "grayscale",
"cursorShape": "bar",
"intenseTextStyle": "all",
"opacity": 95,
"padding": "10",
"scrollbarState": "visible",
"snapOnInput": true,
"useAcrylic": false
},
"list":
[
{
"commandline": "%SystemRoot%\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
"guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
"hidden": false,
"name": "Windows PowerShell"
},
{
"commandline": "%SystemRoot%\\System32\\cmd.exe",
"guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
"hidden": false,
"name": "Command Prompt"
},
{
"guid": "{b453ae62-4e3d-5e58-b989-0a998ec441b8}",
"hidden": false,
"name": "Azure Cloud Shell",
"source": "Windows.Terminal.Azure"
},
{
"elevate": true,
"guid": "{574e775e-4f2a-5b96-ac1e-a2962a402336}",
"hidden": false,
"name": "PowerShell",
"opacity": 95,
"source": "Windows.Terminal.PowershellCore",
"useAcrylic": true
}
]
},
"schemes":
[
{
"name": "Australis",
"foreground": "#a9bcc3",
"background": "#222531",
"cursorColor": "#6388d8",
"selectionBackground": "#6388d8",
"black": "#222531",
"red": "#ff491a",
"green": "#16b866",
"yellow": "#e1c631",
"blue": "#6388d8",
"purple": "#9d78ff",
"cyan": "#00b1a8",
"white": "#a9bcc3",
"brightBlack": "#373b46",
"brightRed": "#ff854f",
"brightGreen": "#51e08a",
"brightYellow": "#ffe14e",
"brightBlue": "#a4c4ff",
"brightPurple": "#d8adff",
"brightCyan": "#42dcd1",
"brightWhite": "#cce7ec"
}
],
"themes": [],
"windowingBehavior": "useAnyExisting"
}