diff --git a/.claude/commands/obsidian-load.md b/.claude/commands/obsidian-load.md new file mode 100644 index 0000000..2b2afb8 --- /dev/null +++ b/.claude/commands/obsidian-load.md @@ -0,0 +1,22 @@ +Load context from Obsidian notes in the `Claude/` directory into the current conversation. + +## Behavior + +1. Derive the project name from the current working directory (use the repo or app folder name). +2. List files in `Claude//` using `mcp__obsidian__list_vault_files`. +3. If `$ARGUMENTS` is provided, treat it as a search query and use `mcp__obsidian__search_vault_smart` to find relevant notes across the entire `Claude/` directory instead of listing by project. +4. Read the most relevant notes: + - Without args: read the 3 most recent notes for the current project (by filename date prefix). + - With args: read the top 3 search results. + - Use `mcp__obsidian__get_vault_file` to fetch each note's content. +5. Synthesize what you loaded into a brief summary for the user, covering: + - What sessions were found and when they occurred + - Key decisions or context that is now loaded + - Any open questions or next steps from prior sessions that are still relevant +6. Explicitly tell the user: "I've loaded this context and will use it going forward in this conversation." + +## Notes + +- If no notes exist for the current project yet, say so and suggest running `/obsidian-save` at the end of a session. +- Do not dump raw note content at the user — synthesize and summarize it. +- If notes contain contradictory information, flag it and ask which is current. diff --git a/.claude/commands/obsidian-save.md b/.claude/commands/obsidian-save.md new file mode 100644 index 0000000..f7eb41a --- /dev/null +++ b/.claude/commands/obsidian-save.md @@ -0,0 +1,64 @@ +Save current conversation context to an Obsidian note under the `Claude/` directory. + +## What to save + +Capture all of the following that are relevant to the current conversation: + +- **Conversation summary**: What the user is trying to accomplish and why +- **Project context**: Relevant architecture, design decisions, or constraints discovered +- **Task state**: What has been completed, what is in progress, what is blocked or pending +- **Key decisions**: Any choices made and the reasoning behind them +- **Open questions**: Unresolved questions or things to revisit +- **Next steps**: Concrete actions that should follow from this session + +## File location + +Derive the project name from the current working directory (use the repo or app folder name). Save to: + +``` +Claude//-.md +``` + +Use today's date and a short 2-4 word slug describing the session topic (e.g. `2026-04-29-ruth-plugin-setup.md`). + +If `$ARGUMENTS` is provided, use it as the slug instead of generating one. + +## Note format + +Use this structure: + +```markdown +--- +date: +project: +tags: [claude-context] +--- + +# + +## Summary +<1-3 sentence overview of what this session was about> + +## Context + + +## Decisions + + +## Task State + + +## Open Questions + + +## Next Steps + +``` + +## Steps + +1. Determine the project name from the working directory. +2. Determine today's date. +3. Draft the note content based on the current conversation. +4. Use `mcp__obsidian__create_vault_file` to write the note to the vault. +5. Confirm to the user where the note was saved. diff --git a/.claude/policy-limits.json b/.claude/policy-limits.json new file mode 100644 index 0000000..95b1212 --- /dev/null +++ b/.claude/policy-limits.json @@ -0,0 +1,14 @@ +{ + "restrictions": { + "allow_remote_control": { + "allowed": false + }, + "allow_quick_web_setup": { + "allowed": false + }, + "enforce_web_search_mcp_isolation": { + "allowed": false + } + }, + "compliance_taints": [] +} \ No newline at end of file diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000..5bcf1e1 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,128 @@ +{ + "env": { + "CLAUDE_CODE_MAX_OUTPUT_TOKENS": "100000" + }, + "hooks": { + "Notification": [ + { + "hooks": [ + { + "type": "command", + "command": "afplay ~/.claude/sounds/mario/pause.wav 2>/dev/null || true", + "async": true + }, + { + "type": "command", + "command": "osascript ~/bin/confetti.scpt", + "async": true + } + ] + } + ], + "PostToolUse": [ + { + "matcher": "Write|Edit|MultiEdit", + "hooks": [ + { + "type": "command", + "command": "/usr/local/bin/aicodemetricsd hook claude --hook-input stdin", + "timeout": 2 + } + ] + } + ], + "PostToolUseFailure": [ + { + "hooks": [ + { + "type": "command", + "command": "afplay ~/.claude/sounds/mario/tool-failure/bowser-fire.wav 2>/dev/null || true", + "async": true + } + ] + } + ], + "PreCompact": [ + { + "hooks": [ + { + "type": "command", + "command": "/usr/local/bin/aicodemetricsd hook claude --hook-input stdin", + "timeout": 2 + } + ] + } + ], + "PreToolUse": [ + { + "matcher": "Write|Edit|MultiEdit", + "hooks": [ + { + "type": "command", + "command": "/usr/local/bin/aicodemetricsd hook claude --hook-input stdin", + "timeout": 2 + } + ] + } + ], + "SessionEnd": [ + { + "hooks": [ + { + "type": "command", + "command": "/usr/local/bin/aicodemetricsd hook claude --hook-input stdin", + "timeout": 2 + } + ] + } + ], + "Stop": [ + { + "hooks": [ + { + "type": "command", + "command": "afplay ~/.claude/sounds/mario/stop/stomp.wav 2>/dev/null || true", + "async": true + } + ] + } + ], + "UserPromptSubmit": [ + { + "hooks": [ + { + "type": "command", + "command": "afplay ~/.claude/sounds/mario/prompt-submit/coin.wav 2>/dev/null || true", + "async": true + }, + { + "type": "command", + "command": "osascript ~/bin/confetti.scpt", + "async": true + } + ] + } + ] + }, + "enabledPlugins": { + "mind@memvid": true, + "superpowers@claude-plugins-official": true + }, + "extraKnownMarketplaces": { + "endless-toil": { + "source": { + "source": "directory", + "path": "/Users/steve.briggs/.endless-toil" + } + }, + "memvid": { + "source": { + "source": "directory", + "path": "/Users/steve.briggs/claude-brain" + } + } + }, + "effortLevel": "xhigh", + "theme": "custom:challengerdeep", + "model": "sonnet" +} diff --git a/.claude/themes/challengerdeep.json b/.claude/themes/challengerdeep.json new file mode 100644 index 0000000..e92fcb2 --- /dev/null +++ b/.claude/themes/challengerdeep.json @@ -0,0 +1,68 @@ +{ + "name": "Challenger Deep", + "base": "dark", + "overrides": { + "claude": "#906cff", + "claudeShimmer": "#c991e1", + "text": "#cbe3e7", + "inverseText": "#100e23", + "inactive": "#a6b3cc", + "inactiveShimmer":"#cbe3e7", + "subtle": "#5a5475", + "suggestion": "#c991e1", + "permission": "#ffe9aa", + "permissionShimmer":"#ffb378", + "remember": "#63f2f1", + + "success": "#62d196", + "error": "#ff5458", + "warning": "#ffb378", + "warningShimmer": "#ffe9aa", + "merged": "#906cff", + + "promptBorder": "#906cff", + "promptBorderShimmer": "#c991e1", + "planMode": "#63f2f1", + "autoAccept": "#62d196", + "bashBorder": "#ffb378", + "ide": "#91ddff", + "fastMode": "#c991e1", + "fastModeShimmer":"#aaffe4", + + "diffAdded": "#1f3a2a", + "diffRemoved": "#3a1f23", + "diffAddedDimmed": "#1a2e22", + "diffRemovedDimmed": "#2e1a1d", + "diffAddedWord": "#2c5a40", + "diffRemovedWord": "#5a2c30", + + "userMessageBackground": "#2a2640", + "userMessageBackgroundHover": "#3b3470", + "messageActionsBackground": "#3b3470", + "bashMessageBackgroundColor": "#2c281a", + "memoryBackgroundColor": "#1f2c3a", + "selectionBg": "#3b3470", + + "rate_limit_fill": "#906cff", + "rate_limit_empty": "#3b3470", + "briefLabelYou": "#ffe9aa", + "briefLabelClaude": "#906cff", + + "red_FOR_SUBAGENTS_ONLY": "#ff5458", + "blue_FOR_SUBAGENTS_ONLY": "#65b2ff", + "green_FOR_SUBAGENTS_ONLY": "#62d196", + "yellow_FOR_SUBAGENTS_ONLY": "#ffe9aa", + "purple_FOR_SUBAGENTS_ONLY": "#906cff", + "orange_FOR_SUBAGENTS_ONLY": "#ffb378", + "pink_FOR_SUBAGENTS_ONLY": "#c991e1", + "cyan_FOR_SUBAGENTS_ONLY": "#63f2f1", + + "rainbow_red": "#ff5458", + "rainbow_orange": "#ffb378", + "rainbow_yellow": "#ffe9aa", + "rainbow_green": "#62d196", + "rainbow_blue": "#65b2ff", + "rainbow_indigo": "#906cff", + "rainbow_violet": "#c991e1" + } +} diff --git a/.local/bin/confetti.scpt b/.local/bin/confetti.scpt new file mode 100755 index 0000000..92980fd --- /dev/null +++ b/.local/bin/confetti.scpt @@ -0,0 +1,3 @@ +tell application "System Events" + keystroke "c" using {option down, command down} +end tell diff --git a/.local/bin/goland b/.local/bin/goland new file mode 100755 index 0000000..6930c39 --- /dev/null +++ b/.local/bin/goland @@ -0,0 +1,3 @@ +#!/bin/sh + +open -na "GoLand.app" --args "$@" diff --git a/.mise.toml b/.mise.toml new file mode 100644 index 0000000..b8ea1ef --- /dev/null +++ b/.mise.toml @@ -0,0 +1,9 @@ +[tools] +helm = "3.17.1" +kubecolor = "latest" +terraform = "1.3.10" +terraform-docs = "0.18.0" +cilium-cli = "0.16.16" +go = "1.23" +vault = "1.18.3" +awscli = "2.25.13" diff --git a/.oh-my-zsh b/.oh-my-zsh new file mode 160000 index 0000000..e64912e --- /dev/null +++ b/.oh-my-zsh @@ -0,0 +1 @@ +Subproject commit e64912e0c1eaa32181c3b5e5e4bf8042ecd0e8a7 diff --git a/.ssh/config b/.ssh/config new file mode 100644 index 0000000..081cd44 --- /dev/null +++ b/.ssh/config @@ -0,0 +1,3 @@ +Host github.com + AddKeysToAgent yes + IdentityFile ~/.ssh/id_ed25519 diff --git a/.zshrc.d/_cht b/.zshrc.d/_cht new file mode 100644 index 0000000..e1a4230 --- /dev/null +++ b/.zshrc.d/_cht @@ -0,0 +1,21 @@ +#compdef cht.sh + +__CHTSH_LANGS=($(curl -s cheat.sh/:list)) +_arguments -C \ + '--help[show this help message and exit]: :->noargs' \ + '--shell[enter shell repl]: :->noargs' \ + '1:Cheat Sheet:->lang' \ + '*::: :->noargs' && return 0 + +if [[ CURRENT -ge 1 ]]; then + case $state in + noargs) + _message "nothing to complete";; + lang) + compadd -X "Cheat Sheets" ${__CHTSH_LANGS[@]};; + *) + _message "Unknown state, error in autocomplete";; + esac + + return +fi diff --git a/.zshrc.d/aliases.zsh b/.zshrc.d/aliases.zsh new file mode 100644 index 0000000..f543cfd --- /dev/null +++ b/.zshrc.d/aliases.zsh @@ -0,0 +1,177 @@ +#=================================== +# DIRECTORY MANAGEMENT +#=================================== +alias ..='cd ..' +alias .1='cd ..' +alias .2='cd ../../' +alias .3='cd ../../../' +alias .4='../../../../' +alias .5='cd ../../../../../' +alias APPS='cd ${HOME}/GIT_REPOS/APPLICATION-DEPLOYMENTS' +alias INFRA='cd ${HOME}/GIT_REPOS/CLOUD-INFRASTRUCTURE-TERRAFORM' +alias EKS-BASE='cd ${HOME}/GIT_REPOS/EKS-BASE-DEPLOY' +alias K8S-BASE='cd ${HOME}/GIT_REPOS/K8S-BASE-DEPLOY' +alias config='/usr/bin/git --git-dir=$HOME/.cfg/.git/ --work-tree=$HOME' + + +#=================================== +# COMMAND MODIFICATIONS & REMAPS +#=================================== +alias l='lsd' +alias la='lsd -aF' +alias vi='nvim' +alias dog='cat' +alias grep='grep --color=auto' +alias Grep='grep' +alias Gerp='grep' +alias gerp='grep' +alias fgrep='fgrep --color=auto' +alias egrep='egrep --color=auto' +alias nano='nvim' +alias emacs='nvim' +alias notepad.exe='nvim' +alias diff='colordiff --side-by-side --suppress-common-lines' +alias header='curl -I' +alias headerc='curl -I --compress' + +#=================================== +# AWS & INFRA-TOOLS +#=================================== +#AWS +alias ac='aws-cred' +alias av='aws-vault' +alias tg='terragrunt' + +#Terraform / Terragrun +alias tgp="terragrunt plan" +alias tgps="terragrunt plan --terragrunt-source-update" +alias tglo="terragrunt providers lock -platform=linux_arm64 -platform=linux_amd64 -platform=darwin_amd64 -platform=darwin_arm6" +alias tga="terragrunt apply" +alias tgaA="terragrunt apply -auto-approve" +alias tgas="terragrunt apply --terragrunt-source-update" +alias tgasA="terragrunt apply --terragrunt-source-update -auto-approve" +alias tgi="terragrunt init" +alias tgis="terragrunt init --terragrunt-source-update" +alias tgo="terragrunt output" + +#Kuberenetes +alias kx='kubectx' +alias kn='kubens' +alias ku='kustomize' +alias kub='kustomize build --enable-alpha-plugins --load-restrictor LoadRestrictionsNone' +alias k='kubectl' +alias kg='kubectl get' +alias kd='kubectl describe' +alias kge='kubectl get events' +alias kgp='kubectl get pods' +alias kgprca="kubectl get pods --all-namespaces --sort-by='.status.containerStatuses[0].restartCount'" +alias kgprc="kubectl get pods --sort-by='.status.containerStatuses[0].restartCount'" +#alias kgn='kubectl get nodes' +alias kgn='kubectl get nodes --sort-by=.metadata.creationTimestamp' +alias kgic='kubectl get ingressclass' +alias kdic='kubectl describe ingressclass' +alias kgpv='kubectl get pv' +alias kdpv='kubectl describe pv' +alias klt='kubectl logs -f' +alias kbug='kubectl run -i --tty --rm debug --image=ubuntu --restart=Never -- /bin/bash' +alias kgsec='kubectl get secret' +alias kgj='kubectl get job' +alias fqdn="kubectl get ingress -o json | jq '.items[] | .metadata.namespace + \": \" + .metadata.annotations.\"external-dns.alpha.kubernetes.io/hostname\"'" +alias fqdna="kubectl get ingress --all-namespaces -o json | jq '.items[] | .metadata.namespace + \": \" + .metadata.annotations.\"external-dns.alpha.kubernetes.io/hostname\"'" +#Kubernetes + Teleport +alias tkl='tsh kube ls' +kutil () { + for host in $(kubectl get nodes --no-headers | cut -d' ' -f1) + do + echo "$host - $(kubectl get nodes -o jsonpath='{.metadata.labels.topology\.kubernetes\.io/zone}' $host)" + kubectl describe node "$host" | grep --color Allocated -A 5 | grep --color -ve Event -ve Allocated -ve percent -ve -- + echo + done +} +#=================================== +# USEFUL / CONVIENENCE +#=================================== +alias untar='tar -zxvf' +alias lstar='tar -tvf' +alias perms='stat -f "%A %Sp -> owner=%SHp group=%SMp other=%SLp"' +#alias pydocs="elinks https://docs.python.org/$(python --version | awk '{print $2}' | sed 's/\.[0-9]*$//')/py-modindex.html" +alias pydocs="open https://docs.python.org/$(python3 --version | awk '{print $2}' | sed 's/\.[0-9]*$//')/py-modindex.html" +alias hr='printf $(printf "\e[$(shuf -i 91-97 -n 1);1m%%%ds\e[0m\n" $(tput cols)) | tr " " =' +alias iac='cd $HOME/projects/IAC' + + +#=================================== +# DO THE SAFETY DANCE +#=================================== +alias cp='cp -i' +alias rm='rm -i' +alias ln='ln -i' +alias mv='mv -i' + +#=================================== +# MAC +#=================================== +alias fudns='sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder' + +#=================================== +# MISC +#=================================== +if [ $UID -ne 0 ]; then + alias reboot='sudo reboot' + if [[ $OSTYPE != 'darwin'* ]]; then + alias upgradeall='sudo apt-get update && sudo apt-get upgrade' + fi +fi + +#=================================== +# FUNCS +#=================================== +#exa deprecated, replacing with lsd (github.com/lsd-rs/lsd) +#alias ls ='lsd' +#i use exa and have ls muscle memory, current version of exa does not take -t and will error out#this is a fair work around; https://github.com/ogham/exa/issues/519#issuecomment-560608534 +#function ls { +# if [ "$1" = "-ltr" ]; then +# exa -lsnew "${@:2}" -l -F --color=auto --icons +# elif [ "$1" = "-lrt" ]; then +# exa -lsnew "${@:2}" -l -F --color=auto --icons +# elif [ "$1" = "-latr" ]; then +# exa -lsnew "${@:2}" -la -F --color=auto --icons +# elif [ "$1" = "-lahtr" ]; then +# exa -lsnew "${@:2}" -lah -F --color=auto --icons +# elif [ "$1" = "-alhtr" ]; then +# exa -lsnew "${@:2}" -lah -F --color=auto --icons +# elif [ "$1" = "latr" ]; then +# exa -lsnew "${@:3}" -lah -F --color=auto --icons +# elif [ "$1" = "altr" ]; then +# exa -lsnew "${@:3}" -lah -F --color=auto --icons +# elif [ "$1" = "lahtr" ]; then +# exa -lsnew "${@:3}" -lah -F --color=auto --icons +# elif [ "$1" = "-altr" ]; then +# exa -lsnew "${@:2}" -lah -F --color=auto --icons +# elif [ "$1" = "a-ltr" ]; then +# exa -lsnew "${@:2}" -lah -F --color=auto --icons +# else +# exa "$@" -a +# fi +#} + +function urlencode { + python -c "import sys; from urllib.parse import quote_plus; print(quote_plus(sys.stdin.read()))" +} + +function urldecode { + python -c "import sys; from urllib.parse import unquote; print(unquote(sys.stdin.read()), end='')" +} + +function tfdocs { + open "https://registry.terraform.io/search/providers?q=`echo "${@}" | urlencode`" +} + +function google { + open "https://www.google.com/search?q=`echo "${@}" | urlencode`" +} + +function hred () { + [ $# -ge 1 -a -f "$1" ] && input="$1" || input="-" + cat $input | grep --color -E -v '^\s*$|^\s*#.*$' +} diff --git a/.zshrc.d/fr.zsh b/.zshrc.d/fr.zsh new file mode 100644 index 0000000..6a43acf --- /dev/null +++ b/.zshrc.d/fr.zsh @@ -0,0 +1,28 @@ +#!/bin/bash +fr () { + FIND="$1" + REPLACE="$2" + FILTER="$3" + if [ -z "${FIND}" ] || [ -z "${REPLACE}" ] + then + echo "ERR: must include two parameters for find and replace" >&2 + fr_usage + return 1 + fi + if command -v rg 2>&1 > /dev/null + then + if [ -z "${FILTER}" ] + then + rg --hidden --glob '!.git/' -l "$FIND" | xargs sed -i "s/${FIND}/${REPLACE}/g" + else + rg --hidden --glob '!.git/' -l "$FIND" | rg --hidden --glob '!.git/' -i "$FILTER" | xargs sed -i "s/${FIND}/${REPLACE}/g" + fi + else + if [ -z "${FILTER}" ] + then + grep --color -l "$FIND" | xargs sed -i "s/${FIND}/${REPLACE}/g" + else + grep --color -l "$FIND" | grep --color -i "$FILTER" | xargs sed -i "s/${FIND}/${REPLACE}/g" + fi + fi +} diff --git a/.zshrc.d/gopath.zsh b/.zshrc.d/gopath.zsh new file mode 100644 index 0000000..c5e37e2 --- /dev/null +++ b/.zshrc.d/gopath.zsh @@ -0,0 +1,6 @@ +# GoPath stuff +export PATH="$PATH:${HOME}/.bin" +export GOPATH="${HOME}/go" +export GOBIN="${HOME}/go/bin/" +export PATH=$PATH:$GOROOT/bin:$GOBIN +export HISTCONTROL=ignorespace:ignoredups diff --git a/.zshrc.d/hred.zsh b/.zshrc.d/hred.zsh new file mode 100644 index 0000000..b1a341d --- /dev/null +++ b/.zshrc.d/hred.zsh @@ -0,0 +1,5 @@ + +hred() { + [ $# -ge 1 -a -f "$1" ] && input="$1" || input="-" + cat $input | grep -E -v '^\s*$|^\s*#.*$' +} diff --git a/.zshrc.d/teleport.zsh b/.zshrc.d/teleport.zsh new file mode 100644 index 0000000..bc9e753 --- /dev/null +++ b/.zshrc.d/teleport.zsh @@ -0,0 +1,3 @@ +export TELEPORT_PROXY=transporter.ic-ops.com:443 +export TELEPORT_CLUSTER=transporter.ic-ops.com +export TELEPORT_USER=steve.briggs@immuta.com diff --git a/.zshrc.d/vscodepath.ksh b/.zshrc.d/vscodepath.ksh new file mode 100644 index 0000000..8ecfd67 --- /dev/null +++ b/.zshrc.d/vscodepath.ksh @@ -0,0 +1 @@ +export PATH=$PATH:/usr/local/bin/code diff --git a/.zshrc.d/work-immuta.zsh b/.zshrc.d/work-immuta.zsh new file mode 100644 index 0000000..d20b2a8 --- /dev/null +++ b/.zshrc.d/work-immuta.zsh @@ -0,0 +1,11 @@ +export VAULT_ADDR=https://vault.immuta.io:8200 +#export VAULT_ADDR=https://vault.infrastructure.immuta.io:8200 +export VAULT_TOKEN=$(cat ~/.vault-token) + +export AWS_VAULT_BACKEND=keychain +export AWS_VAULT_KEYCHAIN_NAME="aws-vault" +export AWS_LOGIN_BROWSER="firefox" + +#export KUBECONFIG=/Users/steve.briggs/.kube/config:/Users/steve.briggs/.kube/minikube +export KUBECONFIG="${HOME}/.kube/teleport-kubeconfig:${HOME}/.kube/config:${HOME}/.kube/minikube" +export PATH=$PATH:/private/var/folders/ky/m6p32md91_n2q6z94fdn8fsw0000gq/T/AppTranslocation/F252CD76-5A71-4D7F-8826-12175DB43E32/d/Visual\ Studio\ Code.app/Contents/Resources/app/bin