Skip to content

Commit 5b6d2e6

Browse files
LeeCampbellclaude
andauthored
feat: fleet.sh assigns issues to containers for parallel isolation (HdrHistogram#121)
* feat: fleet.sh assigns issues to containers for parallel isolation fleet.sh now fetches available issues upfront and launches one container per issue with ISSUE_NUMBER env var, preventing duplicate work. agent-loop.sh pick-issue honours pre-assigned issue when set. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address PR review feedback - Use GH_TOKEN_UPSTREAM for gh issue view in pre-assigned path - Use 'add // []' in jq merge to guard against null Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: sort issues oldest-first in fleet.sh gh issue list defaults to newest-first. Add --search "sort:created-asc" so the fleet processes the oldest issues first. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent bd12dbd commit 5b6d2e6

2 files changed

Lines changed: 62 additions & 20 deletions

File tree

.devcontainer/agent-loop.sh

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -145,23 +145,31 @@ Closes #${ISSUE_NUM}"
145145
;;
146146

147147
pick-issue)
148-
ISSUE_JSON=$(gh issue list --assignee @me --state open \
149-
--repo "$UPSTREAM_REPO" \
150-
--json number,title --limit 1 2>/dev/null || echo "[]")
151-
152-
if [ "$ISSUE_JSON" = "[]" ] || [ "$ISSUE_JSON" = "" ]; then
153-
ISSUE_JSON=$(gh issue list --label agent --state open \
148+
if [ -n "${ISSUE_NUMBER:-}" ]; then
149+
# Issue pre-assigned by fleet.sh
150+
ISSUE_NUM="$ISSUE_NUMBER"
151+
ISSUE_TITLE=$(GH_TOKEN="$GH_TOKEN_UPSTREAM" gh issue view "$ISSUE_NUM" \
152+
--repo "$UPSTREAM_REPO" --json title --jq .title)
153+
else
154+
# Self-select: assigned first, then labelled 'agent'
155+
ISSUE_JSON=$(gh issue list --assignee @me --state open \
154156
--repo "$UPSTREAM_REPO" \
155157
--json number,title --limit 1 2>/dev/null || echo "[]")
156-
fi
157158

158-
ISSUE_NUM=$(echo "$ISSUE_JSON" | jq -r '.[0].number // empty')
159-
if [ -z "$ISSUE_NUM" ]; then
160-
echo "No work available."
161-
exit 0
162-
fi
159+
if [ "$ISSUE_JSON" = "[]" ] || [ "$ISSUE_JSON" = "" ]; then
160+
ISSUE_JSON=$(gh issue list --label agent --state open \
161+
--repo "$UPSTREAM_REPO" \
162+
--json number,title --limit 1 2>/dev/null || echo "[]")
163+
fi
164+
165+
ISSUE_NUM=$(echo "$ISSUE_JSON" | jq -r '.[0].number // empty')
166+
if [ -z "$ISSUE_NUM" ]; then
167+
echo "No work available."
168+
exit 0
169+
fi
163170

164-
ISSUE_TITLE=$(echo "$ISSUE_JSON" | jq -r '.[0].title')
171+
ISSUE_TITLE=$(echo "$ISSUE_JSON" | jq -r '.[0].title')
172+
fi
165173
BRANCH_SLUG=$(echo "$ISSUE_TITLE" | tr '[:upper:]' '[:lower:]' | \
166174
sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | head -c 40)
167175

.devcontainer/fleet.sh

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/bin/bash
2-
# fleet.sh — Spin up N agents, each assigned a different issue
2+
# fleet.sh — Fetch available issues and spin up one agent per issue
33
set -euo pipefail
44

55
FLEET_SIZE="${1:-3}"
@@ -9,11 +9,43 @@ source "$SCRIPT_DIR/.env"
99
# Build the image
1010
docker build -t hdrhistogram-agent -f "$SCRIPT_DIR/Dockerfile" "$SCRIPT_DIR/"
1111

12-
echo "Launching $FLEET_SIZE agents..."
12+
# Fetch available issues (assigned to agent first, then labelled 'agent')
13+
ISSUES=$(GH_TOKEN="$GH_TOKEN_UPSTREAM" gh issue list --assignee "$GIT_USER_NAME" --state open \
14+
--repo "$UPSTREAM_REPO" --json number,title --limit "$FLEET_SIZE" \
15+
--search "sort:created-asc" 2>/dev/null || echo "[]")
1316

14-
for i in $(seq 1 "$FLEET_SIZE"); do
15-
AGENT_NAME="hdrhistogram-agent-$i"
16-
echo "Starting $AGENT_NAME..."
17+
ISSUE_COUNT=$(echo "$ISSUES" | jq 'length')
18+
19+
if [ "$ISSUE_COUNT" -lt "$FLEET_SIZE" ]; then
20+
REMAINING=$((FLEET_SIZE - ISSUE_COUNT))
21+
ASSIGNED_NUMS=$(echo "$ISSUES" | jq -r '.[].number')
22+
23+
EXTRA=$(GH_TOKEN="$GH_TOKEN_UPSTREAM" gh issue list --label agent --state open \
24+
--repo "$UPSTREAM_REPO" --json number,title --limit "$REMAINING" \
25+
--search "sort:created-asc" 2>/dev/null || echo "[]")
26+
27+
# Filter out any already-assigned issues
28+
for num in $ASSIGNED_NUMS; do
29+
EXTRA=$(echo "$EXTRA" | jq --argjson n "$num" '[.[] | select(.number != $n)]')
30+
done
31+
32+
ISSUES=$(echo "$ISSUES $EXTRA" | jq -s 'add // []')
33+
fi
34+
35+
ISSUE_COUNT=$(echo "$ISSUES" | jq 'length')
36+
if [ "$ISSUE_COUNT" -eq 0 ]; then
37+
echo "No issues available."
38+
exit 0
39+
fi
40+
41+
echo "Found $ISSUE_COUNT issue(s). Launching agents..."
42+
43+
for i in $(seq 0 $((ISSUE_COUNT - 1))); do
44+
ISSUE_NUM=$(echo "$ISSUES" | jq -r ".[$i].number")
45+
ISSUE_TITLE=$(echo "$ISSUES" | jq -r ".[$i].title")
46+
AGENT_NAME="hdrhistogram-agent-${ISSUE_NUM}"
47+
48+
echo "Starting $AGENT_NAME for issue #${ISSUE_NUM}: ${ISSUE_TITLE}"
1749

1850
docker run -d --rm \
1951
--name "$AGENT_NAME" \
@@ -22,10 +54,12 @@ for i in $(seq 1 "$FLEET_SIZE"); do
2254
--memory=4g \
2355
--cpus=2 \
2456
--env-file "$SCRIPT_DIR/.env" \
25-
-e MAX_ITERATIONS=15 \
57+
-e ISSUE_NUMBER="$ISSUE_NUM" \
58+
-e MAX_ITERATIONS=50 \
2659
-v nuget-cache:/home/agent/.nuget/packages \
2760
hdrhistogram-agent
2861
done
2962

63+
echo ""
3064
echo "Fleet launched. Monitor with: docker ps --filter name=hdrhistogram-agent"
31-
echo "Logs: docker logs -f hdrhistogram-agent-1"
65+
echo "Logs: docker logs -f hdrhistogram-agent-<issue-number>"

0 commit comments

Comments
 (0)