references/search-patterns.md
# Search Patterns for Reference Repositories
Base directory: `~/projects/referenzen/`
## Find files by name
```bash
# Find a specific file in one repo
find ~/projects/referenzen/repo-name -name "Chart.yaml"
# Find across all repos
find ~/projects/referenzen -name "values.yaml"
```
## Search for patterns (grep)
```bash
# Search in a specific file
grep -n "some-dependency" ~/projects/referenzen/repo-name/pom.xml
# Recursive search in a directory
grep -rn "some-dependency" ~/projects/referenzen/repo-name/
# Search with context lines
grep -rn -A 3 -B 3 "some-pattern" ~/projects/referenzen/repo-name/src/
```
## Explore project structure
```bash
# Top-level structure
ls ~/projects/referenzen/repo-name/
# Helm chart layout
ls ~/projects/referenzen/repo-name/helm-charts/
# Read a specific file
cat ~/projects/referenzen/repo-name/helm-charts/values.yaml
```
## List all available reference repos
```bash
ls ~/projects/referenzen/
# Show tracked repos from list file (if it exists)
cat ~/claude-shared/projekte.txt
```
## Citing patterns
Always tell the user which project and file a pattern came from:
> Pattern adopted from `your-service` →
> `~/projects/referenzen/your-service/helm-charts/Chart.yaml` (line 4)
scripts/clone-or-update.sh
#!/usr/bin/env bash
# Clone a single GitHub repository into ~/projects/referenzen/ or pull if it exists.
# Usage: clone-or-update.sh <owner/repo>
# Exit codes: 0=ok, 1=argument missing, 2=local changes present (pull skipped), 3=clone/pull failed
set -euo pipefail
REFERENZEN_DIR="${REFERENZEN_DIR:-$HOME/projects/referenzen}"
if [[ $# -lt 1 ]]; then
echo "Usage: $0 <owner/repo>" >&2
exit 1
fi
REPO="$1"
NAME="${REPO##*/}"
TARGET="$REFERENZEN_DIR/$NAME"
mkdir -p "$REFERENZEN_DIR"
if [[ -d "$TARGET/.git" ]]; then
STATUS=$(git -C "$TARGET" status --porcelain)
if [[ -n "$STATUS" ]]; then
echo "SKIP $REPO — local changes present, not pulling:"
git -C "$TARGET" status --short | sed 's/^/ /'
exit 2
else
echo "PULL $REPO"
if git -C "$TARGET" pull --ff-only 2>&1; then
echo " OK"
else
echo " FAILED (not fast-forward or network error)" >&2
exit 3
fi
fi
else
echo "CLONE $REPO → $TARGET"
if gh repo clone "$REPO" "$TARGET" -- --quiet 2>&1; then
echo " OK"
else
echo " FAILED" >&2
exit 3
fi
fi
scripts/list-workflow-triggers.sh
#!/usr/bin/env bash
# Generate an overview of GitHub Actions triggers (push, pull_request, schedule, ...)
# and cron schedules across repository checkouts, and write a Markdown report.
# Scheduled workflows are sorted by weekday/time and shown with a human-readable
# run time plus the original cron expression.
#
# Usage: list-workflow-triggers.sh [--root <dir>] [--glob <pattern>] [--out <file>] [--no-report]
#
# --root <dir> directory containing repo checkouts
# (default: $REFERENZEN_DIR or ~/projects/referenzen)
# --glob <pattern> workflow filename filter under .github/workflows
# (default: all *.yml and *.yaml)
# --out <file> Markdown report path (default: target/workflow-triggers.md)
# --no-report only print to stdout, do not write the report file
#
# Examples:
# bash list-workflow-triggers.sh
# bash list-workflow-triggers.sh --root ~/projects/referenzen --glob 'maven-build.yml'
# bash list-workflow-triggers.sh --root /c/development/projects --out target/triggers.md
set -euo pipefail
REFERENZEN_DIR="${REFERENZEN_DIR:-$HOME/projects/referenzen}"
ROOT="$REFERENZEN_DIR"
GLOB=""
OUT="target/workflow-triggers.md"
WRITE_REPORT=1
while [[ $# -gt 0 ]]; do
case "$1" in
--root)
ROOT="$2"
shift 2
;;
--glob)
GLOB="$2"
shift 2
;;
--out)
OUT="$2"
shift 2
;;
--no-report)
WRITE_REPORT=0
shift
;;
-h | --help)
sed -n '2,22p' "$0"
exit 0
;;
*)
echo "Unknown option: $1" >&2
exit 1
;;
esac
done
if [[ ! -d "$ROOT" ]]; then
echo "Directory not found: $ROOT" >&2
exit 1
fi
shopt -s nullglob
# Extract trigger names from the top-level `on:` block, including inline forms.
extract_triggers() {
awk '
function emit(list) {
gsub(/[][ ]/, "", list)
n = split(list, parts, ",")
for (i = 1; i <= n; i++) if (parts[i] != "") print parts[i]
}
/^on:/ {
rest = $0
sub(/^on:[[:space:]]*/, "", rest)
if (rest ~ /^\[/) { gsub(/[\[\]]/, "", rest); emit(rest); in_on = 0; next }
if (rest != "") { print rest; in_on = 0; next }
in_on = 1
next
}
in_on {
if ($0 ~ /^[^[:space:]]/) { in_on = 0; next }
if ($0 ~ /^ [A-Za-z_][A-Za-z0-9_-]*:/) {
key = $0
sub(/^ /, "", key)
sub(/:.*/, "", key)
print key
}
}
' "$1"
}
# Extract cron expressions, stripping quotes, inline comments and whitespace.
extract_crons() {
grep -E '^[[:space:]]*-?[[:space:]]*cron:' "$1" 2>/dev/null |
sed -E "s/^[^:]*cron:[[:space:]]*//; s/[[:space:]]*#.*\$//; s/^['\"]//; s/['\"][[:space:]]*\$//" |
grep -v '^[[:space:]]*$' || true
}
SCHED_TSV="$(mktemp)"
EVENT_TSV="$(mktemp)"
trap 'rm -f "$SCHED_TSV" "$EVENT_TSV"' EXIT
declare -A SEEN_REPOS=()
WF_COUNT=0
SCHED_COUNT=0
for repo in "$ROOT"/*/; do
WF_DIR="${repo%/}/.github/workflows"
[[ -d "$WF_DIR" ]] || continue
REPO_NAME="$(basename "${repo%/}")"
if [[ -n "$GLOB" ]]; then
workflows=("$WF_DIR"/$GLOB)
else
workflows=("$WF_DIR"/*.yml "$WF_DIR"/*.yaml)
fi
for wf in "${workflows[@]}"; do
[[ -f "$wf" ]] || continue
SEEN_REPOS["$REPO_NAME"]=1
WF_COUNT=$((WF_COUNT + 1))
mapfile -t TRIGGERS < <(extract_triggers "$wf")
mapfile -t CRONS < <(extract_crons "$wf")
triggers="—"
if [[ ${#TRIGGERS[@]} -gt 0 ]]; then
triggers="$(printf '%s, ' "${TRIGGERS[@]}")"
triggers="${triggers%, }"
fi
if [[ ${#CRONS[@]} -eq 0 ]]; then
printf '%s\t%s\t%s\n' "$REPO_NAME" "$(basename "$wf")" "$triggers" >>"$EVENT_TSV"
else
crons="$(printf '%s;' "${CRONS[@]}")"
crons="${crons%;}"
printf '%s\t%s\t%s\t%s\n' "$REPO_NAME" "$(basename "$wf")" "$triggers" "$crons" >>"$SCHED_TSV"
SCHED_COUNT=$((SCHED_COUNT + ${#CRONS[@]}))
fi
done
done
# Build sorted scheduled rows: key \t readable \t repo \t workflow \t cron \t triggers
SORTED="$(
awk -F'\t' '
function iso(d) { return (d == 0 ? 7 : d) }
function dowName(d) {
if (d == 0) return "Sunday"
if (d == 1) return "Monday"
if (d == 2) return "Tuesday"
if (d == 3) return "Wednesday"
if (d == 4) return "Thursday"
if (d == 5) return "Friday"
return "Saturday"
}
{
repo = $1; wf = $2; trig = $3
nc = split($4, crons, ";")
for (i = 1; i <= nc; i++) {
cron = crons[i]
gsub(/^[ \t]+|[ \t]+$/, "", cron)
if (cron == "") continue
n = split(cron, f, /[ \t]+/)
if (n != 5) { printf "z\t%s\t%s\t%s\t%s\t%s\n", "custom", repo, wf, cron, trig; continue }
mn = f[1]; hr = f[2]; dom = f[3]; mon = f[4]; dow = f[5]
if (mn !~ /^[0-9]+$/ || hr !~ /^[0-9]+$/) {
printf "z\t%s\t%s\t%s\t%s\t%s\n", "custom", repo, wf, cron, trig; continue
}
if (dow == "*" && dom == "*") { dk = 0; label = "daily" }
else if (dow ~ /^[0-7]$/ && dom == "*") { dk = iso(dow + 0); label = dowName(dow + 0) }
else if (dow == "1-5" && dom == "*") { dk = 1; label = "weekdays" }
else if (dom ~ /^[0-9]+$/ && dow == "*") { dk = 0; label = "monthly day " dom }
else { printf "z\t%s\t%s\t%s\t%s\t%s\n", "custom", repo, wf, cron, trig; continue }
key = sprintf("%02d %02d:%02d", dk, hr + 0, mn + 0)
readable = sprintf("%s %02d:%02d", label, hr + 0, mn + 0)
printf "%s\t%s\t%s\t%s\t%s\t%s\n", key, readable, repo, wf, cron, trig
}
}
' "$SCHED_TSV" | sort
)"
REPO_COUNT=${#SEEN_REPOS[@]}
# --- Console output ---
echo "Scheduled workflows (sorted by weekday/time):"
echo
if [[ -z "$SORTED" ]]; then
echo " (none)"
else
while IFS=$'\t' read -r _key readable repo wf cron triggers; do
printf ' %-16s %-30s %-24s %s\n' "$readable" "$repo" "$wf" "[$cron]"
done <<<"$SORTED"
fi
echo
echo "Event-only workflows (no schedule):"
echo
if [[ ! -s "$EVENT_TSV" ]]; then
echo " (none)"
else
while IFS=$'\t' read -r repo wf triggers; do
printf ' %-30s %-24s %s\n' "$repo" "$wf" "$triggers"
done <"$EVENT_TSV"
fi
echo
echo "Repositories: $REPO_COUNT Workflows: $WF_COUNT Scheduled entries: $SCHED_COUNT"
# --- Markdown report ---
if [[ $WRITE_REPORT -eq 1 ]]; then
mkdir -p "$(dirname "$OUT")"
{
echo "# GitHub Actions Trigger Overview"
echo
echo "- Root: \`$ROOT\`"
echo "- Generated: $(date '+%Y-%m-%d %H:%M:%S %z')"
echo "- Repositories: $REPO_COUNT"
echo "- Workflows: $WF_COUNT"
echo "- Scheduled entries: $SCHED_COUNT"
echo
echo "## Scheduled workflows (sorted by weekday/time)"
echo
if [[ -z "$SORTED" ]]; then
echo "_No scheduled workflows found._"
else
echo "| Run | Repository | Workflow | Cron | Triggers |"
echo "| --- | ---------- | -------- | ---- | -------- |"
while IFS=$'\t' read -r _key readable repo wf cron triggers; do
echo "| $readable | $repo | $wf | \`$cron\` | $triggers |"
done <<<"$SORTED"
fi
echo
echo "## Event-only workflows (no schedule)"
echo
if [[ ! -s "$EVENT_TSV" ]]; then
echo "_None._"
else
echo "| Repository | Workflow | Triggers |"
echo "| ---------- | -------- | -------- |"
while IFS=$'\t' read -r repo wf triggers; do
echo "| $repo | $wf | $triggers |"
done <"$EVENT_TSV"
fi
} >"$OUT"
echo
echo "Report written to $OUT"
fi
scripts/sync-all.sh
#!/usr/bin/env bash
# Sync all repositories to ~/projects/referenzen/.
# Reads from ~/claude-shared/projekte.txt if present, otherwise uses gh repo list.
# Usage: sync-all.sh [--list <file>] [--limit <n>]
# --list <file> override the default projekte.txt path
# --limit <n> max repos when using gh repo list (default: 200)
set -euo pipefail
REFERENZEN_DIR="${REFERENZEN_DIR:-$HOME/projects/referenzen}"
PROJEKTE_FILE="${PROJEKTE_FILE:-$HOME/claude-shared/projekte.txt}"
GH_LIMIT=200
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
while [[ $# -gt 0 ]]; do
case "$1" in
--list)
PROJEKTE_FILE="$2"
shift 2
;;
--limit)
GH_LIMIT="$2"
shift 2
;;
*)
echo "Unknown option: $1" >&2
exit 1
;;
esac
done
mkdir -p "$REFERENZEN_DIR"
# --- Determine repo list ---
if [[ -f "$PROJEKTE_FILE" ]]; then
echo "Source: $PROJEKTE_FILE"
REPOS=$(grep -v '^\s*#' "$PROJEKTE_FILE" | grep -v '^\s*$' || true)
else
echo "Source: gh repo list (limit $GH_LIMIT) — projekte.txt not found at $PROJEKTE_FILE"
REPOS=$(gh repo list --limit "$GH_LIMIT" --json nameWithOwner --jq '.[].nameWithOwner')
fi
TOTAL=$(echo "$REPOS" | grep -c . || true)
echo "Repositories to sync: $TOTAL"
echo "Target directory: $REFERENZEN_DIR"
echo "---"
CLONED=0
PULLED=0
SKIPPED=0
FAILED=0
inc() { eval "$1=\$(( \${$1} + 1 ))"; }
while IFS= read -r REPO; do
[[ -z "$REPO" ]] && continue
NAME="${REPO##*/}"
TARGET="$REFERENZEN_DIR/$NAME"
if [[ -d "$TARGET/.git" ]]; then
STATUS=$(git -C "$TARGET" status --porcelain)
if [[ -n "$STATUS" ]]; then
echo "SKIP $REPO — local changes present:"
git -C "$TARGET" status --short | sed 's/^/ /'
inc SKIPPED
else
echo "PULL $REPO"
if git -C "$TARGET" pull --ff-only 2>&1 | sed 's/^/ /'; then
inc PULLED
else
echo " FAILED" >&2
inc FAILED
fi
fi
else
echo "CLONE $REPO → $TARGET"
if gh repo clone "$REPO" "$TARGET" -- --quiet 2>&1 | sed 's/^/ /'; then
echo " OK"
inc CLONED
else
echo " FAILED" >&2
inc FAILED
fi
fi
done <<<"$REPOS"
echo "---"
echo "Done. Cloned: $CLONED Pulled: $PULLED Skipped (local changes): $SKIPPED Failed: $FAILED"
SKILL.md
---
name: project-references
description: "Look up conventions, patterns, and concrete implementations from your own GitHub repositories checked out locally under ~/projects/referenzen/. Use this skill whenever there is uncertainty about how something is done in your codebase family — e.g. Helm chart structure, Kubernetes manifests, framework configuration patterns, Docker Compose conventions, CI/CD pipeline setup, or any other recurring architectural decision. Invoke it proactively before guessing at a convention; always cite the source project and path when a pattern is adopted. Also use when the user asks to check out, update, or search reference repositories, or to generate an overview/report of GitHub Actions triggers (push, pull_request, schedule/cron) across repositories."
---
---
# Project References
This skill manages a local mirror of your own GitHub repositories under
`~/projects/referenzen/` and lets you look up conventions and implementation
patterns without guessing or reading all repos blindly.
All operations are **read-only** on the reference projects themselves. Only
`git clone` and `git pull` write into that directory — never edits.
---
## Instructions
### Step 1: Check whether the relevant repo is already cloned
```bash
ls ~/projects/referenzen/
```
If the needed repo is missing, run `scripts/clone-or-update.sh owner/repo` to clone it first.
### Step 2: Ask the user which reference project is most relevant
Do not scan all repos blindly — that fills context. Ask: "Which of your sibling projects uses this pattern?" or list the available repos and let the user pick.
### Step 3: Search targeted — file first, then grep
Use `find` to locate a file by name, then `cat` or `grep` to read only the relevant section. For search commands and patterns, consult `references/search-patterns.md`.
### Step 4: Cite the source when adopting a pattern
Always state which project and file path a pattern came from before applying it:
> Pattern adopted from `your-service` → `helm-charts/Chart.yaml` line 4
### Step 5: Sync only when explicitly requested
Run `scripts/sync-all.sh` only when the user says "sync all" or "update all references". For a single repo, prefer `scripts/clone-or-update.sh`.
---
## Examples
### Example 1: Looking up a Helm chart convention
User says: "How should I structure the Helm chart for this project?"
Actions:
1. Run `ls ~/projects/referenzen/` to see available repos
2. Ask: "Which sibling project should I use as reference?" — user says `your-service`
3. Run `find ~/projects/referenzen/your-service -name "Chart.yaml"` to locate it
4. Read the file, note the structure (apiVersion, dependencies, version pattern)
5. Apply the same structure; cite: "adopted from `your-service/helm-charts/Chart.yaml`"
Result: Helm chart consistent with sibling projects, traceable source cited.
### Example 2: Checking out a new reference repo
User says: "Clone my other-service project as a reference"
Actions:
1. Run `bash scripts/clone-or-update.sh owner/other-service`
2. Stream output so user sees CLONE/PULL/SKIP progress
3. Confirm with `ls ~/projects/referenzen/other-service/`
Result: Repo available locally for pattern lookups; no edits made.
### Example 3: Finding a configuration pattern
User says: "How do I configure the database pool like in the other projects?"
Actions:
1. `ls ~/projects/referenzen/` — pick a relevant sibling project
2. `grep -rn "database.pool" ~/projects/referenzen/your-service/src/main/resources/`
3. Read the relevant config section
4. Cite: "pattern from `your-service/src/main/resources/application.yaml` line 42"
Result: Exact config from a proven sibling project, not guessed.
### Example 4: Overview of GitHub Actions triggers
User says: "When do my projects run their GitHub Actions — push, PR, or schedule?"
Actions:
1. Run `bash scripts/list-workflow-triggers.sh` (add `--glob` to narrow to one
pipeline, `--root` for a different checkout directory)
2. Present the sorted overview (weekday/time, human-readable plus original
cron) and the event-only workflows
3. Point the user to the generated report at `target/workflow-triggers.md`
Result: Consolidated, time-sorted trigger overview across all reference repos
plus a Markdown report, without opening each workflow file.
---
## Repository source
Two sources are supported — prefer the manual list when it exists:
1. **Manual list** (`~/claude-shared/projekte.txt`): one GitHub repo URL or
`owner/name` slug per line, blank lines and `#` comments ignored.
2. **Automatic discovery**: `gh repo list --limit 200 --json nameWithOwner`
when the file is absent or the user explicitly asks for a full sync.
---
## Scripts
Two ready-made scripts live in `scripts/` — use them instead of writing
inline Bash. Both accept `REFERENZEN_DIR` as an env override (default:
`~/projects/referenzen`).
### `scripts/clone-or-update.sh <owner/repo>`
Clones a single repository or pulls if it already exists locally. Refuses
to pull when local changes are present (exit code 2) — never stashes or
resets.
```bash
bash scripts/clone-or-update.sh owner/your-repo
```
Exit codes: `0` = ok, `2` = skipped (local changes), `3` = clone/pull failed.
### `scripts/sync-all.sh [--list <file>] [--limit <n>]`
Iterates over all repositories and calls the clone-or-update logic for each.
Prefers `~/claude-shared/projekte.txt` as source; falls back to `gh repo list`
when the file is absent. Prints a summary line at the end.
```bash
# Sync everything (auto-detect source)
bash scripts/sync-all.sh
# Use a specific list file
bash scripts/sync-all.sh --list ~/claude-shared/projekte.txt
# Limit gh repo list to 50 repos
bash scripts/sync-all.sh --limit 50
```
**Do not** run sync-all blindly — use it only when the user explicitly says
"sync all" or "update all references". For a single repo prefer
`clone-or-update.sh`.
### `scripts/list-workflow-triggers.sh [--root <dir>] [--glob <pattern>] [--out <file>] [--no-report]`
Scans every repo checkout for `.github/workflows/*.yml` and `*.yaml`, extracts
the triggers from the `on:` block (`push`, `pull_request`, `schedule`,
`workflow_dispatch`, `release`, …) plus any `cron:` expressions, prints the
overview and writes a Markdown report. Scheduled workflows are **sorted by
weekday/time** and shown with a **human-readable run time** (e.g. `Monday
02:05`) next to the **original cron expression**; workflows without a schedule
are listed in a separate event-only section. Read-only, no network access.
- `--root <dir>` — directory containing repo checkouts. Default:
`$REFERENZEN_DIR` or `~/projects/referenzen`.
- `--glob <pattern>` — optional filename filter, e.g. `maven-build.yml`.
Default: all workflows.
- `--out <file>` — Markdown report path. Default: `target/workflow-triggers.md`
(relative to the current project directory, created if missing).
- `--no-report` — print to stdout only, skip the report file.
```bash
# Overview + report for all reference repos
bash scripts/list-workflow-triggers.sh
# Only maven-build.yml, custom report location
bash scripts/list-workflow-triggers.sh --glob 'maven-build.yml' --out target/maven-triggers.md
# A different checkout root (e.g. Windows mount)
bash scripts/list-workflow-triggers.sh --root /mnt/c/Development/projects/all-git-repos
```
---
## Workflows
### 1. Check out or update repositories
Run the appropriate script and stream output so the user sees every
CLONE / PULL / SKIP action as it happens.
### 2. Search within reference projects
Scope the search to what the user actually needs. Prefer targeted lookups
over broad recursive greps. For ready-made search commands and citing patterns,
consult `references/search-patterns.md`.
### 3. Discover available reference projects
```bash
ls ~/projects/referenzen/
```
If `~/claude-shared/projekte.txt` exists, show its contents alongside to
explain which repos are tracked vs. which are locally present.
### 4. Overview of GitHub Actions triggers
Run `scripts/list-workflow-triggers.sh` to get a cross-repo overview of every
workflow's `on:` triggers and `cron:` entries. It also writes the report to
`target/workflow-triggers.md`. Use `--glob` to focus on a single pipeline
(e.g. `maven-build.yml`) and `--root` for a different checkout directory.
---
## When to suggest this skill proactively
Suggest looking up a reference project when:
- The user asks how something is structured and the answer may vary by
project convention (Helm chart layout, Flyway migration naming, Dockerfile
patterns, Maven plugin ordering, etc.)
- There is more than one reasonable approach and consistency with sibling
projects matters
- The user says "like the other projects" or "same as before" without
specifying which project
Ask the user which reference project is most relevant rather than scanning
all of them — scanning is expensive in context.
---
## Safety rules
- Never edit, stage, commit, or delete files inside `~/projects/referenzen/`.
- If `git pull` would fail due to local changes, report the conflict clearly
and stop — do not stash, reset, or force.
- Do not expose repository contents that contain secrets (`.env`, credential
files) in the response — read and cite structure only.