| name |
description |
status |
created_at |
| _autonomous_pickup |
[SHARED SNIPPET — do not invoke directly] Forgejo queue pickup logic, импортируется во все auto-*.md агенты. Содержит claim/state-transition contract. |
draft |
2026-05-27 |
Autonomous queue pickup — shared contract
NOT a standalone agent. Этот файл — общая инструкция, которую копи-пастят
внутрь каждого auto-*.md. Содержит claim/lifecycle/kill-switch логику.
Forgejo API endpoints (на основе bot-PAT в окружении)
# Базовый URL и auth — приходят через env vars при запуске окна:
# FORGEJO_BASE_URL=https://git.gendsgn.ru/api/v1
# FORGEJO_PAT=<your bot's PAT>
# FORGEJO_REPO=lekss361/gendesign
curl_forgejo() {
curl -sS -H "Authorization: token $FORGEJO_PAT" \
-H "Content-Type: application/json" \
"$FORGEJO_BASE_URL/$1" "${@:2}"
}
Kill-switch check (выполняй ПЕРВЫМ делом в каждом /loop tick)
# Проверка через meta-issue с label "pause-bots"
if curl_forgejo "repos/$FORGEJO_REPO/issues?labels=pause-bots&state=open&limit=1" \
| jq -e 'length > 0' > /dev/null; then
echo "result: paused (pause-bots active)"
exit 0 # /loop спит до следующего тика
fi
Pickup query — по scope
SCOPE="backend" # ∈ {backend, frontend, db, qa, devops}
NEXT=$(curl_forgejo \
"repos/$FORGEJO_REPO/issues?state=open&labels=scope/$SCOPE,status/ready&assigned_to=none&sort=newest&limit=1" \
| jq -r '.[0] | if . then [.number, .title] | @tsv else "" end')
if [[ -z "$NEXT" ]]; then
echo "result: idle, no work for scope/$SCOPE"
exit 0
fi
Claim — atomic-ish через label transition
ISSUE=$(echo "$NEXT" | cut -f1)
# 1. Assign self
curl_forgejo "repos/$FORGEJO_REPO/issues/$ISSUE" -X PATCH \
-d "{\"assignees\": [\"$BOT_USERNAME\"]}"
# 2. Transition ready → wip
curl_forgejo "repos/$FORGEJO_REPO/issues/$ISSUE/labels" -X POST \
-d '{"labels": ["status/wip"]}'
curl_forgejo "repos/$FORGEJO_REPO/issues/$ISSUE/labels/status/ready" -X DELETE
# 3. Verify claim не перехвачен
ASSIGNEE=$(curl_forgejo "repos/$FORGEJO_REPO/issues/$ISSUE" | jq -r '.assignees[0].login // ""')
if [[ "$ASSIGNEE" != "$BOT_USERNAME" ]]; then
echo "result: lost race for #$ISSUE (claimed by $ASSIGNEE)"
exit 0
fi
State transitions reference
| От → К |
Кто переключает |
Условие |
(new) → status/ready |
auto-analyst |
issue декомпозирован, deps удовлетворены |
status/ready → status/wip |
auto-backend / auto-frontend |
claim успешный |
status/wip → status/review |
worker |
PR открыт |
status/review → status/qa |
auto-code-reviewer |
APPROVE + merge |
status/review → status/blocked |
auto-code-reviewer |
BLOCK/FIX verdict |
status/qa → status/done |
auto-qa-tester |
smoke OK, issue closed |
status/qa → status/blocked |
auto-qa-tester |
smoke FAIL |
status/blocked → status/ready |
only human |
manual unblock |
любой + pause-bots присутствует |
(никто не работает) |
kill-switch |
Stale-claim cleanup (cron на VPS — отдельная задача)
# Каждые 30 минут — освобождать issues застрявшие в wip >4h
curl_forgejo "repos/$FORGEJO_REPO/issues?labels=status/wip&state=open" \
| jq -r '.[] | select(.updated_at < (now - 4*3600 | todate)) | .number' \
| while read i; do
curl_forgejo "repos/$FORGEJO_REPO/issues/$i" -X PATCH -d '{"assignees": []}'
curl_forgejo "repos/$FORGEJO_REPO/issues/$i/labels" -X POST -d '{"labels":["status/ready"]}'
curl_forgejo "repos/$FORGEJO_REPO/issues/$i/labels/status/wip" -X DELETE
done
Self-throttle rules
- 3 итерации подряд idle →
sleep = min(current * 1.5, 60m)
- 3 итерации подряд success →
sleep = max(current * 0.8, 5m)
- 24h ничего не закрыл → result: idle 24h, эскалация (label
needs-human)
Error escalation
| Ошибка |
Действие |
| HTTP 401/403 от Forgejo |
PAT истёк / отозван → result: AUTH_ERROR, остановка окна |
| HTTP 500 от Forgejo |
result: forgejo down, sleep 30m |
| Subagent error 3× на одной issue |
+status/blocked +needs-human, отпустить assignee, next issue |