claude-queue 1.5.0 → 1.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +60 -69
  2. package/claude-queue.sh +85 -12
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # claude-queue
2
2
 
3
- Automated GitHub issue solver & creator. Create well-structured issues from a text dump or interactive interview, then let Claude Code solve them overnight.
3
+ A CLI tool that solves GitHub issues using [Claude Code](https://docs.anthropic.com/en/docs/claude-code). It picks up open issues from your repo, solves them one by one, and opens a pull request with all the fixes. It can also create well-structured GitHub issues from a text description or interactive interview.
4
4
 
5
- claude-queue has two modes:
6
- - **Solve** (default) — fetches open issues, uses [Claude Code](https://docs.anthropic.com/en/docs/claude-code) to solve each one, and opens a pull request
7
- - **Create**decomposes a description into well-structured GitHub issues, either from inline text or via an interactive interview
5
+ The typical workflow is: open issues for whatever you need done, run `claude-queue`, and come back to a pull request with everything solved. I usually do this at night and review the PR in the morning.
6
+
7
+ Issues don't have to be code changes they can be investigative tasks like "figure out why the API is slow and document what you find" or "audit the codebase for accessibility issues". Claude will research, document findings, and commit whatever it produces.
8
8
 
9
9
  ## Prerequisites
10
10
 
@@ -18,7 +18,7 @@ claude-queue has two modes:
18
18
  npm install -g claude-queue
19
19
  ```
20
20
 
21
- Or run directly with npx:
21
+ Or run directly:
22
22
 
23
23
  ```bash
24
24
  npx claude-queue
@@ -34,32 +34,40 @@ Run from inside any git repository with GitHub issues:
34
34
  claude-queue
35
35
  ```
36
36
 
37
- #### Solve options
38
-
39
37
  | Flag | Default | Description |
40
38
  |------|---------|-------------|
39
+ | `--issue ID` | all issues | Solve specific issue(s) by ID, URL, or comma-separated IDs |
41
40
  | `--max-retries N` | `3` | Max retry attempts per issue before marking it failed |
42
- | `--max-turns N` | `50` | Max Claude Code turns per attempt (prevents runaway sessions) |
43
- | `--label LABEL` | all issues | Only process issues that have this label |
41
+ | `--max-turns N` | `50` | Max Claude Code turns per attempt |
42
+ | `--label LABEL` | all issues | Only process issues with this label (can be repeated) |
44
43
  | `--model MODEL` | CLI default | Claude model to use (e.g. `claude-sonnet-4-5-20250929`) |
45
- | `-h, --help` | | Show help |
46
-
47
- #### Solve examples
48
44
 
49
45
  ```bash
50
46
  # Solve all open issues
51
47
  claude-queue
52
48
 
49
+ # Solve a specific issue by number
50
+ claude-queue --issue 42
51
+
52
+ # Solve a specific issue by URL
53
+ claude-queue --issue https://github.com/owner/repo/issues/42
54
+
55
+ # Solve multiple specific issues
56
+ claude-queue --issue 1,2,3
57
+
53
58
  # Only solve issues labeled "bug"
54
59
  claude-queue --label bug
55
60
 
61
+ # Filter by multiple labels
62
+ claude-queue --label bug --label urgent
63
+
56
64
  # Use a specific model with more retries
57
65
  claude-queue --max-retries 5 --model claude-sonnet-4-5-20250929
58
66
  ```
59
67
 
60
68
  ### Creating issues
61
69
 
62
- Generate well-structured GitHub issues from a text description or an interactive interview with Claude.
70
+ Generate GitHub issues from a text description or an interactive interview with Claude.
63
71
 
64
72
  ```bash
65
73
  claude-queue create "Add dark mode and fix the login bug"
@@ -71,42 +79,31 @@ There are three ways to provide input:
71
79
  2. **Stdin** — run `claude-queue create` with no arguments, type or paste your text, then press Ctrl+D
72
80
  3. **Interactive** — run `claude-queue create -i` and Claude will ask clarifying questions before generating issues
73
81
 
74
- In all modes, Claude decomposes the input into individual, actionable issues with titles, markdown bodies, and labels (reusing existing repo labels where possible). You get a preview before anything is created.
75
-
76
- #### Create options
82
+ Claude decomposes the input into individual issues with titles, markdown bodies, and labels (reusing existing repo labels where possible). You get a preview before anything is created.
77
83
 
78
84
  | Flag | Default | Description |
79
85
  |------|---------|-------------|
80
86
  | `-i, --interactive` | off | Interview mode — Claude asks clarifying questions first |
81
87
  | `--label LABEL` | none | Add this label to every created issue |
82
88
  | `--model MODEL` | CLI default | Claude model to use |
83
- | `-h, --help` | | Show help for create |
84
-
85
- #### Create examples
86
89
 
87
90
  ```bash
88
- # Create issues from a text description
89
- claude-queue create "Add user avatars, implement search, and fix the 404 on /settings"
90
-
91
- # Interactive mode — Claude asks questions first
91
+ # Interactive mode
92
92
  claude-queue create -i
93
93
 
94
- # Paste a longer description via stdin
95
- claude-queue create
96
-
97
- # Add a label to all created issues (useful with --label on solve)
94
+ # Add a label to all created issues
98
95
  claude-queue create --label backlog "Refactor the auth module and add rate limiting"
99
96
  ```
100
97
 
101
- ### Workflow: create then solve
98
+ ### Create then solve workflow
102
99
 
103
- The `--label` flag on both commands lets you create a workflow where `create` plans the issues and bare `claude-queue` solves them:
100
+ The `--label` flag on both commands lets you create a pipeline where `create` plans the issues and `claude-queue` solves them:
104
101
 
105
102
  ```bash
106
- # Plan: create issues tagged "nightshift"
103
+ # Plan
107
104
  claude-queue create --label nightshift "Add dark mode and fix the login bug"
108
105
 
109
- # Solve: only process those issues
106
+ # Solve
110
107
  claude-queue --label nightshift
111
108
  ```
112
109
 
@@ -120,64 +117,58 @@ Use TypeScript strict mode.
120
117
  Never modify files in the src/legacy/ directory.
121
118
  ```
122
119
 
123
- These instructions are appended to the prompt Claude receives for each issue. This is useful for project-specific conventions that aren't captured in `CLAUDE.md`.
120
+ These instructions are appended to the prompt Claude receives for each issue. Useful for project-specific conventions that aren't in `CLAUDE.md`.
124
121
 
125
122
  ## How It Works
126
123
 
127
- ### 1. Preflight
124
+ ### Preflight
128
125
 
129
- Verifies all dependencies are available (`gh`, `claude`, `git`, `jq`), checks that `gh` is authenticated, and ensures the git working tree is clean. Aborts immediately if anything is missing.
126
+ Verifies all dependencies (`gh`, `claude`, `git`, `jq`), checks that `gh` is authenticated, and ensures the working tree is clean.
130
127
 
131
- ### 2. Label Setup
128
+ ### Label setup
132
129
 
133
130
  Creates three labels on the repo (skips if they already exist):
134
131
 
135
- | Label | Color | Meaning |
136
- |-------|-------|---------|
137
- | `claude-queue:in-progress` | Yellow | Currently being worked on |
138
- | `claude-queue:solved` | Green | Successfully fixed |
139
- | `claude-queue:failed` | Red | Could not be solved after all retries |
132
+ | Label | Meaning |
133
+ |-------|---------|
134
+ | `claude-queue:in-progress` | Currently being worked on |
135
+ | `claude-queue:solved` | Successfully fixed |
136
+ | `claude-queue:failed` | Could not be solved after all retries |
137
+
138
+ ### Branching
140
139
 
141
- These labels let you see at a glance which issues were handled and what the outcome was.
140
+ Creates a branch `claude-queue/YYYY-MM-DD` off your default branch. All fixes go into this one branch. If the branch already exists, a timestamp suffix is added.
142
141
 
143
- ### 3. Branch
142
+ ### Issue processing
144
143
 
145
- Creates a single branch `claude-queue/YYYY-MM-DD` off your default branch. All fixes for the night go into this one branch. If the branch already exists (e.g. from a previous run), a timestamp suffix is added.
144
+ For each open issue (up to 200, oldest first), or for the specific issues passed via `--issue`:
146
145
 
147
- ### 4. Issue Processing
146
+ 1. **Skip** — issues with any `claude-queue:*` label are skipped (unless targeted via `--issue`). Remove the label to re-process.
147
+ 2. **Label** — marks the issue `claude-queue:in-progress`.
148
+ 3. **Solve** — launches Claude Code with a prompt to read the issue, explore the codebase, implement a fix, and run tests.
149
+ 4. **Evaluate** — if Claude produced file changes, they are committed. If not, the attempt is retried.
150
+ 5. **Retry** — on failure, the working tree is reset and Claude gets a fresh context. Up to 3 attempts (configurable with `--max-retries`).
151
+ 6. **Result** — marks the issue `claude-queue:solved` or `claude-queue:failed`.
148
152
 
149
- For each open issue (up to 200, oldest first):
153
+ Issues are solved sequentially so later fixes build on earlier ones within a single branch.
150
154
 
151
- - **Skip check** — issues that already have any `claude-queue:*` label are skipped. Remove the label to re-process.
152
- - **Label** — marks the issue `claude-queue:in-progress`
153
- - **Solve** — launches a fresh Claude Code process (`claude -p`) with a prompt that tells it to:
154
- - Read the issue via `gh issue view`
155
- - Explore the codebase
156
- - Implement a fix
157
- - Run existing tests
158
- - **Evaluate** — if Claude produced file changes, they are committed. If not, the attempt is retried.
159
- - **Retry** — on failure, the working tree is reset to the last checkpoint (`git reset --hard`) and Claude gets a completely fresh context. Up to 3 attempts per issue (configurable with `--max-retries`).
160
- - **Label result** — marks the issue `claude-queue:solved` or `claude-queue:failed`
155
+ ### Review pass
161
156
 
162
- Each issue is solved sequentially so later fixes build on top of earlier onesall in a single branch.
157
+ After all issues are processed, Claude does a second pass reviewing all committed changes for bugs, incomplete implementations, and style issues fixing anything it finds.
163
158
 
164
- ### 5. Pull Request
159
+ ### Pull request
165
160
 
166
- Once all issues are processed, the branch is pushed and a PR is opened with:
161
+ Once done, the branch is pushed and a PR is opened with:
167
162
 
168
- - **Summary table** solved/failed/skipped counts and run duration
169
- - **Solved issues** table of all issues that were fixed with links
170
- - **Failed issues** table of issues that couldn't be solved
171
- - **Chain logs** — collapsible per-issue logs showing Claude's full output for each attempt
163
+ - Summary table with solved/failed/skipped counts and run duration
164
+ - Tables of solved and failed issues with links
165
+ - Collapsible per-issue logs showing Claude's full output
172
166
 
173
- If no issues were solved, no PR is created.
167
+ No PR is created if nothing was solved.
174
168
 
175
- ### Interruption Handling
169
+ ### Interruption handling
176
170
 
177
- If the script is interrupted (Ctrl+C, SIGTERM), it:
178
- - Removes the `claude-queue:in-progress` label from the current issue
179
- - Marks it as `claude-queue:failed`
180
- - Prints where your commits and logs are so nothing is lost
171
+ If interrupted (Ctrl+C, SIGTERM), the script removes the `claude-queue:in-progress` label from the current issue, marks it as failed, and prints where your commits and logs are.
181
172
 
182
173
  ## Logs
183
174
 
@@ -190,7 +181,7 @@ Full logs for each run are saved to `/tmp/claude-queue-DATE-TIMESTAMP/`:
190
181
  ├── issue-42-attempt-2.log # Raw Claude output, attempt 2
191
182
  ├── issue-57.md
192
183
  ├── issue-57-attempt-1.log
193
- └── pr-body.md # The generated PR description
184
+ └── pr-body.md # Generated PR description
194
185
  ```
195
186
 
196
187
  ## License
package/claude-queue.sh CHANGED
@@ -7,9 +7,10 @@
7
7
  # claude-queue create [options] Create issues from text or interactively
8
8
  #
9
9
  # Solve options:
10
+ # --issue ID Solve specific issue(s) by ID, URL, or comma-separated IDs
10
11
  # --max-retries N Max retries per issue (default: 3)
11
12
  # --max-turns N Max Claude turns per attempt (default: 50)
12
- # --label LABEL Only process issues with this label
13
+ # --label LABEL Only process issues with this label (can be repeated)
13
14
  # --model MODEL Claude model to use
14
15
  # -v, --version Show version
15
16
  # -h, --help Show this help message
@@ -26,7 +27,8 @@ VERSION=$(node -p "require('$(dirname "$0")/package.json').version" 2>/dev/null
26
27
 
27
28
  MAX_RETRIES=3
28
29
  MAX_TURNS=50
29
- ISSUE_FILTER=""
30
+ declare -a ISSUE_FILTERS=()
31
+ ISSUE_IDS=""
30
32
  MODEL_FLAG=""
31
33
  DATE=$(date +%Y-%m-%d)
32
34
  TIMESTAMP=$(date +%H%M%S)
@@ -49,6 +51,7 @@ declare -a SOLVED_ISSUES=()
49
51
  declare -a FAILED_ISSUES=()
50
52
  declare -a SKIPPED_ISSUES=()
51
53
  CURRENT_ISSUE=""
54
+ CHILD_PID=""
52
55
  START_TIME=$(date +%s)
53
56
 
54
57
  show_help() {
@@ -59,9 +62,10 @@ show_help() {
59
62
  echo " claude-queue create [options] [text] Create issues from text or interactively"
60
63
  echo ""
61
64
  echo "Solve options:"
65
+ echo " --issue ID Solve specific issue(s) by ID, URL, or comma-separated IDs"
62
66
  echo " --max-retries N Max retries per issue (default: 3)"
63
67
  echo " --max-turns N Max Claude turns per attempt (default: 50)"
64
- echo " --label LABEL Only process issues with this label"
68
+ echo " --label LABEL Only process issues with this label (can be repeated)"
65
69
  echo " --model MODEL Claude model to use"
66
70
  echo " -v, --version Show version"
67
71
  echo " -h, --help Show this help message"
@@ -108,6 +112,17 @@ cleanup() {
108
112
  log "Logs saved to: ${LOG_DIR}"
109
113
  fi
110
114
  }
115
+
116
+ handle_interrupt() {
117
+ if [ -n "$CHILD_PID" ] && kill -0 "$CHILD_PID" 2>/dev/null; then
118
+ kill -TERM "$CHILD_PID" 2>/dev/null || true
119
+ wait "$CHILD_PID" 2>/dev/null || true
120
+ fi
121
+ CHILD_PID=""
122
+ exit 130
123
+ }
124
+
125
+ trap handle_interrupt INT TERM
111
126
  trap cleanup EXIT
112
127
 
113
128
  preflight() {
@@ -181,15 +196,61 @@ setup_branch() {
181
196
  }
182
197
 
183
198
  fetch_issues() {
184
- local args=(--state open --json "number,title,body,labels" --limit 200)
199
+ local args=(--state open --json "number,title,body,labels" --limit 200 --sort created --direction asc)
185
200
 
186
- if [ -n "$ISSUE_FILTER" ]; then
187
- args+=(--label "$ISSUE_FILTER")
188
- fi
201
+ for filter in "${ISSUE_FILTERS[@]}"; do
202
+ args+=(--label "$filter")
203
+ done
189
204
 
190
205
  gh issue list "${args[@]}"
191
206
  }
192
207
 
208
+ parse_issue_number() {
209
+ local input="$1"
210
+
211
+ local num
212
+ num=$(echo "$input" | grep -oE '[0-9]+$' || echo "")
213
+
214
+ if [ -z "$num" ]; then
215
+ log_error "Invalid issue identifier: $input"
216
+ return 1
217
+ fi
218
+
219
+ echo "$num"
220
+ }
221
+
222
+ fetch_specific_issues() {
223
+ local ids_str="$1"
224
+ local result="["
225
+ local first=true
226
+
227
+ IFS=',' read -ra id_array <<< "$ids_str"
228
+ for id in "${id_array[@]}"; do
229
+ id=$(echo "$id" | xargs)
230
+
231
+ local num
232
+ if ! num=$(parse_issue_number "$id"); then
233
+ continue
234
+ fi
235
+
236
+ local issue_json
237
+ issue_json=$(gh issue view "$num" --json "number,title,body,labels" 2>/dev/null) || {
238
+ log_error "Could not fetch issue #${num}"
239
+ continue
240
+ }
241
+
242
+ if [ "$first" = true ]; then
243
+ first=false
244
+ else
245
+ result+=","
246
+ fi
247
+ result+="$issue_json"
248
+ done
249
+
250
+ result+="]"
251
+ echo "$result"
252
+ }
253
+
193
254
  process_issue() {
194
255
  local issue_number=$1
195
256
  local issue_title="$2"
@@ -267,7 +328,10 @@ description of what you changed and why."
267
328
  --dangerously-skip-permissions \
268
329
  --max-turns "$MAX_TURNS" \
269
330
  $MODEL_FLAG \
270
- > "$attempt_log" 2>&1 || claude_exit=$?
331
+ > "$attempt_log" 2>&1 &
332
+ CHILD_PID=$!
333
+ wait "$CHILD_PID" || claude_exit=$?
334
+ CHILD_PID=""
271
335
 
272
336
  if [ "$claude_exit" -ne 0 ]; then
273
337
  log_warn "Claude exited with code ${claude_exit}"
@@ -377,7 +441,10 @@ When you are done, output a line that says CLAUDE_QUEUE_REVIEW followed by a bri
377
441
  --dangerously-skip-permissions \
378
442
  --max-turns "$MAX_TURNS" \
379
443
  $MODEL_FLAG \
380
- > "$review_log" 2>&1 || true
444
+ > "$review_log" 2>&1 &
445
+ CHILD_PID=$!
446
+ wait "$CHILD_PID" 2>/dev/null || true
447
+ CHILD_PID=""
381
448
 
382
449
  local changed_files
383
450
  changed_files=$(git diff --name-only 2>/dev/null; git ls-files --others --exclude-standard 2>/dev/null)
@@ -516,7 +583,12 @@ main() {
516
583
  log_header "Fetching Issues"
517
584
 
518
585
  local issues
519
- issues=$(fetch_issues)
586
+ if [ -n "$ISSUE_IDS" ]; then
587
+ log "Fetching specific issue(s): ${ISSUE_IDS}"
588
+ issues=$(fetch_specific_issues "$ISSUE_IDS")
589
+ else
590
+ issues=$(fetch_issues)
591
+ fi
520
592
  local total
521
593
  total=$(echo "$issues" | jq length)
522
594
 
@@ -533,7 +605,7 @@ main() {
533
605
  title=$(echo "$issues" | jq -r ".[$i].title")
534
606
  labels=$(echo "$issues" | jq -r "[.[$i].labels[].name] | join(\",\")" 2>/dev/null || echo "")
535
607
 
536
- if echo "$labels" | grep -q "claude-queue:"; then
608
+ if [ -z "$ISSUE_IDS" ] && echo "$labels" | grep -q "claude-queue:"; then
537
609
  log "Skipping #${number} (already has a claude-queue label)"
538
610
  SKIPPED_ISSUES+=("${number}|${title}")
539
611
  continue
@@ -931,9 +1003,10 @@ case "$SUBCOMMAND" in
931
1003
  "")
932
1004
  while [[ $# -gt 0 ]]; do
933
1005
  case $1 in
1006
+ --issue) ISSUE_IDS="$2"; shift 2 ;;
934
1007
  --max-retries) MAX_RETRIES="$2"; shift 2 ;;
935
1008
  --max-turns) MAX_TURNS="$2"; shift 2 ;;
936
- --label) ISSUE_FILTER="$2"; shift 2 ;;
1009
+ --label) ISSUE_FILTERS+=("$2"); shift 2 ;;
937
1010
  --model) MODEL_FLAG="--model $2"; shift 2 ;;
938
1011
  -v|--version) echo "claude-queue v${VERSION}"; exit 0 ;;
939
1012
  -h|--help) show_help; exit 0 ;;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-queue",
3
- "version": "1.5.0",
3
+ "version": "1.5.2",
4
4
  "description": "Automated GitHub issue solver powered by Claude Code",
5
5
  "bin": {
6
6
  "claude-queue": "./claude-queue.sh"