I’ve come across multiple neat tools. Given all of my configs are literate programming configs, this sets up those scripts. Otherwise, I’d either not have those tools, or I’d have two processes for getting my dotfiles setup.
snapshot (~/bin/snapshot)#
A simple screenshot tool. Uses screencapture on macOS or
imagemagick’s import on Linux.
#!/bin/bash
name=$1
if [[ "$name" != *"png"* ]]; then
name="$name.png"
fi
if command -v screencapture &>/dev/null; then
screencapture -i ~/Desktop/$name
else
import ~/Desktop/$name
fi
Copy-pasta $ (~/bin/$)#
Allow copying things from the internet which have a preceding $.
#!/usr/bin/env bash
exec "$@"
timestamp conversion (~/bin/epoch)#
I need to convert epochs all the time from log diving. Thanks to Aaron Flatten for the script.
#!/bin/bash
# > epoch # Return the current timestamp
# > epoch <number> # Convert the numeric unix timestamp to a readable date string
# > epoch <str> # Converts the readable date string to a timestamp
if [ $# -eq 0 ]; then
date +%s
elif [[ $1 == *[-T:Z]* ]]; then
python3 -c "from datetime import datetime; import sys; print(int(datetime.fromisoformat(sys.argv[1].replace('Z','+00:00')).timestamp()))" "$1"
else
VAL=$1
if [[ $1 -gt 1000000000000 ]]; then
VAL=$(( $1 / 1000 ))
fi
# macOS date -r, falling back to GNU date -d
date -r "$VAL" 2>/dev/null || date -d "UTC 1970-01-01 $VAL secs" 2>/dev/null
fi
git-churn (~/bin/git-churn)#
When doing some code analysis suggested by the talk Sandi Metz gave at DeconstructConf 2018, I needed to figure out how to calculate the churn of a particular file. This script helps in that regard.
#!/bin/bash
# Written by Corey Haines
# Scriptified by Gary Bernhardt
#
# Put this anywhere on your $PATH (~/bin is recommended). Then git will see it
# and you'll be able to do `git churn`.
#
# Show churn for whole repo:
# $ git churn
#
# Show churn for specific directories:
# $ git churn app lib
#
# Show churn for a time range:
# $ git churn --since='1 month ago'
#
# (These are all standard arguments to `git log`.)
set -e
git log --all -M -C --name-only --format='format:' "$@" | sort | grep -v '^$' | uniq -c | sort -n | awk 'BEGIN {print "count\tfile"} {print $1 "\t" $2}'
git worktrees (~/bin/gwt)#
gwt keeps throwaway and parallel branches out of the source checkout by
placing them under ~/worktrees/<repo>/<branch-slug>. The script does the git
worktree creation; the shell function in the zsh config handles changing into
the new directory because an executable cannot change its parent shell.
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'USAGE'
Usage:
gwt new [--branch BRANCH] [--from REF] NAME
gwt list
gwt remove PATH
gwt prune
Create and manage git worktrees rooted at ${GWT_HOME:-~/worktrees}.
Examples:
gwt new "dry run pr"
gwt new --branch tep-1234-dry-run-pr "dry run pr"
gwt new --from main "spike parser"
USAGE
}
die() {
printf 'gwt: %s\n' "$*" >&2
exit 1
}
slugify() {
local input="$*"
local slug
slug=$(
printf '%s' "$input" |
tr '[:upper:]' '[:lower:]' |
sed -E 's/[^a-z0-9]+/-/g; s/^-+//; s/-+$//; s/-+/-/g'
)
[[ -n "$slug" ]] || die "name must contain at least one letter or number"
printf '%s\n' "$slug"
}
repo_name_for() {
local root="$1"
local primary
primary=$(
git -C "$root" worktree list --porcelain |
awk 'NR == 1 && $1 == "worktree" { sub(/^worktree /, ""); print; exit }'
)
basename "${primary:-$root}"
}
new_worktree() {
local branch=""
local start_point="HEAD"
while [[ $# -gt 0 ]]; do
case "$1" in
-b | --branch)
[[ $# -ge 2 ]] || die "$1 requires a branch name"
branch="$2"
shift 2
;;
--from)
[[ $# -ge 2 ]] || die "$1 requires a ref"
start_point="$2"
shift 2
;;
-h | --help)
usage
exit 0
;;
--)
shift
break
;;
-*)
die "unknown option for new: $1"
;;
*)
break
;;
esac
done
[[ $# -gt 0 ]] || die "new requires a worktree name"
local name="$*"
local slug
local root
local repo_name
local target_root
local target
slug="$(slugify "$name")"
branch="${branch:-$slug}"
root="$(git rev-parse --show-toplevel 2>/dev/null)" || die "not inside a git repository"
repo_name="$(repo_name_for "$root")"
target_root="${GWT_HOME:-$HOME/worktrees}"
target="$target_root/$repo_name/$slug"
[[ ! -e "$target" ]] || die "target already exists: $target"
if git -C "$root" show-ref --verify --quiet "refs/heads/$branch"; then
die "branch already exists: $branch"
fi
mkdir -p "$(dirname "$target")"
git -C "$root" worktree add -b "$branch" "$target" "$start_point" >&2
printf '%s\n' "$target"
}
main() {
local command="${1:-help}"
[[ $# -eq 0 ]] || shift
case "$command" in
new)
new_worktree "$@"
;;
list | ls)
git worktree list "$@"
;;
remove | rm)
git worktree remove "$@"
;;
prune)
git worktree prune "$@"
;;
help | -h | --help)
usage
;;
*)
git worktree "$command" "$@"
;;
esac
}
main "$@"
PR review tools (~/bin/pr-comments, ~/bin/pr-state, ~/bin/pr-doctor, ~/bin/pr-babysit)#
These wrappers expose the shared pr-review-tools agent skill as normal shell
commands. The implementation lives in ~/.agents/skills so Claude, Codex, and
interactive shell use all share the same GitHub PR comment/check logic.
#!/usr/bin/env bash
set -euo pipefail
exec python3 "$HOME/.agents/skills/pr-review-tools/scripts/pr_tool.py" comments "$@"
#!/usr/bin/env bash
set -euo pipefail
exec python3 "$HOME/.agents/skills/pr-review-tools/scripts/pr_tool.py" state "$@"
#!/usr/bin/env bash
set -euo pipefail
exec python3 "$HOME/.agents/skills/pr-review-tools/scripts/pr_tool.py" doctor "$@"
#!/usr/bin/env bash
set -euo pipefail
exec python3 "$HOME/.agents/skills/pr-review-tools/scripts/pr_tool.py" babysit "$@"
Agent GitHub shim (~/bin/agent-shims/gh)#
Claude and Codex sessions put this directory ahead of Homebrew’s gh binary.
The shim keeps regular read/investigation workflows working while stopping
risky org and repo policy mutations unless an explicit Jira-ticket break-glass
environment variable is present.
#!/usr/bin/env bash
set -euo pipefail
shim_path="${BASH_SOURCE[0]}"
shim_dir="$(cd "$(dirname "$shim_path")" && pwd -P)"
find_real_gh() {
if [[ -n "${PARLOA_REAL_GH:-}" && -x "${PARLOA_REAL_GH:-}" ]]; then
printf '%s\n' "$PARLOA_REAL_GH"
return 0
fi
local candidate
for candidate in /opt/homebrew/bin/gh /usr/local/bin/gh /usr/bin/gh; do
if [[ -x "$candidate" && "$candidate" != "$shim_path" ]]; then
printf '%s\n' "$candidate"
return 0
fi
done
local path_dir
IFS=:
for path_dir in $PATH; do
[[ -n "$path_dir" && "$path_dir" != "$shim_dir" ]] || continue
candidate="$path_dir/gh"
if [[ -x "$candidate" && "$candidate" != "$shim_path" ]]; then
printf '%s\n' "$candidate"
return 0
fi
done
unset IFS
return 1
}
real_gh="$(find_real_gh)" || {
printf 'agent-gh: could not find the real gh binary\n' >&2
exit 127
}
break_glass_active() {
[[ "${PARLOA_GH_BREAK_GLASS:-}" =~ ^TEP-[0-9]+$ ]]
}
allow_or_block() {
local reason="$1"
if break_glass_active; then
printf 'agent-gh: break-glass active (%s); allowing %s\n' "$PARLOA_GH_BREAK_GLASS" "$reason" >&2
return 0
fi
cat >&2 <<EOF
agent-gh: blocked $reason
This shell is using the Parloa agent gh shim. If this is intentional, rerun
with a Jira ticket in PARLOA_GH_BREAK_GLASS, for example:
PARLOA_GH_BREAK_GLASS=TEP-3600 gh ...
Real gh binary: $real_gh
EOF
exit 1
}
upper() {
printf '%s' "$1" | tr '[:lower:]' '[:upper:]'
}
normalize_endpoint() {
local endpoint="$1"
endpoint="${endpoint#https://api.github.com}"
endpoint="${endpoint#http://api.github.com}"
endpoint="${endpoint#api.github.com}"
endpoint="${endpoint%%\?*}"
[[ "$endpoint" == /* ]] || endpoint="/$endpoint"
printf '%s\n' "$endpoint"
}
is_mutating_method() {
case "$(upper "$1")" in
POST | PUT | PATCH | DELETE)
return 0
;;
*)
return 1
;;
esac
}
is_dangerous_endpoint() {
local endpoint
endpoint="$(normalize_endpoint "$1")"
case "$endpoint" in
/orgs/parloa/actions | /orgs/parloa/actions/* | \
/orgs/parloa/rulesets | /orgs/parloa/rulesets/* | \
/orgs/parloa/members | /orgs/parloa/members/* | \
/orgs/parloa/teams | /orgs/parloa/teams/* | \
/orgs/parloa/hooks | /orgs/parloa/hooks/* | \
/orgs/parloa/actions/secrets | /orgs/parloa/actions/secrets/* | \
/orgs/parloa/actions/runner-groups | /orgs/parloa/actions/runner-groups/* | \
/orgs/parloa/codespaces/secrets | /orgs/parloa/codespaces/secrets/* | \
/orgs/parloa/dependabot/secrets | /orgs/parloa/dependabot/secrets/* | \
/orgs/parloa/security-managers | /orgs/parloa/security-managers/* | \
/enterprises/*/actions | /enterprises/*/actions/* | \
/enterprises/*/rulesets | /enterprises/*/rulesets/* | \
/enterprises/*/members | /enterprises/*/members/* | \
/enterprises/*/teams | /enterprises/*/teams/* | \
/repos/parloa/*/actions/permissions | /repos/parloa/*/actions/permissions/* | \
/repos/parloa/*/rulesets | /repos/parloa/*/rulesets/* | \
/repos/parloa/*/branches/*/protection | /repos/parloa/*/branches/*/protection/* | \
/repos/parloa/*/collaborators | /repos/parloa/*/collaborators/* | \
/repos/parloa/*/teams | /repos/parloa/*/teams/* | \
/repos/parloa/*/hooks | /repos/parloa/*/hooks/* | \
/repos/parloa/*/actions/secrets | /repos/parloa/*/actions/secrets/*)
return 0
;;
*)
return 1
;;
esac
}
parse_api_call() {
local method=""
local endpoint=""
local fields_make_post=0
local query_value=""
local arg
while [[ $# -gt 0 ]]; do
arg="$1"
case "$arg" in
-X | --method)
[[ $# -ge 2 ]] || break
method="$2"
shift 2
;;
--method=*)
method="${arg#--method=}"
shift
;;
-X*)
method="${arg#-X}"
shift
;;
-f | -F | --field | --raw-field)
fields_make_post=1
if [[ $# -ge 2 && "$2" == query=* ]]; then
query_value="${2#query=}"
fi
if [[ $# -ge 2 ]]; then
shift 2
else
shift
fi
;;
--field=* | --raw-field=*)
fields_make_post=1
if [[ "$arg" == *=query=* ]]; then
query_value="${arg#*=query=}"
fi
shift
;;
--input)
fields_make_post=1
if [[ $# -ge 2 ]]; then
shift 2
else
shift
fi
;;
--input=*)
fields_make_post=1
shift
;;
-H | --header | -p | --preview | -q | --jq | --template | --hostname | --cache)
if [[ $# -ge 2 ]]; then
shift 2
else
shift
fi
;;
--header=* | --preview=* | --jq=* | --template=* | --hostname=* | --cache=*)
shift
;;
--paginate | --slurp | --silent | --verbose)
shift
;;
--)
shift
[[ $# -gt 0 && -z "$endpoint" ]] && endpoint="$1"
break
;;
-*)
shift
;;
*)
[[ -z "$endpoint" ]] && endpoint="$arg"
shift
;;
esac
done
if [[ -z "$method" ]]; then
if [[ "$fields_make_post" -eq 1 ]]; then
method="POST"
else
method="GET"
fi
fi
if [[ "$endpoint" == "graphql" && "$query_value" == *mutation* ]]; then
allow_or_block "GraphQL mutation through gh api"
fi
if [[ -n "$endpoint" ]] && is_mutating_method "$method" && is_dangerous_endpoint "$endpoint"; then
allow_or_block "$(upper "$method") $(normalize_endpoint "$endpoint")"
fi
}
arg_has_org_parloa() {
while [[ $# -gt 0 ]]; do
case "$1" in
--org=parloa | -o=parloa)
return 0
;;
--org | -o)
[[ "${2:-}" == "parloa" ]] && return 0
shift 2
;;
*)
shift
;;
esac
done
return 1
}
parse_high_level_command() {
case "${1:-} ${2:-}" in
"secret set" | "secret delete" | "variable set" | "variable delete")
if arg_has_org_parloa "${@:3}"; then
allow_or_block "gh $1 $2 --org parloa"
fi
;;
"ruleset create" | "ruleset edit" | "ruleset delete")
allow_or_block "gh $1 $2"
;;
"repo delete" | "repo archive")
if [[ "${3:-}" == parloa/* || "${3:-}" == https://github.com/parloa/* ]]; then
allow_or_block "gh $1 $2 ${3:-}"
fi
;;
"repo edit")
if [[ "${3:-}" == parloa/* || "${3:-}" == https://github.com/parloa/* ]]; then
allow_or_block "gh $1 $2 ${3:-}"
fi
;;
esac
}
doctor() {
printf 'agent gh shim: %s\n' "$shim_path"
printf 'real gh: %s\n' "$real_gh"
printf 'PATH gh: %s\n' "$(command -v gh 2>/dev/null || true)"
printf 'GH_CONFIG_DIR: %s\n' "${GH_CONFIG_DIR:-<default gh config>}"
printf 'PARLOA_AGENT_GH_SAFE_MODE: %s\n' "${PARLOA_AGENT_GH_SAFE_MODE:-<unset>}"
if [[ -n "${PARLOA_GH_BREAK_GLASS:-}" ]]; then
printf 'PARLOA_GH_BREAK_GLASS: %s\n' "$PARLOA_GH_BREAK_GLASS"
else
printf 'PARLOA_GH_BREAK_GLASS: <inactive>\n'
fi
printf '\n'
if "$real_gh" auth status --help 2>/dev/null | grep -q -- '--show-token-scopes'; then
"$real_gh" auth status --show-token-scopes || true
else
printf 'Token scopes: unavailable; this gh version only exposes --show-token, which is intentionally not used here.\n\n'
"$real_gh" auth status || true
fi
}
case "${1:-}" in
agent-doctor)
shift
doctor "$@"
exit 0
;;
api)
parse_api_call "${@:2}"
;;
*)
parse_high_level_command "$@"
;;
esac
exec "$real_gh" "$@"