From bc259b802434602ffa995daeca61d703ac695458 Mon Sep 17 00:00:00 2001 From: lekss361 Date: Sun, 24 May 2026 12:13:59 +0300 Subject: [PATCH] =?UTF-8?q?chore(claude):=20agents=20view=20readiness=20?= =?UTF-8?q?=E2=80=94=20cleanup=20script,=20worktreeinclude,=20workflow=20r?= =?UTF-8?q?ules?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Подготовка к переходу на 'claude agents' dashboard как daily driver: - scripts/cleanup-merged-worktrees.sh: removes worktrees whose branch is ancestor of forgejo/main. Run weekly via cron or manually after merge bursts. Safe — skips unmerged branches and current worktree. - .worktreeinclude: copies .env files + .mcp.json into every new worktree (otherwise backend/frontend/MCP fail to start in fresh worktrees Claude creates for background sessions). - .claude/rules/git-pr.md: - new MANDATORY workflow: default 'claude --bg --name X' background session (auto worktree, auto baseRef=fresh) vs foreground fallback - session naming convention (--name kebab-case) - polling section: preferred (agents view row status ●) vs foreground fallback (Skill loop) - new 'Multi-session workflow (Agent View)' section: parallelism budget, Ctrl+T pin, deprecated 'manual git worktree add', weekly cleanup ref Local-only (not in this PR): - .claude/settings.json: worktree.{baseRef:fresh, bgIsolation:worktree} (gitignored as personal preference) Pre-cleanup state: 102 worktrees / 14GB. After: 99 / 14GB — only 3 squash- merged branches removed via safe --is-ancestor check; 99 retained as unmerged WIP. Aggressive cleanup (by age + Forgejo PR check) — future PR. --- .claude/rules/git-pr.md | 46 +++++++++++++++++-- .worktreeinclude | 15 ++++++ scripts/cleanup-merged-worktrees.sh | 71 +++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+), 5 deletions(-) create mode 100644 .worktreeinclude create mode 100755 scripts/cleanup-merged-worktrees.sh diff --git a/.claude/rules/git-pr.md b/.claude/rules/git-pr.md index 4fcb2d0d..8a9d769c 100644 --- a/.claude/rules/git-pr.md +++ b/.claude/rules/git-pr.md @@ -11,19 +11,34 @@ paths: ## Branch + PR (MANDATORY) +**Default workflow — background session через `claude --bg`:** + ``` -1. git fetch forgejo && git checkout -b feat/ forgejo/main # или fix/ refactor/ docs/ chore/ perf/ +1. claude --bg --name "feat-" "task description" + → supervisor создаёт worktree от forgejo/main автоматически + (settings worktree.baseRef=default, bgIsolation=git) +2. Session работает: код → commit → push → mcp__forgejo__create_pull_request +3. PR URL появляется в agent view как row с зелёной/жёлтой/красной ● status dot +4. User делает review через external Claude window (post-push) +5. После merge — `Ctrl+X dwa раза` в agent view = удаление session + worktree +``` + +**Foreground workflow** (когда нужен интерактив, ad-hoc fixes): + +``` +1. git fetch forgejo && git checkout -b feat/ forgejo/main 2. [worker делает код, staged] 3. code-reviewer subagent на staged changes (pre-push) 4. main session: git commit -m "feat(scope): ..." 5. git push -u forgejo feat/ -6. mcp__forgejo__create_pull_request (или curl POST $REPO/pulls) -7. Вернуть PR URL пользователю (https://git.gendsgn.ru/lekss361/gendesign/pulls/) -8. СРАЗУ Skill loop polling (см. Polling loop) +6. mcp__forgejo__create_pull_request +7. Вернуть PR URL пользователю ``` **Никаких direct push в main.** Только через PR merge через Forgejo. `gh` CLI bypassed (2026-05-16) — все PR-операции через `mcp__forgejo__*` или curl + `$FORGEJO_TOKEN`. +**Session naming MANDATORY** для background spawn: `--name "--"` (kebab-case, ≤30 chars). Примеры: `feat-tradein-cron`, `fix-nominatim-rate-limit`, `chore-claude-config`. Resume: `claude --resume feat-tradein-cron`. Filter в agent view: type `feat-tradein` в input. + ## Commit messages - **Conventional**: `feat(scope): ...` / `fix(scope): ...` / `refactor/docs/chore/perf` @@ -49,7 +64,15 @@ Closes #N ## Polling loop -После `mcp__forgejo__create_pull_request` — СРАЗУ `Skill loop` (self-paced, 90-120s) или background Bash poll: +**Preferred (background session):** dispatch'нул через `claude --bg --name "feat-X"` → session сама делает PR + monitor. В `claude agents` row показывает: +- 🟡 yellow ● = waiting on checks/review +- 🟢 green ● = merged +- 🔴 red ● = checks failed +- ⚫ grey ● = draft/closed + +Не нужно отдельный polling loop — supervisor сам обновляет row каждые 15s. Peek (`Space`) для контекста, attach (`Enter`) если нужен fixup. + +**Foreground fallback** — если работаешь без agents view: `Skill loop` (self-paced, 90-120s) или background Bash poll: 1. `mcp__forgejo__get_pull_request` (или `curl -sH "$H" "$REPO/pulls/"`) → читай `state`, `mergeable`, `head.sha` 2. `state == merged` → stop polling @@ -94,6 +117,19 @@ Issues ≥ 1.5 day → 3-4 sub-PRs: **Foundation → Schema → Workers → Inte - **Pre-push** (локально): spawn `code-reviewer` subagent на staged changes → lint pass (security, correctness, conventions). Блокирует push при 🔴 критикал. - **Post-push** (внешнее окно Claude): делает review после PR create, постит комменты от `lekss361`. Main session НЕ дублирует — только acting on review comments (fixup commits). +## Multi-session workflow (Agent View) + +**Default daily driver:** одно окно с `claude agents` всегда открыто. Все задачи dispatch'аются оттуда через type prompt + Enter — каждая создаёт background session с собственной worktree. + +- **Параллелизм**: 3-5 sessions одновременно (>5 = bottleneck на review, не на Claude per Anthropic метрика) +- **Pin (`Ctrl+T`)** для long-running sessions (scraper monitors, deploy watchers) — supervisor не убьёт через 1h idle +- **Cleanup**: `Ctrl+X dwa раза` после merge → session + worktree удалены атомарно +- **NEVER** parallel sessions на one file — каждая ест в own worktree, last-merge wins (используй sequential PR rule выше) + +**Manual `git worktree add` deprecated** — используй `claude --bg --name X`, supervisor сам isolation делает с `baseRef: default` (свежая ветка от main, не от твоей stale-сессии). + +**Worktree cleanup** (cron weekly): `scripts/cleanup-merged-worktrees.sh` — удаляет worktrees для merged branches. Запускать вручную или wee­k­ly cron. + ## Запреты - ❌ `git push forgejo main` / direct push в main diff --git a/.worktreeinclude b/.worktreeinclude new file mode 100644 index 00000000..6f120560 --- /dev/null +++ b/.worktreeinclude @@ -0,0 +1,15 @@ +# Files copied into every new Claude Code worktree (despite being gitignored). +# +# `claude --bg` / `claude --worktree` / `claude agents` create fresh worktrees +# from a clean tree. Without these files copied, backend won't start (missing +# .env), frontend won't connect to API, MCP servers won't authenticate. +# +# Only gitignored files matched by these patterns are copied — tracked files +# are never duplicated. +# +# Reference: https://code.claude.com/docs/en/worktrees#copy-gitignored-files + +backend/.env +backend/.env.runtime +frontend/.env.local +.mcp.json diff --git a/scripts/cleanup-merged-worktrees.sh b/scripts/cleanup-merged-worktrees.sh new file mode 100755 index 00000000..0c9cd672 --- /dev/null +++ b/scripts/cleanup-merged-worktrees.sh @@ -0,0 +1,71 @@ +#!/bin/bash +# Cleanup merged Claude Code background-session worktrees. +# +# `claude agents` / `claude --bg` создают `.claude/worktrees/agent-*` для +# каждой background session. После merge PR worktree остаётся locked +# и не удаляется автоматически — за неделю накапливаются десятки. +# +# Скрипт сравнивает branch каждого worktree с `forgejo/main`; если branch +# полностью в main (merged) — удаляет worktree с `--force` (worktree +# заперт супервизором). Затем `git worktree prune` чистит references. +# +# Запускать вручную или через cron (weekly recommended): +# 0 9 * * MON cd /path/to/gendesign && ./scripts/cleanup-merged-worktrees.sh +# +# Safe: +# - Не трогает unmerged branches (in-progress work, PR ещё не merged) +# - Не трогает worktree.lock с твоими running sessions (force нужен только +# потому что Claude Code ставит lock автоматически) +# - Логи action — каждый удалённый branch выводится отдельной строкой +# +# Reference: https://code.claude.com/docs/en/worktrees#clean-up-worktrees + +set -e + +REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$REPO_ROOT" + +echo "Fetching forgejo/main..." +git fetch forgejo main --quiet + +BEFORE=$(git worktree list | wc -l) +SIZE_BEFORE=$(du -sh .claude/worktrees/ 2>/dev/null | awk '{print $1}') + +echo "Scanning $((BEFORE - 1)) worktrees (skip main)..." + +REMOVED=0 +KEPT=0 + +# Parse `git worktree list --porcelain` into "path branch" pairs. +git worktree list --porcelain | awk '/^worktree/{w=$2} /^branch/{b=$2} /^$/{print w" "b}' | \ +while read path branch; do + # Skip main worktree (no branch field) and detached HEADs. + [ -z "$branch" ] && continue + + short="${branch#refs/heads/}" + + # Don't touch the worktree we're standing in. + if [ "$path" = "$REPO_ROOT" ]; then + continue + fi + + if git merge-base --is-ancestor "$short" forgejo/main 2>/dev/null; then + if git worktree remove --force "$path" 2>/dev/null; then + echo " removed: $short" + REMOVED=$((REMOVED + 1)) + else + echo " failed: $short ($path)" + fi + else + KEPT=$((KEPT + 1)) + fi +done + +git worktree prune + +AFTER=$(git worktree list | wc -l) +SIZE_AFTER=$(du -sh .claude/worktrees/ 2>/dev/null | awk '{print $1}') + +echo "" +echo "Before: $((BEFORE - 1)) worktrees, $SIZE_BEFORE" +echo "After: $((AFTER - 1)) worktrees, $SIZE_AFTER" -- 2.45.3