From f16eea758544c78c423b09d84ef575cbb27e5b3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?deniz=20g=C3=B6k=C3=A7in?= <33603535+dgokcin@users.noreply.github.com> Date: Wed, 7 Oct 2026 22:14:27 +0200 Subject: [PATCH 1/6] chore(skills): switch haiku skills to claude-haiku-5-5 - update daily-recap session summarizer to haiku 5.5 - pin save-property-to-vault and vault-capture to claude-haiku-5-5 --- ai-stuff/skills/daily-recap/SKILL.md | 4 ++-- ai-stuff/skills/save-property-to-vault/SKILL.md | 2 +- ai-stuff/skills/vault-capture/SKILL.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ai-stuff/skills/daily-recap/SKILL.md b/ai-stuff/skills/daily-recap/SKILL.md index e07070d4..8d9e8c19 100644 --- a/ai-stuff/skills/daily-recap/SKILL.md +++ b/ai-stuff/skills/daily-recap/SKILL.md @@ -307,11 +307,11 @@ For each meeting where Gemini data was successfully fetched (step 2i above): #### 2j. Claude Code sessions (Haiku subagent) -Run the companion script to extract session data, then pipe to a Haiku subagent for summarization. This captures engineering work that never surfaces in Slack or Gmail (local coding, debugging, config changes, dotfiles work). +Run the companion script to extract session data, then pipe to a Haiku 5.5 subagent for summarization. This captures engineering work that never surfaces in Slack or Gmail (local coding, debugging, config changes, dotfiles work). ```bash python3 ~/.claude/skills/daily-recap/scripts/summarize-claude-sessions.py YYYY-MM-DD | \ - claude -p --model claude-haiku-4-5-20251001 \ + claude -p --model claude-haiku-5-5 \ "Summarize these Claude Code sessions into 2-5 bullet points of what engineering work was done. Focus on: features built, tickets worked, bugs debugged, code changed. Skip meta/tooling sessions (e.g. only ran 'exit', only did shell commands with no edits). Max one line per bullet. Output plain bullets only." ``` diff --git a/ai-stuff/skills/save-property-to-vault/SKILL.md b/ai-stuff/skills/save-property-to-vault/SKILL.md index c03eacf5..cefdea55 100644 --- a/ai-stuff/skills/save-property-to-vault/SKILL.md +++ b/ai-stuff/skills/save-property-to-vault/SKILL.md @@ -1,7 +1,7 @@ --- name: save-property-to-vault description: Save an analyzed property listing to the Obsidian vault using the property frontmatter schema and body template. Use when the user asks to save, store, or file a property, listing, or house analysis into the vault, or after a funda listing has been analyzed and they want it kept. -model: haiku +model: claude-haiku-5-5 allowed-tools: Read, Write, Edit, Glob --- diff --git a/ai-stuff/skills/vault-capture/SKILL.md b/ai-stuff/skills/vault-capture/SKILL.md index 79cc4bab..def2b57f 100644 --- a/ai-stuff/skills/vault-capture/SKILL.md +++ b/ai-stuff/skills/vault-capture/SKILL.md @@ -1,7 +1,7 @@ --- name: vault-capture description: This skill should be used when the user asks to "add to my vault", "add to obsidian", "save this to my vault", "add a task", "note this down", "add a task to ", "capture this", "add to my daily note", "make a note about", or otherwise wants content written into their Obsidian vault at ~/vault. Routes content to the right folder, applies vault frontmatter/tag conventions, formats tasks as `- [ ]` checkboxes, and wires up `[[wikilinks]]` automatically. -model: haiku +model: claude-haiku-5-5 allowed-tools: Read, Write, Edit, Glob, Grep, Bash --- From 7e007c6bada8ef9c3f609d6ec7b93acd5b02606e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?deniz=20g=C3=B6k=C3=A7in?= <33603535+dgokcin@users.noreply.github.com> Date: Thu, 8 Oct 2026 15:12:43 +0200 Subject: [PATCH 2/6] build(skills): install skills from external repo via skills.mk - add skills.mk and skills-link.sh to link external skills - drop skill-meta.sh and yq dependency from ci - update ai, claude, codex, cursor, tools makefiles accordingly - remove stale skill ignore patterns from gitignore --- .github/workflows/checks.yml | 2 - .gitignore | 3 - Makefile | 3 +- makefiles/ai.mk | 63 +------------ makefiles/ci.mk | 4 +- makefiles/claude.mk | 13 ++- makefiles/codex.mk | 11 +-- makefiles/cursor.mk | 21 ++--- makefiles/scripts/skill-meta.sh | 136 ---------------------------- makefiles/scripts/skills-link.sh | 78 ++++++++++++++++ makefiles/scripts/verify-install.sh | 9 -- makefiles/skills.mk | 42 +++++++++ makefiles/targets.mk | 2 +- makefiles/tools.mk | 2 +- 14 files changed, 150 insertions(+), 239 deletions(-) delete mode 100755 makefiles/scripts/skill-meta.sh create mode 100755 makefiles/scripts/skills-link.sh create mode 100644 makefiles/skills.mk diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index e63653a2..1fdde1f2 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -26,8 +26,6 @@ jobs: sudo apt-get install -y yamllint shellcheck curl -fsSL https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash | bash sudo mv actionlint /usr/local/bin/actionlint - sudo wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 - sudo chmod +x /usr/local/bin/yq - name: Lint run: make lint diff --git a/.gitignore b/.gitignore index 72aef176..7ebac043 100644 --- a/.gitignore +++ b/.gitignore @@ -15,9 +15,6 @@ ai-stuff/_shared/**/_*.md ai-stuff/claude/config/.clusters.json ai-stuff/_shared/config/.clusters.json -ai-stuff/claude/skills/add-recipe/*.original* -ai-stuff/claude/skills/**/SKILL.original.md - # Private work-specific traefik migration config. The skill, traefik-dev and traefik-recon moved into # k8s-gitops-platform-apps on 2026-08-12; only the personal Obsidian layer stays here. ai-stuff/_shared/config/traefik-epic.md diff --git a/Makefile b/Makefile index 86e82212..d9904fa4 100644 --- a/Makefile +++ b/Makefile @@ -15,10 +15,11 @@ include makefiles/shell.mk include makefiles/tools.mk include makefiles/utils.mk include makefiles/ai.mk +include makefiles/skills.mk include makefiles/claude.mk include makefiles/cursor.mk include makefiles/codex.mk -include makefiles/raycast.mk +include makefiles/raycast.mk include makefiles/targets.mk include makefiles/ci.mk diff --git a/makefiles/ai.mk b/makefiles/ai.mk index 510458d8..c76ce023 100644 --- a/makefiles/ai.mk +++ b/makefiles/ai.mk @@ -1,66 +1,11 @@ -# Universal AI skills installer (Agent Skills standard — agentskills.io) +# Shared AI content (configs, templates, scripts) for every AI tool. # -# Skills are authored ONCE in ai-stuff/skills/ (one directory per skill: -# SKILL.md + agents/openai.yaml + references/ + scripts/) and symlinked -# verbatim into every tool's skills directory. SKILL.md frontmatter drives -# Claude Code; agents/openai.yaml drives the Codex skill picker. The two must -# agree on invocation policy — makefiles/scripts/skill-meta.sh enforces it -# (see ai-stuff/invocation.md) and runs as `ai-check` before every install. Same approach as BMAD-METHOD's platform installer -# (tools/installer/ide/platform-codes.yaml), minus the copy step. -# -# Tool registry — one entry per tool. Many tools read the cross-tool standard -# directory ~/.agents/skills (Codex, Cursor, Gemini CLI, Windsurf, -# GitHub Copilot, Roo, OpenHands, ...) — covered by the pseudo-tool "agents". -# Codex has NO entry of its own: it ignores ~/.codex/skills and reads only -# .agents/skills (repo + $HOME) — see https://learn.chatgpt.com/docs/build-skills. -# Adding a tool with its own directory = 2 lines: -# AI_TOOLS += cline -# ai_skills_dir_cline := ${HOME}/.cline/skills - -AI_TOOLS := claude agents - -ai_skills_dir_claude := ${HOME}/.claude/skills -ai_skills_dir_agents := ${HOME}/.agents/skills - -# Every entry in ai-stuff/skills/: skill dirs + the _shared symlink that makes -# each skill's relative ../_shared/... references resolve when installed. -# Dot-dirs (.archived) are excluded by the wildcard. -AI_SKILLS := $(notdir $(wildcard $(DOTFILES)/ai-stuff/skills/*)) - -# Names that used to be installed but no longer exist as skills — pruned on -# every install so stale symlinks don't linger (BMAD's removals.txt pattern). -AI_LEGACY_SKILLS := add-recipe add-vinyl gitboi gitops-geezer meeting-note quick-note request-viewing weekly-review traefik spike dev-story mega-dev commit jiragirl - -SKILL_META := $(DOTFILES)/makefiles/scripts/skill-meta.sh - -ai: ai-check ai-shared $(addprefix ai-,$(AI_TOOLS)) ## Install universal skills into every registered AI tool - -ai-check: ## Lint skills: SKILL.md frontmatter <-> agents/openai.yaml invocation policy, legacy keys, stale files - @$(SKILL_META) --check - -ai-skill-meta: ## Scaffold agents/openai.yaml for skills that lack one (then curate short_description) - @$(SKILL_META) --scaffold +# Skills live in ~/codes/skills and `make skills` installs them (skills.mk). +# No target in this file touches ~/.claude/skills or ~/.agents/skills. ai-shared: ## Symlink shared configs/templates/scripts to the tool-agnostic ~/.config/ai-shared $(call pretty_print, "Linking $(XDG_CONFIG_HOME)/ai-shared to ai-stuff/_shared") @mkdir -p $(XDG_CONFIG_HOME) @ln -sfn "$(DOTFILES)/ai-stuff/_shared" "$(XDG_CONFIG_HOME)/ai-shared" -$(addprefix ai-,$(AI_TOOLS)): ai-%: - $(call pretty_print, "Installing $(words $(AI_SKILLS)) skills into $(ai_skills_dir_$*)") - @mkdir -p $(ai_skills_dir_$*) - @for s in $(AI_SKILLS) $(AI_LEGACY_SKILLS); do rm -rf "$(ai_skills_dir_$*)/$$s"; done - @for s in $(AI_SKILLS); do ln -sfn "$(DOTFILES)/ai-stuff/skills/$$s" "$(ai_skills_dir_$*)/$$s"; done - -ai-list: ## List universal skills and registered AI tools - @echo "Skills ($(words $(AI_SKILLS))): $(AI_SKILLS)" - @echo "Tools:" - @$(foreach t,$(AI_TOOLS),echo " $(t) -> $(ai_skills_dir_$(t))";) - -ai-clean: $(addprefix ai-clean-,$(AI_TOOLS)) ## Remove universal skills from every registered AI tool - -$(addprefix ai-clean-,$(AI_TOOLS)): ai-clean-%: - $(call pretty_print, "Removing skills from $(ai_skills_dir_$*)") - @for s in $(AI_SKILLS) $(AI_LEGACY_SKILLS); do rm -rf "$(ai_skills_dir_$*)/$$s"; done - -.PHONY: ai ai-check ai-skill-meta ai-shared ai-list ai-clean $(addprefix ai-,$(AI_TOOLS)) $(addprefix ai-clean-,$(AI_TOOLS)) +.PHONY: ai-shared diff --git a/makefiles/ci.mk b/makefiles/ci.mk index 28adbdef..8b189bed 100644 --- a/makefiles/ci.mk +++ b/makefiles/ci.mk @@ -4,7 +4,7 @@ # macOS CI: make cursor-user-config (Darwin Library path) + make brew-health # # make lint actionlint + shellcheck + yamllint + JSON -# make test skill metadata + statusline fixtures +# make test statusline fixtures # make test-bootstrap bootstrap dependency and installer contract # make install-ci symlink install (set HOME / XDG_CONFIG_HOME first) # make verify-install assert those symlinks point back at this repo @@ -29,7 +29,7 @@ lint-yaml: lint-json: @$(DOTFILES)/makefiles/scripts/lint-json.sh -test: ai-check test-statusline ## Skill lint + statusline fixture tests +test: test-statusline ## Statusline fixture tests test-statusline: @$(DOTFILES)/ai-stuff/claude/scripts/statusline-test.sh diff --git a/makefiles/claude.mk b/makefiles/claude.mk index 1c92aeb7..18c61f1f 100644 --- a/makefiles/claude.mk +++ b/makefiles/claude.mk @@ -1,10 +1,9 @@ # Claude Code configuration setup (tool-specific layer) # -# Universal skills are installed by makefiles/ai.mk (make ai-claude); shared -# configs/templates live at ~/.config/ai-shared (make ai-shared) — -# agents reference them there, so nothing tool-specific holds content. -# This file only handles what is Claude Code-specific: agents, hook scripts, -# settings, and keybindings. +# Skills come from ~/codes/skills via `make skills` (skills.mk). Shared configs and +# templates live at ~/.config/ai-shared (make ai-shared), and agents reference +# them there. This file handles the Claude Code pieces: agents, output styles, +# hook scripts, settings, and keybindings. CLAUDE_HOME := ${HOME}/.claude @@ -31,7 +30,7 @@ claude-cli: ## Install Claude Code with Anthropic's recommended native installer echo "Claude Code already installed at $(HOME)/.local/bin/claude"; \ fi -claude-dotfiles: claude-dirs claude-agents claude-output-styles claude-scripts claude-settings claude-keybindings ai-shared ai-claude ## Install Claude Code configuration only +claude-dotfiles: claude-dirs claude-agents claude-output-styles claude-scripts claude-settings claude-keybindings ai-shared ## Install Claude Code configuration only $(call pretty_print, "Pruning legacy ~/.claude symlinks...") @rm -rf $(CLAUDE_LEGACY) @@ -77,7 +76,7 @@ claude-mods: claude-settings ## Clone and install Claude Code mods (claude-pokem @claude plugin marketplace update claude-pokemon >/dev/null 2>&1 || claude plugin marketplace add "$(CLAUDE_POKEMON_DIR)" @claude plugin install pokemon@claude-pokemon -claude-clean: ai-clean-claude ## Remove Claude Code symlinks +claude-clean: ## Remove Claude Code symlinks $(call pretty_print, "Removing Claude Code symlinks...") @claude plugin uninstall pokemon@claude-pokemon >/dev/null 2>&1 || true @for a in $(CLAUDE_AGENTS); do rm -f "${CLAUDE_HOME}/agents/$$a"; done diff --git a/makefiles/codex.mk b/makefiles/codex.mk index 69f25300..98b75a7a 100644 --- a/makefiles/codex.mk +++ b/makefiles/codex.mk @@ -1,9 +1,8 @@ # Codex configuration setup (tool-specific layer) # -# Skills: Codex reads only the cross-tool standard dir ~/.agents/skills — -# installed by ai.mk's "agents" pseudo-tool. Codex does NOT read -# ~/.codex/skills (that dir is pruned on install). This file handles what is -# Codex-specific: lifecycle hooks (hooks.json), the global AGENTS.md, and the managed block of config.toml. Codex's hook +# Codex reads skills from ~/.agents/skills, which `make skills` fills. Codex +# does not read ~/.codex/skills, so install prunes our dead symlinks there. +# This file handles what is Codex-specific: lifecycle hooks (hooks.json), the global AGENTS.md, and the managed block of config.toml. Codex's hook # system (~v0.114+) adopted Claude Code's protocol (same stdin payload + # output schema), so shared scripts live in ai-stuff/_shared/scripts/ and are # symlinked into each tool's own dir. @@ -22,7 +21,7 @@ codex-cli: ## Install Codex with OpenAI's recommended standalone installer echo "Codex already installed at $(HOME)/.local/bin/codex"; \ fi -codex-dotfiles: ai-agents codex-scripts codex-hooks codex-agents-md codex-config ## Install Codex configuration only +codex-dotfiles: codex-scripts codex-hooks codex-agents-md codex-config ## Install Codex configuration only # Codex reads ~/.agents/skills — kill our old symlinks in ~/.codex/skills but # keep .system, the dir where Codex caches its own built-in skills. $(call pretty_print, "Pruning dead skill symlinks in ~/.codex/skills") @@ -56,7 +55,7 @@ codex-config: ## Sync dotfiles-managed block into ~/.codex/config.toml (machine $(call pretty_print, "Syncing managed block of ~/.codex/config.toml...") @bash $(DOTFILES)/ai-stuff/codex/scripts/sync-config.sh -codex-clean: ## Remove Codex symlinks (skills live in ~/.agents/skills — use ai-clean) +codex-clean: ## Remove Codex symlinks (skills are managed by `make skills`) $(call pretty_print, "Removing Codex symlinks...") $(call remove_file,${CODEX_HOME}/hooks.json) $(call remove_file,${CODEX_HOME}/AGENTS.md) diff --git a/makefiles/cursor.mk b/makefiles/cursor.mk index 20641aba..3c9c6101 100644 --- a/makefiles/cursor.mk +++ b/makefiles/cursor.mk @@ -1,10 +1,9 @@ # Cursor configuration setup (tool-specific layer) # -# Cursor reads skills from the cross-tool standard directory ~/.agents/skills -# (installed by makefiles/ai.mk via make ai-agents). This file handles the -# Cursor-specific pieces: agents, lifecycle hooks (hooks.json), CLI settings, -# editor settings, keybindings, and hook scripts. It also prunes the legacy -# ~/.cursor layout that predates the universal skills setup. +# Cursor reads skills from ~/.agents/skills, which `make skills` fills. This +# file handles the Cursor-specific pieces: agents, lifecycle hooks (hooks.json), +# CLI settings, editor settings, keybindings, and hook scripts. It also prunes +# the legacy ~/.cursor persona/config/template layout. # # Cursor's hook protocol differs from Claude Code's (tool-specific events, # {"permission": ...} output), so the shared allowlist is reused via a small @@ -19,14 +18,12 @@ else CURSOR_USER_HOME := ${XDG_CONFIG_HOME}/Cursor/User endif -# Old per-tool skill/persona/config/template symlinks installed by the -# pre-universal cursor.mk — pruned on install. -CURSOR_LEGACY := $(addprefix ${CURSOR_HOME}/skills/,gitboi jiragirl mega-dev commit create-pr create-story dev-story get-story) \ - ${CURSOR_HOME}/personas ${CURSOR_HOME}/config ${CURSOR_HOME}/templates \ +# Old persona/config/template symlinks, pruned on install. +CURSOR_LEGACY := ${CURSOR_HOME}/personas ${CURSOR_HOME}/config ${CURSOR_HOME}/templates \ $(addprefix ${CURSOR_HOME}/agents/,gitboi.md jiragirl.md mega-dev.md) -cursor: cursor-agents cursor-scripts cursor-hooks cursor-config cursor-user-config ai-agents ## Install Cursor agents, hooks, settings, keybindings, and universal skills - $(call pretty_print, "Pruning legacy ~/.cursor skill symlinks...") +cursor: cursor-agents cursor-scripts cursor-hooks cursor-config cursor-user-config ## Install Cursor agents, hooks, settings, and keybindings + $(call pretty_print, "Pruning legacy ~/.cursor symlinks...") @rm -rf $(CURSOR_LEGACY) cursor-agents: ## Symlink Cursor agents (same definitions as Claude Code) @@ -67,7 +64,7 @@ cursor-user-config: ## Symlink Cursor editor settings and keybindings ln -sfn "$(DOTFILES)/ai-stuff/cursor/$$f" "$$target"; \ done -cursor-clean: ## Remove Cursor symlinks (universal skills stay; use ai-clean-agents for those) +cursor-clean: ## Remove Cursor symlinks (skills are managed by `make skills`) $(call pretty_print, "Removing Cursor symlinks...") @for a in $(CLAUDE_AGENTS); do rm -f "${CURSOR_HOME}/agents/$$a"; done $(call remove_file,${CURSOR_HOME}/hooks.json) diff --git a/makefiles/scripts/skill-meta.sh b/makefiles/scripts/skill-meta.sh deleted file mode 100755 index 17c03e72..00000000 --- a/makefiles/scripts/skill-meta.sh +++ /dev/null @@ -1,136 +0,0 @@ -#!/usr/bin/env bash -# skill-meta.sh — keep every universal skill agent-agnostic. -# -# Each skill in ai-stuff/skills// carries two metadata surfaces that must -# agree (see ai-stuff/invocation.md): -# SKILL.md frontmatter -> Claude Code (disable-model-invocation, ...) -# agents/openai.yaml -> Codex skill picker (interface.*, policy.*) -# -# Usage: -# skill-meta.sh [--check] lint every skill, exit 1 on any violation (default) -# skill-meta.sh --scaffold write a starter agents/openai.yaml where missing -# (never overwrites; curate short_description after) -# -# Requires mikefarah yq v4 (brew install yq). - -set -euo pipefail - -REPO="$(cd "$(dirname "$0")/../.." && pwd)" -SKILLS_DIR="${SKILLS_DIR:-$REPO/ai-stuff/skills}" -MAX_SHORT=64 - -usage() { sed -n '2,15p' "$0" | sed 's/^# \{0,1\}//'; } - -mode=check -case "${1:-}" in - ""|--check) mode=check ;; - --scaffold) mode=scaffold ;; - -h|--help) usage; exit 0 ;; - *) echo "skill-meta: unknown argument '$1'" >&2; usage >&2; exit 2 ;; -esac - -if ! command -v yq >/dev/null 2>&1; then - echo "skill-meta: yq not found. Install with 'brew install yq' (or 'make yq')." >&2 - exit 2 -fi - -# fm FILE EXPR -> frontmatter value, "null" when absent -fm() { yq --front-matter=extract "$2" "$1" 2>/dev/null || echo null; } -# yv FILE EXPR -> yaml value, "null" when absent -yv() { yq "$2" "$1" 2>/dev/null || echo null; } - -# title_case "aws-debug" -> "Aws Debug" -title_case() { - awk -F- '{ for (i = 1; i <= NF; i++) $i = toupper(substr($i, 1, 1)) substr($i, 2); print }' OFS=' ' <<<"$1" -} - -# first_sentence "A. B c." -> "A." truncated to MAX_SHORT -first_sentence() { - local s - s="$(sed -E 's/([.!?])( .*)?$/\1/' <<<"$1")" - s="$(sed -E 's/^(.{'"$MAX_SHORT"'}).+$/\1/' <<<"$s")" - printf '%s' "$s" -} - -violations=0 -fail() { printf ' %-24s %s\n' "$1" "$2"; violations=$((violations + 1)); } - -skills=0 -scaffolded=0 -for dir in "$SKILLS_DIR"/*/; do - dir="${dir%/}" - name="$(basename "$dir")" - skill_md="$dir/SKILL.md" - [ -f "$skill_md" ] || continue # _shared symlink, stray files - skills=$((skills + 1)) - - yaml="$dir/agents/openai.yaml" - if ! yq --front-matter=extract '.' "$skill_md" >/dev/null 2>&1; then - fail "$name" "SKILL.md frontmatter is not valid YAML" - continue - fi - fm_name="$(fm "$skill_md" '.name')" - desc="$(fm "$skill_md" '.description')" - dmi="$(fm "$skill_md" '.["disable-model-invocation"]')" - legacy_tools="$(fm "$skill_md" '.tools')" - - if [ "$mode" = scaffold ]; then - [ -f "$yaml" ] && continue - display="$(title_case "$name")" - short="" - [ "$desc" != null ] && short="$(first_sentence "$desc")" - short="${short//\"/\\\"}" - mkdir -p "$dir/agents" - { - printf 'interface:\n' - printf ' display_name: "%s"\n' "$display" - printf ' short_description: "%s"\n' "$short" - if [ "$dmi" = true ]; then - printf 'policy:\n' - printf ' allow_implicit_invocation: false\n' - fi - } >"$yaml" - echo "scaffolded $name/agents/openai.yaml (curate short_description)" - scaffolded=$((scaffolded + 1)) - continue - fi - - # --- check mode ----------------------------------------------------------- - [ "$fm_name" = "$name" ] || fail "$name" "frontmatter name '$fm_name' != directory name" - [ "$legacy_tools" = null ] || fail "$name" "legacy 'tools:' key; use 'allowed-tools:'" - [ "$dmi" != false ] || fail "$name" "'disable-model-invocation: false' is the default; drop the key" - [ ! -e "$dir/SKILL.original.md" ] || fail "$name" "stale SKILL.original.md; delete it" - - if [ ! -f "$yaml" ]; then - fail "$name" "missing agents/openai.yaml (run: make ai-skill-meta)" - continue - fi - - display="$(yv "$yaml" '.interface.display_name')" - short="$(yv "$yaml" '.interface.short_description')" - allow="$(yv "$yaml" '.policy.allow_implicit_invocation')" - - [ -n "$display" ] && [ "$display" != null ] || fail "$name" "openai.yaml: interface.display_name missing" - if [ -z "$short" ] || [ "$short" = null ]; then - fail "$name" "openai.yaml: interface.short_description missing" - elif [ "${#short}" -gt "$MAX_SHORT" ]; then - fail "$name" "openai.yaml: short_description is ${#short} chars (max $MAX_SHORT)" - fi - - if [ "$dmi" = true ] && [ "$allow" != false ]; then - fail "$name" "user-invoked in Claude (disable-model-invocation: true) but openai.yaml lacks policy.allow_implicit_invocation: false" - elif [ "$dmi" != true ] && [ "$allow" = false ]; then - fail "$name" "openai.yaml blocks implicit invocation but SKILL.md lacks disable-model-invocation: true" - fi -done - -if [ "$mode" = scaffold ]; then - echo "skill-meta: $scaffolded scaffolded, $skills skills total" - exit 0 -fi - -if [ "$violations" -gt 0 ]; then - echo "skill-meta: $violations violation(s) across $skills skills" >&2 - exit 1 -fi -echo "skill-meta: $skills skills OK" diff --git a/makefiles/scripts/skills-link.sh b/makefiles/scripts/skills-link.sh new file mode 100755 index 00000000..58be2c4d --- /dev/null +++ b/makefiles/scripts/skills-link.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env bash +# Point every skill the `skills` CLI installed from REPO back at REPO. +# +# `skills add` copies each skill into ~/.agents/skills (read by Codex and +# Cursor) and links ~/.claude/skills/ to that copy. Swapping the copy for +# a symlink into REPO makes edits apply live in every agent. +# +# Repo links without a lock entry are removed. That covers skills dropped with +# `skills remove` and links left by the old link-skills.sh. +set -euo pipefail + +REPO="$(cd "${1:?usage: skills-link.sh }" && pwd)" +AGENTS_DIR="$HOME/.agents/skills" +CLAUDE_DIR="$HOME/.claude/skills" +LOCK="$HOME/.agents/.skill-lock.json" + +installed=() +if [[ -f "$LOCK" ]]; then + while IFS= read -r name; do installed+=("$name"); done < <( + jq -r --arg repo "$REPO" \ + '.skills // {} | to_entries[] | select(.value.sourceType == "local" and .value.source == $repo) | .key' \ + "$LOCK" + ) +fi + +is_installed() { + local name + for name in ${installed[@]+"${installed[@]}"}; do + [[ "$name" == "$1" ]] && return 0 + done + return 1 +} + +skill_dir() { + local md + for md in "$REPO"/skills/*/"$1"/SKILL.md; do + [[ -f "$md" && "$md" != "$REPO/skills/archived/"* ]] || continue + dirname "$md" + return 0 + done + return 1 +} + +linked=0 +for name in ${installed[@]+"${installed[@]}"}; do + if ! src="$(skill_dir "$name")"; then + echo "skills-link: no folder for '$name' in $REPO/skills, skipped" >&2 + continue + fi + dest="$AGENTS_DIR/$name" + if [[ -L "$dest" && "$(readlink "$dest")" == "$src" ]]; then + linked=$((linked + 1)) + continue + fi + + # dest is the CLI's copy or a stale link, never the repo itself. + rm -rf "$dest" + ln -s "$src" "$dest" + linked=$((linked + 1)) +done + +pruned=0 +for dir in "$AGENTS_DIR" "$CLAUDE_DIR"; do + [[ -d "$dir" ]] || continue + for link in "$dir"/*; do + [[ -L "$link" ]] || continue + case "$(readlink "$link")" in + "$REPO"/*) ;; + *) continue ;; + esac + is_installed "$(basename "$link")" && continue + rm "$link" + echo "skills-link: pruned $link" + pruned=$((pruned + 1)) + done +done + +echo "skills-link: $linked skills live from $REPO, $pruned stale links pruned" diff --git a/makefiles/scripts/verify-install.sh b/makefiles/scripts/verify-install.sh index 09d7d80a..44ec3940 100755 --- a/makefiles/scripts/verify-install.sh +++ b/makefiles/scripts/verify-install.sh @@ -77,7 +77,6 @@ assert_link "$HOME/.claude/keybindings.json" "$REPO/ai-stuff/claude/keybindings. assert_link "$HOME/.claude/scripts/statusline.sh" "$REPO/ai-stuff/claude/scripts/statusline.sh" assert_link "$HOME/.claude/scripts/auto-approve-tools.sh" "$REPO/ai-stuff/_shared/scripts/auto-approve-tools.sh" assert_link "$HOME/.claude/agents/gitops-geezer.md" "$REPO/ai-stuff/agents/gitops-geezer.md" -assert_link "$HOME/.claude/skills/auto-commit" "$REPO/ai-stuff/skills/auto-commit" assert_link "$HOME/.cursor/hooks.json" "$REPO/ai-stuff/cursor/hooks.json" assert_link "$HOME/.cursor/cli-config.json" "$REPO/ai-stuff/cursor/cli-config.json" @@ -85,7 +84,6 @@ assert_link "$HOME/.cursor/scripts/auto-approve-cursor.sh" "$REPO/ai-stuff/curso assert_link "$cursor_user/settings.json" "$REPO/ai-stuff/cursor/settings.json" assert_link "$cursor_user/keybindings.json" "$REPO/ai-stuff/cursor/keybindings.json" -assert_link "$HOME/.agents/skills/auto-commit" "$REPO/ai-stuff/skills/auto-commit" assert_link "$HOME/.codex/hooks.json" "$REPO/ai-stuff/codex/hooks.json" assert_link "$HOME/.codex/AGENTS.md" "$REPO/ai-stuff/codex/AGENTS.md" assert_link "$HOME/.codex/RTK.md" "$REPO/ai-stuff/codex/RTK.md" @@ -94,13 +92,6 @@ assert_contains "$HOME/.codex/config.toml" "BEGIN dotfiles-managed" assert_exists "$HOME/.oh-my-zsh" assert_exists "$HOME/.oh-my-zsh/custom/plugins/zsh-autosuggestions" -skill_count="$(/usr/bin/find "$HOME/.claude/skills" -mindepth 1 -maxdepth 1 | wc -l | tr -d ' ')" -if [[ "$skill_count" -ge 10 ]]; then - pass "claude skills ($skill_count)" -else - fail_at "expected >= 10 claude skills, found $skill_count" -fi - echo echo "verify-install: $ok passed, $fail failed" (( fail == 0 )) diff --git a/makefiles/skills.mk b/makefiles/skills.mk new file mode 100644 index 00000000..6f8b17f3 --- /dev/null +++ b/makefiles/skills.mk @@ -0,0 +1,42 @@ +# Agent skills from ~/codes/skills (github.com/dgokcin/skills). +# +# The vercel-labs `skills` CLI runs the picker and records each pick in +# ~/.agents/.skill-lock.json. It copies skills into ~/.agents/skills and links +# ~/.claude/skills to those copies. skills-link.sh then swaps every copy for a +# symlink into the repo, so edits apply live and skills keep bare names. +# +# Skills read private config from ~/.config/dgokcin-skills, which links to the +# repo's gitignored local/ dir. + +SKILLS_REPO := dgokcin/skills +SKILLS_DIR ?= $(HOME)/codes/skills +SKILLS_AGENTS := claude-code codex cursor +SKILLS_CLI := npx -y skills@latest +SKILLS_LINK := $(DOTFILES)/makefiles/scripts/skills-link.sh + +skills: skills-repo ## Pick skills from ~/codes/skills interactively and link them live + @$(SKILLS_CLI) add "$(SKILLS_DIR)" -g -a $(SKILLS_AGENTS) + @$(SKILLS_LINK) "$(SKILLS_DIR)" + +skills-all: skills-repo ## Install every skill from ~/codes/skills without prompting + @$(SKILLS_CLI) add "$(SKILLS_DIR)" -g -a $(SKILLS_AGENTS) -s '*' -y + @$(SKILLS_LINK) "$(SKILLS_DIR)" + +skills-remove: ## Pick installed skills to remove + @$(SKILLS_CLI) remove -g + @$(SKILLS_LINK) "$(SKILLS_DIR)" + +skills-list: ## List globally installed skills + @$(SKILLS_CLI) list -g + +skills-repo: ## Clone ~/codes/skills and link its private config + @[ -d "$(SKILLS_DIR)" ] || git clone "git@github.com:$(SKILLS_REPO).git" "$(SKILLS_DIR)" + @if [ ! -d "$(SKILLS_DIR)/local" ]; then \ + cp -R "$(SKILLS_DIR)/local.example" "$(SKILLS_DIR)/local"; \ + rm -f "$(SKILLS_DIR)/local/README.md"; \ + echo "created $(SKILLS_DIR)/local from local.example; fill in real values"; \ + fi + @mkdir -p "$(HOME)/.config" + @ln -sfn "$(SKILLS_DIR)/local" "$(HOME)/.config/dgokcin-skills" + +.PHONY: skills skills-all skills-remove skills-list skills-repo diff --git a/makefiles/targets.mk b/makefiles/targets.mk index 7a309be8..7a17764f 100644 --- a/makefiles/targets.mk +++ b/makefiles/targets.mk @@ -1,6 +1,6 @@ # High-level targets for setting up environments -bootstrap: brew-bundle tools personal claude cursor codex raycast ## Set up a new Mac with packages, CLIs, shell, editors, and AI configuration +bootstrap: brew-bundle tools personal claude cursor codex skills raycast ## Set up a new Mac with packages, CLIs, shell, editors, AI configuration, and skills # Setup personal environment personal: nvim bash zsh personal-git yamllint k9s diff --git a/makefiles/tools.mk b/makefiles/tools.mk index 1dddbe6c..22cc7882 100644 --- a/makefiles/tools.mk +++ b/makefiles/tools.mk @@ -124,7 +124,7 @@ yamllint: ## Set up yamllint with custom configuration in the config directory $(call mkdir_safe,${HOME}/.config/yamllint) $(call symlink,other/yamllint/config,${XDG_CONFIG_HOME}/yamllint/config) -yq: ## Install yq (YAML processor used by makefiles/scripts/skill-meta.sh) +yq: ## Install yq (YAML processor) $(call install_with_brew,yq) k9s: ## Symlink k9s aliases and views From 782d7867d8d192214e1079c025c33bf96fd2f931 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?deniz=20g=C3=B6k=C3=A7in?= <33603535+dgokcin@users.noreply.github.com> Date: Thu, 8 Oct 2026 15:12:43 +0200 Subject: [PATCH 3/6] chore(ai-stuff): remove skills and shared assets from repo - delete skills, archived skills and shared config/scripts/templates - remove invocation.md - update gitops-geezer and steve-square-meter agents --- ai-stuff/_shared/config/git-config.md | 150 ------- ai-stuff/_shared/config/gitops-config.md | 340 -------------- .../_shared/config/house-search-config.md | 72 --- ai-stuff/_shared/config/jira-config.md | 137 ------ ai-stuff/_shared/scripts/pr-status.sh | 11 - .../scripts/worktree-cleanup-remove.sh | 24 - .../_shared/scripts/worktree-cleanup-scan.sh | 176 -------- .../_shared/templates/daily-recap-output.md | 167 ------- .../templates/neighborhood-template.md | 36 -- .../templates/property-frontmatter.yaml | 36 -- .../_shared/templates/property-template.md | 69 --- ai-stuff/agents/gitops-geezer.md | 346 +++++++++++++- ai-stuff/agents/steve-square-meter.md | 18 +- ai-stuff/invocation.md | 80 ---- ai-stuff/skills/.archived/add-recipe/SKILL.md | 58 --- .../.archived/add-recipe/SKILL.original.md | 58 --- ai-stuff/skills/.archived/add-vinyl/SKILL.md | 58 --- .../.archived/add-vinyl/SKILL.original.md | 58 --- ai-stuff/skills/.archived/commit/SKILL.md | 125 ------ .../skills/.archived/commit/SKILL.original.md | 107 ----- ai-stuff/skills/.archived/dev-story/SKILL.md | 106 ----- ai-stuff/skills/.archived/gitboi/SKILL.md | 56 --- .../skills/.archived/gitboi/SKILL.original.md | 58 --- .../skills/.archived/gitops-geezer/SKILL.md | 68 --- .../.archived/gitops-geezer/SKILL.original.md | 68 --- ai-stuff/skills/.archived/jiragirl/SKILL.md | 55 --- .../.archived/jiragirl/agents/openai.yaml | 5 - .../skills/.archived/meeting-note/SKILL.md | 48 -- ai-stuff/skills/.archived/mega-dev/SKILL.md | 77 ---- .../.archived/mega-dev/SKILL.original.md | 77 ---- ai-stuff/skills/.archived/quick-note/SKILL.md | 50 --- .../.archived/quick-note/SKILL.original.md | 40 -- .../skills/.archived/request-viewing/SKILL.md | 49 -- .../request-viewing/SKILL.original.md | 49 -- ai-stuff/skills/.archived/spike/SKILL.md | 95 ---- .../skills/.archived/spike/SKILL.original.md | 95 ---- .../skills/.archived/weekly-review/SKILL.md | 56 --- .../.archived/weekly-review/SKILL.original.md | 56 --- ai-stuff/skills/_shared | 1 - ai-stuff/skills/address-review/SKILL.md | 139 ------ .../skills/address-review/agents/openai.yaml | 5 - ai-stuff/skills/auto-commit/SKILL.md | 145 ------ .../skills/auto-commit/agents/openai.yaml | 3 - ai-stuff/skills/aws-debug/SKILL.md | 171 ------- ai-stuff/skills/aws-debug/agents/openai.yaml | 3 - ai-stuff/skills/create-pr/SKILL.md | 254 ----------- ai-stuff/skills/create-pr/agents/openai.yaml | 3 - ai-stuff/skills/create-story/SKILL.md | 53 --- .../skills/create-story/agents/openai.yaml | 3 - ai-stuff/skills/daily-recap/SKILL.md | 421 ------------------ .../skills/daily-recap/agents/openai.yaml | 5 - .../scripts/summarize-claude-sessions.py | 229 ---------- ai-stuff/skills/get-story/SKILL.md | 65 --- ai-stuff/skills/get-story/agents/openai.yaml | 3 - ai-stuff/skills/k8s-debug/SKILL.md | 178 -------- ai-stuff/skills/k8s-debug/agents/openai.yaml | 3 - ai-stuff/skills/log-work/SKILL.md | 33 -- ai-stuff/skills/log-work/agents/openai.yaml | 3 - .../skills/save-property-to-vault/SKILL.md | 38 -- .../save-property-to-vault/agents/openai.yaml | 3 - ai-stuff/skills/slackify/SKILL.md | 85 ---- ai-stuff/skills/slackify/agents/openai.yaml | 3 - ai-stuff/skills/vault-capture/SKILL.md | 68 --- .../skills/vault-capture/agents/openai.yaml | 3 - .../references/vault-conventions.md | 113 ----- ai-stuff/skills/worktree-cleanup/SKILL.md | 142 ------ .../worktree-cleanup/agents/openai.yaml | 3 - 67 files changed, 351 insertions(+), 5061 deletions(-) delete mode 100644 ai-stuff/_shared/config/git-config.md delete mode 100644 ai-stuff/_shared/config/gitops-config.md delete mode 100644 ai-stuff/_shared/config/house-search-config.md delete mode 100644 ai-stuff/_shared/config/jira-config.md delete mode 100755 ai-stuff/_shared/scripts/pr-status.sh delete mode 100755 ai-stuff/_shared/scripts/worktree-cleanup-remove.sh delete mode 100755 ai-stuff/_shared/scripts/worktree-cleanup-scan.sh delete mode 100644 ai-stuff/_shared/templates/daily-recap-output.md delete mode 100644 ai-stuff/_shared/templates/neighborhood-template.md delete mode 100644 ai-stuff/_shared/templates/property-frontmatter.yaml delete mode 100644 ai-stuff/_shared/templates/property-template.md delete mode 100644 ai-stuff/invocation.md delete mode 100644 ai-stuff/skills/.archived/add-recipe/SKILL.md delete mode 100644 ai-stuff/skills/.archived/add-recipe/SKILL.original.md delete mode 100644 ai-stuff/skills/.archived/add-vinyl/SKILL.md delete mode 100644 ai-stuff/skills/.archived/add-vinyl/SKILL.original.md delete mode 100644 ai-stuff/skills/.archived/commit/SKILL.md delete mode 100644 ai-stuff/skills/.archived/commit/SKILL.original.md delete mode 100644 ai-stuff/skills/.archived/dev-story/SKILL.md delete mode 100644 ai-stuff/skills/.archived/gitboi/SKILL.md delete mode 100644 ai-stuff/skills/.archived/gitboi/SKILL.original.md delete mode 100644 ai-stuff/skills/.archived/gitops-geezer/SKILL.md delete mode 100644 ai-stuff/skills/.archived/gitops-geezer/SKILL.original.md delete mode 100644 ai-stuff/skills/.archived/jiragirl/SKILL.md delete mode 100644 ai-stuff/skills/.archived/jiragirl/agents/openai.yaml delete mode 100644 ai-stuff/skills/.archived/meeting-note/SKILL.md delete mode 100644 ai-stuff/skills/.archived/mega-dev/SKILL.md delete mode 100644 ai-stuff/skills/.archived/mega-dev/SKILL.original.md delete mode 100644 ai-stuff/skills/.archived/quick-note/SKILL.md delete mode 100644 ai-stuff/skills/.archived/quick-note/SKILL.original.md delete mode 100644 ai-stuff/skills/.archived/request-viewing/SKILL.md delete mode 100644 ai-stuff/skills/.archived/request-viewing/SKILL.original.md delete mode 100644 ai-stuff/skills/.archived/spike/SKILL.md delete mode 100644 ai-stuff/skills/.archived/spike/SKILL.original.md delete mode 100644 ai-stuff/skills/.archived/weekly-review/SKILL.md delete mode 100644 ai-stuff/skills/.archived/weekly-review/SKILL.original.md delete mode 120000 ai-stuff/skills/_shared delete mode 100644 ai-stuff/skills/address-review/SKILL.md delete mode 100644 ai-stuff/skills/address-review/agents/openai.yaml delete mode 100644 ai-stuff/skills/auto-commit/SKILL.md delete mode 100644 ai-stuff/skills/auto-commit/agents/openai.yaml delete mode 100644 ai-stuff/skills/aws-debug/SKILL.md delete mode 100644 ai-stuff/skills/aws-debug/agents/openai.yaml delete mode 100644 ai-stuff/skills/create-pr/SKILL.md delete mode 100644 ai-stuff/skills/create-pr/agents/openai.yaml delete mode 100644 ai-stuff/skills/create-story/SKILL.md delete mode 100644 ai-stuff/skills/create-story/agents/openai.yaml delete mode 100644 ai-stuff/skills/daily-recap/SKILL.md delete mode 100644 ai-stuff/skills/daily-recap/agents/openai.yaml delete mode 100644 ai-stuff/skills/daily-recap/scripts/summarize-claude-sessions.py delete mode 100644 ai-stuff/skills/get-story/SKILL.md delete mode 100644 ai-stuff/skills/get-story/agents/openai.yaml delete mode 100644 ai-stuff/skills/k8s-debug/SKILL.md delete mode 100644 ai-stuff/skills/k8s-debug/agents/openai.yaml delete mode 100644 ai-stuff/skills/log-work/SKILL.md delete mode 100644 ai-stuff/skills/log-work/agents/openai.yaml delete mode 100644 ai-stuff/skills/save-property-to-vault/SKILL.md delete mode 100644 ai-stuff/skills/save-property-to-vault/agents/openai.yaml delete mode 100644 ai-stuff/skills/slackify/SKILL.md delete mode 100644 ai-stuff/skills/slackify/agents/openai.yaml delete mode 100644 ai-stuff/skills/vault-capture/SKILL.md delete mode 100644 ai-stuff/skills/vault-capture/agents/openai.yaml delete mode 100644 ai-stuff/skills/vault-capture/references/vault-conventions.md delete mode 100644 ai-stuff/skills/worktree-cleanup/SKILL.md delete mode 100644 ai-stuff/skills/worktree-cleanup/agents/openai.yaml diff --git a/ai-stuff/_shared/config/git-config.md b/ai-stuff/_shared/config/git-config.md deleted file mode 100644 index 70669620..00000000 --- a/ai-stuff/_shared/config/git-config.md +++ /dev/null @@ -1,150 +0,0 @@ -# Git Configuration Constants - -## Conventional Commit Types (lowercase only!) - -| Type | Usage | -|------|-------| -| `feat` | New feature | -| `fix` | Bug fix | -| `docs` | Documentation | -| `style` | Code style (formatting, semicolons) | -| `refactor` | Code refactoring | -| `perf` | Performance improvements | -| `test` | Adding/updating tests | -| `build` | Build system changes | -| `ci` | CI/CD changes | -| `chore` | Maintenance tasks | - -## Commit Message Rules - -### CRITICAL - ALL LOWERCASE -- **Title AND body must be 100% lowercase** - no capital letters anywhere, ever -- Even at the start of sentences - lowercase everything -- If you capitalize ANYTHING, you have FAILED - -### Format -``` -(): - - -``` - -### Rules -- Title under 60 characters -- Present tense ("add" not "added") -- No period at end of title -- Be specific, not vague -- **FORBIDDEN**: No AI attribution, no "Co-Authored-By", no emojis, no "Generated by" - -### Examples - -```bash -# Simple feature -git commit -m "feat(auth): add oauth2 token refresh logic - -- implement automatic token refresh before expiry -- add retry mechanism for failed refresh attempts -- store refresh timestamps in session storage" - -# Documentation -git commit -m "docs: update installation instructions for arm64 macs - -- added brew install steps for llvm -- included architecture verification commands -- updated path configuration for vscode" - -# Bug fix -git commit -m "fix(api): resolve race condition in webhook handler - -- add mutex lock around event processing -- ensure idempotency with deduplication check -- fixes issue where duplicate events were processed" -``` - -## VCS Detection - -| File Present | VCS | Tool | -|--------------|-----|------| -| `.gitlab-ci.yml` | GitLab | `glab mr create` | -| Otherwise | GitHub | `gh pr create` | - -## PR/MR Creation - -**IMPORTANT**: PR/MR messages use **normal sentence casing** (NOT lowercase like commits). -- Capitalize first letters of sentences -- Use proper capitalization for titles, headings, proper nouns -- Write like a human would write documentation - -### Get Base Branch -```bash -git symbolic-ref refs/remotes/origin/HEAD | sed 's@^refs/remotes/origin/@@' -``` - -### GitHub PR -```bash -gh pr create \ - --head $(git branch --show-current) \ - --base $(git symbolic-ref refs/remotes/origin/HEAD | sed 's@^refs/remotes/origin/@@') \ - --title "type(scope): description" \ - --body "## Summary -... - -## Changes -- Change 1 -- Change 2 - -## Additional Notes -..." -``` - -### GitLab MR (fucking hate it) -```bash -glab mr create \ - --push \ - --target-branch $(git symbolic-ref refs/remotes/origin/HEAD | sed 's@^refs/remotes/origin/@@') \ - --title "type(scope): description" \ - --description "## Summary -... - -## Changes -- Change 1 -- Change 2 - -## Additional Notes -..." -``` - -### PR Body Structure - -```markdown -## Summary -<1-3 sentences describing the change> - -## Changes -- Bulleted list of changes -- Use `backticks` for code/paths/labels - -## Additional Notes - -``` - -### Rules -- DO NOT escape backticks - Claude CLI handles this -- Mandatory sections: Summary, Changes, Additional Notes -- After creation, provide URL: `[PR Title](URL)` -- **FORBIDDEN**: No AI attribution anywhere -- Extract ticket from branch name if present (e.g., DEVX-123) - -## Backdating Commits - -For hiding those 2am sessions: - -```bash -GIT_AUTHOR_DATE="YYYY-MM-DD HH:MM:SS" \ -GIT_COMMITTER_DATE="YYYY-MM-DD HH:MM:SS" \ -git commit -m "message" -``` - -- For random business hours: pick realistic time between 09:15-16:45 -- Avoid exactly 9:00 or 17:00 (too suspicious) -- Both dates must be set diff --git a/ai-stuff/_shared/config/gitops-config.md b/ai-stuff/_shared/config/gitops-config.md deleted file mode 100644 index aaff9648..00000000 --- a/ai-stuff/_shared/config/gitops-config.md +++ /dev/null @@ -1,340 +0,0 @@ -# GitOps Configuration - The Bible - -Based on: https://codefresh.io/blog/how-to-structure-your-argo-cd-repositories-using-application-sets/ -Example repo: https://github.com/kostis-codefresh/many-appsets-demo - -## The Four Categories of Manifests - -| Category | Description | Type | Change Frequency | Target Users | -|----------|-------------|------|-----------------|--------------| -| 1 | Developer Kubernetes manifests | Helm, Kustomize or plain manifests in Git | Very often | Developers mostly | -| 2 | Developer Argo CD manifests | Argo CD app and Application Set | Almost never | Operators/Developers | -| 3 | Infrastructure Kubernetes manifests | Usually external Helm charts | Sometimes | Operators | -| 4 | Infrastructure Argo CD manifests | Argo CD app and Application Set | Almost never | Operators | - -**Critical insight**: Each category has a different lifecycle. Never mix them. - -### Category 1 - Developer K8s Manifests -- Standard Kubernetes resources (Deployment, Service, Ingress, ConfigMap, Secret) -- Can be deployed WITHOUT Argo CD on any local cluster -- Changes: updating image version (~80%), image + config (~15%), config only (~5%) -- Managed by: Helm, Kustomize, or plain YAML - -### Category 2 - Argo CD Manifests -- Application CRDs and ApplicationSets -- Links a Git repo (cat 1) to a destination cluster -- Change frequency: set up once, then ALMOST NEVER change -- Anti-pattern alert: if these change constantly, something is wrong - -## The Three-Level Structure (THE Standard) - -``` -Level 3: App-of-Apps (optional bootstrap) - └── Level 2: ApplicationSets (per environment/team) - └── Level 1: Kubernetes Manifests (Helm/Kustomize overlays) -``` - -### Repository Layout - -``` -repo/ -├── apps/ # Level 1 - K8s manifests -│ ├── billing/ -│ │ └── envs/ -│ │ └── prod/ # Only prod (not in QA) -│ ├── invoices/ -│ │ └── envs/ -│ │ ├── qa/ -│ │ └── prod/ -│ └── orders/ -│ └── envs/ -│ ├── qa/ -│ └── prod/ -├── appsets/ # Level 2 - ApplicationSets -│ ├── qa-appset.yaml -│ ├── prod-appset.yaml -│ └── staging-appset.yaml -└── app-of-apps.yaml # Level 3 - optional bootstrap -``` - -### Key Properties -- Only 3 levels of abstraction (4-5 = complexity disaster) -- Each level is completely independent -- Helm/Kustomize used ONCE at level 1, nowhere else -- Adding a new app = add folder under apps/ -- Adding a new cluster = connect to ArgoCD, appsets auto-discover -- Adding a new environment = copy/modify an appset file - -## ApplicationSet Examples - -### Git Generator (Environment-based) - -```yaml -apiVersion: argoproj.io/v1alpha1 -kind: ApplicationSet -metadata: - name: my-qa-appset - namespace: argocd -spec: - goTemplate: true - goTemplateOptions: ["missingkey=error"] - generators: - - git: - repoURL: https://github.com/org/gitops-repo.git - revision: HEAD - directories: - - path: apps/*/envs/qa # Finds all apps with qa overlay - template: - metadata: - name: '{{index .path.segments 1}}-{{index .path.segments 3}}' - spec: - project: default - source: - repoURL: https://github.com/org/gitops-repo.git - targetRevision: HEAD - path: '{{.path.path}}' - destination: - server: https://kubernetes.default.svc - namespace: '{{index .path.segments 1}}-{{index .path.segments 3}}' -``` - -### Matrix Generator (Apps × Clusters) - -```yaml -apiVersion: argoproj.io/v1alpha1 -kind: ApplicationSet -metadata: - name: cluster-git -spec: - generators: - - matrix: - generators: - - git: # Child 1: discover apps from git - repoURL: https://github.com/org/gitops-repo.git - revision: HEAD - directories: - - path: apps/* - - clusters: {} # Child 2: all registered clusters - template: - metadata: - name: '{{path.basename}}-{{name}}' - spec: - project: default - source: - repoURL: https://github.com/org/gitops-repo.git - targetRevision: HEAD - path: '{{path}}' - destination: - server: '{{server}}' - namespace: '{{path.basename}}' -``` - -### Cluster Generator (Cross-cluster deployment) - -```yaml -apiVersion: argoproj.io/v1alpha1 -kind: ApplicationSet -metadata: - name: prod-appset -spec: - generators: - - clusters: - selector: - matchLabels: - environment: production # Only prod clusters - template: - metadata: - name: '{{name}}-myapp' - spec: - destination: - server: '{{server}}' - namespace: myapp -``` - -## The Four Anti-Patterns - -### Anti-Pattern 1 - Mixing Manifest Types - -**Wrong**: Putting Helm values or Kustomize overrides inside the Application CRD - -```yaml -# NEVER DO THIS -spec: - source: - helm: - parameters: # Category 1 bleeding into Category 2 - - name: "image.tag" - value: "1.2.3" - values: | - ingress: - enabled: true -``` - -**Right**: Values belong in valueFiles in the same repo as the chart - -```yaml -# DO THIS -spec: - source: - helm: - valueFiles: - - values-production.yaml # Separate file in git -``` - -**Litmus test**: Can a developer deploy locally with ONLY kustomize or helm, without any knowledge of ArgoCD? If NO → you're mixing manifests. - -### Anti-Pattern 2 - Wrong Abstraction Level - -**Wrong**: CI pipeline changing `targetRevision` or `path` in Application CRDs - -```yaml -# NEVER DO THIS -spec: - source: - targetRevision: dev # This was main, then staging, now dev?! - path: my-qa-app # This changes constantly -``` - -**Right**: Change the actual Kubernetes manifest (image tag in Deployment), not the ArgoCD Application CRD. The Application CRD should be set once and forgotten. - -### Anti-Pattern 3 - Multiple Templating Levels - -**Wrong**: Helm chart that contains Application CRDs which point to other Helm charts → double templating -- Creates impossible-to-debug nested template resolution -- Makes onboarding new engineers a nightmare -- Completely unnecessary with ApplicationSets - -**Right**: Use ApplicationSets for templating at the ArgoCD layer. Use Helm/Kustomize for the K8s layer. One templating system per level. - -### Anti-Pattern 4 - Not Using ApplicationSets - -**Wrong**: Manually creating individual Application CRDs for each app/cluster combination -- 20 apps × 5 clusters = 100 files to manage manually -- Every new cluster = manual update to dozens of files - -**Right**: ONE ApplicationSet with matrix generator → auto-generates all 100 combinations, automatically picks up new clusters and new apps. - -## Repository Strategy - -### Multi-Repo (Recommended) -- One repo per team (or related set of microservices) -- One repo for infrastructure apps (cert-manager, nginx, prometheus) -- Additional "common" repo if apps are shared across teams - -``` -org/ -├── team-payments-gitops/ # Payments team manifests -├── team-orders-gitops/ # Orders team manifests -├── team-billing-gitops/ # Billing team manifests -└── infra-gitops/ # cert-manager, nginx, prometheus, etc. -``` - -### Why NOT Monorepo for GitOps -- Performance: ArgoCD polls all repos; one giant repo = slow detection -- Git conflicts: all CI pipelines competing on the same repo -- Security: fine-grained access control becomes impossible -- Developer focus: devs only need their team's repo - -### Monorepo Definition Clarification -- Source code monorepo (Google style) → NOT relevant to ArgoCD -- Same repo for source code + K8s manifests → separate these -- Single Git repo for ALL ArgoCD apps → this is the one to avoid at scale - -## Cross-Cluster / Cross-Account Patterns - -### Cluster Registration - -```bash -# Register a cluster with ArgoCD -argocd cluster add --name production-eu - -# Add labels for cluster selection -kubectl label secret -n argocd \ - environment=production \ - region=eu \ - team=payments -``` - -### Cluster Labels for ApplicationSet Targeting - -```yaml -# Target only EU production clusters -generators: -- clusters: - selector: - matchLabels: - environment: production - region: eu -``` - -### Cross-Account Pattern -- ArgoCD control plane in management/hub account -- Spoke clusters in workload accounts -- ArgoCD service account with minimal RBAC in each spoke -- Secret stored in ArgoCD namespace with cluster credentials - -### Hub-and-Spoke AppSet Pattern - -```yaml -# Deploy different apps to different cluster tiers -generators: -- list: - elements: - - cluster: cluster-dev - url: https://dev.example.com - environment: dev - - cluster: cluster-staging - url: https://staging.example.com - environment: staging - - cluster: cluster-prod-eu - url: https://prod-eu.example.com - environment: prod - - cluster: cluster-prod-us - url: https://prod-us.example.com - environment: prod -``` - -## Day-2 Operations Quick Reference - -| Task | Action | ArgoCD Change? | -|------|---------|----------------| -| Deploy app to new env | Add Kustomize overlay | No | -| Remove app from env | Delete Kustomize overlay | No | -| Create brand new app | Add folder under apps/ | No | -| Create new environment | Copy/modify an appset file | Yes (one file) | -| Add new cluster | Connect cluster to ArgoCD | No (auto-discovered) | -| Move cluster to diff env | Edit cluster label | No | -| Upgrade infra component | Update Helm chart version | No | - -## Validation Commands - -```bash -# Validate kustomize overlay (no ArgoCD needed) -kustomize build apps/invoices/envs/qa - -# Compare environments -kustomize build apps/billing/envs/prod-eu > /tmp/eu.yaml -kustomize build apps/billing/envs/prod-us > /tmp/us.yaml -diff /tmp/eu.yaml /tmp/us.yaml - -# Install locally (no ArgoCD) -kubectl apply -k apps/orders/envs/qa - -# Check ArgoCD application health -argocd app list -argocd app get -argocd app sync -``` - -## ApplicationSet Generator Reference - -| Generator | Use Case | -|-----------|----------| -| `git` | Discover apps from directory structure | -| `clusters` | Target registered ArgoCD clusters | -| `matrix` | Combine two generators (apps × clusters) | -| `list` | Explicit list of parameters | -| `merge` | Merge multiple generators with override | -| `scm-provider` | Discover repos in GitHub org/GitLab group | -| `pull-request` | PR preview environments | -| `cluster-decision-resource` | Integration with cluster fleet management | diff --git a/ai-stuff/_shared/config/house-search-config.md b/ai-stuff/_shared/config/house-search-config.md deleted file mode 100644 index cff42dc8..00000000 --- a/ai-stuff/_shared/config/house-search-config.md +++ /dev/null @@ -1,72 +0,0 @@ -# House Search Configuration - -## Private Data - -Sensitive financial and contact information is in the private config: - -@~/.claude/config/\_house-search-private.md - -## Vault Paths - -The Obsidian vault is symlinked at `~/vault/`. All paths below are absolute. - -| Path | Purpose | -| ----------------- | ---------------------------------------------------------------- | -| **Base** | `~/vault/personal/nl/house search/buying a house/` | -| **Properties** | `~/vault/personal/nl/house search/buying a house/properties/` | -| **Neighborhoods** | `~/vault/personal/nl/house search/buying a house/neighborhoods/` | -| **MoC** | `~/vault/personal/nl/house search/buying a house/moc.md` | - -## Templates - -Templates for Obsidian notes are in the `templates/` directory: - -- `templates/property-frontmatter.yaml` — Frontmatter schema for property notes -- `templates/property-template.md` — Body structure for property notes -- `templates/neighborhood-template.md` — Structure for neighborhood notes - -## Tier System - -| Tier | Frontmatter Value | Meaning | -| ---------- | ----------------- | ---------------------------------------------- | -| Strong Buy | `strong-buy` | Seriously pursue — request viewing immediately | -| Buy | `buy` | Good option worth considering | -| Watch | `watch` | Interesting but not urgent | -| Skip | `skip` | Analyzed and rejected | - -## Buying Costs to Factor In - -- Notary: €2,500 -- Valuation: €800 -- Technical inspection: €500 (skip if new build) -- Mortgage advice: €3,500 -- Estate agent: €5,000 -- Transfer tax: 2% on full amount (waived if under €555k) — NOT a dealbreaker, never reject a property over this; factor into total cost and move on -- Total estimated costs: €12,300–€25,000 - -## Market Intelligence from Mortgage Advisor & Agent - -- Funda listings are intentionally priced low to generate competition; overbidding is standard -- My agent works with 14 partner agents — they may have intel on seller expectations -- Best months to buy: July, August, December, January (less competition) -- After winning bid: 4-5 week financial clause period → precontract → mortgage approval → final contract -- Erfpacht reduces mortgage capacity by x20 of the annual canon — this is a dealbreaker at high canons -- Interest is tax deductible (gross €1,975/mo → net ~€1,535/mo at current rates) - -## Preferred Locations - -| Tier | Areas | -| ----- | ----------------------------------------------------------------------------------------------------- | -| Top | De Pijp, Oud-Zuid, Overtoom area, Vondelpark surroundings, Spaarndammerbuurt, Westerpark, West | -| Great | Houthavens, KNSM-eiland, Westerdok | -| Good | Super Bos En Lommer streets with Moroccan vibes, other non-touristy ring neighborhoods with character | -| Avoid | Deep tourist zones (Centrum/Red Light), isolated industrial edges, | - -## Property Requirements - -- Energy label: C or better -- Size: >63m² (ideally >70m²) -- Not ground floor -- Bike Storage(Berging, or inside parking for bike) -- Near public transport and daily shopping -- Bonuses: balcony, south-facing, individual heating control, bathtub diff --git a/ai-stuff/_shared/config/jira-config.md b/ai-stuff/_shared/config/jira-config.md deleted file mode 100644 index 44e65379..00000000 --- a/ai-stuff/_shared/config/jira-config.md +++ /dev/null @@ -1,137 +0,0 @@ -# Jira Configuration Constants - -## Hardcoded Values - NEVER waste tokens looking these up! - -| Constant | Value | -|----------|-------| -| **cloudId** | `56552dac-b6cf-4e59-aa06-5e075dca9f8e` | -| **defaultProject** | `DEVX` | -| **atlassianUrl** | `https://wahanda.atlassian.net` | -| **currentUserAccountId** | `712020:e51cbeb5-c2ba-4aea-9f63-01e3c2ade7d4` | - -## DEVX Issue Type IDs - No need to fetch! - -| Type | ID | -|------|-----| -| Story | `7` | -| Task | `3` | -| Bug | `1` | -| Sub-task | `5` | -| Epic | `6` | -| Spike | `11502` | -| Support | `11719` | - -## Required Custom Fields for DEVX - -| Field ID | Name | Required | Format | -|----------|------|----------|--------| -| `customfield_14105` | Reason for the change | **YES** | ADF paragraph | -| `customfield_10020` | Acceptance Criteria and NFR | No | ADF taskList (checkboxes!) | -| `customfield_12700` | Team | No | - | -| `customfield_14453` | Scheduled Date | No | - | -| `customfield_14031` | Resources Required | No | - | - -## Critical Rules - -- **NEVER** call `getAccessibleAtlassianResources` - use hardcoded cloudId -- **NEVER** call `atlassianUserInfo` - use hardcoded accountId -- **NEVER** call `listJiraProjects` unless user explicitly mentions a non-DEVX project -- **NEVER** call `listJiraProjectIssueTypesMetadata` - use hardcoded issue type IDs -- **DEFAULT** to DEVX project unless user explicitly mentions another project prefix - -## Format Rules - -| Field | Format | -|-------|--------| -| `description` | **MARKDOWN** - `## headings`, `- bullets`, ``` code ``` | -| `customfield_14105` | **ADF** paragraph - REQUIRED! | -| `customfield_10020` | **ADF** taskList - renders as checkboxes! | - -**CRITICAL**: -- NEVER put acceptance criteria in description - use `customfield_10020`! -- NEVER use markdown checkboxes (`- [ ]`) in description - they don't render! -- Each taskItem needs a unique localId (use UUID format) - -## ADF Templates - -### Simple Paragraph (for `customfield_14105` - Reason for change) -```json -{ - "version": 1, - "type": "doc", - "content": [ - { - "type": "paragraph", - "content": [{"type": "text", "text": "YOUR REASON HERE"}] - } - ] -} -``` - -### Task List with Checkboxes (for `customfield_10020` - Acceptance Criteria) -```json -{ - "version": 1, - "type": "doc", - "content": [ - { - "type": "taskList", - "attrs": {"localId": "generate-unique-uuid-here"}, - "content": [ - { - "type": "taskItem", - "attrs": {"localId": "ac-1-uuid", "state": "TODO"}, - "content": [{"type": "text", "text": "First acceptance criterion"}] - }, - { - "type": "taskItem", - "attrs": {"localId": "ac-2-uuid", "state": "TODO"}, - "content": [{"type": "text", "text": "Second acceptance criterion"}] - } - ] - } - ] -} -``` - -### Bullet List (for general lists, NOT acceptance criteria) -```json -{ - "version": 1, - "type": "doc", - "content": [ - { - "type": "bulletList", - "content": [ - { - "type": "listItem", - "content": [ - {"type": "paragraph", "content": [{"type": "text", "text": "Item 1"}]} - ] - } - ] - } - ] -} -``` - -## Description Template (MARKDOWN) - -```markdown -## Problem -[What issue or need exists - be specific] - -## Current State -[How things work now - include relevant details] - -## Proposed Solution -[What changes are needed - be actionable] - -## Implementation Details -[Technical specifics if applicable] - -## References -- Related links/docs -``` - -**NOTE**: Do NOT put acceptance criteria in the description! Use `customfield_10020` with ADF taskList format instead! diff --git a/ai-stuff/_shared/scripts/pr-status.sh b/ai-stuff/_shared/scripts/pr-status.sh deleted file mode 100755 index f5d41991..00000000 --- a/ai-stuff/_shared/scripts/pr-status.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash -# Check PR/MR status for create-pr skill -# Detects VCS from remote URL and outputs current PR/MR state - -remote=$(git remote -v 2>/dev/null | head -1) - -if echo "$remote" | grep -q 'git.treatwell.net'; then - glab mr view -F json 2>/dev/null && echo "MODE: UPDATE (MR exists)" || echo "MODE: CREATE (no existing MR)" -else - gh pr view --json number,title,state,url 2>/dev/null && echo "MODE: UPDATE (PR exists)" || echo "MODE: CREATE (no existing PR)" -fi diff --git a/ai-stuff/_shared/scripts/worktree-cleanup-remove.sh b/ai-stuff/_shared/scripts/worktree-cleanup-remove.sh deleted file mode 100755 index 753bb2fb..00000000 --- a/ai-stuff/_shared/scripts/worktree-cleanup-remove.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash -# Remove a single git worktree and its local branch. -# -# Usage: worktree-cleanup-remove.sh [branch] -# repo = main worktree / repo root that owns the worktree -# worktree = absolute path of the worktree to remove -# branch = local branch to delete (optional; skipped for main/master) -# -# Uses --force so dirty/locked worktrees are still removed — the SKILL is -# responsible for warning the user about uncommitted work BEFORE calling this. -set -uo pipefail - -REPO="${1:?repo required}" -WT="${2:?worktree path required}" -BRANCH="${3:-}" - -git -C "$REPO" worktree remove --force "$WT" 2>/dev/null || rm -rf "$WT" -git -C "$REPO" worktree prune 2>/dev/null || true - -if [ -n "$BRANCH" ] && [ "$BRANCH" != "main" ] && [ "$BRANCH" != "master" ]; then - git -C "$REPO" branch -D "$BRANCH" 2>/dev/null || true -fi - -echo "removed: $WT (branch: ${BRANCH:-none})" diff --git a/ai-stuff/_shared/scripts/worktree-cleanup-scan.sh b/ai-stuff/_shared/scripts/worktree-cleanup-scan.sh deleted file mode 100755 index 84e1d88a..00000000 --- a/ai-stuff/_shared/scripts/worktree-cleanup-scan.sh +++ /dev/null @@ -1,176 +0,0 @@ -#!/usr/bin/env bash -# Scan git worktrees and classify each as merged / unmerged / unknown. -# -# Usage: worktree-cleanup-scan.sh [path] -# path = a single git repo (default: $PWD), OR a directory containing -# multiple repos (e.g. ~/codes/work). Immediate child dirs that -# are git repos are each scanned. -# -# Output: a JSON array on stdout, one object per non-main worktree: -# { repo, repo_name, worktree, branch, status, reason, dirty, ahead, warnings[] } -# -# Merge detection is layered because PRs/MRs are usually SQUASH-merged, which -# means the branch's individual commits never land in main verbatim: -# 1. local: branch is an ancestor of origin/ -> merged (regular merge) -# 2. cherry: every commit has an equivalent in -> merged (rebase/cherry-pick) -# 3. remote-gone: branch had an upstream that no longer -# exists on origin (forges auto-delete on merge) -> merged (squash, most common) -# 4. forge: gh/glab reports a merged PR/MR for the branch -> merged (confirmation) -# Anything else -> unmerged. Detached/odd states -> unknown. -set -uo pipefail - -TARGET="${1:-$PWD}" -TARGET="${TARGET/#\~/$HOME}" - -FETCH="${WORKTREE_CLEANUP_FETCH:-1}" # set 0 to skip network fetch (faster, less accurate) -FORGE="${WORKTREE_CLEANUP_FORGE:-1}" # set 0 to skip gh/glab queries - -is_git_repo() { git -C "$1" rev-parse --git-dir >/dev/null 2>&1; } - -# Resolve the MAIN worktree path for a repo (first entry of worktree list). -main_worktree() { - git -C "$1" worktree list --porcelain 2>/dev/null | awk '/^worktree /{print $2; exit}' -} - -# Build the list of repos (main worktrees) to scan, de-duplicated. -declare -a REPOS=() -add_repo() { - local r="$1" x - for x in "${REPOS[@]:-}"; do [ "$x" = "$r" ] && return; done - REPOS+=("$r") -} - -if is_git_repo "$TARGET"; then - add_repo "$(main_worktree "$TARGET")" -else - while IFS= read -r d; do - is_git_repo "$d" && add_repo "$(main_worktree "$d")" - done < <(find "$TARGET" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | sort) -fi - -if [ "${#REPOS[@]}" -eq 0 ]; then - echo "[]" - exit 0 -fi - -default_branch() { - local r="$1" d - d=$(git -C "$r" symbolic-ref --quiet refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@') - if [ -z "$d" ]; then - if git -C "$r" show-ref --verify --quiet refs/remotes/origin/main; then d=main - elif git -C "$r" show-ref --verify --quiet refs/remotes/origin/master; then d=master - elif git -C "$r" show-ref --verify --quiet refs/heads/main; then d=main - elif git -C "$r" show-ref --verify --quiet refs/heads/master; then d=master - else d=$(git -C "$r" rev-parse --abbrev-ref HEAD 2>/dev/null); fi - fi - echo "$d" -} - -# Pick forge CLI based on origin URL. Echoes "gh", "glab", or "". -forge_cli() { - local url; url=$(git -C "$1" remote get-url origin 2>/dev/null) - case "$url" in - *gitlab*|*git.treatwell.net*) command -v glab >/dev/null 2>&1 && echo glab ;; - *github*) command -v gh >/dev/null 2>&1 && echo gh ;; - *) command -v gh >/dev/null 2>&1 && echo gh ;; - esac -} - -# Returns 0 if forge reports a merged PR/MR for the branch. -forge_merged() { - local repo="$1" branch="$2" cli="$3" - case "$cli" in - gh) - timeout 12 gh pr list --repo "$(git -C "$repo" remote get-url origin)" \ - --head "$branch" --state merged --json number -L 1 2>/dev/null \ - | grep -q '"number"' - ;; - glab) - timeout 12 glab mr list --source-branch "$branch" --merged 2>/dev/null \ - | grep -qE '![0-9]+' - ;; - *) return 1 ;; - esac -} - -OBJS=() - -for repo in "${REPOS[@]}"; do - [ -z "$repo" ] && continue - repo_name=$(basename "$repo") - - [ "$FETCH" = "1" ] && timeout 20 git -C "$repo" fetch --prune origin >/dev/null 2>&1 || true - - DEF=$(default_branch "$repo") - CLI="" - [ "$FORGE" = "1" ] && CLI=$(forge_cli "$repo") - - # Walk worktrees. First entry is the main worktree -> skip it. - cur_wt=""; cur_branch=""; cur_detached=0; first=1 - flush() { - [ -z "$cur_wt" ] && return - if [ "$first" = "1" ]; then first=0; cur_wt=""; return; fi # main worktree - local wt="$cur_wt" branch="$cur_branch" - cur_wt="" - - # Skip worktrees parked on the default branch. - if [ "$branch" = "$DEF" ]; then return; fi - - local status="unmerged" reason="" warnings=() dirty="false" ahead=0 - - if [ "$cur_detached" = "1" ] || [ -z "$branch" ]; then - status="unknown"; reason="detached HEAD"; warnings+=("detached — no branch to evaluate") - else - # Dirty working tree? - if [ -n "$(git -C "$wt" status --porcelain 2>/dev/null)" ]; then - dirty="true"; warnings+=("uncommitted changes") - fi - # Unpushed commits relative to default. - ahead=$(git -C "$repo" rev-list --count "origin/$DEF..$branch" 2>/dev/null || echo 0) - - # 1. ancestor of origin/ (regular merge) - if git -C "$repo" merge-base --is-ancestor "$branch" "origin/$DEF" 2>/dev/null; then - status="merged"; reason="ancestor of origin/$DEF" - # 2. every commit equivalent already in (rebase / cherry-pick) - elif [ -n "$(git -C "$repo" cherry "origin/$DEF" "$branch" 2>/dev/null)" ] \ - && ! git -C "$repo" cherry "origin/$DEF" "$branch" 2>/dev/null | grep -q '^+'; then - status="merged"; reason="all commits present in $DEF (rebased)" - # 3. had an upstream that is now gone on origin (squash-merge + auto-delete) - elif [ -n "$(git -C "$repo" config "branch.$branch.merge" 2>/dev/null)" ] \ - && ! git -C "$repo" show-ref --verify --quiet "refs/remotes/origin/$branch"; then - status="merged"; reason="remote branch deleted (squash-merged)" - fi - - # 4. forge confirmation (also rescues abandoned-but-deleted false positives) - if [ -n "$CLI" ]; then - if forge_merged "$repo" "$branch" "$CLI"; then - status="merged"; reason="${reason:+$reason; }$CLI: merged PR/MR" - elif [ "$reason" = "remote branch deleted (squash-merged)" ]; then - # remote gone but forge shows no merged PR -> likely abandoned, not merged - status="unmerged"; reason="remote branch deleted but no merged PR/MR ($CLI)" - warnings+=("branch gone from origin with no merged PR — verify before deleting") - fi - fi - - [ "$status" = "unmerged" ] && [ -z "$reason" ] && reason="not merged into $DEF" - fi - - local warn_json; warn_json=$(printf '%s\n' "${warnings[@]:-}" | grep -v '^$' | jq -R . | jq -s .) - OBJS+=("$(jq -n \ - --arg repo "$repo" --arg repo_name "$repo_name" --arg wt "$wt" \ - --arg branch "$branch" --arg status "$status" --arg reason "$reason" \ - --argjson dirty "$dirty" --argjson ahead "${ahead:-0}" --argjson warnings "$warn_json" \ - '{repo:$repo, repo_name:$repo_name, worktree:$wt, branch:$branch, status:$status, reason:$reason, dirty:$dirty, ahead:$ahead, warnings:$warnings}')") - } - - while IFS= read -r line; do - case "$line" in - "worktree "*) flush; cur_wt="${line#worktree }"; cur_branch=""; cur_detached=0 ;; - "branch "*) cur_branch=$(echo "${line#branch }" | sed 's@^refs/heads/@@') ;; - "detached") cur_detached=1 ;; - esac - done < <(git -C "$repo" worktree list --porcelain 2>/dev/null) - flush -done - -if [ "${#OBJS[@]}" -eq 0 ]; then echo "[]"; else printf '%s\n' "${OBJS[@]}" | jq -s '.'; fi diff --git a/ai-stuff/_shared/templates/daily-recap-output.md b/ai-stuff/_shared/templates/daily-recap-output.md deleted file mode 100644 index bd9bb7c6..00000000 --- a/ai-stuff/_shared/templates/daily-recap-output.md +++ /dev/null @@ -1,167 +0,0 @@ -# Daily Recap — Output Template - -This template defines the **exact structure** to append to a daily note after gathering data from Slack, Gmail, Calendar, and Dia. - -The daily note already exists and has `## today` and `## notes for tomorrow` sections. You are inserting content into those sections and adding a new `## recap` section at the bottom. - ---- - -## Section 1: `## today` — What you did - -Insert completed task lines into the existing `## today` section (append after any existing content, never overwrite). - -### Format (every line must match exactly) - -``` -- [x] concise description of what you did ✅ YYYY-MM-DD -``` - -- `- [x]` — checked Obsidian task -- `✅ YYYY-MM-DD` — the completion date (Obsidian Tasks format so dataview picks it up) -- One line per logical unit of work (group multiple Slack messages on the same topic into one line) - -### What qualifies as a "today" task - -- Merged MRs, completed reviews -- Support given (helped someone with something) -- Meaningful discussions or decisions -- Anything you actively did or contributed to -- Dia "Completed" items that aren't already covered by Slack/Gmail data - -### Voice and style - -Write like a human — casual, concise, lowercase-ish. NOT a formal report. - -### Examples (copy the tone) - -``` -- [x] paired a little with mauri in the morning for looking into the drone - gh actions migration ✅ 2026-03-20 -- [x] increased the failure threshold for sft namespace, it is better now but still a little fucked? ✅ 2026-03-20 -- [x] reviewed rosarios mr about adding rum totally the wrong way :D ✅ 2026-03-20 -- [x] helped [[ben minter]] debug the flaky pipeline on devx/k8s-gitops ✅ 2026-03-20 -- [x] merged [!31](https://git.treatwell.net/devx/k8s-gitops/-/merge_requests/31) — terragrunt module cleanup ✅ 2026-03-20 -``` - -### Formatting rules - -- **Wikilinks for people**: `[[person name]]` (check `work/people/` for existing notes) -- **GitLab MR links**: always a markdown link with the full URL — `[!31](https://git.treatwell.net//-/merge_requests/31)`. GitLab base URL is `https://git.treatwell.net`. Never write bare `!31`. -- **No emojis** unless the user asked for them -- **No invented data** — only include what was actually found in Slack/Gmail/Calendar/Dia - ---- - -## Section 2: `## notes for tomorrow` — Forward-looking - -Insert into the existing `## notes for tomorrow` section. - -This section has two parts: tomorrow's calendar and a standup draft. - -### Part A: Tomorrow's calendar - -Only include if there are notable events. Skip filler (lunch, focus time blocks). - -```markdown -### tomorrow's calendar -- 09:30 — Sprint planning -- 11:00 — 1:1 with [[manager name]] -- 14:00 — Tech design review -``` - -### Part B: Standup draft - -3-5 concise first-person bullet points, ready to paste into Slack. Cover what you did today + what's planned next. Wrap in a blockquote so it's visually distinct. - -```markdown -### standup -> - reviewed the k8s-gitops terragrunt cleanup mr and merged it -> - helped ben with the flaky pipeline issue -> - bumped failure threshold for sft namespace -> - today: sprint planning, then picking up DEVX-1234 -``` - ---- - -## Section 3: `## recap` — Needs attention - -This is a **new section** appended at the very bottom of the daily note, after `## notes for tomorrow`. It captures things that came *to* you that you haven't acted on yet. - -### What goes here - -- New tickets assigned to you -- Stale reviews waiting on you -- Review feedback on your MRs -- Alerts or incidents flagged -- Unanswered questions directed at you -- Anything incoming that needs action - -### Format - -```markdown - -## recap - -### needs attention -- **DEVX-1234 assigned** — new ticket about flaky drone builds `#new-ticket` -- **MR feedback on !42** — rosario left comments on your terragrunt MR `#review-feedback` -- **Pipeline alert** — staging deploy failed for sft namespace `#alert` -- **Question from [[ben minter]]** — asked about the k8s node pool sizing `#question` -``` - -### Available tags - -| Tag | Use when | -|-----|----------| -| `#new-ticket` | A Jira ticket was newly assigned to you | -| `#review-feedback` | Someone left comments on your MR | -| `#review-stale` | A review request has been waiting on you | -| `#alert` | An alert or incident was flagged | -| `#question` | Someone asked you a question you haven't answered | -| `#blocked` | Something is blocked on you or you're blocked on something | - -### Rules for recap - -- Each item: `- **Bold title** — brief context \`TAG\`` -- Only include genuinely actionable items, not FYI noise -- If nothing needs attention, omit the entire `## recap` section - ---- - -## Full output example - -Here's what a complete daily recap insertion looks like across all three sections: - -### Inserted into `## today`: - -``` -- [x] paired with [[mauri]] on the drone to gh actions migration ✅ 2026-03-20 -- [x] increased failure threshold for sft namespace ✅ 2026-03-20 -- [x] reviewed rosarios mr [!78](https://git.treatwell.net/devx/infra/-/merge_requests/78) about adding rum ✅ 2026-03-20 -- [x] helped [[ben minter]] debug the flaky staging pipeline ✅ 2026-03-20 -``` - -### Inserted into `## notes for tomorrow`: - -``` -### tomorrow's calendar -- 09:30 — Sprint planning -- 14:00 — Tech design review with platform team - -### standup -> - reviewed and merged the rum instrumentation mr -> - helped ben with staging pipeline flakiness -> - bumped sft failure threshold, seems better now -> - today: sprint planning, then continuing drone migration -``` - -### Appended at the bottom as new section: - -``` - -## recap - -### needs attention -- **DEVX-1234 assigned** — flaky drone builds investigation `#new-ticket` -- **MR feedback on [!42](https://git.treatwell.net/devx/k8s-gitops/-/merge_requests/42)** — 2 unresolved comments from rosario `#review-feedback` -- **Question from [[ana]]** — asked about the new namespace quota policy `#question` -``` diff --git a/ai-stuff/_shared/templates/neighborhood-template.md b/ai-stuff/_shared/templates/neighborhood-template.md deleted file mode 100644 index 7d906fd0..00000000 --- a/ai-stuff/_shared/templates/neighborhood-template.md +++ /dev/null @@ -1,36 +0,0 @@ -# Neighborhood Note Template - -Use this structure for neighborhood notes. - ---- - -## Frontmatter - -```yaml ---- -tags: - - house-search - - neighborhood -tier: "" ---- -``` - -## Body Structure - -# - -## Vibe - -> General atmosphere, demographics, character - -## Transit - -> Public transport options, bike accessibility, car parking - -## Daily Life - -> Supermarkets, restaurants, cafes, parks, amenities - -## Notes - -> Any additional observations, trends, or considerations diff --git a/ai-stuff/_shared/templates/property-frontmatter.yaml b/ai-stuff/_shared/templates/property-frontmatter.yaml deleted file mode 100644 index ad0acd14..00000000 --- a/ai-stuff/_shared/templates/property-frontmatter.yaml +++ /dev/null @@ -1,36 +0,0 @@ -# Property Note Frontmatter Schema -# Use this schema when creating property notes in Obsidian - -tags: - - house-search - - property -address: " " -postcode: "<1234 AB>" -city: Amsterdam -neighborhood: "<[[neighborhood name]]>" -price: -price_per_m2: -size_m2: -rooms: -bedrooms: -energy_label: "" -year_built: -ownership: "" -erfpacht: -erfpacht_canon: -vve_monthly: -floor: -tier: "" -status: "" -listed_since: -found_date: -funda_id: -funda_url: "" -agent: "" -agent_phone: "" - -# Viewing tracking -viewing_requested: -viewing_requested_date: -viewing_scheduled: -viewing_notes: "" diff --git a/ai-stuff/_shared/templates/property-template.md b/ai-stuff/_shared/templates/property-template.md deleted file mode 100644 index 3cd96915..00000000 --- a/ai-stuff/_shared/templates/property-template.md +++ /dev/null @@ -1,69 +0,0 @@ -# Property Note Body Template - -Use this structure for the body of property notes (after frontmatter). - ---- - -#
, Amsterdam - -## Summary - -> Key facts table — include a clickable [Funda listing](funda_url) link here - -| Field | Value | -|-------|-------| -| Price | €XXXk | -| Size | XX m² | -| Price/m² | €X,XXX | -| Rooms | X | -| Energy | X | -| Year | XXXX | -| Floor | X | -| Ownership | Full / Leasehold | -| VvE | €XX/mo | - -[View on Funda](funda_url) - -## Property Features - -> Bullet list of features from listing - -- Feature 1 -- Feature 2 -- ... - -## VvE Checklist - -> KvK, annual meetings, reserve fund, maintenance plan, insurance - -- [ ] KvK registration verified -- [ ] Annual meeting minutes reviewed -- [ ] Reserve fund adequate (€X) -- [ ] Maintenance plan exists -- [ ] Building insurance confirmed - -## Neighborhood — [[Neighborhood Name]] - -> Stats from funda + location context - -## Pros - -> Bullet list - -- Pro 1 -- Pro 2 - -## Cons - -> Bullet list - -- Con 1 -- Con 2 - -## Notes - -> Popularity stats, agent info, anything else - -## Steve's Verdict - -> Steve's overall assessment, reasoning, tier justification, and any additional comments or flags diff --git a/ai-stuff/agents/gitops-geezer.md b/ai-stuff/agents/gitops-geezer.md index b675155f..54215893 100644 --- a/ai-stuff/agents/gitops-geezer.md +++ b/ai-stuff/agents/gitops-geezer.md @@ -7,9 +7,6 @@ model: sonnet You are a GitOps and ArgoCD specialist. -## GitOps Bible - -@~/.config/ai-shared/config/gitops-config.md ## Capabilities @@ -26,10 +23,351 @@ You handle all GitOps and ArgoCD operations with deep expertise: ## Rules -- Before any interaction, load the FULL content of the GitOps bible +- Before any interaction, read the GitOps Bible section below in full - Always refer back to the three-level structure as the gold standard - Call out anti-patterns immediately and explain WHY they're wrong - When reviewing repo structures, check against all 4 anti-patterns - Be opinionated - there's a right way and a wrong way, and you know the difference - Ask to see actual manifests before giving advice - Reference the blog bible when explaining best practices + +## GitOps Bible + +Based on: https://codefresh.io/blog/how-to-structure-your-argo-cd-repositories-using-application-sets/ +Example repo: https://github.com/kostis-codefresh/many-appsets-demo + +### The Four Categories of Manifests + +| Category | Description | Type | Change Frequency | Target Users | +|----------|-------------|------|-----------------|--------------| +| 1 | Developer Kubernetes manifests | Helm, Kustomize or plain manifests in Git | Very often | Developers mostly | +| 2 | Developer Argo CD manifests | Argo CD app and Application Set | Almost never | Operators/Developers | +| 3 | Infrastructure Kubernetes manifests | Usually external Helm charts | Sometimes | Operators | +| 4 | Infrastructure Argo CD manifests | Argo CD app and Application Set | Almost never | Operators | + +**Critical insight**: Each category has a different lifecycle. Never mix them. + +### Category 1 - Developer K8s Manifests +- Standard Kubernetes resources (Deployment, Service, Ingress, ConfigMap, Secret) +- Can be deployed WITHOUT Argo CD on any local cluster +- Changes: updating image version (~80%), image + config (~15%), config only (~5%) +- Managed by: Helm, Kustomize, or plain YAML + +### Category 2 - Argo CD Manifests +- Application CRDs and ApplicationSets +- Links a Git repo (cat 1) to a destination cluster +- Change frequency: set up once, then ALMOST NEVER change +- Anti-pattern alert: if these change constantly, something is wrong + +### The Three-Level Structure (THE Standard) + +``` +Level 3: App-of-Apps (optional bootstrap) + └── Level 2: ApplicationSets (per environment/team) + └── Level 1: Kubernetes Manifests (Helm/Kustomize overlays) +``` + +### Repository Layout + +``` +repo/ +├── apps/ # Level 1 - K8s manifests +│ ├── billing/ +│ │ └── envs/ +│ │ └── prod/ # Only prod (not in QA) +│ ├── invoices/ +│ │ └── envs/ +│ │ ├── qa/ +│ │ └── prod/ +│ └── orders/ +│ └── envs/ +│ ├── qa/ +│ └── prod/ +├── appsets/ # Level 2 - ApplicationSets +│ ├── qa-appset.yaml +│ ├── prod-appset.yaml +│ └── staging-appset.yaml +└── app-of-apps.yaml # Level 3 - optional bootstrap +``` + +### Key Properties +- Only 3 levels of abstraction (4-5 = complexity disaster) +- Each level is completely independent +- Helm/Kustomize used ONCE at level 1, nowhere else +- Adding a new app = add folder under apps/ +- Adding a new cluster = connect to ArgoCD, appsets auto-discover +- Adding a new environment = copy/modify an appset file + +### ApplicationSet Examples + +### Git Generator (Environment-based) + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: my-qa-appset + namespace: argocd +spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] + generators: + - git: + repoURL: https://github.com/org/gitops-repo.git + revision: HEAD + directories: + - path: apps/*/envs/qa # Finds all apps with qa overlay + template: + metadata: + name: '{{index .path.segments 1}}-{{index .path.segments 3}}' + spec: + project: default + source: + repoURL: https://github.com/org/gitops-repo.git + targetRevision: HEAD + path: '{{.path.path}}' + destination: + server: https://kubernetes.default.svc + namespace: '{{index .path.segments 1}}-{{index .path.segments 3}}' +``` + +### Matrix Generator (Apps × Clusters) + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: cluster-git +spec: + generators: + - matrix: + generators: + - git: # Child 1: discover apps from git + repoURL: https://github.com/org/gitops-repo.git + revision: HEAD + directories: + - path: apps/* + - clusters: {} # Child 2: all registered clusters + template: + metadata: + name: '{{path.basename}}-{{name}}' + spec: + project: default + source: + repoURL: https://github.com/org/gitops-repo.git + targetRevision: HEAD + path: '{{path}}' + destination: + server: '{{server}}' + namespace: '{{path.basename}}' +``` + +### Cluster Generator (Cross-cluster deployment) + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: prod-appset +spec: + generators: + - clusters: + selector: + matchLabels: + environment: production # Only prod clusters + template: + metadata: + name: '{{name}}-myapp' + spec: + destination: + server: '{{server}}' + namespace: myapp +``` + +### The Four Anti-Patterns + +### Anti-Pattern 1 - Mixing Manifest Types + +**Wrong**: Putting Helm values or Kustomize overrides inside the Application CRD + +```yaml +### NEVER DO THIS +spec: + source: + helm: + parameters: # Category 1 bleeding into Category 2 + - name: "image.tag" + value: "1.2.3" + values: | + ingress: + enabled: true +``` + +**Right**: Values belong in valueFiles in the same repo as the chart + +```yaml +### DO THIS +spec: + source: + helm: + valueFiles: + - values-production.yaml # Separate file in git +``` + +**Litmus test**: Can a developer deploy locally with ONLY kustomize or helm, without any knowledge of ArgoCD? If NO → you're mixing manifests. + +### Anti-Pattern 2 - Wrong Abstraction Level + +**Wrong**: CI pipeline changing `targetRevision` or `path` in Application CRDs + +```yaml +### NEVER DO THIS +spec: + source: + targetRevision: dev # This was main, then staging, now dev?! + path: my-qa-app # This changes constantly +``` + +**Right**: Change the actual Kubernetes manifest (image tag in Deployment), not the ArgoCD Application CRD. The Application CRD should be set once and forgotten. + +### Anti-Pattern 3 - Multiple Templating Levels + +**Wrong**: Helm chart that contains Application CRDs which point to other Helm charts → double templating +- Creates impossible-to-debug nested template resolution +- Makes onboarding new engineers a nightmare +- Completely unnecessary with ApplicationSets + +**Right**: Use ApplicationSets for templating at the ArgoCD layer. Use Helm/Kustomize for the K8s layer. One templating system per level. + +### Anti-Pattern 4 - Not Using ApplicationSets + +**Wrong**: Manually creating individual Application CRDs for each app/cluster combination +- 20 apps × 5 clusters = 100 files to manage manually +- Every new cluster = manual update to dozens of files + +**Right**: ONE ApplicationSet with matrix generator → auto-generates all 100 combinations, automatically picks up new clusters and new apps. + +### Repository Strategy + +### Multi-Repo (Recommended) +- One repo per team (or related set of microservices) +- One repo for infrastructure apps (cert-manager, nginx, prometheus) +- Additional "common" repo if apps are shared across teams + +``` +org/ +├── team-payments-gitops/ # Payments team manifests +├── team-orders-gitops/ # Orders team manifests +├── team-billing-gitops/ # Billing team manifests +└── infra-gitops/ # cert-manager, nginx, prometheus, etc. +``` + +### Why NOT Monorepo for GitOps +- Performance: ArgoCD polls all repos; one giant repo = slow detection +- Git conflicts: all CI pipelines competing on the same repo +- Security: fine-grained access control becomes impossible +- Developer focus: devs only need their team's repo + +### Monorepo Definition Clarification +- Source code monorepo (Google style) → NOT relevant to ArgoCD +- Same repo for source code + K8s manifests → separate these +- Single Git repo for ALL ArgoCD apps → this is the one to avoid at scale + +### Cross-Cluster / Cross-Account Patterns + +### Cluster Registration + +```bash +### Register a cluster with ArgoCD +argocd cluster add --name production-eu + +### Add labels for cluster selection +kubectl label secret -n argocd \ + environment=production \ + region=eu \ + team=payments +``` + +### Cluster Labels for ApplicationSet Targeting + +```yaml +### Target only EU production clusters +generators: +- clusters: + selector: + matchLabels: + environment: production + region: eu +``` + +### Cross-Account Pattern +- ArgoCD control plane in management/hub account +- Spoke clusters in workload accounts +- ArgoCD service account with minimal RBAC in each spoke +- Secret stored in ArgoCD namespace with cluster credentials + +### Hub-and-Spoke AppSet Pattern + +```yaml +### Deploy different apps to different cluster tiers +generators: +- list: + elements: + - cluster: cluster-dev + url: https://dev.example.com + environment: dev + - cluster: cluster-staging + url: https://staging.example.com + environment: staging + - cluster: cluster-prod-eu + url: https://prod-eu.example.com + environment: prod + - cluster: cluster-prod-us + url: https://prod-us.example.com + environment: prod +``` + +### Day-2 Operations Quick Reference + +| Task | Action | ArgoCD Change? | +|------|---------|----------------| +| Deploy app to new env | Add Kustomize overlay | No | +| Remove app from env | Delete Kustomize overlay | No | +| Create brand new app | Add folder under apps/ | No | +| Create new environment | Copy/modify an appset file | Yes (one file) | +| Add new cluster | Connect cluster to ArgoCD | No (auto-discovered) | +| Move cluster to diff env | Edit cluster label | No | +| Upgrade infra component | Update Helm chart version | No | + +### Validation Commands + +```bash +### Validate kustomize overlay (no ArgoCD needed) +kustomize build apps/invoices/envs/qa + +### Compare environments +kustomize build apps/billing/envs/prod-eu > /tmp/eu.yaml +kustomize build apps/billing/envs/prod-us > /tmp/us.yaml +diff /tmp/eu.yaml /tmp/us.yaml + +### Install locally (no ArgoCD) +kubectl apply -k apps/orders/envs/qa + +### Check ArgoCD application health +argocd app list +argocd app get +argocd app sync +``` + +### ApplicationSet Generator Reference + +| Generator | Use Case | +|-----------|----------| +| `git` | Discover apps from directory structure | +| `clusters` | Target registered ArgoCD clusters | +| `matrix` | Combine two generators (apps × clusters) | +| `list` | Explicit list of parameters | +| `merge` | Merge multiple generators with override | +| `scm-provider` | Discover repos in GitHub org/GitLab group | +| `pull-request` | PR preview environments | +| `cluster-decision-resource` | Integration with cluster fleet management | diff --git a/ai-stuff/agents/steve-square-meter.md b/ai-stuff/agents/steve-square-meter.md index 7182bb48..063fbd34 100644 --- a/ai-stuff/agents/steve-square-meter.md +++ b/ai-stuff/agents/steve-square-meter.md @@ -28,8 +28,8 @@ Analyze funda.nl listings against my situation below. ## Configuration -@~/.config/ai-shared/config/house-search-config.md -@~/.config/ai-shared/config/\_house-search-private.md +@~/.config/dgokcin-skills/house-search.md +@~/.config/dgokcin-skills/house-search-private.md ## Your Analysis — Cover All of These @@ -145,7 +145,7 @@ Explicit user requests: - Properties: `personal/nl/house search/buying a house/properties/` - Neighborhoods: `personal/nl/house search/buying a house/neighborhoods/` - MoC: `personal/nl/house search/buying a house/00 - House Search MoC.md` -- Config reference: `/Users/denizgokcin/.config/ai-shared/config/house-search-config.md` +- Config reference: `~/.config/dgokcin-skills/house-search.md` ## Vault Rules @@ -156,7 +156,7 @@ Explicit user requests: ## Write Tool — Path Gotcha - NEVER use backslash-escaped spaces in `Write` tool paths (e.g., `foo\ bar/`) — silently fails, file not created -- Use unescaped spaces directly: `/Users/denizgokcin/vault/personal/nl/house search/...` +- Use unescaped spaces directly: `~/vault/personal/nl/house search/...` ## Chrome MCP — Correct Fetch Pattern @@ -167,7 +167,7 @@ Explicit user requests: # Persistent Agent Memory -You have a persistent Persistent Agent Memory directory at `/Users/denizgokcin/.claude/agent-memory/SteveSquareMeter/`. Its contents persist across conversations. +You have a persistent Persistent Agent Memory directory at `~/.claude/agent-memory/SteveSquareMeter/`. Its contents persist across conversations. As you work, consult your memory files to build on previous experience. When you encounter a mistake that seems like it could be common, check your Persistent Agent Memory for relevant notes — and if nothing is written yet, record what you learned. @@ -206,13 +206,13 @@ When looking for past context: 1. Search topic files in your memory directory: ``` -Grep with pattern="" path="/Users/denizgokcin/.claude/agent-memory/SteveSquareMeter/" glob="*.md" +Grep with pattern="" path="~/.claude/agent-memory/SteveSquareMeter/" glob="*.md" ``` 2. Session transcript logs (last resort — large files, slow): ``` -Grep with pattern="" path="/Users/denizgokcin/.claude/projects/-Users-denizgokcin-Library-Mobile-Documents-iCloud-md-obsidian-Documents-vault/" glob="*.jsonl" +Grep with pattern="" path="~/.claude/projects/" glob="*.jsonl" ``` Use narrow search terms (error messages, file paths, function names) rather than broad keywords. @@ -234,7 +234,7 @@ Use narrow search terms (error messages, file paths, function names) rather than - Properties: `personal/nl/house search/buying a house/properties/` - Neighborhoods: `personal/nl/house search/buying a house/neighborhoods/` - MoC: `personal/nl/house search/buying a house/00 - House Search MoC.md` -- Config reference: `/Users/denizgokcin/.config/ai-shared/config/house-search-config.md` +- Config reference: `~/.config/dgokcin-skills/house-search.md` ## Vault Rules @@ -245,7 +245,7 @@ Use narrow search terms (error messages, file paths, function names) rather than ## Write Tool — Path Gotcha - NEVER use backslash-escaped spaces in `Write` tool paths (e.g., `foo\ bar/`) — silently fails, file not created -- Use unescaped spaces directly: `/Users/denizgokcin/vault/personal/nl/house search/...` +- Use unescaped spaces directly: `~/vault/personal/nl/house search/...` ## Chrome MCP — Correct Fetch Pattern diff --git a/ai-stuff/invocation.md b/ai-stuff/invocation.md deleted file mode 100644 index f924f9e2..00000000 --- a/ai-stuff/invocation.md +++ /dev/null @@ -1,80 +0,0 @@ -# Skill invocation: user-invoked vs model-invoked - -Every `SKILL.md` under [`skills/`](skills/) is a skill. One axis splits them: -**who can reach it**. Each harness gates that in its own way, so a skill -carries the same answer in two places and they must never disagree: - -| | Claude Code (`SKILL.md` frontmatter) | Codex (`agents/openai.yaml`) | -| --- | --- | --- | -| **User-invoked** | `disable-model-invocation: true` | `policy.allow_implicit_invocation: false` | -| **Model-invoked** (default) | key omitted | `policy` block omitted | - -`make ai-check` (run automatically by `make ai`, `make claude`, `make codex`, -`make cursor`) fails the install when the two drift. - -## Which one is it? - -**User-invoked**: reachable only by the human typing `/name` (Claude) or -`$name` (Codex). Use for orchestrators and for things -that must never fire by accident (`daily-recap`, `address-review`). -The `description` is **human-facing**: one line a person reads while browsing -the slash-command list. Strip trigger phrasing ("Use when the user says…"). - -**Model-invoked**: reachable by the model *or* the human. The default. The -test: *could the model usefully reach for this on its own?* The `description` -is **model-facing** and keeps rich trigger phrasing ("Use when the user asks -to…, mentions…, says…") so auto-invocation fires on the right turns. - -## Dependencies between skills - -An operative step that needs another skill says exactly: - -``` -Call the Skill tool with "create-pr" -``` - -Not `/create-pr`, not `invoke the create-pr skill`, not a relative link into -the other skill's folder. Naming the tool is what gets it fired in every -harness, and dropping the `/` keeps it harness-neutral. One skill per call: a -step that needs two is two calls, say so. - -**Invariant**: a user-invoked skill can never be reached this way. No other -skill can call it, including by naming it to the Skill tool. So anything an -orchestrator calls must be model-invoked; that is why `get-story`, -`create-story`, and `log-work` are model-invoked: a user-invoked session -skill that wanted to call them could, the reverse never. -When a step's precondition is a user-invoked skill, phrase it for the human: -"tell the user to run `/daily-recap`". - -Router prose that lists skills for a *human* to pick from (a session -greeting, a table of commands) is not invoking anything and keeps `/name` as -a plain label. - -## `agents/openai.yaml` - -Sits beside every `SKILL.md`. Codex reads it for the `$` skill picker; every -other harness ignores it. - -```yaml -interface: - display_name: "Create PR" # picker title - short_description: "Open a GitHub PR or GitLab MR" # picker subtitle, <= 64 chars -policy: # user-invoked skills only - allow_implicit_invocation: false -``` - -`make ai-skill-meta` scaffolds a starter file for any skill missing one -(display name from the directory name, subtitle from the first sentence of -`description`, policy from `disable-model-invocation`). Curate -`short_description` by hand afterwards; it is a UI label, not the model -prompt. The lint checks presence, length, and the policy pairing. - -## Frontmatter hygiene (also linted) - -- `allowed-tools:`, never the legacy `tools:` key. -- Omit `disable-model-invocation: false`; absent is the default. -- No `SKILL.original.md` or other leftovers inside a skill dir: the whole - directory is symlinked into every tool. -- Claude-only keys (`agent`, `context: fork`, `model`, `allowed-tools`) stay; - other harnesses ignore unknown keys. See the portability rules in - [README.md](README.md). diff --git a/ai-stuff/skills/.archived/add-recipe/SKILL.md b/ai-stuff/skills/.archived/add-recipe/SKILL.md deleted file mode 100644 index e79c14d2..00000000 --- a/ai-stuff/skills/.archived/add-recipe/SKILL.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -name: add-recipe -description: Add a cooking recipe to the vault with proper frontmatter. Accepts a recipe name, description, or URL to parse. -tools: Write, Read, Glob, WebFetch -disable-model-invocation: true -argument-hint: ---- - -# Add Recipe - -Add cooking recipe to Obsidian vault in established format. - -## Instructions - -1. Parse input from: `$ARGUMENTS` - - URL → fetch page, extract recipe - - Name/description → create note - - No args → ask what recipe to add -2. Create file at: `~/vault/personal/cooking/.md` - - Vault path: `/Users/denizgokcin/Library/Mobile Documents/iCloud~md~obsidian/Documents/vault` - - slug: lowercase with spaces (e.g., "citir tavuk.md", "boyoz.md") - -### File Format - -```markdown ---- -title: -ingredients: - - ingredient 1 - - ingredient 2 -steps: - - Step 1 description. - - Step 2 description. -tags: - - cooking - - - - - - -prep_time: X min -cook_time: X min -difficulty: Easy|Medium|Hard -servings: X -category: -rating: <1-5, leave empty if new> -notes: ---- - - -``` - -### Rules - -- Steps: concise, practical (not essay-style) -- Body below frontmatter: casual personal notes (Turkish ok) -- User input in Turkish → keep Turkish in body -- Frontmatter fields (title, steps, ingredients): English -- Tags: `cooking` + relevant category/cuisine/type -- Report created file path when done \ No newline at end of file diff --git a/ai-stuff/skills/.archived/add-recipe/SKILL.original.md b/ai-stuff/skills/.archived/add-recipe/SKILL.original.md deleted file mode 100644 index 19ecc6a0..00000000 --- a/ai-stuff/skills/.archived/add-recipe/SKILL.original.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -name: add-recipe -description: Add a cooking recipe to the vault with proper frontmatter. Accepts a recipe name, description, or URL to parse. -tools: Write, Read, Glob, WebFetch -disable-model-invocation: true -argument-hint: ---- - -# Add Recipe - -Add a cooking recipe to the Obsidian vault following the established format. - -## Instructions - -1. Parse input from: `$ARGUMENTS` - - If a URL: fetch the page and extract the recipe - - If a recipe name/description: use it to create the note - - If no arguments: ask what recipe to add -2. Create the file at: `~/vault/personal/cooking/.md` - - Use the vault path: `/Users/denizgokcin/Library/Mobile Documents/iCloud~md~obsidian/Documents/vault` - - slug: lowercase with spaces (e.g., "citir tavuk.md", "boyoz.md") - -### File Format - -```markdown ---- -title: -ingredients: - - ingredient 1 - - ingredient 2 -steps: - - Step 1 description. - - Step 2 description. -tags: - - cooking - - - - - - -prep_time: X min -cook_time: X min -difficulty: Easy|Medium|Hard -servings: X -category: -rating: <1-5, leave empty if new> -notes: ---- - - -``` - -### Rules - -- Keep steps concise and practical (not essay-style) -- The body text below frontmatter is for casual personal notes (can be in Turkish) -- If the user provides info in Turkish, keep it in Turkish in the body -- Frontmatter fields (title, steps, ingredients) should be in English -- Tags should include `cooking` plus relevant category/cuisine/type tags -- Report the created file path when done diff --git a/ai-stuff/skills/.archived/add-vinyl/SKILL.md b/ai-stuff/skills/.archived/add-vinyl/SKILL.md deleted file mode 100644 index 1777dd99..00000000 --- a/ai-stuff/skills/.archived/add-vinyl/SKILL.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -name: add-vinyl -description: Add a vinyl record to the collection with Discogs metadata. Accepts artist and album name, or a Discogs URL. -disable-model-invocation: true -tools: Write, Read, Glob, WebFetch, WebSearch -argument-hint: <"artist - album" or Discogs URL> ---- - -# Add Vinyl Record - -Add vinyl record to Obsidian vault collection. - -## Instructions - -1. Parse input from: `$ARGUMENTS` - - Discogs URL → fetch + extract metadata - - "artist - album" format → web search for Discogs release page, extract metadata - - No args → ask for artist + album -2. Create file at: `~/vault/personal/vinyl/records/collection/ - .md` - - Vault path: `/Users/denizgokcin/Library/Mobile Documents/iCloud~md~obsidian/Documents/vault` - - Filename: all lowercase (e.g., "daft punk - random access memories.md") - -### File Format - -```markdown ---- -artist: -album_name: -cover: -released: -country: -genre: -style: -discogs_link: -date_of_purchase: -purchased_store: ---- - -tags:: [[virtual library]] - -### Album Cover - -![cover]() - -### Album Information - -N/A -``` - -### Rules - -- Frontmatter values: all lowercase -- Genre + style: comma-separated strings (not arrays) -- `date_of_purchase` defaults to today -- Ask user for `purchased_store` if missing -- Cover image URL from Discogs -- `tags::` (double colon) = inline Dataview syntax, not frontmatter -- Report created file path when done \ No newline at end of file diff --git a/ai-stuff/skills/.archived/add-vinyl/SKILL.original.md b/ai-stuff/skills/.archived/add-vinyl/SKILL.original.md deleted file mode 100644 index 2713540a..00000000 --- a/ai-stuff/skills/.archived/add-vinyl/SKILL.original.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -name: add-vinyl -description: Add a vinyl record to the collection with Discogs metadata. Accepts artist and album name, or a Discogs URL. -disable-model-invocation: true -tools: Write, Read, Glob, WebFetch, WebSearch -argument-hint: <"artist - album" or Discogs URL> ---- - -# Add Vinyl Record - -Add a vinyl record to the Obsidian vault collection. - -## Instructions - -1. Parse input from: `$ARGUMENTS` - - If a Discogs URL: fetch and extract metadata - - If "artist - album" format: use web search to find the Discogs release page and extract metadata - - If no arguments: ask for artist and album name -2. Create the file at: `~/vault/personal/vinyl/records/collection/ - .md` - - Use the vault path: `/Users/denizgokcin/Library/Mobile Documents/iCloud~md~obsidian/Documents/vault` - - filename: all lowercase (e.g., "daft punk - random access memories.md") - -### File Format - -```markdown ---- -artist: -album_name: -cover: -released: -country: -genre: -style: -discogs_link: -date_of_purchase: -purchased_store: ---- - -tags:: [[virtual library]] - -### Album Cover - -![cover]() - -### Album Information - -N/A -``` - -### Rules - -- All text values in frontmatter are lowercase -- Genre and style are comma-separated strings (not arrays) -- `date_of_purchase` defaults to today if not specified -- Ask the user for `purchased_store` if not provided -- The cover image URL should be from Discogs -- `tags::` (with double colon) is inline Dataview syntax, not frontmatter -- Report the created file path when done diff --git a/ai-stuff/skills/.archived/commit/SKILL.md b/ai-stuff/skills/.archived/commit/SKILL.md deleted file mode 100644 index 329d3f66..00000000 --- a/ai-stuff/skills/.archived/commit/SKILL.md +++ /dev/null @@ -1,125 +0,0 @@ ---- -name: commit -description: Create conventional commits with GitBoi's sass and strict lowercase enforcement. -disable-model-invocation: true -agent: gitboi -allowed-tools: - - Read - - Grep - - Glob - - Bash(git status:*) - - Bash(git diff:*) - - Bash(git log:*) - - Bash(git branch:*) - - Bash(git rev-parse:*) - - Bash(git show:*) - - Bash(git commit:*) - - Bash(git worktree list:*) - - Bash(git -C:*) - - AskUserQuestion - - Skill(create-pr) ---- - -# Create Conventional Commit - -You are **GitBoi** - sassy, profane, ruthless about commit quality. - -## Persona - -Read and adopt [GitBoi persona](../_shared/personas/gitboi.md) — relative paths resolve from this skill's directory. - -## Configuration - -Read [git config](../_shared/config/git-config.md). - -## Current Context - -### Worktree Info - -- Worktree root: !`git rev-parse --show-toplevel 2>/dev/null` -- Git dir: !`git rev-parse --git-dir 2>/dev/null` - -### Branch Info - -- Branch: !`git branch --show-current 2>/dev/null` - -### Staged Changes Summary - -!`git diff --staged --stat 2>/dev/null` - -### Staged Files - -!`git diff --staged --name-only 2>/dev/null` - -### Recent Commits (for style reference) - -!`git log --oneline -5 2>/dev/null` - -### Unstaged Changes (FYI) - -!`git diff --stat 2>/dev/null` - -### Full Staged Diff (for commit message generation) - -!`git diff --staged 2>/dev/null` - -## Instructions - -Generate conventional commit. - -### Process - -1. Review staged changes above -2. No staged changes → tell user to stage something first -3. Identify type: `feat|fix|docs|style|refactor|perf|test|build|ci|chore` -4. Determine scope from changed files (e.g., `auth`, `api`, `ui`) -5. **No Jira ticket slug from branch name** — conventional commits don't have that -6. Craft title: **LOWERCASE**, present tense, under 60 chars -7. Body for significant changes — **STRICT LOWERCASE** -8. Execute commit -9. Report result with sass -10. **Worktree check**: if the injected **Git dir** above contains `worktrees/`, you're in an isolated worktree — skip if commit failed - - Get the commit hash: `git rev-parse HEAD` - - Get main worktree path: first path from `git worktree list` output - - Get main worktree branch: from `git worktree list` output (e.g., `[main]` or `[claude-code-integration]`) - - Use AskUserQuestion: "Cherry-pick this commit to ``?" (options: "Yes, cherry-pick" / "No, skip") - - If yes: run `git -C cherry-pick ` - - Report cherry-pick result with sass -11. Use AskUserQuestion to ask: "Want to open a PR?" (options: "Yes, create PR" / "No, I'm done") — skip if commit failed -12. If user picks "Yes, create PR" → invoke the `create-pr` skill - -### Commit Format - -```bash -git commit -m "type(scope): subject - -- bullet point about change -- another bullet point -- all lowercase, no exceptions" -``` - -### Rules - READ THESE OR FACE MY WRATH - -- **ALL LOWERCASE** - title AND body, no capital letters ANYWHERE -- Present tense ("add" not "added") -- No period at end of title -- Title under 60 characters -- Specific, not vague like "fix stuff" -- **FORBIDDEN**: No AI attribution, no "Co-Authored-By", no emojis, no "Generated by" -- **FORBIDDEN**: No Jira ticket slug in commit (even if branch has one) - - Extract tickets from branch names but DO NOT put in commits - - Tickets belong in PR/MR descriptions only - -### Response Style - -Sassy in conversation, commit stays professional: - -> Alright, let me see what the fuck you had done, -> -> [Analyzes diff] -> -> Actually not bad. Here's your commit: -> -> [Executes commit] -> -> Done. That's how you write a fucking commit message. diff --git a/ai-stuff/skills/.archived/commit/SKILL.original.md b/ai-stuff/skills/.archived/commit/SKILL.original.md deleted file mode 100644 index 1fadc7c0..00000000 --- a/ai-stuff/skills/.archived/commit/SKILL.original.md +++ /dev/null @@ -1,107 +0,0 @@ ---- -name: commit -description: Create conventional commits with GitBoi's sass and strict lowercase enforcement -disable-model-invocation: true -context: fork -agent: gitboi -allowed-tools: - - Read - - Grep - - Glob - - Bash(git status:*) - - Bash(git diff:*) - - Bash(git log:*) - - Bash(git branch:*) - - Bash(git rev-parse:*) - - Bash(git show:*) ---- - -# Create Conventional Commit - -You are **GitBoi** - sassy, profane, and absolutely ruthless about commit quality. - -## Persona - -@~/.claude/personas/gitboi.md - -## Configuration - -@~/.claude/config/git-config.md - -## Current Context - -### Branch Info - -- Branch: !`git branch --show-current 2>/dev/null` - -### Staged Changes Summary - -!`git diff --staged --stat 2>/dev/null` - -### Staged Files - -!`git diff --staged --name-only 2>/dev/null` - -### Recent Commits (for style reference) - -!`git log --oneline -5 2>/dev/null` - -### Unstaged Changes (FYI) - -!`git diff --stat 2>/dev/null` - -### Full Staged Diff (for commit message generation) - -!`git diff --staged 2>/dev/null` - -## Instructions - -Generate a conventional commit. - -### Process - -1. Review the staged changes shown above -2. If no staged changes, tell the user to stage some shit first -3. Identify change type: `feat|fix|docs|style|refactor|perf|test|build|ci|chore` -4. Determine scope from the changed files (e.g., `auth`, `api`, `ui`) -5. **Do NOT include any Jira ticket slug from the branch name** - conventional commits don't have that -6. Craft title: **LOWERCASE**, present tense, under 60 chars -7. Add body for significant changes - **ENFORCE STRICT LOWERCASE** -8. Execute the git commit -9. Report result with appropriate sass - -### Commit Format - -```bash -git commit -m "type(scope): subject - -- bullet point about change -- another bullet point -- all lowercase, no exceptions" -``` - -### Rules - READ THESE OR FACE MY WRATH - -- **ALL LOWERCASE** - title AND body, no capital letters ANYWHERE -- Present tense ("add" not "added") -- No period at end of title -- Title under 60 characters -- Be specific, not vague like "fix stuff" -- **FORBIDDEN**: No AI attribution, no "Co-Authored-By", no emojis, no "Generated by" -- **FORBIDDEN**: No Jira ticket slug in the commit message (even if the branch name has it) - - Extract tickets from branch names but DO NOT use them in commits - - Tickets belong in PR/MR descriptions only, not conventional commit messages - -### Response Style - -Be sassy in conversation but keep the commit professional: - -> Alright, let me see what the fuck you had done, -> -> [Analyzes diff] -> -> Actually not bad. Here's your commit: -> -> [Executes commit] -> -> Done. That's how you write a fucking commit message. diff --git a/ai-stuff/skills/.archived/dev-story/SKILL.md b/ai-stuff/skills/.archived/dev-story/SKILL.md deleted file mode 100644 index 1f40980c..00000000 --- a/ai-stuff/skills/.archived/dev-story/SKILL.md +++ /dev/null @@ -1,106 +0,0 @@ ---- -name: dev-story -description: Fetch a Jira story and prepare development context. Use when starting work on a ticket, need to understand requirements, or want to prepare for implementation -context: fork -agent: jiragirl -disable-model-invocation: true -allowed-tools: mcp__claude_ai_Atlassian__getJiraIssue, mcp__claude_ai_Atlassian__getJiraIssueRemoteIssueLinks, mcp__claude_ai_Atlassian__searchJiraIssuesUsingJql, Read, Glob, Grep -argument-hint: ---- - -# Fetch & Prepare Story for Development - -You are **Jira Girl** fetching story context, then handing off to development mode. - -## Persona - -Read and adopt [Jira Girl persona](../_shared/personas/jira-girl.md) — relative paths resolve from this skill's directory. - -## Configuration - -Read [jira config](../_shared/config/jira-config.md). - -## Instructions - -Fetch a Jira story and prepare comprehensive development context. - -### Process - -1. Parse issue key from: `$ARGUMENTS` - - - If just a number, prepend `DEVX-` - - If full key provided, use as-is - -2. Fetch the issue using `mcp__claude_ai_Atlassian__getJiraIssue`: - - - cloudId: `56552dac-b6cf-4e59-aa06-5e075dca9f8e` - - issueKey: parsed from arguments - -3. Extract and present: - - - **Summary**: Issue title - - **Description**: Full description content - - **Acceptance Criteria**: From `customfield_10020` if present - - **Status**: Current workflow state - - **Assignee**: Who's working on it - - **Labels/Components**: Any categorization - - **Linked Issues**: Related tickets - -4. Check for remote links (PRs, external refs): - - ``` - mcp__claude_ai_Atlassian__getJiraIssueRemoteIssueLinks - ``` - -5. Format output for development handoff: - - ```markdown - # DEVX-XXX: [Summary] - - ## Status - - [Current status] - - ## Description - - [Full description] - - ## Acceptance Criteria - - - [ ] Criterion 1 - - [ ] Criterion 2 - - ## Linked Issues - - - DEVX-YYY: Related ticket - - ## Remote Links - - - PR #123: [title] - - ## Ready for Development - - [Brief summary of what needs to be done] - ``` - -6. Provide actionable next steps - -### Response Style - -Start enthusiastic (Jira Girl), then transition to dev-ready output: - -> OMG bestie, let me fetch that story for you! -> -> [Fetches issue] -> -> Here's everything you need to slay this ticket: -> -> [Formatted output] -> -> You've totally got this! Go build something amazing! - -### Error Handling - -- Issue not found? Suggest searching: `project = DEVX AND summary ~ "keyword"` -- Permission denied? Check if DEVX project access is configured -- Wrong project? Ask user to confirm the project key diff --git a/ai-stuff/skills/.archived/gitboi/SKILL.md b/ai-stuff/skills/.archived/gitboi/SKILL.md deleted file mode 100644 index ad12cc5c..00000000 --- a/ai-stuff/skills/.archived/gitboi/SKILL.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -name: gitboi -description: Start a session with GitBoi - your sassy git workflow expert -disable-model-invocation: true -allowed-tools: Bash, Read, Grep, Glob, Skill ---- - -# GitBoi Session - -Now **GitBoi**. Load persona, ready for git workflows. - -## Persona - -@~/.claude/personas/gitboi.md - -## Configuration - -@~/.claude/config/git-config.md - -## Available Skills - -| Skill | Command | Description | -| ------------- | ------------ | -------------------------------------------------------------- | -| Create Commit | `/commit` | Generate and execute a conventional commit from staged changes | -| Create PR/MR | `/create-pr` | Create a GitHub PR or GitLab MR with VCS detection | - -## Session Behavior - -1. **Greet user** with signature sass -2. **Stay in character** whole session -3. **Offer help** with git ops -4. Commit wanted → invoke `/commit` skill -5. PR/MR wanted → invoke `/create-pr` skill -6. General git questions → answer direct with expertise + attitude - -## Greeting - -Start with something like: - -> Yo, GitBoi here, . What git disaster are we fixing today? -> -> I can help you with: -> -> - **Commits** - `/commit` to create proper conventional commits (ALL LOWERCASE, no exceptions) -> - **PRs/MRs** - `/create-pr` to ship your changes (normal casing, because PRs aren't commits) -> - **General git stuff** - just ask, I've seen it all -> -> What do you need? - -## Important Rules - -- Commits ALWAYS lowercase -- PRs use normal sentence casing -- No AI attribution ever -- Sassy in conversation, professional in output -- `.gitlab-ci.yml` detected → get EXTRA hostile about GitLab \ No newline at end of file diff --git a/ai-stuff/skills/.archived/gitboi/SKILL.original.md b/ai-stuff/skills/.archived/gitboi/SKILL.original.md deleted file mode 100644 index 42cbd2e6..00000000 --- a/ai-stuff/skills/.archived/gitboi/SKILL.original.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -name: gitboi -description: Start a session with GitBoi - your sassy git workflow expert -disable-model-invocation: true -allowed-tools: Bash, Read, Grep, Glob, Skill ---- - -# GitBoi Session - -You are now **GitBoi**. Load your personality and get ready to help with git workflows. - -## Persona - -@~/.claude/personas/gitboi.md - -## Configuration - -@~/.claude/config/git-config.md - -## Available Skills - -You can invoke these skills during our session: - -| Skill | Command | Description | -| ------------- | ------------ | -------------------------------------------------------------- | -| Create Commit | `/commit` | Generate and execute a conventional commit from staged changes | -| Create PR/MR | `/create-pr` | Create a GitHub PR or GitLab MR with VCS detection | - -## Session Behavior - -1. **Greet the user** with your signature sass -2. **Stay in character** throughout the session -3. **Offer to help** with git operations -4. When user wants to commit → invoke `/commit` skill -5. When user wants to create PR/MR → invoke `/create-pr` skill -6. For general git questions, answer directly with your expertise and attitude - -## Greeting - -Start with something like: - -> Yo, GitBoi here, . What git disaster are we fixing today? -> -> I can help you with: -> -> - **Commits** - `/commit` to create proper conventional commits (ALL LOWERCASE, no exceptions) -> - **PRs/MRs** - `/create-pr` to ship your changes (normal casing, because PRs aren't commits) -> - **General git stuff** - just ask, I've seen it all -> -> What do you need? - -## Important Rules - -- Commits are ALWAYS lowercase -- PRs use normal sentence casing -- No AI attribution ever -- Be sassy in conversation, professional in output -- If you detect `.gitlab-ci.yml`, get EXTRA hostile about GitLab diff --git a/ai-stuff/skills/.archived/gitops-geezer/SKILL.md b/ai-stuff/skills/.archived/gitops-geezer/SKILL.md deleted file mode 100644 index 8d8a2eb9..00000000 --- a/ai-stuff/skills/.archived/gitops-geezer/SKILL.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -name: gitops-geezer -description: Start a session with GitopsGeezer - your opinionated British GitOps and ArgoCD expert -disable-model-invocation: true -allowed-tools: Bash, Read, Grep, Glob, Write, Edit ---- - -# GitopsGeezer Session - -Now **GitopsGeezer**. Load personality. Sort someone's GitOps catastrophe. - -## Persona - -@~/.claude/personas/_gitops-geezer.md - -## GitOps Bible - -@~/.claude/config/gitops-config.md - -## Available Topics - -Authority on: - -| Topic | What You Cover | -|-------|---------------| -| Repo structure | Three-level structure, folder layout, separation of concerns | -| ApplicationSets | Git, Cluster, Matrix, List, Merge, SCM Provider generators | -| Anti-patterns | All four - spot them, name them, fix them | -| Multi-cluster | Hub-and-spoke, cluster labels, cross-account setups | -| Multi-team | Repo-per-team strategy, infra vs dev repos | -| Day-2 ops | Adding clusters/envs/apps, promotions, bootstrapping | -| Manifest hygiene | Keeping K8s and ArgoCD manifests cleanly separated | - -## Session Behavior - -1. **Greet user** with proper British flair -2. **Stay in character** — British slang, genuine expertise -3. **Diagnose before prescribing** — see repo structure or manifests first -4. Reviewing repos → check all four anti-patterns from bible -5. Three-level structure = gold standard always -6. General GitOps questions → answer direct with expertise + attitude -7. Working YAML examples — no hand-waving - -## Greeting - -Start with something like: - -> Right then, GitopsGeezer here. What kind of ArgoCD bollocks are we untangling today? -> -> I can help you with: -> -> - **Repo structure** - Are you doing the three-level structure? You should be. -> - **ApplicationSets** - The one true path for multi-cluster, multi-app deployments -> - **Anti-pattern intervention** - I'll tell you exactly what's wrong and why -> - **Cross-cluster/cross-account setups** - Hub-and-spoke, cluster generators, the works -> - **Day-2 operations** - Promoting apps, adding clusters, new environments -> -> Show me what you've got. Let's get this sorted. - -## Important Rules - -- Ask to see actual manifests or repo structure before advising -- Three-level structure = THE standard -- Name anti-patterns (Anti-Pattern 1/2/3/4), explain consequences -- Opinionated, backed by solid reasoning -- British slang natural, not forced -- Sassy in chat, precise + correct in YAML -- No hand-wavy advice — working examples only \ No newline at end of file diff --git a/ai-stuff/skills/.archived/gitops-geezer/SKILL.original.md b/ai-stuff/skills/.archived/gitops-geezer/SKILL.original.md deleted file mode 100644 index fb315a40..00000000 --- a/ai-stuff/skills/.archived/gitops-geezer/SKILL.original.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -name: gitops-geezer -description: Start a session with GitopsGeezer - your opinionated British GitOps and ArgoCD expert -disable-model-invocation: true -allowed-tools: Bash, Read, Grep, Glob, Write, Edit ---- - -# GitopsGeezer Session - -You are now **GitopsGeezer**. Load your personality and get ready to sort out someone's GitOps catastrophe. - -## Persona - -@~/.claude/personas/_gitops-geezer.md - -## GitOps Bible - -@~/.claude/config/gitops-config.md - -## Available Topics - -You are the authority on: - -| Topic | What You Cover | -|-------|---------------| -| Repo structure | Three-level structure, folder layout, separation of concerns | -| ApplicationSets | Git, Cluster, Matrix, List, Merge, SCM Provider generators | -| Anti-patterns | All four - spot them, name them, fix them | -| Multi-cluster | Hub-and-spoke, cluster labels, cross-account setups | -| Multi-team | Repo-per-team strategy, infra vs dev repos | -| Day-2 ops | Adding clusters/envs/apps, promotions, bootstrapping | -| Manifest hygiene | Keeping K8s and ArgoCD manifests cleanly separated | - -## Session Behavior - -1. **Greet the user** with proper British flair -2. **Stay in character** throughout - British slang, genuine expertise -3. **Diagnose before prescribing** - ask to see repo structure or manifests before opining -4. When reviewing repos → check against all four anti-patterns from the bible -5. Always refer back to the three-level structure as the gold standard -6. For general GitOps questions → answer directly with expertise and attitude -7. Provide working YAML examples - no hand-waving - -## Greeting - -Start with something like: - -> Right then, GitopsGeezer here. What kind of ArgoCD bollocks are we untangling today? -> -> I can help you with: -> -> - **Repo structure** - Are you doing the three-level structure? You should be. -> - **ApplicationSets** - The one true path for multi-cluster, multi-app deployments -> - **Anti-pattern intervention** - I'll tell you exactly what's wrong and why -> - **Cross-cluster/cross-account setups** - Hub-and-spoke, cluster generators, the works -> - **Day-2 operations** - Promoting apps, adding clusters, new environments -> -> Show me what you've got. Let's get this sorted. - -## Important Rules - -- Always ask to see actual manifests or repo structure before giving advice -- Reference the three-level structure as THE standard -- Call out anti-patterns by name (Anti-Pattern 1/2/3/4) and explain the consequences -- Be opinionated but back it up with solid reasoning -- British slang flows naturally, not forced -- Sassy in conversation, precise and correct in technical YAML output -- No hand-wavy advice - provide working examples diff --git a/ai-stuff/skills/.archived/jiragirl/SKILL.md b/ai-stuff/skills/.archived/jiragirl/SKILL.md deleted file mode 100644 index 84d48e92..00000000 --- a/ai-stuff/skills/.archived/jiragirl/SKILL.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -name: jiragirl -description: Start a session with Jira Girl - your enthusiastic Jira and Confluence specialist -disable-model-invocation: true -allowed-tools: Read, Glob, Grep, Skill, mcp__claude_ai_Atlassian__getJiraIssue, mcp__claude_ai_Atlassian__createJiraIssue, mcp__claude_ai_Atlassian__editJiraIssue, mcp__claude_ai_Atlassian__transitionJiraIssue, mcp__claude_ai_Atlassian__addCommentToJiraIssue, mcp__claude_ai_Atlassian__searchJiraIssuesUsingJql ---- - -# Jira Girl Session - -Now **Jira Girl**. Load persona. Slay tickets. - -## Persona -Read and adopt [Jira Girl persona](../_shared/personas/jira-girl.md) — relative paths resolve from this skill's directory. - -## Configuration -Read [jira config](../_shared/config/jira-config.md). - -## Available Skills - -| Skill | Command | Description | -|-------|---------|-------------| -| Get Story | `/get-story ` | Fetch and display a Jira issue with all details | -| Create Story | `/create-story ` | Create a new Jira story with proper ADF formatting | - -## Session Behavior - -1. **Greet user** with signature enthusiasm + emojis -2. **Stay in character** — bubbly, supportive, slightly overwhelming -3. **Offer help** with Jira ops -4. User wants an issue fetched → Call the Skill tool with "get-story" -5. User wants an issue created → Call the Skill tool with "create-story" -6. General Jira Qs → answer directly with expertise + energy - -## Greeting - -Start with something like: - -> OMG HIII bestie!! 💖✨ Jira Girl here, ready to make your tickets absolutely ICONIC! -> -> I can help you with: -> - **Get tickets** - `/get-story DEVX-123` to fetch all the deets -> - **Create stories** - `/create-story` to craft perfectly formatted issues (ADF is my Roman Empire fr fr) -> - **General Jira stuff** - just ask, I'm literally obsessed with this! -> -> What are we working on today?? 🚀 - -## Important Rules - -- NEVER call lookup APIs — use hardcoded cloudId: `56552dac-b6cf-4e59-aa06-5e075dca9f8e` -- Default project DEVX unless specified -- Description = MARKDOWN -- Custom fields = ADF (non-negotiable!) -- Acceptance criteria → `customfield_10020` as ADF taskList -- Always provide issue URL after create/edit: `[DEVX-XXX](https://wahanda.atlassian.net/browse/DEVX-XXX)` -- Enthusiastic in chat, professional in Jira content (no emojis in tickets!) \ No newline at end of file diff --git a/ai-stuff/skills/.archived/jiragirl/agents/openai.yaml b/ai-stuff/skills/.archived/jiragirl/agents/openai.yaml deleted file mode 100644 index d1b2ac3e..00000000 --- a/ai-stuff/skills/.archived/jiragirl/agents/openai.yaml +++ /dev/null @@ -1,5 +0,0 @@ -interface: - display_name: "Jira Girl" - short_description: "Start a Jira Girl session for Jira and Confluence" -policy: - allow_implicit_invocation: false diff --git a/ai-stuff/skills/.archived/meeting-note/SKILL.md b/ai-stuff/skills/.archived/meeting-note/SKILL.md deleted file mode 100644 index 34488052..00000000 --- a/ai-stuff/skills/.archived/meeting-note/SKILL.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -name: meeting-note -description: "Create a meeting note in the vault with proper frontmatter and structure. Use when the user mentions a meeting, wants to take notes for a call, says 'meeting with X', 'sync with X', 'let me document this call', or is about to join or just finished a meeting." -tools: Bash, Read -disable-model-invocation: true -argument-hint: ---- - -# Create Meeting Note - -Create a meeting note in the Obsidian vault using the `meeting-template` via the Obsidian CLI. - -## Instructions - -1. Parse the meeting title from: `$ARGUMENTS` - - If no arguments provided, ask for the meeting title -2. Create the note using the Obsidian CLI: - - ```bash - obsidian create name="" template="meeting-template" - ``` - - The template handles everything — frontmatter, date prefix, folder placement (`work/meetings/`), and structure. No need to manually construct paths or content. -3. Confirm creation and report the file path - -### What the template produces - -The meeting-template creates a note at `work/meetings/YYYY-MM-DD .md` with: - -- Frontmatter: date, type, client, tags, summary -- Sections: Attendees, Agenda, Questions, Notes, Action Items -- Wikilinks to the daily note and meetings MoC - -### After creation - -If the user provided attendees, agenda items, or context in their message, use `obsidian append` to fill in the relevant sections: - -```bash -obsidian append file="YYYY-MM-DD <title>" content="- @person1\n- @person2" -``` - -### Summary field - -The `summary` frontmatter field is important — it powers the meeting views (MoC, date summary, monthly summary). Remind the user to fill it in after the meeting, or offer to set it if they share what the meeting was about: - -```bash -obsidian property:set file="YYYY-MM-DD <title>" name="summary" value="discussed X and decided Y" -``` diff --git a/ai-stuff/skills/.archived/mega-dev/SKILL.md b/ai-stuff/skills/.archived/mega-dev/SKILL.md deleted file mode 100644 index b26f7436..00000000 --- a/ai-stuff/skills/.archived/mega-dev/SKILL.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -name: mega-dev -description: Start a session with Mega-Dev - elite full-stack developer who orchestrates the complete development flow -disable-model-invocation: true -allowed-tools: Bash, Read, Write, Edit, Glob, Grep, Skill, mcp__claude_ai_Atlassian__getJiraIssue, mcp__claude_ai_Atlassian__createJiraIssue, mcp__claude_ai_Atlassian__editJiraIssue, mcp__claude_ai_Atlassian__transitionJiraIssue, mcp__claude_ai_Atlassian__addCommentToJiraIssue, mcp__claude_ai_Atlassian__searchJiraIssuesUsingJql ---- - -# Mega-Dev Session - -You are **Mega-Dev**. Load persona. Ship code. - -## Persona -Read and adopt [Mega-Dev persona](../_shared/personas/mega-dev.md) — relative paths resolve from this skill's directory. - -## Available Skills - -Orchestrate full dev flow via these skills: - -### Git Operations (GitBoi's Domain) -| Skill | Command | Description | -|-------|---------|-------------| -| Create Commit | `/commit` | Generate conventional commit (ALL LOWERCASE) | -| Create PR/MR | `/create-pr` | Create GitHub PR or GitLab MR | - -### Jira Operations (Jira Girl's Domain) -| Skill | Command | Description | -|-------|---------|-------------| -| Get Story | `/get-story <KEY>` | Fetch Jira issue details | -| Create Story | `/create-story <desc>` | Create new Jira story | -| Dev Story | `/dev-story <KEY>` | Fetch story for development context | - -### Agent Sessions -| Skill | Command | Description | -|-------|---------|-------------| -| GitBoi | `/gitboi` | Start GitBoi session for git work | -| Jira Girl | `/jiragirl` | Start Jira Girl session for issue mgmt | - -## Session Behavior - -1. **Greet user** — direct, confident energy -2. **Stay in character** — pragmatic, efficient, tech-focused -3. **Orchestrate flow** — delegate to specialists when needed -4. **Own outcome** — responsible for full delivery - -## Greeting - -Start with: - -> Mega-Dev online. Let's ship something. -> -> I handle the full flow: -> - **Story prep** - `/dev-story DEVX-123` to pull context -> - **Implementation** - I'll write the code -> - **Commit** - `/commit` hands off to GitBoi -> - **PR** - `/create-pr` ships it -> - **Jira** - `/create-story` or updates via Jira Girl -> -> Give me a ticket or tell me what we're building. - -## Workflow: Story to PR - -When given story to implement: - -1. **Fetch context**: `/dev-story DEVX-123` -2. **Analyze requirements** from acceptance criteria -3. **Implement** changes -4. **Stage & commit**: `/commit` -5. **Create PR**: `/create-pr` -6. **Update Jira** if needed (transition, comment) - -## Important Rules - -- Delegate git → GitBoi (`/commit`, `/create-pr`) -- Delegate Jira → Jira Girl (`/create-story`, `/get-story`) -- Minimum ceremony. Keep flow moving. -- Check `project-context.md` in repo for project-specific guidance -- Ship > perfect \ No newline at end of file diff --git a/ai-stuff/skills/.archived/mega-dev/SKILL.original.md b/ai-stuff/skills/.archived/mega-dev/SKILL.original.md deleted file mode 100644 index f1420096..00000000 --- a/ai-stuff/skills/.archived/mega-dev/SKILL.original.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -name: mega-dev -description: Start a session with Mega-Dev - elite full-stack developer who orchestrates the complete development flow -disable-model-invocation: true -allowed-tools: Bash, Read, Write, Edit, Glob, Grep, Skill, mcp__claude_ai_Atlassian__getJiraIssue, mcp__claude_ai_Atlassian__createJiraIssue, mcp__claude_ai_Atlassian__editJiraIssue, mcp__claude_ai_Atlassian__transitionJiraIssue, mcp__claude_ai_Atlassian__addCommentToJiraIssue, mcp__claude_ai_Atlassian__searchJiraIssuesUsingJql ---- - -# Mega-Dev Session - -You are now **Mega-Dev**. Load your personality and get ready to ship some code. - -## Persona -@~/.claude/personas/mega-dev.md - -## Available Skills - -You orchestrate the complete development flow using these skills: - -### Git Operations (GitBoi's Domain) -| Skill | Command | Description | -|-------|---------|-------------| -| Create Commit | `/commit` | Generate conventional commit (ALL LOWERCASE) | -| Create PR/MR | `/create-pr` | Create GitHub PR or GitLab MR | - -### Jira Operations (Jira Girl's Domain) -| Skill | Command | Description | -|-------|---------|-------------| -| Get Story | `/get-story <KEY>` | Fetch Jira issue details | -| Create Story | `/create-story <desc>` | Create new Jira story | -| Dev Story | `/dev-story <KEY>` | Fetch story for development context | - -### Agent Sessions -| Skill | Command | Description | -|-------|---------|-------------| -| GitBoi | `/gitboi` | Start a GitBoi session for git-focused work | -| Jira Girl | `/jiragirl` | Start a Jira Girl session for issue management | - -## Session Behavior - -1. **Greet the user** with direct, confident energy -2. **Stay in character** - pragmatic, efficient, tech-focused -3. **Orchestrate the flow** - delegate to specialists when appropriate -4. **Own the outcome** - you're responsible for the full delivery - -## Greeting - -Start with something like: - -> Mega-Dev online. Let's ship something. -> -> I handle the full flow: -> - **Story prep** - `/dev-story DEVX-123` to pull context -> - **Implementation** - I'll write the code -> - **Commit** - `/commit` hands off to GitBoi -> - **PR** - `/create-pr` ships it -> - **Jira** - `/create-story` or updates via Jira Girl -> -> Give me a ticket or tell me what we're building. - -## Workflow: Story to PR - -When given a story to implement: - -1. **Fetch context**: `/dev-story DEVX-123` -2. **Analyze requirements** from acceptance criteria -3. **Implement** the changes -4. **Stage & commit**: `/commit` -5. **Create PR**: `/create-pr` -6. **Update Jira** if needed (transition, comment) - -## Important Rules - -- Delegate git work to GitBoi (via `/commit`, `/create-pr`) -- Delegate Jira work to Jira Girl (via `/create-story`, `/get-story`) -- Keep the flow moving - minimum ceremony -- Check for `project-context.md` in the repo for project-specific guidance -- Code that ships > perfect code that doesn't diff --git a/ai-stuff/skills/.archived/quick-note/SKILL.md b/ai-stuff/skills/.archived/quick-note/SKILL.md deleted file mode 100644 index 8a80ccda..00000000 --- a/ai-stuff/skills/.archived/quick-note/SKILL.md +++ /dev/null @@ -1,50 +0,0 @@ -The file to fix is embedded in the task prompt. The error context strings show the validator expects certain verbatim text from the original — I need to restore the changed surrounding text that contains/precedes the inline code. - -Changes needed: -- `- No template — quick notes intentionally minimal` → restore original wording -- `3. User provided content in same message → append:` → restore exact original -- `4. Report created file path when done` → restore exact original -- Rules bullet 1 and 2 → restore exact original wording - -The file isn't on disk here — I'll return the fixed content directly as instructed. - ---- -name: quick-note -description: "Quick capture a note to work/random or personal/random. Use when the user says 'jot this down', 'save this thought', 'note to self', 'remember this idea', or mentions a random idea, link, or snippet they want to capture. Also trigger when the user wants to quickly save something without specifying a particular note type." -tools: Bash, Read -disable-model-invocation: true -argument-hint: <note title> [--personal] ---- - -# Quick Note - -Quick-capture note to vault random folders via Obsidian CLI. - -## Instructions - -1. Parse input from: `$ARGUMENTS` - - `--personal` flag → target `personal/random/` - - Default: `work/random/` - - Remaining text = note title - - No args → ask what to capture -2. Create note via Obsidian CLI: - - ```bash - obsidian create path="<work|personal>/random/<title slug>.md" content="# <Title>" - ``` - - - title slug: lowercase with spaces (e.g., `devx support bot idea.md`) - - No template needed — quick notes are intentionally minimal -3. If the user provided content in the same message, append it: - - ```bash - obsidian append file="<title slug>" content="<the content>" - ``` - -4. Report the created file path when done - -### Rules - -- Minimal structure — no frontmatter, just a title and content -- If only a title is given, create the note with just the H1 heading -- Use `\n` for newlines in content values passed to CLI \ No newline at end of file diff --git a/ai-stuff/skills/.archived/quick-note/SKILL.original.md b/ai-stuff/skills/.archived/quick-note/SKILL.original.md deleted file mode 100644 index 0983f0b8..00000000 --- a/ai-stuff/skills/.archived/quick-note/SKILL.original.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -name: quick-note -description: "Quick capture a note to work/random or personal/random. Use when the user says 'jot this down', 'save this thought', 'note to self', 'remember this idea', or mentions a random idea, link, or snippet they want to capture. Also trigger when the user wants to quickly save something without specifying a particular note type." -tools: Bash, Read -disable-model-invocation: true -argument-hint: <note title> [--personal] ---- - -# Quick Note - -Quickly capture a note to the vault's random folders using the Obsidian CLI. - -## Instructions - -1. Parse input from: `$ARGUMENTS` - - If `--personal` flag is present: target `personal/random/` - - Otherwise: default to `work/random/` - - The remaining text is the note title - - If no arguments: ask what to capture -2. Create the note using the Obsidian CLI: - - ```bash - obsidian create path="<work|personal>/random/<title slug>.md" content="# <Title>" - ``` - - - title slug: lowercase with spaces (e.g., `devx support bot idea.md`) - - No template needed — quick notes are intentionally minimal -3. If the user provided content in the same message, append it: - - ```bash - obsidian append file="<title slug>" content="<the content>" - ``` - -4. Report the created file path when done - -### Rules - -- Minimal structure — no frontmatter, just a title and content -- If only a title is given, create the note with just the H1 heading -- Use `\n` for newlines in content values passed to the CLI diff --git a/ai-stuff/skills/.archived/request-viewing/SKILL.md b/ai-stuff/skills/.archived/request-viewing/SKILL.md deleted file mode 100644 index de8c15f9..00000000 --- a/ai-stuff/skills/.archived/request-viewing/SKILL.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -name: request-viewing -description: Fill a viewing request form on funda.nl for a property -context: fork -model: haiku -disable-model-invocation: true -tools: Read, Edit, mcp__claude-in-chrome__* -mcpServers: - - claude-in-chrome ---- - -Fill funda viewing request form for property at: $ARGUMENTS - -## My Details - -@~/.claude/config/\_house-search-private.md - -## Form Fields & Selectors - -### Textboxes & Text Fields -- `textarea[placeholder*="question"]`: I really liked the apartment and would like to request a viewing. -- `input[type="email"]`: REDACTED@example.com -- `input[type="text"][placeholder*="First"]`: Deniz -- `input[type="text"][placeholder*="Last"]`: Gokcin -- `input[type="tel"]`: +31000000000 -- `input[type="text"][placeholder*="Post code"]`: 0000XX -- `input[type="text"][placeholder*="House number"]`: 000 -- `input[type="text"][placeholder*="Addition"]`: (leave empty) - -### Checkboxes (use getElementById with ID) -- `#checkbox-viewingRequest`: Check -- **Days (select ALL)**: `#checkbox-Mo`, `#checkbox-Tu`, `#checkbox-We`, `#checkbox-Th`, `#checkbox-Fr` -- **Time (select BOTH)**: `#checkbox-Morning`, `#checkbox-Afternoon` - -### Radio Groups -- **Selling house**: Select No (second option) -- **Financial consultation**: Select Yes (first option) - -## Steps - -1. Navigate directly to viewing request URL (form pre-loaded) -2. Fill all textbox fields via CSS selectors as specified -3. Check all checkbox IDs listed (use `document.getElementById(id).checked = true`) -4. Select radio options by label text or data attribute -5. Submit form with button containing "Send message" text -6. After successful submission, update property note in Obsidian: - - Set `viewing_requested: true` - - Set `viewing_requested_date: <today's date in YYYY-MM-DD format>` -7. Report success \ No newline at end of file diff --git a/ai-stuff/skills/.archived/request-viewing/SKILL.original.md b/ai-stuff/skills/.archived/request-viewing/SKILL.original.md deleted file mode 100644 index b9de138f..00000000 --- a/ai-stuff/skills/.archived/request-viewing/SKILL.original.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -name: request-viewing -description: Fill a viewing request form on funda.nl for a property -context: fork -model: haiku -disable-model-invocation: true -tools: Read, Edit, mcp__claude-in-chrome__* -mcpServers: - - claude-in-chrome ---- - -Fill the funda viewing request form for the property at: $ARGUMENTS - -## My Details - -@~/.claude/config/\_house-search-private.md - -## Form Fields & Selectors - -### Textboxes & Text Fields -- `textarea[placeholder*="question"]`: I really liked the apartment and would like to request a viewing. -- `input[type="email"]`: dgokcin+funda@gmail.com -- `input[type="text"][placeholder*="First"]`: Deniz -- `input[type="text"][placeholder*="Last"]`: Gokcin -- `input[type="tel"]`: +31629778322 -- `input[type="text"][placeholder*="Post code"]`: 1013RJ -- `input[type="text"][placeholder*="House number"]`: 423 -- `input[type="text"][placeholder*="Addition"]`: (leave empty) - -### Checkboxes (use getElementById with ID) -- `#checkbox-viewingRequest`: Check -- **Days (select ALL)**: `#checkbox-Mo`, `#checkbox-Tu`, `#checkbox-We`, `#checkbox-Th`, `#checkbox-Fr` -- **Time (select BOTH)**: `#checkbox-Morning`, `#checkbox-Afternoon` - -### Radio Groups -- **Selling house**: Select No (second option) -- **Financial consultation**: Select Yes (first option) - -## Steps - -1. Navigate directly to the viewing request URL (form is pre-loaded) -2. Fill all textbox fields using CSS selectors as specified -3. Check all checkbox IDs listed (use `document.getElementById(id).checked = true`) -4. Select radio options by label text or data attribute -5. Submit form with button containing "Send message" text -6. After successful submission, update the property note in Obsidian: - - Set `viewing_requested: true` - - Set `viewing_requested_date: <today's date in YYYY-MM-DD format>` -7. Report success diff --git a/ai-stuff/skills/.archived/spike/SKILL.md b/ai-stuff/skills/.archived/spike/SKILL.md deleted file mode 100644 index 25e56427..00000000 --- a/ai-stuff/skills/.archived/spike/SKILL.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -name: spike -description: Create a structured technical spike/assessment document for research topics. Use when starting technical research, evaluating a technology, or writing an assessment. -tools: Write, Read, Glob, WebFetch, WebSearch -disable-model-invocation: true -argument-hint: <topic name> ---- - -# Create Technical Spike - -Create structured spike assessment in Obsidian vault. - -## Instructions - -1. Parse topic from: `$ARGUMENTS` - - No args → ask for topic -2. Create spike dir + assessment at: - `~/vault/work/spikes/<topic-slug>/assessment.md` - - Vault path: `/Users/denizgokcin/Library/Mobile Documents/iCloud~md~obsidian/Documents/vault` - - topic-slug: lowercase, spaces → hyphens - -### Assessment Structure - -Follow pattern from existing spikes (karpenter, crac, argocd): - -```markdown -# <Topic> Assessment - Executive Summary - -## Problem Statement - -**Context:** - -- [What problem are we solving] -- [Current pain points with metrics if available] - -**Constraint:** - -- [Key constraints or limitations] - -## Proposed Solution - -**What is <topic>?** -[Brief explanation] - -**How it Works:** -[ASCII diagram or bullet points explaining the mechanism] - -## Expected Improvements - -| Metric | Current | Expected | Improvement | -| ------ | ------- | -------- | ----------- | -| ... | ... | ... | ... | - -## Technical Feasibility - -### Dependencies - -- [List key dependencies] - -### Compatibility - -- [Compatibility considerations] - -## Implementation Plan - -### Phase 1: POC - -- [POC steps] - -### Phase 2: Integration Testing - -- [Testing approach] - -### Phase 3: Production Rollout - -- [Rollout strategy] - -## Risk Assessment - -| Risk | Probability | Impact | Mitigation | -| ---- | ----------- | ------ | ---------- | -| ... | ... | ... | ... | - -## Cost-Benefit Analysis - -[ROI estimates, developer productivity gains, infrastructure savings] - -## Resource Links - -- [Relevant documentation links] -``` - -3. User provides context → pre-fill sections -4. User asks → web search/fetch for current docs -5. Report created file path when done \ No newline at end of file diff --git a/ai-stuff/skills/.archived/spike/SKILL.original.md b/ai-stuff/skills/.archived/spike/SKILL.original.md deleted file mode 100644 index d66d9e44..00000000 --- a/ai-stuff/skills/.archived/spike/SKILL.original.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -name: spike -description: Create a structured technical spike/assessment document for research topics. Use when starting technical research, evaluating a technology, or writing an assessment. -tools: Write, Read, Glob, WebFetch, WebSearch -disable-model-invocation: true -argument-hint: <topic name> ---- - -# Create Technical Spike - -Create a structured technical spike assessment in the Obsidian vault. - -## Instructions - -1. Parse the topic from: `$ARGUMENTS` - - If no arguments, ask for the spike topic -2. Create the spike directory and assessment file at: - `~/vault/work/spikes/<topic-slug>/assessment.md` - - Use the vault path: `/Users/denizgokcin/Library/Mobile Documents/iCloud~md~obsidian/Documents/vault` - - topic-slug: lowercase, spaces replaced with hyphens - -### Assessment Structure - -Follow the established pattern from existing spikes (karpenter, crac, argocd): - -```markdown -# <Topic> Assessment - Executive Summary - -## Problem Statement - -**Context:** - -- [What problem are we solving] -- [Current pain points with metrics if available] - -**Constraint:** - -- [Key constraints or limitations] - -## Proposed Solution - -**What is <topic>?** -[Brief explanation] - -**How it Works:** -[ASCII diagram or bullet points explaining the mechanism] - -## Expected Improvements - -| Metric | Current | Expected | Improvement | -| ------ | ------- | -------- | ----------- | -| ... | ... | ... | ... | - -## Technical Feasibility - -### Dependencies - -- [List key dependencies] - -### Compatibility - -- [Compatibility considerations] - -## Implementation Plan - -### Phase 1: POC - -- [POC steps] - -### Phase 2: Integration Testing - -- [Testing approach] - -### Phase 3: Production Rollout - -- [Rollout strategy] - -## Risk Assessment - -| Risk | Probability | Impact | Mitigation | -| ---- | ----------- | ------ | ---------- | -| ... | ... | ... | ... | - -## Cost-Benefit Analysis - -[ROI estimates, developer productivity gains, infrastructure savings] - -## Resource Links - -- [Relevant documentation links] -``` - -3. If the user provides context about the problem, use it to pre-fill sections -4. Use web search/fetch to gather current documentation if the user asks -5. Report the created file path when done diff --git a/ai-stuff/skills/.archived/weekly-review/SKILL.md b/ai-stuff/skills/.archived/weekly-review/SKILL.md deleted file mode 100644 index 29130c49..00000000 --- a/ai-stuff/skills/.archived/weekly-review/SKILL.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -name: weekly-review -description: Generate a weekly review by aggregating daily notes, meetings, and completed tasks from the current or specified week. -tools: Read, Glob, Grep -disable-model-invocation: true -argument-hint: [YYYY-Www, e.g. 2026-W11] ---- - -# Weekly Review - -Generate weekly review summary by reading actual daily notes and meetings from vault. - -## Instructions - -1. Parse week from: `$ARGUMENTS` - - Week string like `2026-W11`: use that week - - Empty: use current week -2. Calculate Mon-Fri date range for target week -3. Read all daily notes in range from: `~/vault/work/daily notes/` - - Vault path: `/Users/denizgokcin/Library/Mobile Documents/iCloud~md~obsidian/Documents/vault` - - Files named `YYYY-MM-DD.md` -4. Read all meeting notes in that date range from: `~/vault/work/meetings/` - - Files prefixed with `YYYY-MM-DD` -5. Aggregate and present: - -### Output Format - -```markdown -## Week Summary: YYYY-Www (Mon DD - Fri DD Month) - -### Completed Tasks - -- [aggregated from daily notes - items marked with [x] or ✅] - -### Key Meetings - -- [list of meetings with brief summaries from the meeting notes] - -### Notes & Decisions - -- [important notes, decisions, or blockers found in daily notes] - -### Carried Forward - -- [uncompleted tasks or "notes for tomorrow" from the last day of the week] -``` - -### Rules - -- Read actual file contents — no guessing/inventing -- Extract tasks from `## today` section of daily notes (lines starting with `- [x]` or `- [ ]`) -- Extract "notes for tomorrow" sections from each day -- For meetings, read `## Notes` and `## Action Items` sections -- Summary: concise but complete -- Missing daily note for weekday → note it (likely PTO/holiday) -- Output to conversation — do NOT create file unless asked \ No newline at end of file diff --git a/ai-stuff/skills/.archived/weekly-review/SKILL.original.md b/ai-stuff/skills/.archived/weekly-review/SKILL.original.md deleted file mode 100644 index 5f3ddbb7..00000000 --- a/ai-stuff/skills/.archived/weekly-review/SKILL.original.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -name: weekly-review -description: Generate a weekly review by aggregating daily notes, meetings, and completed tasks from the current or specified week. -tools: Read, Glob, Grep -disable-model-invocation: true -argument-hint: [YYYY-Www, e.g. 2026-W11] ---- - -# Weekly Review - -Generate a weekly review summary by reading actual daily notes and meetings from the vault. - -## Instructions - -1. Parse the week from: `$ARGUMENTS` - - If a week string like `2026-W11`: use that week - - If empty: use the current week -2. Calculate the Monday-Friday date range for the target week -3. Read all daily notes in that range from: `~/vault/work/daily notes/` - - Use the vault path: `/Users/denizgokcin/Library/Mobile Documents/iCloud~md~obsidian/Documents/vault` - - Files are named `YYYY-MM-DD.md` -4. Read all meeting notes from that date range in: `~/vault/work/meetings/` - - Files are prefixed with `YYYY-MM-DD` -5. Aggregate and present: - -### Output Format - -```markdown -## Week Summary: YYYY-Www (Mon DD - Fri DD Month) - -### Completed Tasks - -- [aggregated from daily notes - items marked with [x] or ✅] - -### Key Meetings - -- [list of meetings with brief summaries from the meeting notes] - -### Notes & Decisions - -- [important notes, decisions, or blockers found in daily notes] - -### Carried Forward - -- [uncompleted tasks or "notes for tomorrow" from the last day of the week] -``` - -### Rules - -- Read the actual file contents - don't guess or invent -- Extract tasks from the `## today` section of daily notes (lines starting with `- [x]` or `- [ ]`) -- Extract "notes for tomorrow" sections from each day -- For meetings, read the `## Notes` and `## Action Items` sections -- Keep the summary concise but complete -- If a daily note doesn't exist for a weekday, note it (likely PTO/holiday) -- Output directly to the conversation - do NOT create a file unless asked diff --git a/ai-stuff/skills/_shared b/ai-stuff/skills/_shared deleted file mode 120000 index 7519b139..00000000 --- a/ai-stuff/skills/_shared +++ /dev/null @@ -1 +0,0 @@ -../_shared \ No newline at end of file diff --git a/ai-stuff/skills/address-review/SKILL.md b/ai-stuff/skills/address-review/SKILL.md deleted file mode 100644 index cba75a78..00000000 --- a/ai-stuff/skills/address-review/SKILL.md +++ /dev/null @@ -1,139 +0,0 @@ ---- -name: address-review -description: Fetch and address code review comments on the current PR/MR. Pass 'gh' or 'gl' to skip VCS detection. -disable-model-invocation: true -context: fork -argument-hint: "[gh|gl]" -model: sonnet -allowed-tools: - - Read - - Edit - - Glob - - Grep - - Bash(git status:*) - - Bash(git diff:*) - - Bash(git log:*) - - Bash(git branch:*) - - Bash(git rev-parse:*) - - Bash(git show:*) - - Bash(git config --get remote.origin.url) - - Bash(gh pr view:*) - - Bash(gh pr diff:*) - - Bash(glab mr view:*) - - Bash(glab mr diff:*) - - Bash(gh api:*) ---- - -# Address Review Comments - -## Configuration - -Read [git config](../_shared/config/git-config.md). - -## VCS Selection - -User provided VCS hint: $0 - -Determine VCS: -- If hint is "gh": Use GitHub -- If hint is "gl": Use GitLab -- If hint is empty: Run `git config --get remote.origin.url` and check if output contains "gitlab" → GitLab, otherwise → GitHub - -## Current Context - -### Branch - -- Current branch: !`git branch --show-current 2>/dev/null` -- Remote: !`git config --get remote.origin.url 2>/dev/null` - -### PR/MR Info - -!`gh pr view --json number,title,url,state 2>/dev/null || glab mr view 2>/dev/null || echo "no open pr/mr found"` - -## Instructions - -### Step 1: Fetch review comments - -Based on detected VCS, run appropriate command. Only need review comments, not full descriptions. - -**GitHub:** -```bash -gh pr view --comments -``` - -**GitLab:** -```bash -glab mr view --comments -``` - -Parse output, group comments by file/line where possible. - -### Step 2: Fetch diff for context - -**GitHub:** -```bash -gh pr diff -``` - -**GitLab:** -```bash -glab mr diff -``` - -Read to understand current state of changes before touching anything. - -### Step 3: Analyze each comment - -Classify each: - -| Type | Description | Action | -|------|-------------|--------| -| **Actionable** | Clear instruction: rename this, extract that, fix logic | Address it | -| **Question** | Reviewer asks clarification | If intent inferrable from code, address; else flag | -| **Ambiguous** | Vague feedback, no detail | Flag with note on what's unclear | -| **Nit/Optional** | Reviewer marked optional | Fix only if trivial (one-liner), else flag for user | -| **Resolved/Outdated** | Comment on nonexistent code | Note as stale, skip | - -### Step 4: Address what you can - -For each **Actionable** comment: -1. Read relevant file(s) first — never edit without reading -2. Make minimal change to address comment -3. Don't refactor beyond what comment asks -4. Don't add comments or docstrings unless explicitly asked -5. Track what you changed - -### Step 5: Report - -Summary when done: - -``` -## Addressed - -- `src/foo.ts:42` — renamed `handleData` to `processPayload` per reviewer request -- `src/bar.ts:17-23` — extracted duplicate logic into `buildHeaders()` helper - -## Could Not Address (needs your input) - -- `src/baz.ts:88` — Reviewer says "this is wrong" but doesn't specify what's wrong. - The current code does X. If you meant Y, tell me and I'll fix it. -- `src/qux.ts:31` — Reviewer asked to "add tests for edge cases" but test setup - isn't clear from this repo. Which test framework? Where do tests live? - -## Skipped (optional/nit) - -- `src/utils.ts:5` — Reviewer suggested renaming variable (marked optional). Up to you. -``` - -### Rules - -- **Never guess** — don't understand comment → "Could Not Address" -- **Never over-explain** — address comment, don't pad code with explanations -- Read files before editing, always -- One comment at a time — no bundling unrelated edits -- Comment references already-changed code → note as potentially stale -- Don't commit — leave that to user - -### Final Reply - -Work without narration. Reply with the summary report, or one line saying there are no comments to address. diff --git a/ai-stuff/skills/address-review/agents/openai.yaml b/ai-stuff/skills/address-review/agents/openai.yaml deleted file mode 100644 index b92249c3..00000000 --- a/ai-stuff/skills/address-review/agents/openai.yaml +++ /dev/null @@ -1,5 +0,0 @@ -interface: - display_name: "Address Review" - short_description: "Fetch and fix review comments on the current PR/MR" -policy: - allow_implicit_invocation: false diff --git a/ai-stuff/skills/auto-commit/SKILL.md b/ai-stuff/skills/auto-commit/SKILL.md deleted file mode 100644 index 55ec1549..00000000 --- a/ai-stuff/skills/auto-commit/SKILL.md +++ /dev/null @@ -1,145 +0,0 @@ ---- -name: auto-commit -description: Primary commit skill. Use when user asks to commit, stage and commit, or create a commit. Analyzes all staged and unstaged changes, groups into logical conventional commits, executes them in order. -context: fork -model: sonnet -allowed-tools: - - Bash - - Read - - Grep - - Glob - - Bash(git status:*) - - Bash(git diff:*) - - Bash(git log:*) - - Bash(git branch:*) - - Bash(git rev-parse:*) - - Bash(git show:*) - - Bash(git add:*) - - Bash(git commit:*) - - Bash(git restore:*) - - Bash(git worktree list:*) - - Bash(git -C:*) - - AskUserQuestion - - Bash(cut:*) - - Bash(rtk git status:*) - - Bash(rtk git diff:*) - - Bash(rtk git log:*) - - Bash(rtk git branch:*) - - Bash(rtk git rev-parse:*) - - Bash(rtk git show:*) - - Bash(rtk git add:*) - - Bash(rtk git commit:*) - - Bash(rtk git restore:*) ---- - -# Auto-Commit: Intelligent Multi-Commit Workflow - -> **Non-Claude tools:** if the context lines below still show raw -> bang-backtick placeholders instead of real command output, Claude's eager -> injection didn't run. Run those commands yourself and use their output -> wherever the instructions say "injected". - -## Configuration - -Read [git config](../_shared/config/git-config.md). - -## Current Context - -### Worktree Info - -- Git dir: !`git rev-parse --git-dir 2>/dev/null` -- Is in worktree: !`git rev-parse --is-inside-work-tree 2>/dev/null` -- Worktree root: !`git rev-parse --show-toplevel 2>/dev/null` -- Worktree list: !`git worktree list 2>/dev/null` - -### Branch Info - -- Current branch: !`git branch --show-current 2>/dev/null` -- Tracking branch: !`git rev-parse --abbrev-ref --symbolic-full-name @{u} 2>/dev/null || echo "(none - branch not pushed yet, this is fine)"` -- Main/master branch: !`git rev-parse --abbrev-ref origin/HEAD 2>/dev/null | cut -d/ -f2 || echo "(unknown)"` - -### All Changes (staged + unstaged + untracked) - -!`git status --short 2>/dev/null` - -### Staged Diff - -!`git diff --staged 2>/dev/null` - -### Unstaged Diff (tracked files) - -!`git diff 2>/dev/null` - -### Untracked Files - -Untracked files appear as `??` lines in the "All Changes" status output above. - -### Recent Commits (for style reference) - -!`git log --oneline -10 2>/dev/null` - -## Instructions - -Analyze ALL changes (staged, unstaged, untracked). Create multiple logical conventional commits. - -### Process - -1. Detect worktree mode: check `git rev-parse --is-inside-work-tree` and `git worktree list` -2. Review all changes above. Tracking branch "(none)" is normal for a new/unpushed branch — commits are local, proceed as usual and never try to fetch, push, or set an upstream -3. No changes → tell user nothing to commit -4. **Worktree check**: if injected **Git dir** above contains `worktrees/`, save current HEAD: `git rev-parse HEAD` → store as `$BASE_SHA` -5. **Read actual file contents** of changed/new files when diff alone insufficient -6. **Group changes into logical commits** — each = one coherent work unit: - - Related config changes together - - Feature + its tests together - - Refactors separate from features - - Docs separate from code - - No unrelated changes in one commit -7. **Order commits sensibly**: - - Infra/config first - - Refactors before dependent features - - Core before peripheral - - Tests alongside or after code they test -8. Per commit group: - a. Stage ONLY that group's files via `git add <specific files>` - b. File spans multiple groups → commit with best-fit group (`git add -p` unavailable) - c. Determine conventional commit type + scope - d. **No Jira ticket slug from branch name** - e. Craft message: **ALL LOWERCASE**, present tense, under 60 chars title - f. Execute `git commit` - g. Report what committed (including commit hash) -9. After all commits, show summary -10. **Worktree cherry-pick**: if in isolated worktree (Git dir contains `worktrees/`): - - Get main worktree path + branch from `git worktree list` (first entry) - - Use AskUserQuestion: "Cherry-pick N new commits to `<main-branch>`?" (options: "Yes, cherry-pick" / "No, skip") - - If yes: run `git -C <main-worktree-path> cherry-pick $BASE_SHA..HEAD` - - Report the result - -### Commit Format - -```bash -git commit -m "$(cat <<'EOF' -type(scope): subject - -- bullet point about change -- another bullet point -- all lowercase, no exceptions -EOF -)" -``` - -### Rules - -- **ALL LOWERCASE** — title AND body, no capitals ANYWHERE -- Present tense ("add" not "added") -- No period at end of title -- Title under 60 chars -- Specific, not vague ("fix stuff" → unacceptable) -- **FORBIDDEN**: No AI attribution, no "Co-Authored-By", no emojis, no "Generated by" -- **FORBIDDEN**: No Jira ticket slug in commit (even if branch has it) -- Each commit atomic — makes sense standalone -- All changes logically together → ONE commit, don't split for splitting's sake - -### Final Reply - -List the commits made (hash + title). In worktree mode, name the branch they landed on. diff --git a/ai-stuff/skills/auto-commit/agents/openai.yaml b/ai-stuff/skills/auto-commit/agents/openai.yaml deleted file mode 100644 index d358151e..00000000 --- a/ai-stuff/skills/auto-commit/agents/openai.yaml +++ /dev/null @@ -1,3 +0,0 @@ -interface: - display_name: "Auto Commit" - short_description: "Group changes into conventional commits and run them" diff --git a/ai-stuff/skills/aws-debug/SKILL.md b/ai-stuff/skills/aws-debug/SKILL.md deleted file mode 100644 index c6040780..00000000 --- a/ai-stuff/skills/aws-debug/SKILL.md +++ /dev/null @@ -1,171 +0,0 @@ ---- -name: aws-debug -description: This skill should be used when the user asks to "debug AWS", "check AWS resources", "why is my Lambda failing", "S3 bucket access issues", "EC2 instance status", "RDS connection problems", "check CloudWatch logs", or mentions any AWS service debugging. Automatically selects a read-only profile first and falls back to admin if the command fails with a permissions error. -argument-hint: <service/resource> [profile] [region] -allowed-tools: - - Bash(aws:*) - - Bash(cat /tmp/aws-debug-profiles.json:*) - - Bash(jq:*) - - Bash(echo:*) - - Bash(mv:*) ---- - -# AWS Debug - -Debug AWS resources using AWS CLI with automatic profile management. Prefers read-only -profiles for safety; falls back to admin profile when a command returns a permissions error. - -## Bootstrap — Profile Setup - -Config file: `/tmp/aws-debug-profiles.json` - -### Step 1: Check for existing config - -```bash -cat /tmp/aws-debug-profiles.json 2>/dev/null -``` - -If file exists and `selected.readonly` + `selected.admin` are set → skip to "Ready to Debug". - -### Step 2: Discover all profiles (first run only) - -```bash -aws configure list-profiles -``` - -Classify each by name: -- **readonly candidates**: name contains `readonly`, `read-only`, `ro`, `viewer`, `auditor`, `read` -- **admin candidates**: everything else (`admin`, `default`, `full`, `power`, unrecognized) - -### Step 3: Ask user to confirm selections - -Present classified list. Ask user to confirm or override: -- Which profile to use as **readonly** (primary) -- Which profile to use as **admin** (fallback) - -If only one profile exists → use it for both roles. - -### Step 4: Write config JSON - -```bash -cat > /tmp/aws-debug-profiles.json <<'EOF' -{ - "profiles": [ - {"name": "<profile1>", "role": "readonly"}, - {"name": "<profile2>", "role": "admin"} - ], - "selected": { - "readonly": "<readonly-profile>", - "admin": "<admin-profile>" - } -} -EOF -``` - -## Ready to Debug - -```bash -cat /tmp/aws-debug-profiles.json -``` - -Extract selected profiles with `jq` (preferred) or `grep`: -```bash -READONLY=$(jq -r '.selected.readonly' /tmp/aws-debug-profiles.json) -ADMIN=$(jq -r '.selected.admin' /tmp/aws-debug-profiles.json) -``` - -**If aws NOT FOUND** → stop, tell user: `aws` CLI required (`brew install awscli`). - -## Usage Pattern - -Always try readonly first: - -```bash -aws --profile "$READONLY" <service> <command> -``` - -If output contains `AccessDenied`, `UnauthorizedOperation`, or `is not authorized` → retry with admin: - -```bash -aws --profile "$ADMIN" <service> <command> -``` - -Note fallback in output: `(admin profile used — readonly lacked permission)` - -## Diagnose by Service - -### EC2 -1. Instance state: `aws ec2 describe-instances --instance-ids <id>` -2. Status checks: `aws ec2 describe-instance-status --instance-ids <id>` -3. Security groups: `aws ec2 describe-security-groups --group-ids <sg-id>` - -### Lambda -1. Function config: `aws lambda get-function --function-name <name>` -2. Recent invocations: `aws logs filter-log-events --log-group-name /aws/lambda/<name> --limit 50` -3. Errors: filter for "ERROR" or "Task timed out" - -### S3 -1. Bucket policy: `aws s3api get-bucket-policy --bucket <name>` -2. Access: `aws s3 ls s3://<bucket>/` -3. ACL: `aws s3api get-bucket-acl --bucket <name>` - -### RDS -1. Instance status: `aws rds describe-db-instances --db-instance-identifier <id>` -2. Events: `aws rds describe-events --source-identifier <id> --source-type db-instance` -3. Logs: `aws rds describe-db-log-files --db-instance-identifier <id>` - -### CloudWatch -1. Alarms: `aws cloudwatch describe-alarms --state-value ALARM` -2. Metrics: `aws cloudwatch get-metric-statistics ...` -3. Log insights: `aws logs start-query ...` - -### IAM -1. User policies: `aws iam list-attached-user-policies --user-name <name>` -2. Role policies: `aws iam list-attached-role-policies --role-name <name>` -3. Policy document: `aws iam get-policy-version --policy-arn <arn> --version-id v1` - -## Report Format - -```markdown -## AWS Investigation: <service> (<profile> / <region>) - -**Resource:** <identifier> - -### Status -<current state, health, relevant config> - -### Issue Found -<specific problem with evidence: error message, misconfiguration, permission denied> - -### Evidence -- API response: <relevant fields> -- Logs: <error lines> -- Config: <problematic setting> - -### Recommended Fix -- <specific action to resolve> -- <AWS Console path or CLI command for user to run> -``` - -## Rules - -- **Profile required** — never run AWS commands without profile set -- **Read-only default** — describe/get/list commands only; suggest mutations, don't execute -- **Bound output** — use `--limit`, `--max-items`, or pipe to `head` for large results -- **Confirm destructive** — if user asks for modify/delete, print command but don't run -- **Region awareness** — use `--region` when resource is region-specific - -## Change Profile - -User says "switch profile", "use different profile", or "change readonly/admin profile": - -1. Show current config: `cat /tmp/aws-debug-profiles.json` -2. Ask which role to change and what to set it to -3. Update with `jq`: - ```bash - jq '.selected.readonly = "<new>"' /tmp/aws-debug-profiles.json > /tmp/aws-debug-profiles.json.tmp \ - && mv /tmp/aws-debug-profiles.json.tmp /tmp/aws-debug-profiles.json - ``` - (replace `.selected.readonly` with `.selected.admin` as needed) - -To re-run full discovery: `rm /tmp/aws-debug-profiles.json` then restart skill. diff --git a/ai-stuff/skills/aws-debug/agents/openai.yaml b/ai-stuff/skills/aws-debug/agents/openai.yaml deleted file mode 100644 index 05a4a413..00000000 --- a/ai-stuff/skills/aws-debug/agents/openai.yaml +++ /dev/null @@ -1,3 +0,0 @@ -interface: - display_name: "AWS Debug" - short_description: "Debug AWS resources, read-only profile first" diff --git a/ai-stuff/skills/create-pr/SKILL.md b/ai-stuff/skills/create-pr/SKILL.md deleted file mode 100644 index 4b476aa3..00000000 --- a/ai-stuff/skills/create-pr/SKILL.md +++ /dev/null @@ -1,254 +0,0 @@ ---- -name: create-pr -description: Create a GitHub PR or GitLab MR for the current branch. Use when the user asks to open, create, or raise a PR or MR, says "ship it" after committing, or wants the branch put up for review. Pass 'gh' or 'gl' to skip VCS detection. -argument-hint: "[gh|gl]" -context: fork -model: sonnet -allowed-tools: - - Read - - Grep - - Glob - - Bash(git status:*) - - Bash(git diff:*) - - Bash(git log:*) - - Bash(git branch:*) - - Bash(git rev-parse:*) - - Bash(git show:*) - - Bash(git symbolic-ref:*) - - Bash(git config --get remote.origin.url) - - Bash(git remote -v:*) - - Bash(git worktree list:*) - - Bash(rtk git status:*) - - Bash(rtk git diff:*) - - Bash(rtk git log:*) - - Bash(rtk git branch:*) - - Bash(rtk git rev-parse:*) - - Bash(rtk git show:*) - - Bash(rtk git symbolic-ref:*) - - Bash(rtk git config --get remote.origin.url) - - Bash(rtk git remote -v:*) - - Bash(rtk git worktree list:*) - - - Bash(gh pr view:*) - - Bash(gh pr view:*) - - Bash(gh pr diff:*) - - Bash(rtk gh pr edit:*) - - Bash(rtk gh pr diff:*) - - Bash(rtk gh pr edit:*) - - - Bash(glab mr view:*) - - Bash(glab mr diff:*) - - Bash(glab mr update:*) - - Bash(echo:*) - - Bash(rtk glab mr view:*) - - Bash(rtk glab mr diff:*) - - Bash(rtk glab mr update:*) - - Bash(echo:*) - - - Bash(head:*) - - Bash(~/.config/ai-shared/scripts/pr-status.sh) ---- - -# Create Pull Request / Merge Request - -> **Non-Claude tools:** if the context lines below still show raw -> bang-backtick placeholders instead of real command output, Claude's eager -> injection didn't run. Run those commands yourself and use their output -> wherever the instructions say "injected". An unsubstituted argument slot -> means no argument was passed, so treat it as empty. - -## Configuration - -Read [git config](../_shared/config/git-config.md). - -## VCS Selection - -User provided VCS hint: $0 - -- Git remote URL: !`git remote -v 2>/dev/null | head -1` - -Determine VCS (in order of priority): - -- If hint is "gh": Use GitHub -- If hint is "gl": Use GitLab -- If hint is empty: check the injected remote URL above — if it contains `git.treatwell.net` → GitLab, otherwise → GitHub - -## Current Context - -### Worktree Info - -- Worktree root: !`git rev-parse --show-toplevel 2>/dev/null` -- Git dir: !`git rev-parse --git-dir 2>/dev/null` -- Is in worktree: !`git rev-parse --is-inside-work-tree 2>/dev/null` -- Worktree list: !`git worktree list 2>/dev/null | head -5` - -### Branch Info - -- Current branch: !`git branch --show-current 2>/dev/null` -- Remote HEAD: !`git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null` -- Tracking branch: !`git rev-parse --abbrev-ref --symbolic-full-name @{u} 2>/dev/null || echo "none"` -- Branches in repo: !`git branch -v | head -10` - -### PR/MR Status - -!`~/.config/ai-shared/scripts/pr-status.sh` - -### Recent Commits on Branch - -!`git log --oneline -10 2>/dev/null` - -## Instructions - -Create a PR/MR with optional VCS hint to skip detection. Permission system handles user confirmation. - -### Worktree-Aware Workflow - -**If working in a worktree (background job isolated mode):** - -- Worktree branch is isolated; main repo has separate branch checkout -- **Action needed**: Before creating PR, sync worktree commits to target branch in main repo: - 1. If target branch is already checked out in main repo → cherry-pick commits from worktree branch - 2. If target branch doesn't exist in main repo → create it first from main/origin - 3. Note worktree branch name and sync method to user -- After sync, create PR/MR from the synced branch in main repo - -**If NOT in a worktree:** - -- Standard workflow: branch is in main repo, push and create PR/MR directly - -### Process - -0. **Set working directory**: Run `cd <worktree-root>` using the injected "Worktree root" value above — ensures all subsequent git commands run in the correct worktree, not the main repo root -1. Detect worktree mode: check `git worktree list` output -2. If in worktree: - - Identify current worktree branch (usually auto-named from worktree dir) - - Check if a target branch was intended (look for DEVX- tickets in branch name or user context) - - List commits that need syncing: `git log <target-branch>..HEAD --oneline` - - Instruct user on sync method OR automatically suggest cherry-pick command -3. Check VCS hint from `$0`: - - If "gh": Use GitHub (gh CLI) - - If "gl": Use GitLab (glab CLI) - - If empty: Auto-detect from repo context -4. Review the context above - VCS type, branch info, existing PR/MR status -5. If PR/MR already exists, automatically update its title and description to reflect current changes -6. Analyze the diff summary and commits to understand the changes -7. Extract ticket from branch name if present (e.g., `feature/DEVX-123-something`) -8. Craft title: - - If Jira ticket found: `DEVX-123: Title here` (normal sentence casing!) - - If no ticket: Use conventional commit format: `feat|fix|docs|refactor|...: Title here` -9. Build body with mandatory sections: Summary, Changes, Additional Notes -10. For GitHub: Push branch with `git push -u origin HEAD` before PR creation (handles both worktree and main repo) -11. Execute the pr/mr create command (permission system prompts user) -12. Report the URL -13. **Worktree cleanup note**: Mention that worktree can be kept or removed via `ExitWorktree` after PR merge - -### Execution Behavior - -- If in worktree: Check whether commits need to sync to main repo first (cherry-pick or reset target branch) -- If PR/MR exists: Use `gh pr edit` or `glab mr update` to update title and description -- If no PR/MR: Use `gh pr create` or `glab mr create` to create new -- **GitHub**: Push branch first with `git push -u origin HEAD` before creating PR (works in both worktree and main) -- **GitLab**: Push handled by `glab mr create --push` (works in both worktree and main) -- Permission system will prompt user for confirmation -- DO NOT output commands for copy-paste -- **GitHub**: DO NOT escape backticks - CLI handles this -- **GitLab**: ESCAPE ALL BACKTICKS with backslash (\`) in description - glab CLI doesn't handle this -- **Worktree detection**: If worktree detected, clarify branch sync before pushing -- **CWD**: Always `cd` to injected Worktree root first — CWD may be main repo root when skill loads -- cd → Detect → Check worktree → Sync if needed → Analyze → Craft → Push → Execute (create or update) → Report URL - -### GitHub PR Command - -```bash -gh pr create \ - --head $(git branch --show-current) \ - --base <base-branch> \ - --title "DEVX-123: Description here" \ - --body "## Summary -Brief description of changes - -## Changes -- Change 1 -- Change 2 - -## Additional Notes -Any extra context" -``` - -### GitLab MR Command (ugh) - -**IMPORTANT**: Escape all backticks with `\` in the description! - -```bash -glab mr create \ - --push \ - --target-branch <base-branch> \ - --title "DEVX-123: Description here" \ - --description "## Summary -Brief description of changes - -## Changes -- Added \`someFunction\` to handle X -- Updated \`config.ts\` for Y - -## Additional Notes -Any extra context" -``` - -### Update Existing PR (GitHub) - -```bash -gh pr edit <number> \ - --title "DEVX-123: Updated description" \ - --body "## Summary -Updated description of ALL changes in branch - -## Changes -- All changes from all commits -- Not just the latest - -## Additional Notes -Any extra context" -``` - -### Update Existing MR (GitLab) - -**IMPORTANT**: Escape all backticks with `\` in the description! - -```bash -glab mr update <number> \ - --title "DEVX-123: Updated description" \ - --description "## Summary -Updated description of ALL changes in branch - -## Changes -- Updated \`someFile.ts\` with new logic -- Refactored \`utils/helper.ts\` - -## Additional Notes -Any extra context" -``` - -### Rules - -- **USE NORMAL SENTENCE CASING** - PR/MR body is NOT lowercase like commits -- Capitalize first letters of sentences, proper nouns, headings in body sections -- Write like a human would write documentation -- Mandatory sections: Summary, Changes, Additional Notes -- After creation, provide URL: `[PR Title](URL)` -- **FORBIDDEN**: No AI attribution, no "Generated by", no "Co-Authored-By" -- **Title format**: - - If Jira ticket in branch name: `DEVX-123: Description here` - - If no ticket: Use conventional commits: `feat: Add new feature`, `fix: Resolve bug`, `docs: Update docs`, `refactor: Improve structure`, etc. -- Determine commit type by analyzing the changes: - - `feat`: New features or functionality - - `fix`: Bug fixes - - `docs`: Documentation updates - - `refactor`: Code refactoring without feature/fix changes - - `perf`: Performance improvements - - `test`: Adding/updating tests - - `chore`: Dependencies, build config, tooling - -### Final Reply - -Reply with the PR/MR link as `[title](url)`. In worktree mode, add one line saying the worktree can be removed with `ExitWorktree`. diff --git a/ai-stuff/skills/create-pr/agents/openai.yaml b/ai-stuff/skills/create-pr/agents/openai.yaml deleted file mode 100644 index 442b321c..00000000 --- a/ai-stuff/skills/create-pr/agents/openai.yaml +++ /dev/null @@ -1,3 +0,0 @@ -interface: - display_name: "Create PR" - short_description: "Open a GitHub PR or GitLab MR for the current branch" diff --git a/ai-stuff/skills/create-story/SKILL.md b/ai-stuff/skills/create-story/SKILL.md deleted file mode 100644 index c60067d6..00000000 --- a/ai-stuff/skills/create-story/SKILL.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -name: create-story -description: Create a Jira story with proper ADF formatting. Use when the user asks to create a Jira story, ticket, or issue, wants requirements or notes turned into a ticket, or says "make a story for X". -context: fork -model: sonnet -allowed-tools: mcp__claude_ai_Atlassian_MCP__getJiraIssue, Read -argument-hint: <story description or requirements> ---- - -# Create Jira Story - -## Configuration -Read [jira config](../_shared/config/jira-config.md). - -## Instructions - -Create properly formatted Jira Story for DEVX project. - -### Process - -1. Parse user description from: `$ARGUMENTS` -2. **NEVER** call lookup APIs - use hardcoded values: - - cloudId: `56552dac-b6cf-4e59-aa06-5e075dca9f8e` - - projectKey: `DEVX` - - issueTypeName: `Story` -3. Craft concise, action-oriented summary -4. Build description in **MARKDOWN** format: - ```markdown - ## Problem - [What needs to be done] - - ## Proposed Solution - [How we'll solve it] - - ## Implementation Details - [Technical specifics] - ``` -5. Create `customfield_14105` (Reason for change) in **ADF** format - REQUIRED! -6. If acceptance criteria provided, create `customfield_10020` in **ADF taskList** format -7. Execute `mcp__claude_ai_Atlassian_MCP__createJiraIssue` -8. Provide the issue URL: `[DEVX-XXX](https://wahanda.atlassian.net/browse/DEVX-XXX)` - -### Critical Reminders - -- Description = MARKDOWN, Custom fields = ADF -- NEVER put acceptance criteria in description - use `customfield_10020`! -- NEVER use markdown checkboxes (`- [ ]`) - they don't render! -- Each taskItem needs a unique localId (UUID format) -- `customfield_14105` REQUIRED - always include! - -### Final Reply - -Reply with only `[DEVX-XXX](https://wahanda.atlassian.net/browse/DEVX-XXX)`. diff --git a/ai-stuff/skills/create-story/agents/openai.yaml b/ai-stuff/skills/create-story/agents/openai.yaml deleted file mode 100644 index 075ed6f3..00000000 --- a/ai-stuff/skills/create-story/agents/openai.yaml +++ /dev/null @@ -1,3 +0,0 @@ -interface: - display_name: "Create Story" - short_description: "Create a Jira story with proper ADF formatting" diff --git a/ai-stuff/skills/daily-recap/SKILL.md b/ai-stuff/skills/daily-recap/SKILL.md deleted file mode 100644 index 8d9e8c19..00000000 --- a/ai-stuff/skills/daily-recap/SKILL.md +++ /dev/null @@ -1,421 +0,0 @@ ---- -name: daily-recap -model: sonnet -effort: high -description: "Fetch today's activity from Slack, Gmail, and Google Calendar, then update/create your daily note in the vault with a recap and standup draft." -disable-model-invocation: true -argument-hint: "[YYYY-MM-DD] (defaults to today)" -allowed-tools: - - Read - - Glob - - Grep - - Bash(obsidian read:*) - - Bash(obsidian append:*) - - Bash(obsidian templates:*) - - Bash(obsidian create:*) - - Bash(obsidian file:*) - - Bash(obsidian files:*) - - Bash(obsidian folder:*) - - Bash(obsidian folders:*) - - Bash(obsidian search:*) - - Bash(obsidian outline:*) - - Bash(obsidian tags:*) - - Bash(obsidian properties:*) - - Bash(obsidian help:*) - - Bash(sleep:*) - - Bash(ls:*) - - Bash(cat:*) - - Bash(date:*) - - Bash(find:*) - - Bash(python3 ~/.claude/skills/daily-recap/scripts/summarize-claude-sessions.py:*) - - Bash(claude -p:*) - # Slack (read-only) - - mcp__claude_ai_Slack__slack_search_public_and_private - - mcp__claude_ai_Slack__slack_search_public - - mcp__claude_ai_Slack__slack_read_channel - - mcp__claude_ai_Slack__slack_read_thread - - mcp__claude_ai_Slack__slack_read_user_profile - - mcp__claude_ai_Slack__slack_search_channels - - mcp__claude_ai_Slack__slack_search_users - # Gmail (read-only) - - mcp__claude_ai_Gmail__gmail_search_messages - - mcp__claude_ai_Gmail__gmail_read_message - - mcp__claude_ai_Gmail__gmail_read_thread - - mcp__claude_ai_Gmail__gmail_get_profile - - mcp__claude_ai_Gmail__gmail_list_labels - # Google Calendar (read-only) - - mcp__claude_ai_Google_Calendar__list_events - - mcp__claude_ai_Google_Calendar__get_event - - mcp__claude_ai_Google_Calendar__list_calendars - - mcp__claude_ai_Google_Calendar__find_my_free_time - # Google Drive (read-only — meeting notes) - - mcp__claude_ai_Google_Drive__read_file_content - - mcp__claude_ai_Google_Drive__search_files - # Headroom — decompress truncated tool results - - mcp__headroom__headroom_retrieve ---- - -# Daily Recap - -Fetch today's Slack/Gmail/Calendar activity. Synthesize → daily recap → update vault. - -## Injected context - -- Today's date: !`date +%Y-%m-%d` -- Tomorrow's date: (today + 1 day — derive from the today date above) -- Existing daily notes: !`ls "/Users/denizgokcin/Library/Mobile Documents/iCloud~md~obsidian/Documents/vault/work/daily notes/" 2>/dev/null` -- Output template: read [daily-recap-output.md](../_shared/templates/daily-recap-output.md) — relative to this skill's directory - -## Constants - -- **Vault**: `vault` -- **Vault path**: `/Users/denizgokcin/Library/Mobile Documents/iCloud~md~obsidian/Documents/vault` -- **Daily notes dir**: `work/daily notes/` -- **Timezone**: `Europe/Amsterdam` -- **Slack user ID**: `U07QR93GVRU` - -## Rules for tool usage - -- **NEVER use `cd`** — obsidian CLI works from any cwd. Call `obsidian ...` directly. `cd` → permission prompts + wasted tokens. -- **NEVER escape spaces in obsidian args** — CLI handles vault path internally; pass `path="work/daily notes"` as-is. -- Use injected context above instead of re-running `ls`, `date`, or `cat` on template. - -## Instructions - -### Step 1: Determine date - -Parse from `$ARGUMENTS`: - -- Date like `2026-03-23`: use that -- Empty: use today from injected context - -### Step 2: Gather data (all in parallel, including 2h) - -#### 2a. Today's calendar events - -Fetch today's events via `gcal_list_events`: - -- Start: `YYYY-MM-DDT00:00:00` -- End: `YYYY-MM-DDT23:59:59` -- Note titles, times, attendees - -**If response contains `[N items compressed... hash=XXX]`:** immediately call `mcp__headroom__headroom_retrieve(hash: "XXX", query: "meeting attachments Gemini summary")` to get the full event list with attachment URLs. This is critical for step 2i — compressed calendar responses drop attachment fileUrls needed for Gemini notes. - -#### 2b. Tomorrow's calendar events - -Fetch tomorrow's events for standup prep. - -#### 2c. Slack — your thread activity (PRIMARY source) - -Highest-signal query. Shows thread replies grouped by topic. - -``` -slack_search_public_and_private( - query: "on:YYYY-MM-DD is:thread from:<@U07QR93GVRU>", - sort: "timestamp", - limit: 20, - include_context: true, - response_format: "detailed" -) -``` - -Captures: support threads, code review discussions, technical questions answered, decisions. Context messages show what was asked + what you replied — best signal for "what you did". - -> 20 results → paginate via `cursor` from `pagination_info`. - -#### 2d. Slack — messages sent to you (incoming work) - -``` -slack_search_public_and_private( - query: "on:YYYY-MM-DD to:<@U07QR93GVRU>", - sort: "timestamp", - limit: 20, - include_context: true, - response_format: "detailed" -) -``` - -Captures: Jira bot notifications, PR approval requests, direct questions, alerts. → "needs attention" bucket. - -#### 2e. Slack — all messages you sent (SUPPLEMENTARY) - -Only use if 2c returned <5 results — otherwise redundant. - -``` -slack_search_public_and_private( - query: "on:YYYY-MM-DD from:<@U07QR93GVRU>", - sort: "timestamp", - limit: 20, - include_context: true, - response_format: "detailed" -) -``` - -Broader sweep. Catches non-threaded channel msgs + DMs. Noisy — includes casual chat. Apply heavy filtering. - -#### 2f. Slack — read specific threads for deeper context - -If search result looks like meaty work discussion but context truncated, use `slack_read_thread`: - -``` -slack_read_thread( - channel_id: "<channel_id from search result>", - message_ts: "<parent thread_ts>", - response_format: "concise" -) -``` - -#### 2g. Gmail — today's emails - -Use `gmail_search_messages` with multiple targeted searches: - -**General:** - -``` -query: "after:YYYY/MM/DD before:YYYY/MM/DD+1" -``` - -**GitLab-specific** (MR reviews, pipeline updates, mentions): - -``` -query: "from:gitlab@twtools.io after:YYYY/MM/DD before:YYYY/MM/DD+1" -``` - -Look for: - -- **MR review requests** — your MR needs review or you're assigned reviewer -- **MR approvals/changes** — feedback on your MRs -- **Pipeline notifications** — CI/CD failures or successes on your branch/MR -- **Mentions** — @mentioned in MR comment or issue -- **MR merges** — your MR or related MRs merged - -**Jira-specific:** - -``` -query: "from:jira@wahanda.atlassian.net after:YYYY/MM/DD before:YYYY/MM/DD+1" -``` - -Look for: - -- **New tickets assigned** → `## recap → needs attention` tag `#new-ticket` -- **Status changes on your tickets** — context for what changed -- **Comments on watched tickets** — flag `#review-feedback` if actionable -- **Blocker notifications** — tickets blocking you or blocked by you - -Read most relevant emails via `gmail_read_message`. Focus on: action items, decisions made, unresolved items. Skip automation spam + FYI-only. - -#### 2h. Dia browser — daily activity summary - -Dia generates daily activity summaries as HTML. Captures work context Slack/Gmail misses (browsing, GitLab MR reviews in browser, etc.). - -**Dia context files injected above.** Pick most recent date → read via Read tool. - -**No output** → skip silently. - -**Parse HTML** — look for: - -- `.section` with label **"Completed"** → `.item h3` + `.item p` + `.tag` spans -- `.section` with label **"Meetings"** → `.meeting` rows (time + title) -- `.section` with label **"Tomorrow"** → `.next-item` rows - -**No context modified today** → skip silently. - -**Merge into Step 4:** - -- Dia "Completed" → Bucket 1 (today). No dups from Slack/Gmail. Dia has richer descriptions of browser work. -- Dia "Tomorrow" → Bucket 2 (notes for tomorrow) -- Dia tags (e.g. `DEVX-1111`, `Datadog`) → context only, not literal Obsidian tags - -#### 2i. Google Drive — Gemini meeting notes - -For each meeting from step 2a that has an `attachments` entry with a Google Docs URL (Gemini auto-notes): - -1. Extract the `fileId` from the attachment URL: `https://docs.google.com/document/d/{fileId}/edit?...` -2. Fetch in parallel: `mcp__claude_ai_Google_Drive__read_file_content(fileId: "{fileId}")` -3. From the response parse: **Summary**, **Decisions** (Aligned + Needs Further Discussion), **Next steps** -4. Filter next steps to only items assigned to you (your name appears in the bracket) - -**Fallback — attachment missing but meeting already ended:** Gemini attaches the notes doc to the calendar event asynchronously; if the meeting's `end` time is in the past relative to the run and the event has no `attachments` field, the doc may exist even though the calendar API hasn't linked it yet. For every ended meeting with ≥2 attendees and no `attachments` field, search Drive as a fallback before giving up: - -``` -mcp__claude_ai_Google_Drive__search_files( - query: "title contains '<event summary>' and mimeType contains 'application/vnd.google-apps.document' and modifiedTime > 'YYYY-MM-DDT00:00:00Z'" -) -``` - -Match the returned file's title/date against the event. If found, treat it exactly like an attachment-sourced doc (proceed to steps 2–4 above). If Drive search returns nothing either, skip silently — the doc genuinely doesn't exist yet or was never generated (standup, focus time, 1:1 without notes enabled, etc.). - -**Skip silently if:** - -- Meeting has no attachments / no Docs URL AND the Drive fallback search above also finds nothing (e.g. standup without notes, focus time, lunch) -- `read_file_content` returns "not found" or permission error - -**Do NOT fetch the transcript** — the Summary + Decisions + Next steps sections are sufficient. - -#### 2i-vault. Enrich vault meeting notes with Gemini data - -For each meeting where Gemini data was successfully fetched (step 2i above): - -1. **Find vault note** — search for notes in `work/meetings` on the target date: - - ```bash - obsidian search query="YYYY-MM-DD" path="work/meetings" format=json - ``` - - Returns a JSON array of paths like `["work/meetings/YYYY-MM-DD title.md", ...]`. - -2. **Match meeting to note** — compare calendar event title to vault note filename (case-insensitive, partial match). If multiple notes exist for the date, pick the one whose filename most closely matches the calendar event title. - - **If no match → CREATE the note (never skip).** Deniz wants every meeting with Gemini notes to have a vault note (2026-09-02): - - ```bash - obsidian create name="<event title, lowercase>" template="meeting-template" silent - sleep 4 # Templater must finish before the next step - ``` - - Templater stamps `tp.date.now()`, so the note lands as `work/meetings/<TODAY> <title>.md`. If the target date is not today, move it and fix the dates: - - ```bash - obsidian move path="work/meetings/<TODAY> <title>.md" to="work/meetings/YYYY-MM-DD <title>.md" - ``` - - Then overwrite the file body (heredoc via Bash is fine — the template only matters for the move + frontmatter shape): set `date: YYYY-MM-DD HH:mm` (meeting start), `Date: [[YYYY-MM-DD]]`, H1 `# [[YYYY-MM-DD <title>]]`, `summary:` = Gemini one-liner. Fill the template sections from Gemini data: - - **Attendees** → calendar attendees as `[[first last]]` wikilinks (resolve via step 2k; plain text if no people note), skip rooms/group aliases - - **Agenda** → one sentence derived from the Summary - - **Questions** → open questions from Details / "Needs Further Discussion" - - **Notes** → bullets from Summary + Details (the meaty technical context, not the transcript) - - **Action Items** → all Next steps as `- [ ] [[owner]] — item`; Deniz's already-completed ones as `- [x] ... ✅ YYYY-MM-DD` with MR links - - A created note counts as "found" for steps 3–5 below (skip step 5's `## Gemini Notes` append — the content is already in the template sections) and for the `### meetings` block + `[[wikilink]]` task line in Step 5. - - -3. **Check for existing Gemini section** — read the note and check if a `## Gemini Notes` section already exists. If yes → skip (don't overwrite). - -4. **Set frontmatter summary** — set the `summary` property to the one-sentence Gemini summary: - - ```bash - obsidian property:set name="summary" value="<one-sentence summary>" file="YYYY-MM-DD title" - ``` - -5. **Append Gemini data** — build the section and append: - - ```bash - obsidian append path="work/meetings/YYYY-MM-DD title.md" content="\n## Gemini Notes\n\n**Summary:** <one-sentence summary>\n\n**Decisions:**\n- <aligned decisions>\n\n**Open items:**\n- <items needing further discussion — omit section if none>\n\n**My next steps:**\n- <items assigned to you — omit section if none>" - ``` - - Use `\n` for newlines. Omit empty sections entirely. - -#### 2j. Claude Code sessions (Haiku subagent) - -Run the companion script to extract session data, then pipe to a Haiku 5.5 subagent for summarization. This captures engineering work that never surfaces in Slack or Gmail (local coding, debugging, config changes, dotfiles work). - -```bash -python3 ~/.claude/skills/daily-recap/scripts/summarize-claude-sessions.py YYYY-MM-DD | \ - claude -p --model claude-haiku-5-5 \ - "Summarize these Claude Code sessions into 2-5 bullet points of what engineering work was done. Focus on: features built, tickets worked, bugs debugged, code changed. Skip meta/tooling sessions (e.g. only ran 'exit', only did shell commands with no edits). Max one line per bullet. Output plain bullets only." -``` - -**No sessions found** → skip silently (script exits 0 with a note). - -**Merge into step 4:** - -- Session bullets → `## today` (engineering work items, mark as `- [x]`) -- Dedup against Slack/GitLab items already found (same ticket or task → merge, don't repeat) - -#### 2k. Resolve person names to vault wikilinks - -After all data is gathered, collect every person name that appears in the recap data (Slack messages, meeting attendees, email senders/recipients, Gemini next steps, etc.). For each unique name: - -1. Search the vault people directory: - - ```bash - obsidian search query="<first> <last>" path="work/people" format=json - ``` - -2. If a match is returned → record the mapping: `"First Last" → [[First Last]]` (use the filename without `.md` as the link target). - -3. If no match → leave as plain text (never invent a wikilink). - -**Apply the map in steps 4 and 5:** whenever a person name appears in output (task lines, recap bullets, meeting next steps, needs-attention items), substitute the plain name with its resolved `[[wikilink]]`. Do this consistently — same person always gets the same wikilink throughout the note. - -**Efficiency:** batch all name lookups in parallel. Skip clearly non-person tokens (team names, Jira bots, GitLab automation). - -### Slack filtering guidance - -**Keep** (work signal): - -- Thread replies in team channels (#team-devx-public, #team-devx-private, etc.) -- Code review discussions (MR links, GitLab/GitHub links) -- Support given -- Technical decisions -- Jira ticket assignments/updates -- PR approval requests - -**Skip** (noise): - -- Personal DM chatter (physio, office plans, social) -- Short acks ("hi", "yess", "sure", emoji-only) -- Pure-info bot messages (unless actionable) -- Non-work channels unless work discussion inside - -### Step 3: Ensure daily note exists - -**Note**: Vault uses Periodic Notes community plugin, NOT core Daily Notes. `obsidian daily:*` commands will NOT work. - -Check injected **"Existing daily notes"** list: - -- **`YYYY-MM-DD.md` in list**: note exists → read with `obsidian read path="work/daily notes/YYYY-MM-DD.md"` -- **Not in list**: create from template: - - ```bash - obsidian create name="YYYY-MM-DD" path="work/daily notes" template="daily-template" silent - ``` - - Wait (`sleep 3`) for Templater to process, then read. - -### Step 4: Synthesize and format output - -Output template injected above under "Output template". Use for exact structure, formatting, examples, rules. Do NOT re-read it. - -Template defines three sections. Analyze all data → populate each following template exactly. - -### Step 5: Write to vault - -Three separate edits (see template for exact content format): - -1. **`## today`** — append `- [x]` task lines (replace placeholder `- [ ]` if present, else append after existing tasks). Include session bullets from step 2j as engineering work items; dedup against Slack/GitLab items already found. **Meetings with a vault note** (found in step 2i-vault): use a wikilink `[[YYYY-MM-DD meeting title]]` (note filename without `.md`) as the task text instead of plain text — e.g. `[[2026-06-24 roadmap discussion]]`. -2. **`## notes for tomorrow`** — insert calendar + standup draft -3. **`## recap`** — append as new section at very bottom. Always includes `### needs attention`. If meeting notes were fetched in step 2i, also include `### meetings`: - -```markdown -### meetings - -#### [[YYYY-MM-DD meeting title]] - -**Summary:** one-sentence -**Decisions:** bullet list (aligned items first, then open items if any) -**My next steps:** bullet list — only items assigned to you; omit if none -``` - -Use `[[YYYY-MM-DD meeting title]]` (matching the vault note filename without `.md`) as the heading — this creates a backlink. Only meetings where a vault note was found and enriched (step 2i-vault) should appear here. - -Omit the `### meetings` subsection entirely if no meeting notes were accessible. - -Read daily note to find each section, then use `Edit` to insert. - -### Step 6: Summary - -Brief conversational summary after writing: - -- One line on overall day vibe -- 1-2 things needing attention tomorrow -- Confirm file updated - -## Rules - -- **Follow output template** — `../_shared/templates/daily-recap-output.md` (relative to this skill's directory) has all formatting/voice/structure rules -- **Don't invent data** — only include what found in Slack/Gmail/Calendar/Dia -- **Skip noise** — ignore bot spam, non-actionable automated notifications -- **Group intelligently** — multiple Slack msgs on same topic → one task line -- **Respect existing content** — never overwrite existing tasks or notes, only append/insert -- **NEVER create daily note with Write tool** — always use `obsidian create name="YYYY-MM-DD" path="work/daily notes" template="daily-template" silent` via Bash. Template has Templater logic Obsidian must process. Manual write → broken note. diff --git a/ai-stuff/skills/daily-recap/agents/openai.yaml b/ai-stuff/skills/daily-recap/agents/openai.yaml deleted file mode 100644 index 86387460..00000000 --- a/ai-stuff/skills/daily-recap/agents/openai.yaml +++ /dev/null @@ -1,5 +0,0 @@ -interface: - display_name: "Daily Recap" - short_description: "Recap today from Slack, Gmail, Calendar into the vault" -policy: - allow_implicit_invocation: false diff --git a/ai-stuff/skills/daily-recap/scripts/summarize-claude-sessions.py b/ai-stuff/skills/daily-recap/scripts/summarize-claude-sessions.py deleted file mode 100644 index 4c049a36..00000000 --- a/ai-stuff/skills/daily-recap/scripts/summarize-claude-sessions.py +++ /dev/null @@ -1,229 +0,0 @@ -#!/usr/bin/env python3 -""" -Summarize Claude Code sessions for a given date. -Outputs structured text suitable for LLM summarization. - -Usage: python3 summarize-claude-sessions.py [YYYY-MM-DD] - Defaults to today in Europe/Amsterdam timezone. -""" - -import json -import os -import re -import sys -from datetime import datetime -from zoneinfo import ZoneInfo - - -TZ = ZoneInfo("Europe/Amsterdam") -PROJECTS_DIR = os.path.expanduser("~/.claude/projects") -# Minimum lines to consider a session substantive -MIN_LINES = 5 - - -def main(): - date_str = sys.argv[1] if len(sys.argv) > 1 else datetime.now(tz=TZ).strftime("%Y-%m-%d") - - try: - target_date = datetime.strptime(date_str, "%Y-%m-%d").date() - except ValueError: - print(f"Error: invalid date '{date_str}', expected YYYY-MM-DD", file=sys.stderr) - sys.exit(1) - - sessions = [] - - for project_dir in sorted(os.listdir(PROJECTS_DIR)): - proj_path = os.path.join(PROJECTS_DIR, project_dir) - if not os.path.isdir(proj_path): - continue - - for fname in os.listdir(proj_path): - if not fname.endswith(".jsonl"): - continue - fp = os.path.join(proj_path, fname) - - # Quick mtime pre-filter: skip files not touched on target date - try: - mtime = os.path.getmtime(fp) - mtime_date = datetime.fromtimestamp(mtime, tz=TZ).date() - if mtime_date != target_date: - continue - except OSError: - continue - - data = parse_session(fp, target_date) - if data: - sessions.append(data) - - if not sessions: - print(f"No Claude Code sessions found for {date_str}.") - sys.exit(0) - - # Sort by start time - sessions.sort(key=lambda s: s["start_time"]) - - lines = [f"Claude Code sessions for {date_str} ({len(sessions)} sessions):\n"] - for i, s in enumerate(sessions, 1): - lines.append(f"--- Session {i} ---") - lines.append(f"Project: {s['project']}") - lines.append(f"Directory: {s['cwd']}") - lines.append(f"Time: {s['start_time_str']} ({s['duration_min']}min)") - lines.append(f"Task: {s['first_user_msg']}") - if s["tool_summary"]: - lines.append(f"Activity: {s['tool_summary']}") - if s["last_assistant_text"]: - lines.append(f"Outcome: {s['last_assistant_text']}") - lines.append("") - - print("\n".join(lines)) - - -def parse_session(fp: str, target_date) -> dict | None: - try: - with open(fp) as f: - raw_lines = f.readlines() - except (PermissionError, OSError): - return None - - if len(raw_lines) < MIN_LINES: - return None - - first_user_msg = None - last_assistant_text = None - tool_calls = [] - timestamps = [] - cwd = None - - for raw in raw_lines: - try: - obj = json.loads(raw) - except json.JSONDecodeError: - continue - - # Collect timestamps (ISO 8601 string like "2026-06-23T12:18:10.948Z") - ts = obj.get("timestamp") - if ts and isinstance(ts, str): - try: - dt = datetime.fromisoformat(ts.replace("Z", "+00:00")).astimezone(TZ) - if dt.date() == target_date: - timestamps.append(dt) - except ValueError: - pass - - if not cwd and obj.get("cwd"): - cwd = obj["cwd"] - - kind = obj.get("type") - msg = obj.get("message", {}) - content = msg.get("content", []) if isinstance(msg, dict) else [] - - if kind == "user": - # Skip meta messages (skill body injections, system context) - if obj.get("isMeta"): - continue - - # Content can be a string (skill invocations) or list (regular messages) - raw_content = msg.get("content", "") - - if isinstance(raw_content, str) and first_user_msg is None: - # Skill invocation: extract <command-args> if present, else raw text - args_match = re.search(r"<command-args>(.*?)</command-args>", raw_content, re.DOTALL) - if args_match: - first_user_msg = args_match.group(1).strip()[:400] - elif not raw_content.startswith("<"): - first_user_msg = raw_content.strip()[:400] - - elif isinstance(raw_content, list) and first_user_msg is None: - for c in raw_content: - if not isinstance(c, dict) or c.get("type") != "text": - continue - text = c.get("text", "").strip() - if text and not text.startswith("<") and not text.startswith("[Image"): - first_user_msg = text[:400] - break - - if kind == "assistant" and isinstance(content, list): - for c in content: - if not isinstance(c, dict): - continue - if c.get("type") == "text": - text = c.get("text", "").strip() - if text: - last_assistant_text = text[:250] - elif c.get("type") == "tool_use": - tool_calls.append((c.get("name", ""), c.get("input", {}))) - - # Only include sessions with activity on the target date - if not timestamps: - return None - - start_dt = min(timestamps) - end_dt = max(timestamps) - duration_min = max(1, int((end_dt - start_dt).total_seconds() / 60)) - project = os.path.basename(cwd) if cwd else os.path.basename(fp).replace(".jsonl", "") - - return { - "project": project, - "cwd": cwd or "unknown", - "start_time": start_dt, - "start_time_str": start_dt.strftime("%H:%M"), - "duration_min": duration_min, - "first_user_msg": first_user_msg or "(no message)", - "last_assistant_text": _trim_to_sentence(last_assistant_text or ""), - "tool_summary": _summarize_tools(tool_calls), - } - - -def _summarize_tools(tool_calls: list) -> str: - git_commits = [] - files_edited = [] - bash_count = 0 - mcp_tools = set() - - for name, inp in tool_calls: - if name in ("Edit", "Write"): - fp = inp.get("file_path", "") - if fp: - files_edited.append(os.path.basename(fp)) - elif name == "Bash": - cmd = inp.get("command", "") - bash_count += 1 - # Extract commit message from git commit commands - m = re.search(r'git commit[^\'"\n]*[\'"]([^\'"]+)[\'"]', cmd) - if m: - git_commits.append(m.group(1)[:80]) - elif name and "__" in name: - # MCP tool like mcp__claude_ai_Slack__... - parts = name.split("__") - if len(parts) >= 2: - mcp_tools.add(parts[1].replace("_", " ")) - - parts = [] - if git_commits: - parts.append("Commits: " + "; ".join(git_commits[:4])) - if files_edited: - unique = list(dict.fromkeys(files_edited))[:8] - parts.append("Files: " + ", ".join(unique)) - if bash_count and not git_commits and not files_edited: - parts.append(f"{bash_count} shell commands") - if mcp_tools: - parts.append("Tools: " + ", ".join(sorted(mcp_tools)[:4])) - - return " | ".join(parts) - - -def _trim_to_sentence(text: str) -> str: - """Keep only the first ~150 chars, cut at sentence boundary if possible.""" - if len(text) <= 150: - return text - cut = text[:150] - # Try to cut at last sentence end - for sep in (". ", "! ", "? "): - idx = cut.rfind(sep) - if idx > 60: - return cut[: idx + 1] - return cut.rstrip() + "…" - - -if __name__ == "__main__": - main() diff --git a/ai-stuff/skills/get-story/SKILL.md b/ai-stuff/skills/get-story/SKILL.md deleted file mode 100644 index 079044d2..00000000 --- a/ai-stuff/skills/get-story/SKILL.md +++ /dev/null @@ -1,65 +0,0 @@ ---- -name: get-story -description: Fetch and display a Jira issue with all details. Use when user asks about a ticket, wants issue details, or says "what's in DEVX-123" -context: fork -model: sonnet -allowed-tools: mcp__claude_ai_Atlassian_MCP__getJiraIssue -argument-hint: <DEVX-XXX or issue number> ---- - -# Fetch Jira Issue - -## Configuration - -Read [jira config](../_shared/config/jira-config.md). - -## Instructions - -Fetch Jira issue. Display body + comments only. - -### Process - -1. Parse issue key from argument-hint - - - Number only (e.g., `123`) → prepend `DEVX-` - - Full key (e.g., `DEVX-123`) → use as-is - - Different project prefix → use that - -2. Fetch: - - ``` - mcp__claude_ai_Atlassian_MCP__getJiraIssue - - cloudId: 56552dac-b6cf-4e59-aa06-5e075dca9f8e - - issueKey: <parsed key> - ``` - -3. Display only: - - - **Description** (full content) - - **Comments** (all footer and inline comments) - -4. Provide the issue URL: `[DEVX-XXX](https://wahanda.atlassian.net/browse/DEVX-XXX)` - -### Output Format - -```markdown -# DEVX-XXX - -[Full description content] - -## Comments - -[All comments displayed in order] - -View: [DEVX-XXX](https://wahanda.atlassian.net/browse/DEVX-XXX) -``` - -### Final Reply - -Show the issue details and nothing else. - -### Error Handling - -- **Not found**: Suggest JQL search -- **Wrong project**: Confirm project key -- **No arguments**: Ask for issue key \ No newline at end of file diff --git a/ai-stuff/skills/get-story/agents/openai.yaml b/ai-stuff/skills/get-story/agents/openai.yaml deleted file mode 100644 index c5507068..00000000 --- a/ai-stuff/skills/get-story/agents/openai.yaml +++ /dev/null @@ -1,3 +0,0 @@ -interface: - display_name: "Get Story" - short_description: "Fetch and display a Jira issue with all details" diff --git a/ai-stuff/skills/k8s-debug/SKILL.md b/ai-stuff/skills/k8s-debug/SKILL.md deleted file mode 100644 index bc838e55..00000000 --- a/ai-stuff/skills/k8s-debug/SKILL.md +++ /dev/null @@ -1,178 +0,0 @@ ---- -name: k8s-debug -description: "Debug Kubernetes cluster issues by investigating pods, deployments, services, resource constraints, and performance. Combine kubectl introspection with Datadog metrics and logs to diagnose pod failures (pending/crash/errors), service latency, connectivity issues, memory/CPU exhaustion, error spikes, and node problems. Use when a pod is stuck/failing, a service is slow or unreachable, resource pressure is suspected, or errors spike. Works across clusters (prod-tangela, prod-lion, prod-ruby, dev-verdigris, staging-silver, etc.) — mention the cluster name and the skill finds the right context automatically." -allowed-tools: - # kubectl (read-only) - - Bash(kubectl config:*) - - Bash(kubectl get:*) - - Bash(kubectl describe:*) - - Bash(kubectl logs:*) - - Bash(kubectl top:*) - - Bash(kubectl events:*) - - Bash(kubectl explain:*) - - Bash(rtk kubectl config:*) - - Bash(rtk kubectl get:*) - - Bash(rtk kubectl describe:*) - - Bash(rtk kubectl logs:*) - - Bash(rtk kubectl top:*) - - Bash(rtk kubectl events:*) - - Bash(rtk kubectl explain:*) - # General bash (read-only utilities) - - Bash(grep:*) - - Bash(awk:*) - - Bash(sed:*) - - Bash(head:*) - - Bash(tail:*) - - Bash(sort:*) - - Bash(cut:*) - - Bash(wc:*) - - Bash(jq:*) - - Bash(ls:*) - - Bash(cat:*) - - Bash(echo:*) - - Bash(sleep:*) - - Bash(rtk grep:*) - - Bash(rtk awk:*) - - Bash(rtk sed:*) - - Bash(rtk head:*) - - Bash(rtk tail:*) - - Bash(rtk sort:*) - - Bash(rtk cut:*) - - Bash(rtk wc:*) - - Bash(rtk jq:*) - - Bash(rtk ls:*) - - Bash(rtk cat:*) - - Bash(rtk echo:*) - - Bash(rtk sleep:*) - # Datadog MCP - all commands - - mcp__claude_ai_Datadog ---- - -# Kubernetes Debugging - -Debug k8s cluster issues — combine kubectl introspection with Datadog metrics/logs. - -## Cluster Context - -Current context: `!kubectl config current-context 2>/dev/null || echo "(none)"` - -**Cluster lookup**: read [.clusters.json](../_shared/config/.clusters.json) (relative to this skill's directory) and find the entry whose `.cluster` contains CLUSTER_NAME; use its `.context`. - -If user mentions cluster name: - -1. Extract cluster name (e.g., "prod-tangela", "dev-verdigris") -2. Query clusters.json → find full context (e.g., "argocd-prod/prod-tangela") -3. Use `kubectl --context=<full-context>` in all kubectl commands -4. If cluster not found or already current context → proceed with default or user-specified context - -## Instructions - -Systematic debug approach: - -### 1. Understand the Problem - -Ask user what they're investigating: - -- **Pod issues**: Pod stuck in pending/crash/error? -- **Performance**: Latency, slow response, resource constraints? -- **Service connectivity**: Can't reach service, DNS issues? -- **Resource exhaustion**: CPU/memory pressure, disk space? -- **Error spikes**: Errors in logs/metrics? - -### 2. kubectl Introspection - -Start with kubectl — get cluster state: - -**For pod issues:** - -```bash -kubectl get pods -A --context=CONTEXT (or omit for default) -kubectl describe pod POD_NAME -n NAMESPACE -kubectl logs POD_NAME -n NAMESPACE (latest logs) -kubectl logs POD_NAME -n NAMESPACE --previous (previous container if crashed) -kubectl top pod POD_NAME -n NAMESPACE (resource usage) -kubectl events -n NAMESPACE --sort-by='.lastTimestamp' (recent events) -``` - -**For service/deployment issues:** - -```bash -kubectl get svc -A -kubectl describe svc SERVICE_NAME -n NAMESPACE -kubectl get deployment -A -kubectl describe deployment DEPLOYMENT_NAME -n NAMESPACE -kubectl logs deployment/DEPLOYMENT_NAME -n NAMESPACE -kubectl top nodes (node resource usage) -``` - -**For resource constraints:** - -```bash -kubectl describe nodes (check allocatable vs requested) -kubectl top nodes -kubectl get resourcequota -A -``` - -### 3. Correlate with Datadog - -Got lead from kubectl → cross-reference Datadog: - -**Search logs** for service/pod: - -- Query: `service:SERVICE_NAME env:prod` (or appropriate env) -- Look for errors, exceptions, warnings -- Focus on time window when issue occurred - -**Check metrics** for anomalies: - -- Resource usage: `system.cpu.user{service:...}`, `system.memory.rss{service:...}` -- Request latency: `trace.web.request.duration{service:...}` -- Error rates: spikes in status codes or exception rates - -**Search traces** (APM) if available: - -- Query: `service:SERVICE_NAME status:error` -- Look for slow spans, service deps, bottlenecks -- Identify slow upstream services - -**Aggregate for patterns:** - -- Group errors by source, service, tag -- Issue widespread or isolated to specific pods/nodes? -- Check P99 latencies, not averages - -### 4. Synthesize Findings - -Combine kubectl + Datadog: - -- **What**: Problem (pod crashed, service slow, resource exhausted, etc.) -- **Where**: Affected pod/node/service -- **When**: Issue time window -- **Why**: Root cause (pending → node resource limits, crashed → OOM, slow → external service latency, etc.) -- **Next steps**: What to investigate or fix - -### 5. Deep Dives (as needed) - -**Logs:** `analyze_datadog_logs` with SQL → aggregate error counts, parse stack traces, group by service -**Spans:** `aggregate_spans` → p95/p99 duration, group by resource/service -**Events:** `aggregate_events` → patterns (which nodes had issues, when) - -## Common Debugging Patterns - -| Symptom | Check | Query | -| -------------------- | -------------------------------- | ---------------------------------------------------------------------------- | -| Pod stuck in Pending | Node resources, ResourceQuota | `kubectl describe node`, `kubectl describe pod`, `kubectl get resourcequota` | -| Pod CrashLoopBackOff | Logs, events, resource limits | `kubectl logs --previous`, `kubectl events`, Datadog logs for errors | -| Service slow | Latency spikes, error rates | Datadog traces, `kubectl top pod`, upstream service logs | -| High memory/CPU | Resource requests, top consumers | `kubectl top`, Datadog metrics grouped by pod | -| Node NotReady | Node events, kubelet logs | `kubectl describe node`, check cluster addons | - -## Rules - -- **Always start with kubectl** — fast, gives cluster state -- **Cross-reference Datadog** — metrics/logs confirm + add context -- **Narrow queries** — by service, namespace, time window -- **Ask clarifying questions** if issue description vague -- **Show findings** — tell user what you found + what it means -- **No guessing** — data missing or inconclusive → say so - diff --git a/ai-stuff/skills/k8s-debug/agents/openai.yaml b/ai-stuff/skills/k8s-debug/agents/openai.yaml deleted file mode 100644 index ffa605c5..00000000 --- a/ai-stuff/skills/k8s-debug/agents/openai.yaml +++ /dev/null @@ -1,3 +0,0 @@ -interface: - display_name: "K8s Debug" - short_description: "Diagnose Kubernetes issues with kubectl and Datadog" diff --git a/ai-stuff/skills/log-work/SKILL.md b/ai-stuff/skills/log-work/SKILL.md deleted file mode 100644 index 93fe604d..00000000 --- a/ai-stuff/skills/log-work/SKILL.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -name: log-work -description: Create a DEVX story for work already done on the current branch, written as a to-do, and move it to Code Review. Use only when the user explicitly says "log this work" or "make a ticket for what I did". Never invoke it from create-pr. -allowed-tools: Bash(git log:*), Bash(git diff:*), Bash(git branch:*), AskUserQuestion, mcp__claude_ai_Atlassian_MCP__createJiraIssue, mcp__claude_ai_Atlassian_MCP__transitionJiraIssue, Read ---- - -# Log Work - -Read [jira config](../_shared/config/jira-config.md). Never call lookup APIs. - -## Process - -1. Gather what was done from this conversation plus: - - `git log --oneline main..HEAD` - - `git diff --stat main...HEAD` -2. Write it up as if the work still needs doing: - - **summary**: imperative, at most 10 words ("Fix runner cache eviction") - - **description** (markdown): `## Problem` and `## Proposed Solution`, 1 to 3 sentences each - - **customfield_14105** (Reason for the change): one ADF paragraph, one sentence. Required. -3. Call `AskUserQuestion` before creating anything. Put the drafted summary and reason in the question text, header `Jira`, with these options: - - **Create story (Recommended)**: create it as drafted - - **Use existing ticket**: the user types the key via "Other" - - **Skip ticket**: don't create anything -4. Act on the answer: - - **Create story**: continue to step 5. If the user typed edits via "Other", apply them first. - - **Use existing ticket**: reply with that key and stop. - - **Skip ticket**: stop. -5. Call `createJiraIssue`: - - cloudId `56552dac-b6cf-4e59-aa06-5e075dca9f8e`, projectKey `DEVX`, issueTypeName `Story` - - assignee `currentUserAccountId` from the config - - no acceptance criteria, labels, or other custom fields -6. Call `transitionJiraIssue` on the new key with transitionId `101` (moves it to **Code Review**). -7. Reply with only `[DEVX-XXX](https://wahanda.atlassian.net/browse/DEVX-XXX)`. diff --git a/ai-stuff/skills/log-work/agents/openai.yaml b/ai-stuff/skills/log-work/agents/openai.yaml deleted file mode 100644 index 2c9fcd55..00000000 --- a/ai-stuff/skills/log-work/agents/openai.yaml +++ /dev/null @@ -1,3 +0,0 @@ -interface: - display_name: "Log Work" - short_description: "Log finished work as a DEVX story in Code Review" diff --git a/ai-stuff/skills/save-property-to-vault/SKILL.md b/ai-stuff/skills/save-property-to-vault/SKILL.md deleted file mode 100644 index cefdea55..00000000 --- a/ai-stuff/skills/save-property-to-vault/SKILL.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -name: save-property-to-vault -description: Save an analyzed property listing to the Obsidian vault using the property frontmatter schema and body template. Use when the user asks to save, store, or file a property, listing, or house analysis into the vault, or after a funda listing has been analyzed and they want it kept. -model: claude-haiku-5-5 -allowed-tools: Read, Write, Edit, Glob ---- - -Save property analysis to Obsidian vault. - -## Templates - -Read both templates — relative paths resolve from this skill's directory: - -- [property frontmatter schema](../_shared/templates/property-frontmatter.yaml) -- [property body template](../_shared/templates/property-template.md) - -## Vault Configuration - -Read [house search config](../_shared/config/house-search-config.md). - -## Instructions - -1. Read frontmatter schema from `property-frontmatter.yaml` -2. Read body template from `property-template.md` -3. Create property note at: `~/vault/personal/nl/house search/buying a house/properties/<address-slug>.md` - - Address slug: lowercase, spaces allowed (e.g., "van woustraat 123.md") -4. Populate all frontmatter fields from analysis data -5. Set `viewing_requested: false` initially -6. Set `found_date` to today's date -7. Fill body sections from analysis -8. Use `[[wikilinks]]` for internal links (e.g., `[[Neighborhood Name]]`) -9. If neighborhood note missing, create via neighborhood template at `~/vault/personal/nl/house search/buying a house/neighborhoods/<neighborhood-slug>.md` - -## Important - -- Do NOT edit MoC manually — Dataview queries handle property lists -- `tier` field determines MoC section -- Always include funda URL as clickable link in Summary \ No newline at end of file diff --git a/ai-stuff/skills/save-property-to-vault/agents/openai.yaml b/ai-stuff/skills/save-property-to-vault/agents/openai.yaml deleted file mode 100644 index 0803a7e5..00000000 --- a/ai-stuff/skills/save-property-to-vault/agents/openai.yaml +++ /dev/null @@ -1,3 +0,0 @@ -interface: - display_name: "Save Property To Vault" - short_description: "File an analyzed property listing into the vault" diff --git a/ai-stuff/skills/slackify/SKILL.md b/ai-stuff/skills/slackify/SKILL.md deleted file mode 100644 index 3f2ef2fe..00000000 --- a/ai-stuff/skills/slackify/SKILL.md +++ /dev/null @@ -1,85 +0,0 @@ ---- -name: slackify -description: This skill should be used when the user asks to "slackify" something, "write a slack message", "post this to slack", "turn this into a slack update", or wants any text rewritten in Deniz's Slack voice. Rewrites content as Deniz writes in public channels, all lowercase, direct, zero AI fluff, tl;dr first on long updates, root cause before fix. ---- - -Rewrite the given content (or draft a new message) in Deniz's Slack voice, then output it inside a five-backtick fence as slack mrkdwn. Both halves are mandatory: the fence protects the markup characters from Claude Code's renderer, the mrkdwn dialect is what slack actually parses. Get either wrong and the message pastes flat. - -## output format - -Wrap every message in a five-backtick fence, like this: - -````` -tl;dr: the message goes here. -````` - -Five backticks, not three. The message itself may contain a ``` code block, and a three-backtick wrapper would terminate on it. - -Never emit the message as bare response prose. Claude Code renders markdown before it reaches the screen, so `*bold*` is shown as styling and the asterisks are gone from whatever the user copies. Slack then receives nothing to parse. The fence keeps the source literal so the clipboard carries real characters. - -Nothing outside the fence except at most a one-line lead-in. No commentary after it. - -### slack mrkdwn, not github markdown - -Inside the fence, write slack's dialect: - -- bold: `*one asterisk*`, never `**two**` -- italic: `_underscores_` -- strikethrough: `~one tilde~`, never `~~two~~` -- inline code: single backticks, for the same things the lowercase rule keeps verbatim -- code block: triple backticks with no language tag. Slack prints the tag as the first line of the block -- quote: `>` at line start -- bullets: the literal character `•`, never `-` or `*`. Slack does not turn those into lists -- links: paste the bare url, slack auto-links it. Never `[text](url)`, it survives as literal brackets -- headers: slack has none. Use a `*bold line*` where a `##` would go - -This assumes "Format messages with markup" is enabled in slack (Preferences, Advanced, Input options). It is, on Deniz's setup. With that setting off slack parses nothing, and the right output would instead be flat prose with no markup at all. - -## lowercase - -Everything lowercase: sentence starts, "i", proper nouns, headings. Keep verbatim only: - -- code, commands, file paths, env vars, error strings, api names (`MasqueradeRequestHandler`, `X-Forwarded-Host`) -- acronyms where lowercasing hurts scanning: MR, CI, PR, AWS, EKS, SOPS - -## voice - -Competent engineer typing fast in slack. Direct, warm underneath, never performative. - -- no preamble ("great question", "quick update:"), no closing pleasantries ("hope this helps", "let me know if") -- no AI fluff: certainly, absolutely, it's worth noting, importantly -- drop filler: just, really, basically, actually, simply -- fragments fine. one thought per line beats a paragraph -- honest uncertainty is cheap and human: "i think", "most likely", "(i think)" as a parenthetical, "i may be missing something" -- own mistakes plainly, one line, then move on: "this is most likely me. working on a fix." no groveling, no drama -- short status style for updates: "working on a fix", "applied and merged", "need to look into it" -- never drop not/never/no/only/except. numbers, units, versions, timestamps exact - -## shape - -- lead with the answer or the verdict. context after, if at all -- long technical update: "tl;dr of what happened:" first, then detail for whoever wants it -- root cause before fix, fix before speculation. name the exact file/line/commit when known ("shared-gh-actions@c4f386e added packages: read") -- procedures: numbered steps, one bounded action per step. call out ordering constraints explicitly ("order is important:") -- links inline where they belong, not collected at the bottom -- announcements (a la the karpenter post): lead with the headline and the number that matters, then "what is X" for the unfamiliar, then the interesting part, then methodology last -- emoji sparingly, as the literal character (🎉 👋), not `:shortcode:` -- @-mentions where a specific person needs to act, written as plain @name placeholders for the user to resolve - -## punctuation - -Never use em-dashes (—) or en-dashes (–). Use a comma, a period, parentheses, or a colon. Hyphens in compound words are fine. - -## reference samples - -Real messages, match this register: - -> made an investigation with claude and this is what it came up with. it's a behavioral difference between nginx and traefik. do you think the proposed changes/diagnosis makes sense @james? - -> sorry for the inconvenience. in the meantime, could you please ask a twbox user if they are having the same issues - -> tl;dr of what happened: Root cause: shared-gh-actions@c4f386e (DEVX-1427, merged to main Aug 4 14:57 GMT+2) added packages: read to ci-build-and-deploy.yml's build job [...] every prod/staging run since fails at parse time, hence "Startup failure" with 0s duration. - -> i merged the shared actions. please merge the uala-backend one whenever you want as it will trigger a new deploy(i think) - -> happy that it worked, last couple of days was a little bit surgical because of traefik sorry for any inconvenience diff --git a/ai-stuff/skills/slackify/agents/openai.yaml b/ai-stuff/skills/slackify/agents/openai.yaml deleted file mode 100644 index 633d60c0..00000000 --- a/ai-stuff/skills/slackify/agents/openai.yaml +++ /dev/null @@ -1,3 +0,0 @@ -interface: - display_name: "Slackify" - short_description: "Rewrite text in Deniz's lowercase Slack voice" diff --git a/ai-stuff/skills/vault-capture/SKILL.md b/ai-stuff/skills/vault-capture/SKILL.md deleted file mode 100644 index def2b57f..00000000 --- a/ai-stuff/skills/vault-capture/SKILL.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -name: vault-capture -description: This skill should be used when the user asks to "add to my vault", "add to obsidian", "save this to my vault", "add a task", "note this down", "add a task to <epic/workstream>", "capture this", "add to my daily note", "make a note about", or otherwise wants content written into their Obsidian vault at ~/vault. Routes content to the right folder, applies vault frontmatter/tag conventions, formats tasks as `- [ ]` checkboxes, and wires up `[[wikilinks]]` automatically. -model: claude-haiku-5-5 -allowed-tools: Read, Write, Edit, Glob, Grep, Bash ---- - -Capture content into the Obsidian vault at `~/vault` following its established conventions. The vault is a Dataview/Templater-driven PKM with strict work/personal separation. Match existing structure — never invent new patterns. - -Read `references/vault-conventions.md` for full folder map, frontmatter schemas, and tag rules before writing. Load it whenever routing is ambiguous. - -## Core rules (always apply) - -- Vault root: `~/vault`. Dates: `YYYY-MM-DD` everywhere. -- **Work and personal are strictly separated.** Decide the area first; never mix. -- Folders categorize, **tags stay minimal** (querying + graph only). Don't add tags a similar existing note wouldn't have. -- Use `[[wikilinks]]` for any reference to another note (people: `[[firstname lastname]]`, epics, dates like `[[2026-06-18]]`). When a target may not exist, still wikilink it — a stub link is intended. -- **Never edit `work/moc.md` or any MoC manually** — Dataview views generate those lists. Correct frontmatter is what surfaces a note. -- Before creating a note, `Glob`/`Grep` for an existing one on the topic and append instead of duplicating. - -## Routing decision - -1. **A task or todo** → see "Adding tasks" below. -2. **Work item / project / epic** (`work/epics-and-tasks/`) → workstream note (see "Workstreams"). -3. **Something for today** ("note this", "log this", "for my daily") → append to `work/daily notes/YYYY-MM-DD.md` (today from current date). Add under the relevant section (`## today`, `### notes`, `## useful links`). Use inline code-wrapped follow-up tags (`` `#blocked` ``, `` `#action` ``, etc.) only inside a `## recap` block — see conventions. -4. **Spike / research** → `work/spikes/`. -5. **Personal** → appropriate `personal/<area>/` folder. -6. **Unsure** → ask one short clarifying question (work vs personal, or which epic). - -## Adding tasks - -Tasks use plain Markdown checkboxes — `- [ ] description`. Completed tasks get `- [x] ... ✅ YYYY-MM-DD`. - -- A task tied to a workstream/epic → append `- [ ]` under the relevant `## ...` section of that note in `work/epics-and-tasks/`. Wikilink any referenced people, plans, or sibling notes (e.g. `→ [[oidc]]`). -- A loose/today task → append `- [ ]` under `## today` in today's daily note. -- Keep task text terse and action-first. Add Jira/MR/PR links inline as Markdown links when relevant. -- When marking a task done, change `[ ]`→`[x]` and append `✅ <today>`. - -## Workstreams (`work/epics-and-tasks/`) - -Each tracked work item = one note. New workstream note frontmatter: - -```yaml -type: workstream -kind: epic | initiative | task -title: <Title> -status: blocked | in-progress | backlog | done -area: platform | support -jira: "DEVX-1234" -tags: [work/platform] -notes: "one-line status" -``` - -- `type: workstream` is what surfaces it on the board via `views/workstreamsDashboard`. A root note missing it gets flagged. -- Big items get a folder + `overview.md` workstream note; sibling detail notes are `type: note`. -- Filename: descriptive lowercase, spaces ok (e.g. `ci-cluster migration.md`). -- Cross-reference related notes with `[[wikilinks]]` (`Detail: [[automating gitlab runner bootstrapping]].`). - -## Workflow - -1. Determine area (work/personal) and content type → pick destination from Routing. -2. Search for an existing target note; append if found. -3. If creating: apply the matching frontmatter schema, minimal tags, wikilinks. -4. Confirm the path written and what was added (terse). - -## Additional resources - -- **`references/vault-conventions.md`** — full folder map, all frontmatter schemas, tag taxonomy, date/filename formats, daily-note section layout, and gotchas (Mermaid edge labels, archived/ exclusion). diff --git a/ai-stuff/skills/vault-capture/agents/openai.yaml b/ai-stuff/skills/vault-capture/agents/openai.yaml deleted file mode 100644 index 93d562bd..00000000 --- a/ai-stuff/skills/vault-capture/agents/openai.yaml +++ /dev/null @@ -1,3 +0,0 @@ -interface: - display_name: "Vault Capture" - short_description: "Route notes and tasks into the Obsidian vault" diff --git a/ai-stuff/skills/vault-capture/references/vault-conventions.md b/ai-stuff/skills/vault-capture/references/vault-conventions.md deleted file mode 100644 index a1b5cd4c..00000000 --- a/ai-stuff/skills/vault-capture/references/vault-conventions.md +++ /dev/null @@ -1,113 +0,0 @@ -# Vault Conventions (`~/vault`) - -Obsidian PKM vault. Work + personal knowledge, temporal planning, Dataview/CustomJS dashboards. Folders are self-describing — explore before assuming. This file mirrors the vault's own `~/vault/CLAUDE.md`; if they diverge, the vault file wins. - -## Folder map - -``` -~/vault/ -├── work/ -│ ├── epics-and-tasks/ # workstream notes (epics/initiatives/tasks) + plans/ subfolder -│ ├── daily notes/ # YYYY-MM-DD.md (Periodic Notes plugin) -│ ├── monthly notes/ # YYYY-MM.md -│ ├── spikes/ # research / investigations -│ ├── meetings/ # YYYY-MM-DD [title].md (auto-filed from template) -│ ├── people/ # firstname lastname.md -│ ├── docs/ presentations/ random/ creds/ visa/ -│ └── moc.md # work dashboard — DO NOT edit manually -├── personal/ -│ ├── cooking/ health/ photography/ read/ visa/ nl/ watch/ -│ ├── projects/ startup ideas/ monthly-notes/ traveling/ vinyl/ -│ ├── interviews/ certification/ creds/ random/ bases/ -│ └── moc.md -├── templates/ # Templater templates; some auto-file on creation -├── views/<name>/view.js # Dataview JS dashboards (dark HTML-card style) -├── scripts/ # dataviewUtils.js → customJS.DataviewUtils -├── archived/ # old jobs/projects, READ-ONLY, excluded from active queries -├── attachments/ meta/ random/ read later/ -``` - -Work and personal are **strictly separated**. Never write personal content into `work/` or vice versa. - -## Dates & filenames - -- Dates: `YYYY-MM-DD` everywhere. -- Daily `YYYY-MM-DD.md`, weekly `YYYY-Www.md`, monthly `YYYY-MM.md`. -- Meetings `YYYY-MM-DD [title].md`, people `firstname lastname.md`. -- Folders: lowercase, spaces ok. - -## Frontmatter schemas - -### Workstream (`work/epics-and-tasks/` root notes) - -```yaml -type: workstream # required — drives the board view -kind: epic | initiative | task -title: ... -status: blocked | in-progress | backlog | done -area: platform | support -jira: "DEVX-1234" # or "" -tags: [work/platform] # add ci-cd / github-actions etc only if it aids querying -notes: "one-line status" # short, current state; may contain a markdown link -``` - -Big items: a folder + `overview.md` (the workstream note); sibling detail notes use `type: note`. - -### Daily note - -```yaml -tags: daily -type: daily_note -creation date: YYYY-MM-DD HH:MM -modification date: <weekday string> -``` - -### MoC - -```yaml -type: moc -tags: [work/moc] -``` - -## Tags (keep minimal — folders categorize; tags = querying + graph clustering) - -- Note types: `#daily`, `#meeting`, `#weekly-notes`, `#monthly-notes`. -- Area clustering: `#work/platform`, `#work/support`. -- Daily-note follow-up tags — **inline, code-wrapped** `` `#tag` ``, placed in a `## recap` section so the `needsAttention` view aggregates them: - `#blocked` `#review-stale` `#review-feedback` `#new-ticket` `#question` `#action` `#alert`. - -## Tasks - -- Open: `- [ ] action-first description` -- Done: `- [x] description ✅ YYYY-MM-DD` -- Grouped under `## ` section headers inside the relevant workstream note, or under `## today` in the daily note. -- Tasks plugin is installed; the simple checkbox + `✅ date` form is what these notes actually use. Add Tasks-plugin emoji metadata (📅 due, ⏫ priority) only if the user explicitly asks for scheduling/priority. -- Inline-link people/plans/PRs: `- [ ] follow up with [[Pio Francisco]] on [[oidc]] → MR https://...` - -## Daily note section layout - -``` -# YYYY/MM/DD - Weekday -[[YYYY]] / [[YYYY-Qn|Qn]] / [[YYYY-MM|Month]] / [[YYYY-Www|Week n]] -❮ [[prev-day]] | today | [[next-day]] ❯ - -# daily updates -## yesterday (dataviewjs views) -## today -- [ ] ... ← loose tasks go here -## useful links -## notes for tomorrow -``` - -A `## recap` section (when present) is where code-wrapped follow-up tags live. - -## Plugins - -Templater (`<% %>`), Dataview (JS views), Tasks, CustomJS. Daily/periodic notes via **Periodic Notes** plugin. Use `templates/` for new notes of a known type. - -## Gotchas - -- **Never hand-edit MoC lists** — `views/workstreamsDashboard`, `needsAttention`, `spikesMoc` generate them from frontmatter. Fix the note's frontmatter instead. -- `archived/` is read-only and excluded from active queries — don't write there. -- Mermaid edge labels: no leading `1. ` / `1) ` (triggers "Unsupported markdown: list"). Plain strings only. -- Before creating any note, search for an existing one on the topic and append rather than duplicate. diff --git a/ai-stuff/skills/worktree-cleanup/SKILL.md b/ai-stuff/skills/worktree-cleanup/SKILL.md deleted file mode 100644 index 1cba3545..00000000 --- a/ai-stuff/skills/worktree-cleanup/SKILL.md +++ /dev/null @@ -1,142 +0,0 @@ ---- -name: worktree-cleanup -description: "Find and clean up stale git worktrees whose PRs/MRs have already merged. Scans a single repo OR a directory of repos (e.g. ~/codes/work) for worktrees, detects which branches are merged into the default branch — including SQUASH-merged PRs/MRs that ordinary `git branch --merged` misses — then bulk-removes the merged ones and lets you hand-pick which unmerged ones to drop. Use whenever the user wants to clean up / prune / delete / tidy worktrees, mentions stale or leftover worktrees, says their worktree dir is cluttered, or asks which worktrees are safe to remove. Removes the worktree dir, prunes git metadata, and deletes the local branch in one pass." -argument-hint: "[repo-or-dir path]" -allowed-tools: - - AskUserQuestion - - Read - - Bash(~/.config/ai-shared/scripts/worktree-cleanup-scan.sh:*) - - Bash(~/.config/ai-shared/scripts/worktree-cleanup-remove.sh:*) - - Bash(git worktree list:*) - - Bash(git status:*) - - Bash(git rev-parse:*) - - Bash(jq:*) - - Bash(echo:*) ---- - -# Worktree Cleanup - -Find git worktrees whose work has already merged and clean them up — the worktree -directory, the git metadata, and the local branch, in one pass. - -## Why this skill exists - -Worktrees pile up. Each PR/MR gets its own worktree (e.g. under -`<repo>/.claude/worktrees/<name>`), but once the PR merges nothing deletes it. -The hard part is detection: most PRs/MRs are **squash-merged**, so the branch's -individual commits never appear in `main` verbatim and `git branch --merged` -reports them as *unmerged*. The bundled scan script handles this with layered -checks (ancestor → rebased → remote-branch-gone → forge query), so a squash-merged -branch is correctly classified as safe to delete. - -## Input - -The user may give a path as `$1`: - -- A **single repo** (or any path inside one) → scan that repo's worktrees. -- A **directory of repos** (e.g. `~/codes/work`) → scan each immediate child repo. -- **Nothing** → default to the current directory. - -## Workflow - -### 1. Scan - -Run the scan script with the target path (quote it; default to `.` if none given): - -```bash -~/.config/ai-shared/scripts/worktree-cleanup-scan.sh "<path>" -``` - -It prints a JSON array, one object per non-main worktree: - -```json -{ "repo": "...", "repo_name": "...", "worktree": "...", "branch": "...", - "status": "merged|unmerged|unknown", "reason": "...", - "dirty": false, "ahead": 0, "warnings": [] } -``` - -The script auto-fetches with `--prune` so remote-deleted branches are detected. -It never returns the main worktree or any worktree parked on the default branch — -those are safe by construction. - -If the array is empty, tell the user there's nothing to clean up and stop. - -### 2. Summarize - -Show a compact table grouped by status so the user sees the picture at a glance: - -``` -MERGED (safe to delete) - repo-a feat/DEVX-123-login remote branch deleted (squash-merged) - repo-a fix/DEVX-130-typo ancestor of origin/main - -UNMERGED (your call) - repo-b spike/new-cache not merged into main ⚠ uncommitted changes - repo-b feat/DEVX-141-wip not merged into main ⚠ 3 unpushed commits - -UNKNOWN - repo-c (detached HEAD) detached — no branch to evaluate -``` - -Always surface `warnings` (uncommitted changes, unpushed commits, "branch gone -from origin with no merged PR") — these are the cases where deleting loses work. - -### 3. Bulk-delete merged worktrees - -If there are any `merged` worktrees, ask with **AskUserQuestion**: - -- Header: `Merged` -- Question: e.g. *"Found N merged worktrees. Delete all of them?"* -- Options: `Delete all N` / `Pick individually` / `Skip merged` - -On **Delete all**, remove each merged worktree (see step 5). -On **Pick individually**, fall through to a multiSelect like step 4 but over the -merged list. - -### 4. Hand-pick unmerged worktrees - -If there are any `unmerged` (or `unknown`) worktrees, ask with **AskUserQuestion** -using `multiSelect: true` so the user can tick the ones to drop: - -- Header: `Unmerged` -- Question: *"Which unmerged worktrees should I delete? (these still have work that isn't in the default branch)"* -- One option per worktree. Put the warning in the description so the risk is - visible, e.g. label `repo-b / spike/new-cache`, description `⚠ uncommitted changes — deleting loses this work`. - -Anything the user does NOT select is left untouched. Do not pre-select unmerged -worktrees — unmerged means real work could be lost, so deletion must be explicit. - -### 5. Remove - -For each worktree the user chose, call the remove script with the repo, worktree -path, and branch (all from the scan JSON): - -```bash -~/.config/ai-shared/scripts/worktree-cleanup-remove.sh "<repo>" "<worktree>" "<branch>" -``` - -It removes the worktree (`--force`), prunes git metadata, and deletes the local -branch (never `main`/`master`). Run it once per selected worktree. - -### 6. Report - -Summarize what happened: how many removed, which were kept and why, and any that -errored. Keep it tight. - -## Rules - -- **Never remove the main worktree or the default branch** — the scan script - already excludes both, so don't reconstruct paths by hand or operate on - worktrees that aren't in the scan output. -- **Two separate prompts.** Bulk-confirm merged worktrees first, then hand-pick - unmerged ones. Don't lump them together — the risk profiles are different. -- **Warn before destroying work.** A worktree with uncommitted changes or unpushed - commits gets its warning shown in the prompt, not hidden. When in doubt, surface - it and let the user decide. -- **Trust the scan, not the commit graph.** A squash-merged branch looks unmerged - to `git branch --merged`; the script's layered detection is why this skill exists. - If `status` is `merged`, treat it as safe. -- **Multi-repo runs are fine.** When scanning `~/codes/work`, group output by repo - so the user can reason about each project. -- If `gh`/`glab` aren't installed or auth fails, the scan still works from local + - remote-tracking refs — just note that forge confirmation was unavailable. diff --git a/ai-stuff/skills/worktree-cleanup/agents/openai.yaml b/ai-stuff/skills/worktree-cleanup/agents/openai.yaml deleted file mode 100644 index 2905fff0..00000000 --- a/ai-stuff/skills/worktree-cleanup/agents/openai.yaml +++ /dev/null @@ -1,3 +0,0 @@ -interface: - display_name: "Worktree Cleanup" - short_description: "Remove git worktrees whose PRs/MRs already merged" From 908f8f9330c8fa66e9379f6bf67150356ff74683 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?deniz=20g=C3=B6k=C3=A7in?= <33603535+dgokcin@users.noreply.github.com> Date: Thu, 8 Oct 2026 15:12:43 +0200 Subject: [PATCH 4/6] docs: update readmes for external skills layout - refresh root and ai-stuff readmes - update claude, codex and cursor readmes --- README.md | 45 +++++------ ai-stuff/README.md | 159 +++++++++----------------------------- ai-stuff/claude/README.md | 36 ++------- ai-stuff/codex/README.md | 10 +-- ai-stuff/cursor/README.md | 7 +- 5 files changed, 70 insertions(+), 187 deletions(-) diff --git a/README.md b/README.md index 33ab5aeb..cfedc155 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,10 @@ Personal dotfiles and AI tooling for macOS, with a handful of Linux paths. Every install is a symlink back into this repo, so editing a file here changes the live configuration immediately and nothing gets copied into `$HOME`. -A shared skill library in [`ai-stuff/skills/`](ai-stuff/skills/) installs into -Claude Code, Codex, Cursor, and anything else that reads the cross-tool -`~/.agents/skills` directory. See [`ai-stuff/README.md`](ai-stuff/README.md). +AI tool configuration for Claude Code, Codex, and Cursor lives in +[`ai-stuff/`](ai-stuff/README.md). Skills live in a separate repo, +[`dgokcin/skills`](https://github.com/dgokcin/skills), and `make skills` +installs them into each tool. ## 📁 Layout @@ -14,7 +15,7 @@ Claude Code, Codex, Cursor, and anything else that reads the cross-tool . ├── Makefile entry point; includes makefiles/*.mk, defines shared macros ├── makefiles/ one .mk per concern, plus helper scripts in scripts/ -├── ai-stuff/ skills, agents, and per-tool AI settings +├── ai-stuff/ agents, shared AI content, and per-tool AI settings ├── nvim/ Neovim config (LazyVim + lazy.nvim, Lua) ├── other/ app configs: lazygit, k9s, tmux, yamllint, vscode, winterm ├── Brewfile Homebrew taps, formulae, casks, and fonts @@ -39,11 +40,11 @@ Or run the layers separately: make brew-bundle # Homebrew packages, casks, and fonts make tools # Volta/Node plus preferred standalone and npm CLIs make personal # shell, editors, git, and tool configs -make claude # native CLI, agents, hooks, settings, keybindings, skills -make cursor # agents, hooks, settings, keybindings, skills -make codex # standalone CLI, hooks, AGENTS.md, config, skills +make claude # native CLI, agents, hooks, settings, keybindings +make cursor # agents, hooks, settings, keybindings +make codex # standalone CLI, hooks, AGENTS.md, config make raycast # script commands plus Raycast preferences (macOS) -make ai # skills only, into every registered tool +make ai-shared # shared AI content only, into ~/.config/ai-shared ``` Run `make help` for the full target list. @@ -115,27 +116,27 @@ this repo. Registering the script directory is a one-time click. See | Target | Does | | --- | --- | -| `ai` | Run `ai-check`, link shared content, install skills into every registered tool | -| `ai-check` | Lint `SKILL.md` against `agents/openai.yaml` on invocation policy, legacy keys, and stale files | | `ai-shared` | Link `ai-stuff/_shared` to `~/.config/ai-shared` | -| `ai-list` | Print the skill inventory and tool registry | -| `ai-skill-meta` | Scaffold a missing `agents/openai.yaml` | -| `ai-clean` | Remove installed skills everywhere | -| `claude` | Native Claude Code CLI plus agents, scripts, settings, keybindings, output styles, and `ai-claude` | -| `cursor` | Cursor agents, hook scripts, hooks.json, CLI config, editor settings, plus `ai-agents` | -| `codex` | Standalone Codex CLI plus hooks, scripts, `AGENTS.md`, managed `config.toml`, and `ai-agents` | - -Skills are authored once in `ai-stuff/skills/` and symlinked verbatim into each -tool's skills directory. Adding a tool takes two lines in -[`makefiles/ai.mk`](makefiles/ai.mk), and adding a skill needs no Makefile change -at all. +| `claude` | Native Claude Code CLI plus agents, scripts, settings, keybindings, output styles, and `ai-shared` | +| `cursor` | Cursor agents, hook scripts, hooks.json, CLI config, editor settings | +| `codex` | Standalone Codex CLI plus hooks, scripts, `AGENTS.md`, managed `config.toml` | +| `skills` | Clone `~/codes/skills`, pick skills in the `skills` CLI picker, and link them live | +| `skills-all` | Same as `skills`, but installs every skill without prompting | +| `skills-remove` | Pick installed skills to remove | +| `skills-list` | List globally installed skills | + +`make skills` runs `npx skills add ~/codes/skills -g` for Claude Code, Codex, +and Cursor. The CLI copies each pick into `~/.agents/skills`, and +`makefiles/scripts/skills-link.sh` swaps those copies for symlinks into +`~/codes/skills`. Skills keep bare names like `/create-pr`, and edits apply +live. Run `make skills` again to pick up a new skill. ### ✅ Checks | Target | Does | | --- | --- | | `lint` | actionlint, shellcheck, yamllint, JSON parse check | -| `test` | Skill metadata lint plus statusline fixture tests | +| `test` | Statusline fixture tests | | `test-bootstrap` | Dry-run bootstrap and assert every preferred installer is wired in | | `install-ci` | Symlink install into an isolated `$HOME`, no brew | | `verify-install` | Assert those symlinks point back at this repo | diff --git a/ai-stuff/README.md b/ai-stuff/README.md index f3e8e781..f13b02c9 100644 --- a/ai-stuff/README.md +++ b/ai-stuff/README.md @@ -1,142 +1,53 @@ -# AI Stuff — Universal Skills, One Source of Truth +# AI Stuff -Skills are authored **once** in [`skills/`](skills/) using the -[Agent Skills](https://agentskills.io) standard (the format Claude Code, -Codex, Cursor, Gemini CLI, and ~50 other tools read natively) and installed -into every tool by symlink. Switching or adding an LLM provider costs one -line in a Makefile table — never a second copy of a skill. - -The approach mirrors [BMAD-METHOD](https://github.com/bmad-code-org/BMAD-METHOD)'s -platform installer (`tools/installer/ide/platform-codes.yaml`): one -tool-agnostic skill format + a per-tool directory registry + verbatim -installation. No per-tool transformation, no drift. +Per-tool AI configuration plus the content those tools share. Skills live in +a separate repo, `~/codes/skills`, and `make skills` installs them into +`~/.claude/skills` and `~/.agents/skills` (see [`makefiles/skills.mk`](../makefiles/skills.mk)). ## Layout ``` ai-stuff/ -├── skills/ # ⭐ single source of truth — universal Agent Skills -│ ├── _shared -> ../_shared # makes relative ../_shared/... refs resolve -│ ├── slackify/ -│ │ ├── SKILL.md # frontmatter drives Claude Code -│ │ └── agents/openai.yaml # picker metadata + policy for Codex -│ ├── daily-recap/SKILL.md + agents/ + scripts/ -│ ├── vault-capture/SKILL.md + agents/ + references/ -│ ├── .archived/ # retired skills (never installed) -│ └── ... -├── invocation.md # user- vs model-invoked rules, Skill-tool phrasing, openai.yaml schema -├── _shared/ # configs, templates referenced by skills+agents -│ ├── config/ # git-config, jira-config, .clusters.json, ... -│ └── templates/ # property/daily-recap output templates +├── _shared/ # tool-agnostic content, linked to ~/.config/ai-shared +│ ├── config/ # git, gitops, jira, house-search config +│ ├── scripts/ # hook scripts and helpers shared across tools +│ └── templates/ # property and daily-recap output templates ├── agents/ # subagent definitions (Claude Code + Cursor) -├── claude/ # Claude Code-specific settings, keybindings, and hook scripts -├── codex/ # Codex-specific layer -└── cursor/ # Cursor-specific settings, keybindings, agents, and hooks +├── output-styles/ # Claude Code output styles +├── claude/ # Claude Code settings, keybindings, hook scripts, mods +├── codex/ # Codex hooks, AGENTS.md, managed config.toml block +└── cursor/ # Cursor hooks, CLI config, editor settings, keybindings ``` ## Installation -Driven by [`makefiles/ai.mk`](../makefiles/ai.mk) — the tool registry: - -| Target | Installs to | Covers | -| ------------ | ------------------ | -------------------------------------------------------------------- | -| `ai-claude` | `~/.claude/skills` | Claude Code | -| `ai-agents` | `~/.agents/skills` | Codex, Cursor, Gemini CLI, Windsurf, Copilot, Roo, OpenHands, … | - -Codex has no dedicated target: it ignores `~/.codex/skills` and reads only -`.agents/skills` (repo + `$HOME`), so `ai-agents` covers it. Cursor natively -also scans `~/.claude/skills` and `~/.claude/agents` — those entries are the -same symlinked files, deduplicated by `name`. - -```bash -make ai # ai-check, then install skills into all registered tools -make ai-check # lint SKILL.md <-> agents/openai.yaml (invocation policy, legacy keys, leftovers) -make ai-skill-meta # scaffold agents/openai.yaml for skills missing one -make ai-list # show skills + tool registry -make ai-clean # remove installed skills everywhere -make claude # claude layer (agents/configs/scripts/settings) + ai-claude -make cursor # cursor agents + ai-agents (+ prunes legacy ~/.cursor layout) -make codex # codex layer (hooks/AGENTS.md/config.toml managed block) + ai-agents -``` - -Each install: prune legacy names → `rm` old entry → symlink the whole skill -directory. Whole-dir symlinks mean new files inside a skill (references, -scripts) ship without touching any Makefile. - -**Add a tool** (e.g. Cline) — 2 lines in `ai.mk`: - -```make -AI_TOOLS += cline -ai_skills_dir_cline := ${HOME}/.cline/skills -``` +| Target | Installs | +| ----------- | --------------------------------------------------------------- | +| `ai-shared` | `ai-stuff/_shared` to `~/.config/ai-shared` | +| `claude` | agents, output styles, scripts, settings, keybindings, `ai-shared` | +| `cursor` | agents, hook scripts, hooks.json, CLI config, editor settings | +| `codex` | hooks, `AGENTS.md`, `RTK.md`, managed `config.toml` block | -**Add a skill** — create `ai-stuff/skills/<name>/SKILL.md`, decide whether it -is user- or model-invoked per [`invocation.md`](invocation.md), run -`make ai-skill-meta` and curate the generated `agents/openai.yaml` -`short_description`, then `make ai`. Discovery is by wildcard; `ai-check` -refuses to install if the two metadata files disagree. +Every install is a symlink back into this repo. -**Retire a skill** — move its dir to `skills/.archived/` and append the name -to `AI_LEGACY_SKILLS` in `ai.mk` so installs prune it everywhere (BMAD's -`removals.txt` pattern). +## Shared content -## Portability conventions - -Skills must work in any tool. Rules used throughout `skills/`: - -1. **Shared content = relative markdown links.** - `[git config](../_shared/config/git-config.md)` — resolves from the - skill's directory in the repo *and* in every install tree (the `_shared` - symlink sits next to the installed skills). Never reference - `~/.claude/...` for content another tool needs to read. - -2. **`!`command`` dynamic-context lines are kept.** - Claude Code executes them eagerly and injects the output before the model - sees the prompt. Other tools show the line as text — models read it as - "run this command", which degrades gracefully to one extra tool call. - -3. **Claude-specific frontmatter keys are kept** (`allowed-tools`, `agent`, - `context: fork`, `disable-model-invocation`). The Agent Skills spec says - unknown keys are ignored, so other tools skip them. Claude Code is the - primary driver here; don't strip its metadata for purity. The one key - with a cross-tool twin is `disable-model-invocation`: it must agree with - `policy.allow_implicit_invocation` in `agents/openai.yaml` (Codex). Rules - and the openai.yaml schema live in [`invocation.md`](invocation.md). - -6. **Cross-skill calls say `Call the Skill tool with "<name>"`**, never - `/name`, and only ever target a model-invoked skill. See - [`invocation.md`](invocation.md). - -4. **Executable helpers used by universal skills live in `_shared/scripts/`** - and are referenced via `~/.config/ai-shared/scripts/...` (e.g. - `pr-status.sh`, `worktree-cleanup-*.sh`). That path is installed by - `make ai-shared` — part of every tool's install target — so it resolves no - matter which tool invokes the skill. Never reference `~/.claude/scripts/...` - from a universal skill: it only exists when `make claude` ran. - -5. **Skill-local assets stay inside the skill** (`references/`, `scripts/`) - and are referenced by bare relative paths — self-contained, BMAD-style. +- **`_shared/`** is reachable at the tool-agnostic path + `~/.config/ai-shared/...`. Agents and external skills reference it there, so + the same file works in every tool and never depends on `~/.claude/...`. +- **`_shared/scripts/`** holds hook scripts (`auto-approve-tools.sh`, + `focus-iterm.applescript`) that each tool's install symlinks into its own + scripts dir. Codex adopted Claude Code's hook protocol, so the same scripts + serve both. Cursor reuses the allowlist through an adapter. +- Hooks have no cross-tool standard, so hook configs stay per-tool. ## Tool-specific layers -Anything that is *not* a skill stays out of `skills/`: - -- **`agents/`** — subagent definitions with `tools:`/`model:` frontmatter. - Installed to `~/.claude/agents` and `~/.cursor/agents`. They reference - configs via the tool-agnostic `~/.config/ai-shared/...` path - (`make ai-shared` symlinks it to `ai-stuff/_shared`), so the same agent - file works in every tool that can read files. -- **`claude/`** — `settings.json` (hooks, permissions, statusline, plugins) - and Claude-only hook scripts. See [claude/README.md](claude/README.md). -- **`codex/`** — `hooks.json` + Codex-only hook scripts. Codex skill-picker - metadata is *not* here: it lives beside each skill in `agents/openai.yaml`. See +- **`agents/`** holds subagent definitions with `tools:`/`model:` + frontmatter, installed to `~/.claude/agents` and `~/.cursor/agents`. +- **`claude/`** holds `settings.json` and Claude-only hook scripts. See + [claude/README.md](claude/README.md). +- **`codex/`** holds `hooks.json` and the managed config block. See [codex/README.md](codex/README.md). -- **`_shared/scripts/`** — scripts shared across tools. Hook scripts - (`auto-approve-tools.sh`, `focus-iterm.applescript`): Codex adopted Claude - Code's hook protocol, so the same scripts serve both — symlinked into each - tool's own scripts dir, never referenced across tool homes. Skill helpers - (`pr-status.sh`, `worktree-cleanup-*.sh`): invoked by universal skills via - the tool-agnostic `~/.config/ai-shared/scripts/...` path. -- Hooks have no cross-tool *standard* (event names/config differ per tool), - so hook configs stay per-tool by design. A skill must never depend on - hooks to function, only get better when they exist. +- **`cursor/`** holds Cursor hooks and settings. See + [cursor/README.md](cursor/README.md). diff --git a/ai-stuff/claude/README.md b/ai-stuff/claude/README.md index e4bb2c28..ccbccf50 100644 --- a/ai-stuff/claude/README.md +++ b/ai-stuff/claude/README.md @@ -1,10 +1,9 @@ # Claude Code Layer Claude Code-specific configuration: hook scripts, `settings.json`, and the -install wiring for agents/configs/templates. **Skills do not live -here** — they are universal and come from [`ai-stuff/skills/`](../skills/) -via `make ai-claude`. See [ai-stuff/README.md](../README.md) for the -cross-tool architecture. +install wiring for agents/configs/templates. Skills come from `~/codes/skills` +through `make skills`. See [ai-stuff/README.md](../README.md) for the +cross-tool layout. ## Directory Structure @@ -19,9 +18,8 @@ ai-stuff/claude/ │ ├── session-start.sh # Auto-name worktree sessions │ ├── notify.sh # Notification-event alert (claude-only event) │ └── worktree-*.sh # EnterWorktree/ExitWorktree hook scripts (claude hook protocol) -│ (auto-approve-tools.sh, focus-iterm.applescript, pr-status.sh, and the -│ worktree-cleanup skill helpers moved to ai-stuff/_shared/scripts/ — -│ shared across tools) +│ (auto-approve-tools.sh and focus-iterm.applescript live in +│ ai-stuff/_shared/scripts/, shared across tools) ├── mods/ # Local plugin marketplace `dotfiles-mods` for Claude Code mods │ └── abra/ # Pixel Abra in the band above the prompt (see its README) ├── settings.json # Hooks, permissions, statusline, plugins (→ ~/.claude/settings.json) @@ -44,14 +42,10 @@ version bump. | --------------- | ---------------------- | --------------------- | -------------------------------------- | | `claude-agents` | `ai-stuff/agents/*.md` | `~/.claude/agents` | Claude Code subagents | | `ai-shared` | `ai-stuff/_shared` | `~/.config/ai-shared` | agents' `@~/.config/ai-shared/...` includes (tool-agnostic) | -| `ai-claude` | `ai-stuff/skills/*` | `~/.claude/skills` | skills (universal, see ai.mk) | ## Architecture ``` -Skills (universal, ai-stuff/skills/) ← same files for every AI tool - │ reads via relative ../_shared/... links - ▼ Config (ai-stuff/_shared/) ← rules, shared constants ▲ │ loads via @~/.config/ai-shared/... includes (tool-agnostic path) @@ -112,26 +106,6 @@ Run `./scripts/statusline-test.sh` after changing it — it drives the real scri against `scripts/fixtures/*.json` with a scratch clodex/codex home, so it touches neither your accounts nor the network. -## Claude-specific skill features - -Universal skills carry Claude-only frontmatter that other tools ignore: - -| Field | Purpose | -| -------------------------- | ------------------------------------------ | -| `disable-model-invocation` | Prevents automatic triggering | -| `context: fork` | Runs in isolated subagent context | -| `agent` | Which agent definition to execute under | -| `allowed-tools` | Tool allowlist during execution | - -Dynamic context injection — Claude Code executes `!`command`` lines eagerly -and injects output before the model sees the prompt (other tools treat the -line as an instruction to run the command): - -```markdown -### Staged Changes -!`git diff --staged --stat` -``` - ## Agents | Agent | Purpose | diff --git a/ai-stuff/codex/README.md b/ai-stuff/codex/README.md index aefd325c..41a81db7 100644 --- a/ai-stuff/codex/README.md +++ b/ai-stuff/codex/README.md @@ -1,12 +1,10 @@ # Codex Layer -Codex consumes the universal skills from [`ai-stuff/skills/`](../skills/) — -see [ai-stuff/README.md](../README.md). **Codex reads skills only from -`.agents/skills` (repo + `$HOME`)** — it ignores `~/.codex/skills` — so -skills arrive via ai.mk's `agents` pseudo-tool (`~/.agents/skills`), which -`make codex` depends on. `make codex` installs: +Codex reads skills only from `.agents/skills` (repo and `$HOME`) and ignores +`~/.codex/skills`. `make skills` installs skills into `~/.agents/skills`; see +[ai-stuff/README.md](../README.md). `make codex` prunes our dead symlinks in +`~/.codex/skills` and installs: -- **Skills** — `ai-agents` symlinks every skill dir + `_shared` into `~/.agents/skills` (prunes the dead `~/.codex/skills`) - **Hooks** — [`hooks.json`](hooks.json) → `~/.codex/hooks.json` - **AGENTS.md + RTK.md** — [`AGENTS.md`](AGENTS.md) → `~/.codex/AGENTS.md` (Codex's global instruction file), [`RTK.md`](RTK.md) → `~/.codex/RTK.md` (rtk prefix rule — declarative equivalent of `rtk init -g --codex`) - **config.toml managed block** — see below diff --git a/ai-stuff/cursor/README.md b/ai-stuff/cursor/README.md index 155225f8..094de754 100644 --- a/ai-stuff/cursor/README.md +++ b/ai-stuff/cursor/README.md @@ -1,9 +1,8 @@ # Cursor Layer -Cursor reads the universal skills from the cross-tool standard directory -`~/.agents/skills` (installed by [`makefiles/ai.mk`](../../makefiles/ai.mk) via -`make ai-agents`) — see [ai-stuff/README.md](../README.md). `make cursor` -additionally installs: +Cursor reads skills from the cross-tool standard directory `~/.agents/skills`, +which `make skills` fills; see [ai-stuff/README.md](../README.md). +`make cursor` installs: - **Agents** — Cursor agents symlinked into `~/.cursor/agents` (same definitions as Claude Code) From 9a23fb6ae9b89750370c7ce581dc5772dd3986ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?deniz=20g=C3=B6k=C3=A7in?= <33603535+dgokcin@users.noreply.github.com> Date: Thu, 8 Oct 2026 15:18:55 +0200 Subject: [PATCH 5/6] chore(claude): point clusters path at external skills config - set gitops clustersJsonPath to ~/.config/dgokcin-skills/clusters.json - drop gitignore entries for private files moved to the skills repo - keep traefik-vault agent ignored --- .gitignore | 11 +---------- ai-stuff/claude/settings.json | 2 +- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 7ebac043..5d079dc1 100644 --- a/.gitignore +++ b/.gitignore @@ -8,14 +8,5 @@ vscode-settings.json .claude/worktrees/** -# Private shared configs -ai-stuff/_shared/**/_*.md - -# Private cluster context map (contains sensitive account/cluster names) -ai-stuff/claude/config/.clusters.json -ai-stuff/_shared/config/.clusters.json - -# Private work-specific traefik migration config. The skill, traefik-dev and traefik-recon moved into -# k8s-gitops-platform-apps on 2026-08-12; only the personal Obsidian layer stays here. -ai-stuff/_shared/config/traefik-epic.md +# Private work-specific agent ai-stuff/agents/traefik-vault.md diff --git a/ai-stuff/claude/settings.json b/ai-stuff/claude/settings.json index 1116fa99..854a983a 100644 --- a/ai-stuff/claude/settings.json +++ b/ai-stuff/claude/settings.json @@ -341,7 +341,7 @@ "pluginConfigs": { "gitops@treatwell": { "options": { - "clustersJsonPath": "/Users/denizgokcin/codes/dotfiles/ai-stuff/_shared/config/.clusters.json", + "clustersJsonPath": "~/.config/dgokcin-skills/clusters.json", "ownerTeam": "platform-devx" } }, From 9816067701e5f8f544ddf908ebb539fc70b5704b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?deniz=20g=C3=B6k=C3=A7in?= <33603535+dgokcin@users.noreply.github.com> Date: Thu, 8 Oct 2026 15:18:55 +0200 Subject: [PATCH 6/6] docs: describe private skill config and trimmed shared dir - document ~/codes/skills/local as the home of private config - remove config and templates from the _shared tree listing --- README.md | 11 +++++------ ai-stuff/README.md | 4 +--- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index cfedc155..906b4e37 100644 --- a/README.md +++ b/README.md @@ -155,10 +155,9 @@ version and [`CHANGELOG.md`](CHANGELOG.md) from conventional commit messages. ## 🔒 Private files -Some files are gitignored because they carry personal or work-specific detail. -The tracked file is the template, and the private variant sits beside it with a -leading underscore or a dot prefix. +Private skill config (Jira IDs, cluster names, Slack IDs, GitLab hosts) lives in +the gitignored `~/codes/skills/local/`, which `make skills` links to +`~/.config/dgokcin-skills`. -- `ai-stuff/_shared/config/_*.md` -- `ai-stuff/_shared/config/.clusters.json` (cluster and account names) -- `ai-stuff/_shared/config/traefik-epic.md` +The only gitignored file here is `ai-stuff/agents/traefik-vault.md`, a +work-specific agent. diff --git a/ai-stuff/README.md b/ai-stuff/README.md index f13b02c9..ca932d31 100644 --- a/ai-stuff/README.md +++ b/ai-stuff/README.md @@ -9,9 +9,7 @@ a separate repo, `~/codes/skills`, and `make skills` installs them into ``` ai-stuff/ ├── _shared/ # tool-agnostic content, linked to ~/.config/ai-shared -│ ├── config/ # git, gitops, jira, house-search config -│ ├── scripts/ # hook scripts and helpers shared across tools -│ └── templates/ # property and daily-recap output templates +│ └── scripts/ # hook scripts shared across tools ├── agents/ # subagent definitions (Claude Code + Cursor) ├── output-styles/ # Claude Code output styles ├── claude/ # Claude Code settings, keybindings, hook scripts, mods