# God Devex Tooling

> God-level developer experience and tooling: IDE mastery (VS Code extensions/settings/keybindings/devcontainers, JetBrains IDE features, Vim/Neovim with LSP/Treesitter/telescope), terminal productivity (zsh/bash/fish, oh-my-zsh/starship, tmux, fzf, ripgrep, bat, eza, zoxide, delta), debuggers (gdb, lldb, pdb/ipdb, Delve for Go, IntelliJ debugger, VS Code launch.json), linters and formatters (ESLint, Prettier, Ruff, Black, gofmt/golangci-lint, ktlint, Checkstyle, clang-format, yamllint, hadolint), pre-commit hooks (husky, lefthook, pre-commit framework), static analysis (SonarQube, CodeClimate, semgrep, codeql), AI coding assistants (GitHub Copilot, Cursor AI, Cody, Tabnine, Aider), shell scripting (bash strict mode, arrays, parameter expansion, here-docs, process substitution), Makefile patterns, task runners (just, Taskfile.yml), and productivity systems. Never back down — master every tool in the developer's arsenal.

- Skill: `ardurai/god-devex-tooling` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add ardurai/god-devex-tooling`
- Raw SKILL.md: https://api.skillmd.com/api/skills/ardurai/god-devex-tooling/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- License: MIT
- Author: ArdurAI (https://skillmd.com/u/ardurai)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/ardurai/god-devex-tooling

---


# god-devex-tooling

You are a developer experience architect and tooling craftsperson who has set up development environments for thousands of engineers, debugged mysterious editor failures at 11 PM before a release, and written shell scripts that have run in production for a decade. You never back down from a slow build, a cryptic error message, or a broken local setup. You know that 10 minutes spent improving a tool that runs 50 times a day yields hours of compound return. You approach developer tooling like a master woodworker approaches their shop: every tool has a purpose, is kept sharp, and is used with precision.

---

## Core Philosophy

- **Fast feedback loops compound.** A test suite that runs in 2 seconds instead of 20 saves hours per week per engineer.
- **Reproducibility is infrastructure.** "Works on my machine" is a bug. Dev containers and lockfiles are the fix.
- **Automate the boring parts.** Linting, formatting, and basic checks should run automatically — never manually.
- **Learn your editor deeply.** 1% faster editing across 8 hours/day = 5 minutes/day = 20 hours/year per engineer.
- **Never back down.** When a tool misbehaves, understand why. Don't restart it and hope — diagnose it.
- **Zero hallucination.** Tool flags, config syntax, and behavior change across versions. Verify with `--help`, `man`, or official docs before asserting.

---

## VS Code Mastery

### settings.json Structure

```json
// ~/.config/Code/User/settings.json (user-level)
// .vscode/settings.json (workspace-level — committed to repo)
{
  // Editor
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.tabSize": 2,
  "editor.insertSpaces": true,
  "editor.rulers": [80, 120],
  "editor.minimap.enabled": false,
  "editor.linkedEditing": true,
  "editor.bracketPairColorization.enabled": true,
  "editor.guides.bracketPairs": "active",
  "editor.inlineSuggest.enabled": true,
  
  // Per-language formatters (override default)
  "[python]": {
    "editor.defaultFormatter": "charliermarsh.ruff",
    "editor.formatOnSave": true
  },
  "[go]": {
    "editor.formatOnSave": true
  },
  "[rust]": {
    "editor.defaultFormatter": "rust-lang.rust-analyzer"
  },
  
  // Files
  "files.autoSave": "onFocusChange",
  "files.trimTrailingWhitespace": true,
  "files.insertFinalNewline": true,
  "files.exclude": {
    "**/__pycache__": true,
    "**/.pytest_cache": true,
    "**/node_modules": true
  },
  
  // Terminal
  "terminal.integrated.shell.linux": "/bin/zsh",
  "terminal.integrated.fontSize": 13,
  "terminal.integrated.scrollback": 10000,
  
  // Git
  "git.autofetch": true,
  "git.confirmSync": false,
  "diffEditor.ignoreTrimWhitespace": false
}
```

### Essential Extensions

```
# Language support
rust-lang.rust-analyzer          # Rust LSP (use this, not others)
golang.go                         # Go LSP + tools
ms-python.python                  # Python LSP
ms-python.vscode-pylance          # Python type checking
charliermarsh.ruff                # Python linter + formatter (fast)
dbaeumer.vscode-eslint            # ESLint integration
esbenp.prettier-vscode            # Prettier formatter

# Productivity
eamodio.gitlens                   # GitLens: blame, history, code authorship
humao.rest-client                 # .http files for API testing
rangav.vscode-thunder-client      # GUI REST client
usernamehw.errorlens              # Inline error display (no more red squiggles)
gruntfuggly.todo-tree             # TODO/FIXME tree view
oderwat.indent-rainbow            # Color-coded indentation
johnpapa.vscode-peacock           # Workspace color coding
PKief.material-icon-theme         # File icons

# Editing
formulahendry.auto-rename-tag     # Auto-rename HTML/JSX closing tags
streetsidesoftware.code-spell-checker  # Spell check in code

# DevOps
ms-vscode-remote.remote-ssh       # Remote SSH development
ms-vscode-remote.remote-containers # Dev Containers
hashicorp.terraform                # Terraform syntax + validation
redhat.vscode-yaml                 # YAML with schema validation
```

### Keybindings and Multi-Cursor

```json
// keybindings.json — examples with when clause
[
  {
    "key": "ctrl+shift+d",
    "command": "editor.action.copyLinesDownAction",
    "when": "editorTextFocus && !editorReadonly"
  },
  {
    "key": "alt+j",
    "command": "workbench.action.moveEditorToNextGroup"
  }
]
```

**Multi-cursor operations** (know these cold):
- `Alt+Click`: Add cursor at click position
- `Ctrl+D` (Mac: `Cmd+D`): Select next occurrence of current selection
- `Ctrl+Shift+L` (Mac: `Cmd+Shift+L`): Select all occurrences
- `Ctrl+Alt+Up/Down` (Mac: `Cmd+Alt+Up/Down`): Add cursor above/below
- `Alt+Shift+I`: Add cursor to end of each selected line
- `Escape`: Return to single cursor

**Productivity shortcuts**:
- `Ctrl+P`: Quick file open
- `Ctrl+Shift+P`: Command palette
- `Ctrl+G`: Go to line
- `Ctrl+Shift+F`: Search across files
- `F12`: Go to definition
- `Alt+F12`: Peek definition (inline)
- `Shift+F12`: Find all references
- `F2`: Rename symbol
- `Ctrl+.`: Quick fix / code action
- `Ctrl+/`: Toggle line comment
- `Alt+Shift+F`: Format document

**Zen mode**: `Ctrl+K Z` — hides UI chrome, full focus on code. Exit: `Escape` twice.

### Remote Development

```json
// .devcontainer/devcontainer.json
{
  "name": "My Project Dev Container",
  "image": "mcr.microsoft.com/devcontainers/base:ubuntu-22.04",
  "features": {
    "ghcr.io/devcontainers/features/docker-in-docker:2": {},
    "ghcr.io/devcontainers/features/github-cli:1": {},
    "ghcr.io/devcontainers/features/node:1": { "version": "20" },
    "ghcr.io/devcontainers/features/python:1": { "version": "3.11" }
  },
  "forwardPorts": [3000, 8080, 5432],
  "postCreateCommand": "npm install && pip install -r requirements.txt",
  "postStartCommand": "git config --global --add safe.directory ${containerWorkspaceFolder}",
  "customizations": {
    "vscode": {
      "extensions": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"],
      "settings": {
        "terminal.integrated.defaultProfile.linux": "zsh"
      }
    }
  },
  "remoteUser": "vscode",
  "mounts": [
    "source=${localEnv:HOME}/.ssh,target=/home/vscode/.ssh,type=bind,readonly"
  ]
}
```

**Benefits**: Identical environment for all team members. Dependencies in container, not host. Switch between projects without conflicts. Works in GitHub Codespaces.

### tasks.json and launch.json

```json
// .vscode/tasks.json
{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "Build",
      "type": "shell",
      "command": "npm run build",
      "group": { "kind": "build", "isDefault": true },
      "problemMatcher": ["$eslint-stylish"],
      "presentation": { "reveal": "always", "panel": "dedicated" }
    },
    {
      "label": "Test",
      "type": "shell",
      "command": "npm test -- --watchAll=false",
      "group": { "kind": "test", "isDefault": true }
    }
  ]
}

// .vscode/launch.json
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Node.js Debug",
      "type": "node",
      "request": "launch",
      "program": "${workspaceFolder}/src/index.js",
      "env": { "NODE_ENV": "development" },
      "console": "integratedTerminal",
      "restart": true  // Auto-restart on file change
    },
    {
      "name": "Python Debug",
      "type": "python",
      "request": "launch",
      "program": "${workspaceFolder}/main.py",
      "args": ["--debug"],
      "justMyCode": false  // Step into library code
    },
    {
      "name": "Go Debug",
      "type": "go",
      "request": "launch",
      "mode": "auto",
      "program": "${workspaceFolder}/cmd/server",
      "env": { "PORT": "8080" }
    },
    {
      "name": "Attach to Process",
      "type": "node",
      "request": "attach",
      "port": 9229,
      "restart": true
    }
  ]
}
```

---

## JetBrains IDE Features

### Structural Search and Replace (SSR)

Search for code patterns, not just text. Understands AST structure.

In IntelliJ: Edit → Find → Search Structurally. Example pattern:
- Search: `$x$.foo($params$)` → finds all calls to any method named `foo`
- Replace: `$x$.bar($params$)` → renames all `foo` calls to `bar`

Use for: renaming methods across codebase while respecting call sites, finding specific API usage patterns, migrating deprecated API calls.

### Live Templates

Code snippets with variable interpolation. `Ctrl+J` to expand.

Built-in examples:
- `fori` → `for (int i = 0; i < ...; i++) {}`
- `psvm` → `public static void main(String[] args) {}`
- `sout` → `System.out.println()`

Custom template: Settings → Editor → Live Templates → Add.

### Built-in HTTP Client

Create `.http` files (JetBrains) or `.rest` files:

```http
### Get user
GET https://api.example.com/users/123
Authorization: Bearer {{auth_token}}
Accept: application/json

### Create user
POST https://api.example.com/users
Content-Type: application/json

{
  "name": "Alice",
  "email": "alice@example.com"
}

### Variables in http-client.env.json
{
  "development": {
    "auth_token": "dev-token-123",
    "base_url": "http://localhost:8080"
  },
  "production": {
    "auth_token": "{{$env AUTH_TOKEN}}",
    "base_url": "https://api.example.com"
  }
}
```

### Multiple Carets

- `Alt+Shift+Click`: Add caret at click
- `Ctrl+Ctrl` (hold second): Multi-caret column selection
- Select + `Alt+J`: Add next occurrence to selection
- `Ctrl+Alt+Shift+J`: Select all occurrences

---

## Neovim / Vim Mastery

### Modal Editing — Core Motions

```
Normal mode motions:
  w/W  — word forward (w: stops at punctuation, W: stops at whitespace)
  b/B  — word backward
  e/E  — end of word
  f{c} — find character c (forward on line); ; repeats, , reverses
  t{c} — till character c (stops before it)
  F{c} — find character c (backward)
  0    — start of line
  ^    — first non-blank of line
  $    — end of line
  gg   — first line
  G    — last line
  {N}G — line N
  %    — matching bracket/brace/paren
  H/M/L — top/middle/bottom of screen
  Ctrl+f/b — page forward/backward
  Ctrl+d/u — half page down/up
```

### Operators and Text Objects

```
Operators (apply to motions or text objects):
  d — delete (cut)
  c — change (delete + enter insert)
  y — yank (copy)
  v — visual select
  > / < — indent/dedent
  = — autoindent
  ~ — toggle case

Text objects (use with operators):
  iw / aw — inner word / a word (includes space)
  is / as — inner sentence / a sentence
  ip / ap — inner paragraph / a paragraph
  i" / a" — inside/around double quotes
  i' / a' — inside/around single quotes
  i` / a` — inside/around backticks
  i( / a( — inside/around parentheses (also i)/a))
  i{ / a{ — inside/around braces (also iB/aB)
  i[ / a[ — inside/around brackets
  it / at — inside/around XML/HTML tags

Examples:
  diw  — delete word under cursor
  ci"  — change text inside double quotes
  ya{  — yank including surrounding braces
  vip  — visually select paragraph
  =ip  — autoindent paragraph
```

### Registers

```
"" — unnamed register (last delete/yank)
"0 — yank register (only yank, not delete)
"a-"z — named registers (use with "a{op} to store, "ap to paste)
"+ — system clipboard
"* — selection clipboard (X11 primary)
": — last command
"/ — last search
". — last inserted text
"% — current filename

# Copy to system clipboard
"+yy    — yank line to clipboard
"+p     — paste from clipboard

# In insert mode
Ctrl+R {reg}  — paste from register
```

### Macros

```
qa    — start recording macro into register 'a'
<do stuff>
q     — stop recording

@a    — replay macro 'a'
@@    — replay last macro
10@a  — replay macro 'a' 10 times

# Practical example: add semicolon to end of 50 lines
qa
$a;<Esc>j
q
49@a
```

### Neovim LSP Setup (nvim-lspconfig)

```lua
-- Using lazy.nvim
{
  "neovim/nvim-lspconfig",
  dependencies = {
    "williamboman/mason.nvim",     -- LSP/DAP/linter installer
    "williamboman/mason-lspconfig.nvim",
  },
  config = function()
    require("mason").setup()
    require("mason-lspconfig").setup({
      ensure_installed = { "lua_ls", "pyright", "ts_ls", "gopls", "rust_analyzer" }
    })
    
    local lspconfig = require("lspconfig")
    local on_attach = function(client, bufnr)
      local opts = { buffer = bufnr }
      vim.keymap.set("n", "gd", vim.lsp.buf.definition, opts)
      vim.keymap.set("n", "K", vim.lsp.buf.hover, opts)
      vim.keymap.set("n", "<leader>rn", vim.lsp.buf.rename, opts)
      vim.keymap.set("n", "<leader>ca", vim.lsp.buf.code_action, opts)
      vim.keymap.set("n", "gr", vim.lsp.buf.references, opts)
    end
    
    lspconfig.pyright.setup({ on_attach = on_attach })
    lspconfig.gopls.setup({ on_attach = on_attach })
    lspconfig.ts_ls.setup({ on_attach = on_attach })
    lspconfig.rust_analyzer.setup({ on_attach = on_attach })
  end
}
```

### Telescope.nvim

```lua
-- Keymaps
vim.keymap.set("n", "<leader>ff", require("telescope.builtin").find_files)
vim.keymap.set("n", "<leader>fg", require("telescope.builtin").live_grep)
vim.keymap.set("n", "<leader>fb", require("telescope.builtin").buffers)
vim.keymap.set("n", "<leader>fh", require("telescope.builtin").help_tags)
vim.keymap.set("n", "<leader>fr", require("telescope.builtin").resume)
vim.keymap.set("n", "<leader>gd", require("telescope.builtin").lsp_definitions)
vim.keymap.set("n", "<leader>gr", require("telescope.builtin").lsp_references)

-- In telescope: Ctrl+/ for help, Ctrl+u/d to scroll preview
```

---

## Terminal Productivity

### Zsh Configuration

```zsh
# ~/.zshrc essentials

# History
HISTFILE=~/.zsh_history
HISTSIZE=50000
SAVEHIST=50000
setopt HIST_IGNORE_ALL_DUPS
setopt HIST_FIND_NO_DUPS
setopt SHARE_HISTORY           # Share history across terminals
setopt INC_APPEND_HISTORY_TIME # Append with timestamps

# Aliases
alias ll='eza -la --git --icons'
alias la='eza -a'
alias lt='eza --tree --level=2'
alias cat='bat'
alias grep='rg'
alias cd='z'            # Use zoxide
alias vim='nvim'
alias g='git'
alias k='kubectl'
alias tf='terraform'

# Functions
mkcd() { mkdir -p "$1" && cd "$1"; }
extract() {
  case "$1" in
    *.tar.gz|*.tgz) tar xzf "$1" ;;
    *.tar.bz2)      tar xjf "$1" ;;
    *.zip)           unzip "$1" ;;
    *.gz)            gunzip "$1" ;;
    *.rar)           unrar x "$1" ;;
    *)               echo "Unknown format: $1" ;;
  esac
}
```

### Starship Prompt

```toml
# ~/.config/starship.toml
format = """
$username$hostname$directory$git_branch$git_status$python$node$go$rust$time$line_break$character"""

[directory]
truncation_length = 4
truncate_to_repo = true

[git_branch]
symbol = " "
format = "[$symbol$branch]($style) "

[git_status]
format = '([\[$all_status$ahead_behind\]]($style) )'
conflicted = "⚔️ "
ahead = "⇡${count}"
behind = "⇣${count}"
modified = "!${count}"
untracked = "?${count}"

[python]
format = "[${symbol}${pyenv_prefix}(${version} )(\\($virtualenv\\))]($style) "
symbol = " "

[time]
disabled = false
format = "[$time]($style) "
```

### tmux

```bash
# tmux.conf key bindings (prefix is Ctrl+B by default, change to Ctrl+A)
# ~/.tmux.conf

set -g prefix C-a
unbind C-b
bind C-a send-prefix

# Split panes
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"

# Navigate panes (vim-like)
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R

# Resize panes
bind -r H resize-pane -L 5
bind -r J resize-pane -D 5
bind -r K resize-pane -U 5
bind -r L resize-pane -R 5

# Mouse support
set -g mouse on

# 256 color
set -g default-terminal "screen-256color"

# Start index at 1 (easier keyboard reach)
set -g base-index 1
set -g pane-base-index 1

# Plugin manager (TPM)
set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-resurrect'    # Save/restore sessions
set -g @plugin 'tmux-plugins/tmux-continuum'    # Auto-save every 15m
set -g @continuum-restore 'on'
```

```bash
# Common tmux commands
tmux new -s myproject      # New named session
tmux ls                    # List sessions
tmux attach -t myproject   # Attach to session
tmux kill-session -t old   # Kill session

# In session:
Ctrl+A c    # New window
Ctrl+A n/p  # Next/previous window
Ctrl+A ,    # Rename window
Ctrl+A d    # Detach
Ctrl+A [    # Copy mode (vi keys to navigate, Space/Enter to copy)
Ctrl+A ]    # Paste
```

### fzf

```bash
# Installation adds these keybindings to zsh/bash:
Ctrl+R   # Fuzzy history search
Ctrl+T   # Fuzzy file finder (outputs file path)
Alt+C    # Fuzzy cd into directory

# fzf with preview
fzf --preview 'bat --color=always {}'

# Most useful aliases
alias fh='history | fzf --tac | sed "s/ *[0-9]* *//"'  # fuzzy history execute

# Kill processes interactively
kill -9 $(ps aux | fzf | awk '{print $2}')

# Git checkout with fzf
alias gcob='git checkout $(git branch | fzf)'
alias glb='git log --oneline | fzf | awk "{print \$1}" | xargs git show'

# Env vars for fzf
export FZF_DEFAULT_COMMAND='rg --files --hidden --follow --glob "!.git"'
export FZF_DEFAULT_OPTS='--height 40% --layout=reverse --border'
export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"
```

### ripgrep

```bash
# Basic search
rg "search pattern" 

# Search specific file type
rg --type python "import os"
rg -t py "import os"

# Respect .gitignore (default), search hidden files too
rg --hidden "secret"

# Include files that gitignore would exclude
rg --no-ignore "vendor_code"

# Context lines (before/after/context)
rg -B2 -A5 "def process_payment"

# Count matches per file
rg --count "TODO"

# Replace (dry run then actual)
rg -l "oldFunction" | xargs sed -i 's/oldFunction/newFunction/g'

# Search with glob pattern
rg "pattern" --glob "*.{ts,tsx}" --glob "!*.test.ts"

# Show only filenames
rg -l "pattern"

# Case insensitive
rg -i "pattern"

# Multiline match
rg -U "pattern\nacross\nlines"
```

### bat, eza, zoxide, delta

```bash
# bat: cat with syntax highlighting and git integration
bat file.py                # With line numbers, syntax, git diff markers
bat --plain file.py        # No decorations
bat --style=numbers file.py
cat large.log | bat        # Pipe input with highlighting

# eza: modern ls replacement
eza -la                    # Long format with hidden files
eza -la --git              # Show git status per file
eza --tree --level=3       # Tree view, 3 levels deep
eza --icons                # File type icons
eza -la --sort=modified    # Sort by modification time

# zoxide: smarter cd
z projects                 # Jump to most frecent directory matching "projects"
z proj pay                 # Match multiple terms
zi                         # Interactive fzf mode

# delta: git diff with syntax highlighting
# ~/.gitconfig
[core]
    pager = delta
[interactive]
    diffFilter = delta --color-only
[delta]
    navigate = true
    line-numbers = true
    syntax-theme = Dracula
[merge]
    conflictstyle = diff3
[diff]
    colorMoved = default
```

---

## Shell Scripting Best Practices

### Bash Strict Mode

```bash
#!/usr/bin/env bash
set -euo pipefail
# -e: exit on any error
# -u: treat unset variables as error
# -o pipefail: pipe fails if any command fails (not just last)

# Also useful:
set -x  # Print each command before executing (debugging)
IFS=$'\n\t'  # Safe field separator (no space splitting)
```

### Arrays and Associative Arrays

```bash
# Indexed arrays
declare -a fruits=("apple" "banana" "cherry")
fruits+=("date")                    # Append
echo "${fruits[0]}"                 # First element
echo "${fruits[@]}"                 # All elements
echo "${#fruits[@]}"                # Count
echo "${fruits[@]:1:2}"             # Slice: elements 1 and 2
unset fruits[1]                     # Remove element

# Iterate
for fruit in "${fruits[@]}"; do
    echo "$fruit"
done

# Associative arrays (Bash 4+)
declare -A config
config["host"]="localhost"
config["port"]="5432"
config["db"]="myapp"

echo "${config[host]}"
for key in "${!config[@]}"; do      # Iterate keys
    echo "$key = ${config[$key]}"
done
```

### Parameter Expansion

```bash
name="World"

# Default values
${name:-"default"}    # Use "default" if name is unset or empty
${name:="default"}    # Assign "default" if name is unset or empty
${name:?"Error msg"}  # Exit with error if name is unset or empty
${name:+"has value"}  # Use "has value" if name IS set

# String manipulation
path="/usr/local/bin/python3"
${path%/*}            # Remove shortest suffix matching /*   → /usr/local/bin
${path%%/*}           # Remove longest suffix matching /*    → (empty)
${path#*/}            # Remove shortest prefix matching */   → usr/local/bin/python3
${path##*/}           # Remove longest prefix matching */    → python3
${path//local/LOCAL}  # Replace all occurrences → /usr/LOCAL/bin/python3
${path/local/LOCAL}   # Replace first occurrence → /usr/LOCAL/bin/python3
${#path}              # Length of string → 22
${path:4:5}           # Substring: start 4, length 5 → /loca
${name^^}             # Uppercase → WORLD
${name,,}             # Lowercase → world
```

### Here-Docs and Process Substitution

```bash
# Here-doc
cat <<EOF
Line 1
Line 2 with $variable interpolation
EOF

# Here-doc with indentation (leading tabs stripped — must be TAB, not spaces)
cat <<-EOF
	Indented line (leading tab removed)
	Another indented line
EOF

# Here-doc without interpolation (quote delimiter)
cat <<'EOF'
This $variable will NOT be interpolated
EOF

# Process substitution: treat command output as file
diff <(sort file1.txt) <(sort file2.txt)

# Feed process output as stdin to another process
while read -r line; do
    echo "Processing: $line"
done < <(find . -name "*.py" -newer requirements.txt)

# Capture and redirect simultaneously
tee >(gzip > output.gz) < input.txt | wc -l
```

### Trap and Cleanup

```bash
#!/usr/bin/env bash
set -euo pipefail

TMPDIR=$(mktemp -d)
LOCKFILE="/tmp/myapp.lock"

cleanup() {
    local exit_code=$?
    rm -rf "$TMPDIR"
    rm -f "$LOCKFILE"
    if [[ $exit_code -ne 0 ]]; then
        echo "Script failed with exit code $exit_code" >&2
    fi
}

trap cleanup EXIT  # Runs on any exit
trap 'cleanup; exit 130' INT   # Ctrl+C
trap 'cleanup; exit 143' TERM  # kill command

# Argument parsing with getopts
usage() { echo "Usage: $0 [-v] [-o output_file] input_file" >&2; exit 1; }

VERBOSE=false
OUTPUT_FILE=""

while getopts "vo:" opt; do
    case $opt in
        v) VERBOSE=true ;;
        o) OUTPUT_FILE="$OPTARG" ;;
        *) usage ;;
    esac
done
shift $((OPTIND - 1))

[[ $# -lt 1 ]] && usage
INPUT_FILE="$1"
```

---

## Debuggers

### GDB

```bash
# Compile with debug symbols
gcc -g -O0 -o myprogram myprogram.c
# Start debugging
gdb ./myprogram
gdb --args ./myprogram arg1 arg2

# GDB commands
(gdb) break main           # Breakpoint at main
(gdb) break file.c:42      # Breakpoint at line 42
(gdb) break MyClass::method # Breakpoint at method
(gdb) condition 1 x > 5    # Conditional breakpoint (breakpoint 1)
(gdb) run                  # Start program
(gdb) next (n)             # Next line (don't step into)
(gdb) step (s)             # Step into function
(gdb) continue (c)         # Continue to next breakpoint
(gdb) finish               # Run until function returns
(gdb) print x              # Print variable
(gdb) print *ptr           # Dereference pointer
(gdb) display x            # Auto-print x after every step
(gdb) watch x              # Break when x changes (watchpoint)
(gdb) backtrace (bt)       # Stack trace
(gdb) frame 2              # Switch to frame 2
(gdb) info locals          # Local variables in current frame
(gdb) info registers       # CPU registers
(gdb) disassemble          # Disassemble current function
(gdb) x/10wx $rsp          # Examine 10 words at stack pointer
(gdb) set x = 42           # Modify variable
# Core dump analysis
gdb ./myprogram core       # Load core dump
(gdb) where                # Show where crash occurred
```

### Python pdb/ipdb

```python
# In code (Python 3.7+)
breakpoint()  # Uses PYTHONBREAKPOINT env var, defaults to pdb

# Or explicitly
import pdb; pdb.set_trace()

# ipdb: enhanced pdb with syntax highlighting
import ipdb; ipdb.set_trace()
```

```
# pdb commands
l (list)        — Show source code around current line
n (next)        — Next line (don't step into)
s (step)        — Step into function
c (continue)    — Continue to next breakpoint
r (return)      — Continue until function returns
b 42            — Set breakpoint at line 42
b func_name     — Set breakpoint at function
cl 1            — Clear breakpoint 1
p variable      — Print variable
pp variable     — Pretty-print variable
a               — Print all function arguments
u / d           — Up / down stack frame
interact        — Start interactive Python shell in current context
q (quit)        — Quit debugger
```

### Go Delve

```bash
# Debug a package
dlv debug ./cmd/server

# Debug with arguments
dlv debug ./cmd/server -- --port 8080

# Attach to running process
dlv attach <pid>

# Debug test
dlv test ./pkg/... -- -run TestMyFunc

# Delve commands
(dlv) break main.main           # Breakpoint at function
(dlv) break server.go:42        # Breakpoint at line
(dlv) continue (c)              # Run to next breakpoint
(dlv) next (n)                  # Next line
(dlv) step (s)                  # Step into
(dlv) stepout (so)              # Step out of function
(dlv) print (p) variable        # Print variable
(dlv) locals                    # All local variables
(dlv) args                      # Function arguments
(dlv) goroutines                # List all goroutines
(dlv) goroutine 5               # Switch to goroutine 5
(dlv) goroutine 5 bt            # Backtrace of goroutine 5
(dlv) stack                     # Current goroutine stack
(dlv) frame 2                   # Switch to frame 2
(dlv) vars main                 # Package-level variables
(dlv) whatis x                  # Type of variable
```

---

## Linters and Formatters

### ESLint (Flat Config — eslint.config.js)

```javascript
// eslint.config.js (new flat config, ESLint 8.21+)
import js from "@eslint/js";
import tseslint from "typescript-eslint";
import reactPlugin from "eslint-plugin-react";

export default [
  js.configs.recommended,
  ...tseslint.configs.recommended,
  {
    plugins: { react: reactPlugin },
    rules: {
      "no-console": ["warn", { allow: ["error", "warn"] }],
      "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
      "@typescript-eslint/explicit-function-return-type": "off",
      "react/jsx-no-target-blank": "error",
    },
    settings: { react: { version: "detect" } }
  },
  {
    files: ["**/*.test.ts"],
    rules: { "@typescript-eslint/no-explicit-any": "off" }
  }
];
```

```bash
# CLI usage
eslint src/                  # Lint directory
eslint src/ --fix            # Auto-fix
eslint src/ --format=compact # Compact output for CI
eslint --print-config file.ts  # Debug: show effective config
```

### Prettier

```json
// .prettierrc
{
  "printWidth": 100,
  "tabWidth": 2,
  "useTabs": false,
  "semi": true,
  "singleQuote": true,
  "trailingComma": "all",
  "bracketSpacing": true,
  "arrowParens": "always",
  "endOfLine": "lf",
  "overrides": [
    {
      "files": "*.md",
      "options": { "printWidth": 80, "proseWrap": "always" }
    }
  ]
}
```

```bash
prettier --write src/          # Format all files
prettier --check src/          # Check (CI mode, exit 1 if not formatted)
prettier --write '**/*.{ts,tsx,json,css,md}'
```

### Ruff (Python — replaces flake8, isort, pyupgrade, and more)

```toml
# pyproject.toml
[tool.ruff]
target-version = "py311"
line-length = 100
src = ["src", "tests"]

[tool.ruff.lint]
select = [
  "E",    # pycodestyle errors
  "W",    # pycodestyle warnings  
  "F",    # pyflakes
  "I",    # isort
  "B",    # flake8-bugbear
  "C4",   # flake8-comprehensions
  "UP",   # pyupgrade
  "SIM",  # flake8-simplify
]
ignore = ["E501"]  # Line too long (handled by formatter)

[tool.ruff.format]
quote-style = "double"
indent-style = "space"
```

```bash
ruff check src/           # Lint
ruff check src/ --fix     # Lint + auto-fix
ruff format src/          # Format (Black-compatible)
ruff check --select I src/  # Only isort check
```

### golangci-lint

```yaml
# .golangci.yml
run:
  timeout: 5m
  tests: true

linters:
  enable:
    - staticcheck    # Advanced static analysis
    - errcheck       # Check all errors are handled
    - gosec          # Security issues
    - govet          # Report suspicious constructs
    - ineffassign    # Detect ineffectual assignments
    - unused         # Find unused code
    - misspell       # Fix common misspellings
    - goimports      # Fixes imports
    - exhaustive     # Check switch exhaustiveness
    - bodyclose      # Check HTTP response body closure
    - noctx          # Sends http request without context.Context

linters-settings:
  errcheck:
    check-type-assertions: true
  govet:
    enable-all: true
  gosec:
    excludes: [G104]  # Errors unhandled (too noisy for tests)

issues:
  exclude-rules:
    - path: _test\.go
      linters: [gosec, errcheck]
```

```bash
golangci-lint run ./...
golangci-lint run --fix ./...
golangci-lint run --timeout 5m ./...
```

### hadolint (Dockerfile linting)

```bash
hadolint Dockerfile
hadolint --ignore DL3008 Dockerfile  # Ignore specific rule
hadolint --format json Dockerfile    # JSON output for CI
# DL3008: Pin package versions in apt-get install
# DL3025: Use arguments JSON notation for CMD and ENTRYPOINT
# SC2086: Double quote variable to prevent word splitting
```

---

## Pre-commit Hooks

### pre-commit Framework

```yaml
# .pre-commit-config.yaml
repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.5.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-json
      - id: check-merge-conflict
      - id: detect-private-key
      - id: no-commit-to-branch
        args: ["--branch", "main", "--branch", "production"]

  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.3.0
    hooks:
      - id: ruff
        args: [--fix]
      - id: ruff-format

  - repo: https://github.com/pre-commit/mirrors-prettier
    rev: v3.1.0
    hooks:
      - id: prettier
        types_or: [javascript, typescript, json, css, markdown]

  - repo: https://github.com/hadolint/hadolint
    rev: v2.12.0
    hooks:
      - id: hadolint-docker
```

```bash
pre-commit install          # Install into .git/hooks
pre-commit run --all-files  # Run on all files (CI)
pre-commit run ruff         # Run specific hook
pre-commit autoupdate       # Update hook versions
pre-commit clean            # Clear cache
```

### lefthook (Go-based, fast parallel execution)

```yaml
# lefthook.yml
pre-commit:
  parallel: true
  commands:
    lint:
      glob: "*.{ts,tsx}"
      run: npx eslint {staged_files} --fix
    format:
      glob: "*.{ts,tsx,json}"
      run: npx prettier --write {staged_files}
    python-lint:
      glob: "*.py"
      run: ruff check {staged_files} --fix

pre-push:
  commands:
    tests:
      run: npm test -- --passWithNoTests
```

```bash
lefthook install    # Install hooks
lefthook run pre-commit  # Manual run
```

---

## Static Analysis

### semgrep

```bash
# Scan with auto-detected rules
semgrep --config auto src/

# Use specific registry rules
semgrep --config p/python src/
semgrep --config p/javascript src/
semgrep --config p/owasp-top-ten src/

# Write custom rule
cat > rule.yaml <<'EOF'
rules:
  - id: hardcoded-secret
    pattern: password = "$WORD"
    message: "Hardcoded password found"
    languages: [python, javascript]
    severity: ERROR
EOF
semgrep --config rule.yaml src/

# CI mode (SARIF output for GitHub Code Scanning)
semgrep --config auto --sarif > semgrep.sarif
```

### CodeQL

```yaml
# .github/workflows/codeql.yml
name: CodeQL
on: [push, pull_request]
jobs:
  analyze:
    runs-on: ubuntu-latest
    permissions:
      security-events: write
    steps:
      - uses: actions/checkout@v4
      - uses: github/codeql-action/init@v3
        with:
          languages: javascript, python  # or: go, java, csharp, ruby, swift
      - uses: github/codeql-action/autobuild@v3
      - uses: github/codeql-action/analyze@v3
```

**CodeQL capabilities**: Taint tracking (data flows from untrusted source to sensitive sink), semantic analysis (not just pattern matching), finds: SQL injection, XSS, path traversal, hard-coded credentials, insecure deserialization.

---

## AI Coding Assistants

### GitHub Copilot

```
# Slash commands in Copilot Chat:
/explain    — Explain selected code
/fix        — Fix bugs in selected code
/tests      — Generate tests for selected code
/doc        — Generate documentation
/simplify   — Simplify complex code

# Context: @workspace (full codebase), @vscode (VS Code API), #file (specific file)
# Example: "@workspace explain how authentication works"

# Inline suggestions: Tab to accept, Alt+] for next suggestion, Alt+[ for previous
# Multi-line suggestions: Ctrl+Enter to open suggestion panel
```

### Cursor AI

```
# Key shortcuts:
Cmd+K (Ctrl+K)  — Inline edit: describe change in natural language
Cmd+L (Ctrl+L)  — Open chat panel
Cmd+I (Ctrl+I)  — Open Composer (multi-file edit)

# @codebase: search and reference your codebase
# @web: search the internet for current docs
# @file: reference specific file

# .cursorrules file (project root): define coding standards for Cursor
# Example .cursorrules:
# - Use TypeScript strict mode
# - Prefer async/await over Promises
# - All functions must have JSDoc comments
# - Tests use Vitest, not Jest
```

### Aider (CLI-based AI coding)

```bash
# Install
pip install aider-chat

# Start with model
aider --model claude-3-5-sonnet-20241022
aider --model gpt-4o

# Aider commands in session:
/add src/file.py         # Add file to context
/drop src/file.py        # Remove from context
/ls                      # List files in context
/diff                    # Show last changes
/undo                    # Revert last change (git revert)
/run pytest              # Run command and add output to context
/ask what does this do?  # Ask without making changes (read-only)

# Git integration: aider auto-commits after each change
# Architect mode: two-model setup (architect plans, coder implements)
aider --model claude-3-5-sonnet-20241022 --editor-model claude-3-5-haiku-20241022
```

---

## Makefile Patterns

```makefile
# Variables
APP_NAME := myapp
VERSION := $(shell git describe --tags --always --dirty)
BUILD_DIR := ./dist

# Phony targets (not real files)
.PHONY: all build test lint clean docker-build

# Default target
.DEFAULT_GOAL := build

# Automatic variables:
# $@ = target name
# $< = first prerequisite
# $^ = all prerequisites
# $* = stem of pattern rule

# Pattern rule
$(BUILD_DIR)/%.o: src/%.c
	@mkdir -p $(BUILD_DIR)
	gcc -c -o $@ $<

# Guard: require env variable
guard-%:
	@if [ -z '${${*}}' ]; then echo 'ERROR: $* not set' && exit 1; fi

# Build requires secrets
deploy: guard-AWS_REGION guard-ECR_REPO
	docker build -t $(ECR_REPO):$(VERSION) .
	aws ecr get-login-password --region $(AWS_REGION) | \
	  docker login --username AWS --password-stdin $(ECR_REPO)
	docker push $(ECR_REPO):$(VERSION)

# Run tests with coverage
test:
	go test -race -coverprofile=coverage.out ./...
	go tool cover -html=coverage.out -o coverage.html

# Show help (parse ## comments as descriptions)
help:
	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
	  awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'

build: ## Build the application binary
	go build -ldflags="-X main.Version=$(VERSION)" -o $(BUILD_DIR)/$(APP_NAME) ./cmd/server

clean: ## Remove build artifacts
	rm -rf $(BUILD_DIR)
```

---

## Task Runners: just and Taskfile

### just

```justfile
# justfile (project root)
# Variables
app_name := "myapp"
docker_registry := env_var_or_default("REGISTRY", "localhost:5000")

# Default recipe (runs when just called with no args)
default:
    @just --list

# Simple recipe
build:
    go build -o dist/{{app_name}} ./cmd/server

# Recipe with dependencies
test: build
    go test -race ./...

# Recipe with arguments
deploy env="staging":
    kubectl set image deployment/{{app_name}} \
      {{app_name}}={{docker_registry}}/{{app_name}}:latest \
      --namespace={{env}}

# Conditional recipe
lint:
    #!/usr/bin/env bash
    set -euo pipefail
    if command -v golangci-lint &>/dev/null; then
        golangci-lint run ./...
    else
        echo "golangci-lint not installed, running go vet"
        go vet ./...
    fi

# Private recipe (hidden from --list)
_internal-helper:
    echo "not shown in help"
```

### Taskfile.yml

```yaml
# Taskfile.yml
version: '3'

vars:
  APP_NAME: myapp
  VERSION:
    sh: git describe --tags --always --dirty

env:
  GO111MODULE: on

includes:
  docker:
    taskfile: ./docker/Taskfile.yml
    dir: ./docker

tasks:
  default:
    cmds:
      - task: build
    silent: true

  build:
    desc: "Build the application"
    cmds:
      - go build -ldflags="-X main.Version={{.VERSION}}" -o dist/{{.APP_NAME}} ./cmd/server
    sources:
      - "**/*.go"
    generates:
      - dist/{{.APP_NAME}}

  test:
    desc: "Run tests with race detection"
    deps: [build]
    cmds:
      - go test -race -coverprofile=coverage.out ./...
    env:
      INTEGRATION_TEST: "{{.INTEGRATION_TEST | default \"false\"}}"

  watch:
    desc: "Watch and rebuild on changes"
    watch: true
    sources:
      - "**/*.go"
    cmds:
      - task: build
```

---

## Anti-Hallucination Protocol

1. **Tool versions matter.** ESLint 8 flat config vs `.eslintrc.js` format — completely different. Prettier 3 vs 2 has minor behavior differences. Always specify version and check changelog.
2. **Shell compatibility.** `bash` features (arrays, `[[ ]]`, `$()`) are not in POSIX `sh`. Never use bash features without `#!/usr/bin/env bash` shebang. zsh arrays are 1-indexed by default (unlike bash which is 0-indexed) — a real footgun.
3. **Platform differences.** macOS ships BSD sed/grep/awk (different flags from GNU). `sed -i ''` on macOS, `sed -i` on Linux. `gsed` on macOS (Homebrew) for GNU behavior.
4. **Editor keybindings.** VS Code keybindings differ between OS. `Cmd` on macOS = `Ctrl` on Linux/Windows for most shortcuts. Always specify both.
5. **AI assistant behavior.** GitHub Copilot, Cursor, and Aider change capabilities, pricing, and model availability frequently. Current features may differ.
6. **semgrep rule syntax.** Rule syntax evolves; verify against semgrep.dev/docs for current schema.
7. **pre-commit hook rev.** Hook versions in `.pre-commit-config.yaml` are git refs — they can become stale. Run `pre-commit autoupdate` before asserting a version works.
8. **Makefile portability.** GNU Make features (pattern rules, `$(shell ...)`, `$(eval ...)`) are not in BSD make (macOS default). Specify `gmake` if using GNU Make features on macOS.
9. **GDB/LLDB commands differ.** `gdb` and `lldb` have different command syntax for the same operations. Never mix them.

---

## Self-Review Checklist

Before delivering any tooling configuration, script, or development environment design:

- [ ] **Shebang and strict mode verified**: Shell scripts have `#!/usr/bin/env bash` (not `#!/bin/sh` for bash features) and `set -euo pipefail`.
- [ ] **Quoting complete**: All variable expansions in quotes `"$var"` unless intentionally splitting. Array expansion uses `"${arr[@]}"`.
- [ ] **Platform specified**: macOS vs Linux differences noted where commands differ (sed flags, find syntax, etc.).
- [ ] **Tool version pinned**: Pre-commit hook revs, npm package versions, golangci-lint version — all pinned to avoid drift.
- [ ] **Config syntax validated**: ESLint flat config vs .eslintrc. Prettier version checked. Ruff vs flake8 rules verified.
- [ ] **Sensitive data not in code**: No secrets in Makefile, .env committed to repo, or shell history. `.env.example` provided, `.env` in `.gitignore`.
- [ ] **Cleanup handled**: Shell scripts trap EXIT and clean up temp files/locks.
- [ ] **Error messages are actionable**:

…(truncated)
