Skip to content

Instantly share code, notes, and snippets.

@ramsunvtech
Created June 21, 2026 11:00
Show Gist options
  • Select an option

  • Save ramsunvtech/c06c2b780a4f1e72f3ff23b4a05d9165 to your computer and use it in GitHub Desktop.

Select an option

Save ramsunvtech/c06c2b780a4f1e72f3ff23b4a05d9165 to your computer and use it in GitHub Desktop.
Frontend Claude MD Generator
#!/usr/bin/env bash
# Regenerates the "Routes" section of CLAUDE.md from a Next.js project.
# Works with App Router (app/) or Pages Router (pages/), auto-detected.
# Handles any route group names (parens), dynamic segments ([id], [...slug]),
# and flat structures with no groups at all.
# Everything outside the BEGIN/END markers is left untouched.
# Run from the repo root: ./update-claude-md.sh
set -euo pipefail
FILE="CLAUDE.md"
BEGIN="<!-- BEGIN:routes -->"
END="<!-- END:routes -->"
if [ ! -f "$FILE" ]; then
echo "Error: $FILE not found in $(pwd). Create it first." >&2
exit 1
fi
# Detect router type. Supports a /src layout too.
ROOT_DIR=""
ROUTER_TYPE=""
for candidate in "app" "src/app"; do
if [ -d "$candidate" ]; then
ROOT_DIR="$candidate"
ROUTER_TYPE="App Router"
break
fi
done
if [ -z "$ROOT_DIR" ]; then
for candidate in "pages" "src/pages"; do
if [ -d "$candidate" ]; then
ROOT_DIR="$candidate"
ROUTER_TYPE="Pages Router"
break
fi
done
fi
if [ -z "$ROOT_DIR" ]; then
echo "Error: no app/ or pages/ directory found. Run this from the repo root." >&2
exit 1
fi
# Folders to ignore anywhere in the tree (not routes)
EXCLUDE_NAMES="api|components|lib|utils|hooks|styles|constants|types|context|provider|redux|store|services|config|__tests__|node_modules"
is_route_group() {
[[ "$1" == \(*\) ]]
}
is_excluded() {
local name="$1"
[[ "$name" =~ ^(${EXCLUDE_NAMES})$ ]]
}
# List route-like children of a dir (skips excluded names, includes route groups & dynamic segments)
list_children() {
local dir="$1"
find "$dir" -mindepth 1 -maxdepth 1 -type d | sort | while IFS= read -r entry; do
basename "$entry"
done
}
LINES=""
while IFS= read -r name; do
full="$ROOT_DIR/$name"
if is_route_group "$name"; then
children=$(list_children "$full" | grep -vE "^(${EXCLUDE_NAMES})$" || true)
children_csv=$(echo "$children" | sed '/^$/d' | tr '\n' ',' | sed 's/,/, /g; s/, $//')
if [ -n "$children_csv" ]; then
LINES="${LINES}- \`${name}/\`${children_csv}\n"
else
LINES="${LINES}- \`${name}/\` (empty)\n"
fi
elif is_excluded "$name"; then
continue
else
LINES="${LINES}- \`${name}/\`\n"
fi
done < <(list_children "$ROOT_DIR")
if [ -z "$LINES" ]; then
LINES="(no routes found under ${ROOT_DIR}/)\n"
fi
BLOCK="${BEGIN}
## Routes (${ROUTER_TYPE}, \`${ROOT_DIR}/\`)
$(printf '%b' "$LINES")
${END}"
if grep -q "$BEGIN" "$FILE" 2>/dev/null; then
awk -v block="$BLOCK" -v begin="$BEGIN" -v end="$END" '
$0 ~ begin {print block; skip=1; next}
$0 ~ end {skip=0; next}
!skip {print}
' "$FILE" > "${FILE}.tmp" && mv "${FILE}.tmp" "$FILE"
echo "Updated route map in $FILE ($ROUTER_TYPE detected at $ROOT_DIR/)"
else
printf '\n%s\n' "$BLOCK" >> "$FILE"
echo "Added route map block to $FILE ($ROUTER_TYPE detected at $ROOT_DIR/)"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment