Merge remote-tracking branch 'origin/master'
# Conflicts: # home_config/ghostty/config # home_root/.zshrc
This commit is contained in:
+5
-1
@@ -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/
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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" },
|
||||
|
||||
@@ -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"
|
||||
@@ -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 = '❯❯ '
|
||||
Binary file not shown.
Binary file not shown.
@@ -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
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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": **3–7 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
@@ -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,5 +1,4 @@
|
||||
~/.config/tmux/plugins
|
||||
~/.config/thefuck/__pycache__
|
||||
~/.config/btop
|
||||
~/.config/neofetch
|
||||
~/.config/zinit
|
||||
|
||||
@@ -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
@@ -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
@@ -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."
|
||||
|
||||
@@ -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
|
||||
Executable
+100
@@ -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."
|
||||
@@ -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
|
||||
@@ -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 +0,0 @@
|
||||
curl -s https://ohmyposh.dev/install.sh | bash -s
|
||||
@@ -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/
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
@@ -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!"
|
||||
@@ -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"
|
||||
}
|
||||
Reference in New Issue
Block a user