Compare commits

..
8 Commits
54 changed files with 162 additions and 32 deletions
+3
View File
@@ -0,0 +1,3 @@
[submodule "mattpocock-skills"]
path = mattpocock-skills
url = ssh://git@git.grosinger.net:22322/tgrosinger/mattpocock-skills.git
+1
View File
@@ -0,0 +1 @@
../../../mattpocock-skills/skills/engineering/code-review
+1
View File
@@ -0,0 +1 @@
../../../mattpocock-skills/skills/engineering/codebase-design
+1
View File
@@ -0,0 +1 @@
../../../mattpocock-skills/skills/engineering/diagnosing-bugs
+1
View File
@@ -0,0 +1 @@
../../../mattpocock-skills/skills/engineering/domain-modeling
+1
View File
@@ -0,0 +1 @@
../../../mattpocock-skills/skills/engineering/grill-with-docs
+1
View File
@@ -0,0 +1 @@
../../../mattpocock-skills/skills/productivity/grilling
+1
View File
@@ -0,0 +1 @@
../../../mattpocock-skills/skills/productivity/handoff
+1
View File
@@ -0,0 +1 @@
../../../mattpocock-skills/skills/engineering/implement
+1
View File
@@ -0,0 +1 @@
../../../mattpocock-skills/skills/engineering/improve-codebase-architecture
+1
View File
@@ -0,0 +1 @@
../../../mattpocock-skills/skills/engineering/prototype
+1
View File
@@ -0,0 +1 @@
../../../mattpocock-skills/skills/engineering/research
+1
View File
@@ -0,0 +1 @@
../../../mattpocock-skills/skills/engineering/resolving-merge-conflicts

Before

Width:  |  Height:  |  Size: 420 B

After

Width:  |  Height:  |  Size: 420 B

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

+1
View File
@@ -0,0 +1 @@
../../../mattpocock-skills/skills/engineering/tdd
+1
View File
@@ -0,0 +1 @@
../../../mattpocock-skills/skills/productivity/teach
+1
View File
@@ -0,0 +1 @@
../../../mattpocock-skills/skills/productivity/to-questionnaire
+1
View File
@@ -0,0 +1 @@
../../../mattpocock-skills/skills/engineering/to-spec
+1
View File
@@ -0,0 +1 @@
../../../mattpocock-skills/skills/engineering/to-tickets
+1
View File
@@ -0,0 +1 @@
../../../mattpocock-skills/skills/productivity/wait-what
+1
View File
@@ -0,0 +1 @@
../../../mattpocock-skills/skills/engineering/wayfinder
+1
View File
@@ -0,0 +1 @@
../../../mattpocock-skills/skills/engineering/wizard
+1
View File
@@ -0,0 +1 @@
../../../mattpocock-skills/skills/productivity/writing-for-agents
+27
View File
@@ -0,0 +1,27 @@
#!/bin/bash
# Source: https://github.com/mattpocock/skills
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command')
DANGEROUS_PATTERNS=(
"git push"
"git reset --hard"
"git clean -fd"
"git clean -f"
"git branch -D"
"git checkout \."
"git restore \."
"push --force"
"reset --hard"
)
for pattern in "${DANGEROUS_PATTERNS[@]}"; do
if echo "$COMMAND" | grep -qE "$pattern"; then
echo "BLOCKED: '$COMMAND' matches dangerous pattern '$pattern'. The user has prevented you from doing this." >&2
exit 2
fi
done
exit 0
+98
View File
@@ -0,0 +1,98 @@
#!/bin/bash
# Blocks Bash commands that delete or destroy files.
# Companion to CLAUDE.md's "never delete files" rule.
block() {
printf 'BLOCKED: %s\n' "$1" >&2
exit 2
}
command -v jq >/dev/null 2>&1 || block "jq is required to validate Bash commands."
command -v realpath >/dev/null 2>&1 || block "realpath is required to validate deletion paths."
command -v stat >/dev/null 2>&1 || block "stat is required to validate the temporary directory."
INPUT=$(cat) || block "could not read hook input."
COMMAND=$(printf '%s' "$INPUT" | jq -er '.tool_input.command | select(type == "string")') ||
block "hook input does not contain a valid tool_input.command string."
# Do not trust TMPDIR: when it is unset, `$TMPDIR/path` expands to `/path`.
# This fixed per-user directory is the only place where deletion is permitted.
TMP_ROOT="/tmp/claude-$(id -u)"
# True only for one command in one of these exact forms:
# rm -- /tmp/claude-UID/path [...]
# rm -f|-r|-rf|-fr -- /tmp/claude-UID/path [...]
#
# Paths are deliberately restricted to an unquoted, expansion-free character
# set. The filesystem checks reject an escaping canonical path and any symlink
# that already exists in the path. This is defense against accidental deletion,
# not a race-free security boundary against a process changing paths concurrently.
confined_to_tmp() {
local cmd="$1" option_part path_part path canonical component partial mode uid
local -a paths components
uid=$(id -u) || return 1
[[ -d "$TMP_ROOT" && ! -L "$TMP_ROOT" ]] || return 1
[[ "$(realpath -e -- "$TMP_ROOT" 2>/dev/null)" == "$TMP_ROOT" ]] || return 1
[[ "$(stat -c '%u' -- "$TMP_ROOT" 2>/dev/null)" == "$uid" ]] || return 1
mode=$(stat -c '%a' -- "$TMP_ROOT" 2>/dev/null) || return 1
(( (8#$mode & 0022) == 0 )) || return 1
if [[ "$cmd" =~ ^rm\ (--|-f\ --|-r\ --|-rf\ --|-fr\ --)\ (/tmp/claude-[0-9]+/[A-Za-z0-9._/+,=:@%-]+(\ /tmp/claude-[0-9]+/[A-Za-z0-9._/+,=:@%-]+)*)$ ]]; then
option_part="${BASH_REMATCH[1]}"
path_part="${BASH_REMATCH[2]}"
else
return 1
fi
# The regex excludes shell syntax and whitespace within paths, so this split
# does not attempt to interpret arbitrary Bash source.
read -r -a paths <<< "$path_part"
((${#paths[@]} > 0)) || return 1
for path in "${paths[@]}"; do
[[ "$path" == "$TMP_ROOT"/?* ]] || return 1
[[ "$path" != */./* && "$path" != */../* && "$path" != */. && "$path" != */.. ]] || return 1
canonical=$(realpath -m -- "$path" 2>/dev/null) || return 1
[[ "$canonical" == "$TMP_ROOT"/?* ]] || return 1
# realpath catches symlink escapes. Reject in-tree symlinks too, since rm
# must not traverse a link whose target happens to currently be in the tree.
partial=""
IFS='/' read -r -a components <<< "$path"
for component in "${components[@]}"; do
[[ -n "$component" ]] || continue
partial="$partial/$component"
[[ ! -L "$partial" ]] || return 1
done
done
# Keep the variable used so shellcheck documents that only allowlisted option
# spellings can reach this point.
[[ -n "$option_part" ]]
}
confined_to_tmp "$COMMAND" && exit 0
# These patterns are a backstop for ordinary Bash spellings, not a parser.
# Include quotes and backslashes between letters to catch forms such as r""m
# and r\m that Bash resolves to rm.
DANGEROUS_PATTERNS=(
'\br["'"'"'\\]*m\b'
'\bu["'"'"'\\]*n["'"'"'\\]*l["'"'"'\\]*i["'"'"'\\]*n["'"'"'\\]*k\b'
'\br["'"'"'\\]*m["'"'"'\\]*d["'"'"'\\]*i["'"'"'\\]*r\b'
'\bshred\b'
'\btruncate\b'
'\bfind\b.*-delete\b'
'\btrash\b'
)
for pattern in "${DANGEROUS_PATTERNS[@]}"; do
if printf '%s\n' "$COMMAND" | grep -qE "$pattern"; then
block "'$COMMAND' is a deletion command. Only literal 'rm [-f|-r|-rf|-fr] -- $TMP_ROOT/path' commands without variables, quotes, globs, shell operators, or symlinks are allowed."
fi
done
exit 0
+2 -5
View File
@@ -18,9 +18,6 @@
"Bash(ssh *)", "Bash(ssh *)",
"Bash(ssh)", "Bash(ssh)",
"Bash(scp *)", "Bash(scp *)",
"Bash(rm:*)",
"Bash(unlink:*)",
"Bash(rmdir:*)",
"Bash(shred:*)", "Bash(shred:*)",
"Bash(truncate:*)", "Bash(truncate:*)",
"Bash(trash:*)", "Bash(trash:*)",
@@ -33,7 +30,7 @@
], ],
"defaultMode": "auto" "defaultMode": "auto"
}, },
"model": "opus[1m]", "model": "claude-opus-4-8",
"disableClaudeAiConnectors": true, "disableClaudeAiConnectors": true,
"hooks": { "hooks": {
"PostToolUse": [ "PostToolUse": [
@@ -146,7 +143,7 @@
"Thinking" "Thinking"
] ]
}, },
"effortLevel": "high", "effortLevel": "xhigh",
"tui": "fullscreen", "tui": "fullscreen",
"voice": { "voice": {
"enabled": false, "enabled": false,
+1
View File
@@ -0,0 +1 @@
../.agents/skills
+2
View File
@@ -4,6 +4,8 @@ workspaces = true
keymap_mode = "auto" keymap_mode = "auto"
enter_accept = true enter_accept = true
sync_address = "https://atuin.i.grosinger.net"
history_filter = [ history_filter = [
"^cd$", "^cd$",
"^lg$", "^lg$",
+4
View File
@@ -2,6 +2,10 @@
# Interactive sessions get exact versions from `mise activate` below. # Interactive sessions get exact versions from `mise activate` below.
fish_add_path --global ~/.local/bin ~/.local/share/mise/shims ~/go/bin fish_add_path --global ~/.local/bin ~/.local/share/mise/shims ~/go/bin
if test -d ~/code/yt-dlp
fish_add_path --global ~/code/yt-dlp
end
if status is-interactive if status is-interactive
# Commands to run in interactive sessions can go here # Commands to run in interactive sessions can go here
+1
View File
@@ -21,3 +21,4 @@ pnpm = "latest"
"github:Satty-org/Satty" = "0.20.1" "github:Satty-org/Satty" = "0.20.1"
"github:F1bonacc1/process-compose" = "latest" "github:F1bonacc1/process-compose" = "latest"
"npm:@earendil-works/pi-coding-agent" = "latest" "npm:@earendil-works/pi-coding-agent" = "latest"
uv = "latest"
-3
View File
@@ -90,9 +90,6 @@
[status] [status]
submoduleSummary = true submoduleSummary = true
[url "ssh://git@gitlab.i.extrahop.com/"]
insteadOf = https://gitlab.i.extrahop.com/
[merge] [merge]
conflictstyle = zdiff3 conflictstyle = zdiff3
-8
View File
@@ -1,8 +0,0 @@
#/bin/bash
podman run --rm -i \
-v ${HOME}/Music:/downloads:z \
--userns keep-id:uid=1000,gid=1000 \
--entrypoint spotdl \
yt-dlp:latest $@
-7
View File
@@ -1,7 +0,0 @@
#/bin/bash
podman run --rm \
-v ${HOME}/Videos/youtube:/downloads:z \
--userns keep-id:uid=1000,gid=1000 \
yt-dlp:latest -S 'res:1080' --extractor-args "youtube:player-client=web_embedded" $@
-7
View File
@@ -1,7 +0,0 @@
#/bin/bash
podman run --rm \
-v ${HOME}/Videos/youtube:/downloads:z \
--userns keep-id:uid=1000,gid=1000 \
yt-dlp:latest --embed-metadata -o "%(playlist)s/%(playlist_index)s - %(title)s.%(ext)s" -S 'res:1080' $@
+2 -2
View File
@@ -1,8 +1,8 @@
{ {
"lastChangelogVersion": "0.79.8", "lastChangelogVersion": "0.83.0",
"theme": "catppuccin-latte", "theme": "catppuccin-latte",
"defaultProvider": "openai-codex", "defaultProvider": "openai-codex",
"defaultModel": "gpt-5.5", "defaultModel": "gpt-5.6-luna",
"defaultThinkingLevel": "high", "defaultThinkingLevel": "high",
"skills": [ "skills": [
"~/.claude/skills" "~/.claude/skills"
+1
Submodule mattpocock-skills added at 0bec6ef0f5