From edee9b8dcca0b9d9c3a904949eee17b315cc26ca Mon Sep 17 00:00:00 2001 From: Alexander Whitestone Date: Sun, 22 Mar 2026 19:39:46 -0400 Subject: [PATCH] fix: agents self-assign unassigned issues for max throughput Workers now pick ANY open issue (assigned to them OR unassigned) and self-assign via Gitea API before starting work. No more empty queues. Co-Authored-By: Claude Opus 4.6 --- bin/claude-loop.sh | 29 +++++++++++++++++------------ bin/gemini-loop.sh | 15 ++++++++++++++- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/bin/claude-loop.sh b/bin/claude-loop.sh index c4d2450..da04ae9 100755 --- a/bin/claude-loop.sh +++ b/bin/claude-loop.sh @@ -160,9 +160,9 @@ def priority(i): all_issues.sort(key=priority) for i in all_issues: - # Must be assigned to claude assignees = [a['login'] for a in (i.get('assignees') or [])] - if 'claude' not in assignees: + # Take issues assigned to claude OR unassigned (self-assign) + if assignees and 'claude' not in assignees: continue title = i['title'].lower() @@ -171,23 +171,28 @@ for i in all_issues: if '[showcase]' in title: continue num_str = str(i['number']) + if num_str in active_issues: continue - # Skip if already being worked on by another worker - if num_str in active_issues: - continue - - # Check skip list entry = skips.get(num_str, {}) - if entry and entry.get('until', 0) > time.time(): - continue + if entry and entry.get('until', 0) > time.time(): continue - # Check lock dir lock = '${LOCK_DIR}/' + i['_repo'].replace('/', '-') + '-' + num_str + '.lock' - if os.path.isdir(lock): - continue + if os.path.isdir(lock): continue repo = i['_repo'] owner, name = repo.split('/') + + # Self-assign if unassigned + if not assignees: + try: + data = json.dumps({'assignees': ['claude']}).encode() + req2 = urllib.request.Request( + f'{base}/api/v1/repos/{repo}/issues/{i[\"number\"]}', + data=data, method='PATCH', + headers={'Authorization': f'token {token}', 'Content-Type': 'application/json'}) + urllib.request.urlopen(req2, timeout=5) + except: pass + print(json.dumps({ 'number': i['number'], 'title': i['title'], diff --git a/bin/gemini-loop.sh b/bin/gemini-loop.sh index 505ef42..d65abb5 100755 --- a/bin/gemini-loop.sh +++ b/bin/gemini-loop.sh @@ -149,7 +149,8 @@ all_issues.sort(key=priority) for i in all_issues: assignees = [a['login'] for a in (i.get('assignees') or [])] - if 'gemini' not in assignees: + # Take issues assigned to gemini OR unassigned (self-assign) + if assignees and 'gemini' not in assignees: continue title = i['title'].lower() @@ -168,6 +169,18 @@ for i in all_issues: repo = i['_repo'] owner, name = repo.split('/') + + # Self-assign if unassigned + if not assignees: + try: + data = json.dumps({'assignees': ['gemini']}).encode() + req2 = urllib.request.Request( + f'{base}/api/v1/repos/{repo}/issues/{i["number"]}', + data=data, method='PATCH', + headers={'Authorization': f'token {token}', 'Content-Type': 'application/json'}) + urllib.request.urlopen(req2, timeout=5) + except: pass + print(json.dumps({ 'number': i['number'], 'title': i['title'],