Repository files navigation

dotfiles

Personal machine setup: zsh, tmux, Ghostty, neovim (AstroVim), Zed, IntelliJ (IdeaVim), hammerspoon.

Install

./install

Symlinks the configs in this repo to their expected locations, and clones TPM (tmux plugin manager) if it's not already present. After installing, open tmux and press prefix I (C-a I) to install the tmux plugins themselves.

Also symlinks .gitconfig and .ideavimrc to $HOME, and settings.json to ~/.config/zed/settings.json.

Global git ignore (separate from this repo's own .gitignore) is set up once, manually, and not managed by install:

git config --global core.excludesFile '~/.gitignore'

zsh

.zshrc is the single source of truth β€” it's what's actually symlinked to ~/.zshrc and running on this machine.

Secrets (API tokens, etc.) do not live in this repo. They go in ~/.zshrc.secrets, an untracked file outside the repo directory, which .zshrc sources automatically if present:

[ -f~/.zshrc.secrets ] &&source~/.zshrc.secrets

On a new machine, recreate that file with whatever tokens you need before sourcing .zshrc.

Every new interactive shell auto-attaches to a tmux session (main) β€” see the guarded block at the bottom of .zshrc. It deliberately does nothing inside Zed's or JetBrains' integrated terminals, since replacing those login shells with exec tmux breaks their terminal UX.

tmux

See docs/tmux.md for the full hotkey cheat sheet. Prefix is C-a.

neovim

AstroVim v4, tracked in nvim/ and symlinked to ~/.config/nvim. See nvim/README.md for what's actually customized (LSP servers, formatting, treesitter parsers) versus left as inert template stubs. nvim/lazy-lock.json pins exact plugin versions and is committed intentionally, so a fresh install reproduces the same plugin set.

Ghostty

ghostty/config is symlinked to ~/.config/ghostty/config (the only path Ghostty actually reads β€” no file extension). Cherry-picked a few settings from fatih/dotfiles: auto light/dark theme switching, macos-option-as-alt = left (left Option drives Alt bindings, right Option stays free for composed input), shift+enter for multiline input in TUIs like Claude Code, and unfocused-split dimming. Skipped his fish-shell integration and C-f-prefix tmux passthrough keybinds, since this setup uses zsh + tmux with a C-a prefix instead.

IntelliJ / IdeaVim

.ideavimrc is symlinked to ~/.ideavimrc.

Terminal notes

  • Ghostty relies on .zshrc's tmux auto-attach β€” it doesn't launch tmux itself, so behavior stays consistent across terminals and there's only one place (.zshrc) to maintain the IDE guard logic.

Other configs (not symlinked)

These live in the repo for reference/backup but aren't wired up by install, since both apps require pointing at the file manually through their own UI rather than a fixed path:

  • .obsidian.vimrc β€” Obsidian's Vim mode config.
  • RectangleConfig.json β€” Rectangle window management layout, importable via Rectangle's own settings UI.

About

πŸ’» personal system config

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

dotfiles

Personal machine setup: zsh, tmux, Ghostty, neovim (AstroVim), Zed, IntelliJ (IdeaVim), hammerspoon.

Install

./install

Symlinks the configs in this repo to their expected locations, and clones TPM (tmux plugin manager) if it's not already present. After installing, open tmux and press prefix I (C-a I) to install the tmux plugins themselves.

Also symlinks .gitconfig and .ideavimrc to $HOME, and settings.json to ~/.config/zed/settings.json.

Global git ignore (separate from this repo's own .gitignore) is set up once, manually, and not managed by install:

git config --global core.excludesFile '~/.gitignore'

zsh

.zshrc is the single source of truth β€” it's what's actually symlinked to ~/.zshrc and running on this machine.

Secrets (API tokens, etc.) do not live in this repo. They go in ~/.zshrc.secrets, an untracked file outside the repo directory, which .zshrc sources automatically if present:

[ -f~/.zshrc.secrets ] &&source~/.zshrc.secrets

On a new machine, recreate that file with whatever tokens you need before sourcing .zshrc.

Every new interactive shell auto-attaches to a tmux session (main) β€” see the guarded block at the bottom of .zshrc. It deliberately does nothing inside Zed's or JetBrains' integrated terminals, since replacing those login shells with exec tmux breaks their terminal UX.

tmux

See docs/tmux.md for the full hotkey cheat sheet. Prefix is C-a.

neovim

AstroVim v4, tracked in nvim/ and symlinked to ~/.config/nvim. See nvim/README.md for what's actually customized (LSP servers, formatting, treesitter parsers) versus left as inert template stubs. nvim/lazy-lock.json pins exact plugin versions and is committed intentionally, so a fresh install reproduces the same plugin set.

Ghostty

ghostty/config is symlinked to ~/.config/ghostty/config (the only path Ghostty actually reads β€” no file extension). Cherry-picked a few settings from fatih/dotfiles: auto light/dark theme switching, macos-option-as-alt = left (left Option drives Alt bindings, right Option stays free for composed input), shift+enter for multiline input in TUIs like Claude Code, and unfocused-split dimming. Skipped his fish-shell integration and C-f-prefix tmux passthrough keybinds, since this setup uses zsh + tmux with a C-a prefix instead.

IntelliJ / IdeaVim

.ideavimrc is symlinked to ~/.ideavimrc.

Terminal notes

  • Ghostty relies on .zshrc's tmux auto-attach β€” it doesn't launch tmux itself, so behavior stays consistent across terminals and there's only one place (.zshrc) to maintain the IDE guard logic.

Other configs (not symlinked)

These live in the repo for reference/backup but aren't wired up by install, since both apps require pointing at the file manually through their own UI rather than a fixed path:

  • .obsidian.vimrc β€” Obsidian's Vim mode config.
  • RectangleConfig.json β€” Rectangle window management layout, importable via Rectangle's own settings UI.

About

πŸ’» personal system config

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

dotfiles

Personal machine setup: zsh, tmux, Ghostty, neovim (AstroVim), Zed, IntelliJ (IdeaVim), hammerspoon.

Install

./install

Symlinks the configs in this repo to their expected locations, and clones TPM (tmux plugin manager) if it's not already present. After installing, open tmux and press prefix I (C-a I) to install the tmux plugins themselves.

Also symlinks .gitconfig and .ideavimrc to $HOME, and settings.json to ~/.config/zed/settings.json.

Global git ignore (separate from this repo's own .gitignore) is set up once, manually, and not managed by install:

git config --global core.excludesFile '~/.gitignore'

zsh

.zshrc is the single source of truth β€” it's what's actually symlinked to ~/.zshrc and running on this machine.

Secrets (API tokens, etc.) do not live in this repo. They go in ~/.zshrc.secrets, an untracked file outside the repo directory, which .zshrc sources automatically if present:

[ -f~/.zshrc.secrets ] &&source~/.zshrc.secrets

On a new machine, recreate that file with whatever tokens you need before sourcing .zshrc.

Every new interactive shell auto-attaches to a tmux session (main) β€” see the guarded block at the bottom of .zshrc. It deliberately does nothing inside Zed's or JetBrains' integrated terminals, since replacing those login shells with exec tmux breaks their terminal UX.

tmux

See docs/tmux.md for the full hotkey cheat sheet. Prefix is C-a.

neovim

AstroVim v4, tracked in nvim/ and symlinked to ~/.config/nvim. See nvim/README.md for what's actually customized (LSP servers, formatting, treesitter parsers) versus left as inert template stubs. nvim/lazy-lock.json pins exact plugin versions and is committed intentionally, so a fresh install reproduces the same plugin set.

Ghostty

ghostty/config is symlinked to ~/.config/ghostty/config (the only path Ghostty actually reads β€” no file extension). Cherry-picked a few settings from fatih/dotfiles: auto light/dark theme switching, macos-option-as-alt = left (left Option drives Alt bindings, right Option stays free for composed input), shift+enter for multiline input in TUIs like Claude Code, and unfocused-split dimming. Skipped his fish-shell integration and C-f-prefix tmux passthrough keybinds, since this setup uses zsh + tmux with a C-a prefix instead.

IntelliJ / IdeaVim

.ideavimrc is symlinked to ~/.ideavimrc.

Terminal notes

  • Ghostty relies on .zshrc's tmux auto-attach β€” it doesn't launch tmux itself, so behavior stays consistent across terminals and there's only one place (.zshrc) to maintain the IDE guard logic.

Other configs (not symlinked)

These live in the repo for reference/backup but aren't wired up by install, since both apps require pointing at the file manually through their own UI rather than a fixed path:

  • .obsidian.vimrc β€” Obsidian's Vim mode config.
  • RectangleConfig.json β€” Rectangle window management layout, importable via Rectangle's own settings UI.

About

πŸ’» personal system config

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

dotfiles

Personal machine setup: zsh, tmux, Ghostty, neovim (AstroVim), Zed, IntelliJ (IdeaVim), hammerspoon.

Install

./install

Symlinks the configs in this repo to their expected locations, and clones TPM (tmux plugin manager) if it's not already present. After installing, open tmux and press prefix I (C-a I) to install the tmux plugins themselves.

Also symlinks .gitconfig and .ideavimrc to $HOME, and settings.json to ~/.config/zed/settings.json.

Global git ignore (separate from this repo's own .gitignore) is set up once, manually, and not managed by install:

git config --global core.excludesFile '~/.gitignore'

zsh

.zshrc is the single source of truth β€” it's what's actually symlinked to ~/.zshrc and running on this machine.

Secrets (API tokens, etc.) do not live in this repo. They go in ~/.zshrc.secrets, an untracked file outside the repo directory, which .zshrc sources automatically if present:

[ -f~/.zshrc.secrets ] &&source~/.zshrc.secrets

On a new machine, recreate that file with whatever tokens you need before sourcing .zshrc.

Every new interactive shell auto-attaches to a tmux session (main) β€” see the guarded block at the bottom of .zshrc. It deliberately does nothing inside Zed's or JetBrains' integrated terminals, since replacing those login shells with exec tmux breaks their terminal UX.

tmux

See docs/tmux.md for the full hotkey cheat sheet. Prefix is C-a.

neovim

AstroVim v4, tracked in nvim/ and symlinked to ~/.config/nvim. See nvim/README.md for what's actually customized (LSP servers, formatting, treesitter parsers) versus left as inert template stubs. nvim/lazy-lock.json pins exact plugin versions and is committed intentionally, so a fresh install reproduces the same plugin set.

Ghostty

ghostty/config is symlinked to ~/.config/ghostty/config (the only path Ghostty actually reads β€” no file extension). Cherry-picked a few settings from fatih/dotfiles: auto light/dark theme switching, macos-option-as-alt = left (left Option drives Alt bindings, right Option stays free for composed input), shift+enter for multiline input in TUIs like Claude Code, and unfocused-split dimming. Skipped his fish-shell integration and C-f-prefix tmux passthrough keybinds, since this setup uses zsh + tmux with a C-a prefix instead.

IntelliJ / IdeaVim

.ideavimrc is symlinked to ~/.ideavimrc.

Terminal notes

  • Ghostty relies on .zshrc's tmux auto-attach β€” it doesn't launch tmux itself, so behavior stays consistent across terminals and there's only one place (.zshrc) to maintain the IDE guard logic.

Other configs (not symlinked)

These live in the repo for reference/backup but aren't wired up by install, since both apps require pointing at the file manually through their own UI rather than a fixed path:

  • .obsidian.vimrc β€” Obsidian's Vim mode config.
  • RectangleConfig.json β€” Rectangle window management layout, importable via Rectangle's own settings UI.

About

πŸ’» personal system config

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

dotfiles

Personal machine setup: zsh, tmux, Ghostty, neovim (AstroVim), Zed, IntelliJ (IdeaVim), hammerspoon.

Install

./install

Symlinks the configs in this repo to their expected locations, and clones TPM (tmux plugin manager) if it's not already present. After installing, open tmux and press prefix I (C-a I) to install the tmux plugins themselves.

Also symlinks .gitconfig and .ideavimrc to $HOME, and settings.json to ~/.config/zed/settings.json.

Global git ignore (separate from this repo's own .gitignore) is set up once, manually, and not managed by install:

git config --global core.excludesFile '~/.gitignore'

zsh

.zshrc is the single source of truth β€” it's what's actually symlinked to ~/.zshrc and running on this machine.

Secrets (API tokens, etc.) do not live in this repo. They go in ~/.zshrc.secrets, an untracked file outside the repo directory, which .zshrc sources automatically if present:

[ -f~/.zshrc.secrets ] &&source~/.zshrc.secrets

On a new machine, recreate that file with whatever tokens you need before sourcing .zshrc.

Every new interactive shell auto-attaches to a tmux session (main) β€” see the guarded block at the bottom of .zshrc. It deliberately does nothing inside Zed's or JetBrains' integrated terminals, since replacing those login shells with exec tmux breaks their terminal UX.

tmux

See docs/tmux.md for the full hotkey cheat sheet. Prefix is C-a.

neovim

AstroVim v4, tracked in nvim/ and symlinked to ~/.config/nvim. See nvim/README.md for what's actually customized (LSP servers, formatting, treesitter parsers) versus left as inert template stubs. nvim/lazy-lock.json pins exact plugin versions and is committed intentionally, so a fresh install reproduces the same plugin set.

Ghostty

ghostty/config is symlinked to ~/.config/ghostty/config (the only path Ghostty actually reads β€” no file extension). Cherry-picked a few settings from fatih/dotfiles: auto light/dark theme switching, macos-option-as-alt = left (left Option drives Alt bindings, right Option stays free for composed input), shift+enter for multiline input in TUIs like Claude Code, and unfocused-split dimming. Skipped his fish-shell integration and C-f-prefix tmux passthrough keybinds, since this setup uses zsh + tmux with a C-a prefix instead.

IntelliJ / IdeaVim

.ideavimrc is symlinked to ~/.ideavimrc.

Terminal notes

  • Ghostty relies on .zshrc's tmux auto-attach β€” it doesn't launch tmux itself, so behavior stays consistent across terminals and there's only one place (.zshrc) to maintain the IDE guard logic.

Other configs (not symlinked)

These live in the repo for reference/backup but aren't wired up by install, since both apps require pointing at the file manually through their own UI rather than a fixed path:

  • .obsidian.vimrc β€” Obsidian's Vim mode config.
  • RectangleConfig.json β€” Rectangle window management layout, importable via Rectangle's own settings UI.

About

πŸ’» personal system config

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

dotfiles

Personal machine setup: zsh, tmux, Ghostty, neovim (AstroVim), Zed, IntelliJ (IdeaVim), hammerspoon.

Install

./install

Symlinks the configs in this repo to their expected locations, and clones TPM (tmux plugin manager) if it's not already present. After installing, open tmux and press prefix I (C-a I) to install the tmux plugins themselves.

Also symlinks .gitconfig and .ideavimrc to $HOME, and settings.json to ~/.config/zed/settings.json.

Global git ignore (separate from this repo's own .gitignore) is set up once, manually, and not managed by install:

git config --global core.excludesFile '~/.gitignore'

zsh

.zshrc is the single source of truth β€” it's what's actually symlinked to ~/.zshrc and running on this machine.

Secrets (API tokens, etc.) do not live in this repo. They go in ~/.zshrc.secrets, an untracked file outside the repo directory, which .zshrc sources automatically if present:

[ -f~/.zshrc.secrets ] &&source~/.zshrc.secrets

On a new machine, recreate that file with whatever tokens you need before sourcing .zshrc.

Every new interactive shell auto-attaches to a tmux session (main) β€” see the guarded block at the bottom of .zshrc. It deliberately does nothing inside Zed's or JetBrains' integrated terminals, since replacing those login shells with exec tmux breaks their terminal UX.

tmux

See docs/tmux.md for the full hotkey cheat sheet. Prefix is C-a.

neovim

AstroVim v4, tracked in nvim/ and symlinked to ~/.config/nvim. See nvim/README.md for what's actually customized (LSP servers, formatting, treesitter parsers) versus left as inert template stubs. nvim/lazy-lock.json pins exact plugin versions and is committed intentionally, so a fresh install reproduces the same plugin set.

Ghostty

ghostty/config is symlinked to ~/.config/ghostty/config (the only path Ghostty actually reads β€” no file extension). Cherry-picked a few settings from fatih/dotfiles: auto light/dark theme switching, macos-option-as-alt = left (left Option drives Alt bindings, right Option stays free for composed input), shift+enter for multiline input in TUIs like Claude Code, and unfocused-split dimming. Skipped his fish-shell integration and C-f-prefix tmux passthrough keybinds, since this setup uses zsh + tmux with a C-a prefix instead.

IntelliJ / IdeaVim

.ideavimrc is symlinked to ~/.ideavimrc.

Terminal notes

  • Ghostty relies on .zshrc's tmux auto-attach β€” it doesn't launch tmux itself, so behavior stays consistent across terminals and there's only one place (.zshrc) to maintain the IDE guard logic.

Other configs (not symlinked)

These live in the repo for reference/backup but aren't wired up by install, since both apps require pointing at the file manually through their own UI rather than a fixed path:

  • .obsidian.vimrc β€” Obsidian's Vim mode config.
  • RectangleConfig.json β€” Rectangle window management layout, importable via Rectangle's own settings UI.

About

πŸ’» personal system config

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

dotfiles

Personal machine setup: zsh, tmux, Ghostty, neovim (AstroVim), Zed, IntelliJ (IdeaVim), hammerspoon.

Install

./install

Symlinks the configs in this repo to their expected locations, and clones TPM (tmux plugin manager) if it's not already present. After installing, open tmux and press prefix I (C-a I) to install the tmux plugins themselves.

Also symlinks .gitconfig and .ideavimrc to $HOME, and settings.json to ~/.config/zed/settings.json.

Global git ignore (separate from this repo's own .gitignore) is set up once, manually, and not managed by install:

git config --global core.excludesFile '~/.gitignore'

zsh

.zshrc is the single source of truth β€” it's what's actually symlinked to ~/.zshrc and running on this machine.

Secrets (API tokens, etc.) do not live in this repo. They go in ~/.zshrc.secrets, an untracked file outside the repo directory, which .zshrc sources automatically if present:

[ -f~/.zshrc.secrets ] &&source~/.zshrc.secrets

On a new machine, recreate that file with whatever tokens you need before sourcing .zshrc.

Every new interactive shell auto-attaches to a tmux session (main) β€” see the guarded block at the bottom of .zshrc. It deliberately does nothing inside Zed's or JetBrains' integrated terminals, since replacing those login shells with exec tmux breaks their terminal UX.

tmux

See docs/tmux.md for the full hotkey cheat sheet. Prefix is C-a.

neovim

AstroVim v4, tracked in nvim/ and symlinked to ~/.config/nvim. See nvim/README.md for what's actually customized (LSP servers, formatting, treesitter parsers) versus left as inert template stubs. nvim/lazy-lock.json pins exact plugin versions and is committed intentionally, so a fresh install reproduces the same plugin set.

Ghostty

ghostty/config is symlinked to ~/.config/ghostty/config (the only path Ghostty actually reads β€” no file extension). Cherry-picked a few settings from fatih/dotfiles: auto light/dark theme switching, macos-option-as-alt = left (left Option drives Alt bindings, right Option stays free for composed input), shift+enter for multiline input in TUIs like Claude Code, and unfocused-split dimming. Skipped his fish-shell integration and C-f-prefix tmux passthrough keybinds, since this setup uses zsh + tmux with a C-a prefix instead.

IntelliJ / IdeaVim

.ideavimrc is symlinked to ~/.ideavimrc.

Terminal notes

  • Ghostty relies on .zshrc's tmux auto-attach β€” it doesn't launch tmux itself, so behavior stays consistent across terminals and there's only one place (.zshrc) to maintain the IDE guard logic.

Other configs (not symlinked)

These live in the repo for reference/backup but aren't wired up by install, since both apps require pointing at the file manually through their own UI rather than a fixed path:

  • .obsidian.vimrc β€” Obsidian's Vim mode config.
  • RectangleConfig.json β€” Rectangle window management layout, importable via Rectangle's own settings UI.

About

πŸ’» personal system config

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

dotfiles

Personal machine setup: zsh, tmux, Ghostty, neovim (AstroVim), Zed, IntelliJ (IdeaVim), hammerspoon.

Install

./install

Symlinks the configs in this repo to their expected locations, and clones TPM (tmux plugin manager) if it's not already present. After installing, open tmux and press prefix I (C-a I) to install the tmux plugins themselves.

Also symlinks .gitconfig and .ideavimrc to $HOME, and settings.json to ~/.config/zed/settings.json.

Global git ignore (separate from this repo's own .gitignore) is set up once, manually, and not managed by install:

git config --global core.excludesFile '~/.gitignore'

zsh

.zshrc is the single source of truth β€” it's what's actually symlinked to ~/.zshrc and running on this machine.

Secrets (API tokens, etc.) do not live in this repo. They go in ~/.zshrc.secrets, an untracked file outside the repo directory, which .zshrc sources automatically if present:

[ -f~/.zshrc.secrets ] &&source~/.zshrc.secrets

On a new machine, recreate that file with whatever tokens you need before sourcing .zshrc.

Every new interactive shell auto-attaches to a tmux session (main) β€” see the guarded block at the bottom of .zshrc. It deliberately does nothing inside Zed's or JetBrains' integrated terminals, since replacing those login shells with exec tmux breaks their terminal UX.

tmux

See docs/tmux.md for the full hotkey cheat sheet. Prefix is C-a.

neovim

AstroVim v4, tracked in nvim/ and symlinked to ~/.config/nvim. See nvim/README.md for what's actually customized (LSP servers, formatting, treesitter parsers) versus left as inert template stubs. nvim/lazy-lock.json pins exact plugin versions and is committed intentionally, so a fresh install reproduces the same plugin set.

Ghostty

ghostty/config is symlinked to ~/.config/ghostty/config (the only path Ghostty actually reads β€” no file extension). Cherry-picked a few settings from fatih/dotfiles: auto light/dark theme switching, macos-option-as-alt = left (left Option drives Alt bindings, right Option stays free for composed input), shift+enter for multiline input in TUIs like Claude Code, and unfocused-split dimming. Skipped his fish-shell integration and C-f-prefix tmux passthrough keybinds, since this setup uses zsh + tmux with a C-a prefix instead.

IntelliJ / IdeaVim

.ideavimrc is symlinked to ~/.ideavimrc.

Terminal notes

  • Ghostty relies on .zshrc's tmux auto-attach β€” it doesn't launch tmux itself, so behavior stays consistent across terminals and there's only one place (.zshrc) to maintain the IDE guard logic.

Other configs (not symlinked)

These live in the repo for reference/backup but aren't wired up by install, since both apps require pointing at the file manually through their own UI rather than a fixed path:

  • .obsidian.vimrc β€” Obsidian's Vim mode config.
  • RectangleConfig.json β€” Rectangle window management layout, importable via Rectangle's own settings UI.

About

πŸ’» personal system config

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages