bzr 0.4.4

A CLI for Bugzilla, inspired by gh
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
# Writing Claude Code Skills for bzr

This document is specific to Claude Code's skill format. For IBM Bob's skill format, see [bob-skills.md](bob-skills.md).

A guide for writing [Claude Code skills](https://docs.anthropic.com/en/docs/claude-code/skills) that drive bzr. Skills turn natural-language prompts into repeatable Bugzilla workflows your agent can execute.

bzr is a good fit for skills because every command supports `--json`, flags are consistent across subcommands, and the CLI covers the full Bugzilla lifecycle (bugs, comments, attachments, flags, products, users, groups, templates, saved queries, config).

For the full command reference, see [bzr-cli.md](bzr-cli.md).

## Directory Layout

Skills live in `.claude/skills/` as `SKILL.md` files. Since bzr skills are server-agnostic (use `--server` to target any configured instance), place them in your home directory so they work across all projects:

```
~/.claude/skills/
  bzr-triage/SKILL.md
  bzr-investigate/SKILL.md
  bzr-bug-summary/SKILL.md
  bzr-file-bug/SKILL.md
  bzr-review/SKILL.md
  bzr-setup/SKILL.md
  bzr-admin/SKILL.md
  bzr-saved-queries/SKILL.md
```

One skill per directory. The directory name becomes the `/slash-command` name.

## Key Patterns

Three patterns every bzr skill should use:

### `--json` goes before the subcommand

The `--json` flag is global — it must appear before the subcommand:

```bash
# preferred (shorthand)
bzr --json bug list --product Fedora

# also works (original form)
bzr --output json bug list --product Fedora

# wrong — flag is ignored
bzr bug list --product Fedora --output json
```

Always use `--json` in skills so the agent gets structured data it can parse.

### `allowed-tools` scopes permissions

Restrict what the skill can run. Add `Bash(jq *)` when the skill needs to parse JSON:

```yaml
allowed-tools: Bash(bzr *), Bash(jq *)
```

### `$ARGUMENTS` passes dynamic input

Use `$ARGUMENTS` for bug IDs, search terms, product names. The user provides them when invoking the skill:

```
/bzr-investigate 12345
```

Inside the skill body, `$ARGUMENTS` expands to `12345`.

### Avoid interactive or ambiguous steps

Skills should prefer explicit, non-interactive commands and should gather missing inputs before invoking write operations.

Examples:

- `bzr comment add 12345` at a TTY opens `$EDITOR`, which hangs non-interactive skill runs. Use `bzr comment add 12345 --body "text"` or pipe stdin instead.
- "File a bug" is incomplete if the skill has not collected `product`, `component`, and a useful description. Ask for them first, or use `bzr bug create --template <name> --summary "..." --description "..."`.
- "Resolve this bug" is risky if the skill has not checked valid status and resolution values for that server. Verify them with `bzr field list status` and `bzr field list resolution` before calling `bzr bug update`.

## Skill Examples

Eight complete skills covering common Bugzilla workflows. Copy any of these into `~/.claude/skills/<name>/SKILL.md`.

### bzr-triage — Search and prioritize NEW bugs

```yaml
---
name: bzr-triage
description: Search for NEW bugs in a product and help prioritize them
argument-hint: [product]
allowed-tools: Bash(bzr *), Bash(jq *)
---

# Triage NEW Bugs

Search for untriaged bugs in the **$ARGUMENTS** product and help prioritize them.

## Steps

1. List NEW bugs:
   `bzr --json bug list --product "$ARGUMENTS" --status NEW --limit 50`
2. Look up valid priorities and severities:
   `bzr --json field list priority`
   `bzr --json field list severity`
3. Present a summary table of bugs (ID, summary, severity, assignee)
4. For each bug the user selects, update priority/severity/assignee:
   `bzr bug update <ID> --priority <P> --severity <S>`

Always confirm before updating bugs.
```

### bzr-investigate — Deep-dive into a single bug

```yaml
---
name: bzr-investigate
description: Gather all context for a bug — details, comments, history, and attachments
argument-hint: [bug-id]
allowed-tools: Bash(bzr *), Bash(jq *)
---

# Investigate Bug

Gather full context for bug **$ARGUMENTS**.

## Steps

1. View the bug:
   `bzr --json bug view $ARGUMENTS`
2. List comments:
   `bzr --json comment list $ARGUMENTS`
3. View change history:
   `bzr --json bug history $ARGUMENTS`
4. List attachments:
   `bzr --json attachment list $ARGUMENTS`
5. Summarize findings: current status, key discussion points,
   recent changes, and any pending review requests or needinfo flags.
```

### bzr-bug-summary — Analyze and summarize bug history

```yaml
---
name: bzr-bug-summary
description: Fetch bug details and generate a concise summary of status, history, blockers, and next actions
argument-hint: [bug-id...]
allowed-tools: Bash(bzr *), Bash(jq *)
---

# Summarize Bugzilla Bugs

Analyze one or more bugs from **$ARGUMENTS** and produce a concise technical summary.

## Steps

1. For each bug, fetch core details:
   `bzr --json bug view <BUG_ID>`
2. Fetch change history:
   `bzr --json bug history <BUG_ID>`
3. Fetch comments when recent discussion matters:
   `bzr --json comment list <BUG_ID>`
4. Fetch attachments when patches, logs, or test cases may affect the summary:
   `bzr --json attachment list <BUG_ID>`
5. Extract the important points: status, assignee, component, whiteboard, dependencies, recent activity, and any blockers or next actions.
6. Present results:
   - For a single bug, summarize the issue, current state, recent activity, blockers, and recommended next step.
   - For multiple bugs, start with a comparison table and then give short summaries for each bug.

Keep the summary factual and concise. Do not speculate about root cause when the bug history does not support it.
```

### bzr-file-bug — File a new bug interactively

```yaml
---
name: bzr-file-bug
description: File a new bug with product/component validation
argument-hint: [product]
disable-model-invocation: true
allowed-tools: Bash(bzr *), Bash(jq *)
---

# File a New Bug

File a bug in the **$ARGUMENTS** product.

## Steps

1. Verify the product exists and list its components:
   `bzr --json product view "$ARGUMENTS"`
2. Look up valid priorities and severities:
   `bzr --json field list priority`
   `bzr --json field list severity`
3. Ask the user for: component, summary, description, priority, severity
4. Check for saved templates:
   `bzr template list`
   If one matches the product, use it:
   `bzr bug create --template <TMPL> --summary "<S>" --description "<D>"`
5. Otherwise, create the bug (always pass `--description` to avoid opening `$EDITOR`):
   `bzr bug create --product "$ARGUMENTS" --component <C> --summary "<S>" --description "<D>" --priority <P> --severity <S>`
6. Show the created bug ID.
```

### bzr-review — Review patches on a bug

```yaml
---
name: bzr-review
description: Download and review patch attachments on a bug
argument-hint: [bug-id]
allowed-tools: Bash(bzr *), Bash(jq *), Bash(cat /tmp/bzr-review-*)
---

# Review Patches

Review patch attachments on bug **$ARGUMENTS**.

## Steps

1. List attachments and filter for patches:
   `bzr --json attachment list $ARGUMENTS | jq '[.[] | select(.is_patch == true and .is_obsolete == false)]'`
2. For each active patch, download to `/tmp`:
   `bzr attachment download <ID> -o /tmp/bzr-review-<ID>.patch`
3. Read and review each patch file
4. Present a review summary for each patch:
   - What the patch changes
   - Potential issues or risks
   - Suggested review flag (review+, review-, review?)
5. If the user approves, post a review comment:
   `bzr comment add $ARGUMENTS --body "<review text>"`
   And optionally set the review flag:
   `bzr attachment update <ID> --flag "review+(user@example.com)"`
```

### bzr-setup — Configure a Bugzilla server

```yaml
---
name: bzr-setup
description: Walk through configuring a new Bugzilla server connection
disable-model-invocation: true
allowed-tools: Bash(bzr *)
---

# Set Up a Bugzilla Server

Walk the user through connecting to a Bugzilla server.

## Steps

1. Ask for: server alias name, URL, API key, and optionally email
   (email is needed for Bugzilla 5.0 or earlier)
2. Configure the server:
   `bzr config set-server <NAME> --url <URL> --api-key-env <ENV_VAR>`
   Add `--email <EMAIL>` if provided.
3. Verify the connection:
   `bzr --server <NAME> whoami`
4. Show server info:
   `bzr --server <NAME> server info`
5. If this is the first server, it becomes the default automatically.
   Otherwise ask if the user wants to set it as default:
   `bzr config set-default <NAME>`
6. Show final config:
   `bzr --json config show`
```

### bzr-admin — Admin: products, users, groups

```yaml
---
name: bzr-admin
description: Admin operations — create/update products, components, users, and groups
disable-model-invocation: true
allowed-tools: Bash(bzr *), Bash(jq *)
---

# Bugzilla Admin Operations

Perform admin operations on the Bugzilla server. All commands below
require admin privileges.

## Available operations

Ask the user what they want to do:

### Products
- List products: `bzr --json product list`
- View product: `bzr --json product view "<NAME>"`
- Create product: `bzr product create --name "<N>" --description "<D>"`
- Update product: `bzr product update "<NAME>" --description "<D>"`

### Components
- Create: `bzr component create --product "<P>" --name "<N>" --description "<D>" --default-assignee <E>`
- Update: `bzr component update <ID> --name "<N>"`

### Users
- Search: `bzr --json user search "<QUERY>"`
- Create: `bzr user create --email <E> --full-name "<N>"`
- Update: `bzr user update <USER> --real-name "<N>"`

### Groups
- View: `bzr --json group view <GROUP>`
- List members: `bzr --json group list-users --group <G>`
- Create: `bzr group create --name "<N>" --description "<D>"`
- Add user: `bzr group add-user --group <G> --user <U>`
- Remove user: `bzr group remove-user --group <G> --user <U>`

Confirm before every write operation.
```

### bzr-saved-queries — Manage and run saved queries

```yaml
---
name: bzr-saved-queries
description: Save, list, and run reusable bug queries
argument-hint: [action] [name]
allowed-tools: Bash(bzr *), Bash(jq *)
---

# Saved Queries

Manage saved bug queries. Saved queries store filter combinations
locally and can be executed later with `query run`.

## Steps

Parse `$ARGUMENTS` as `<action> [name] [extra]`:

### save
1. Ask the user for filters: product, component, status, priority,
   severity, assignee, creator, limit. At least one filter is required.
   For free-text search queries, use `--search` instead of list filters.
2. Save the query:
   `bzr query save <name> --product P --status NEW --status CONFIRMED --limit 50`
   Or for search queries:
   `bzr query save <name> --search "crash on startup" --limit 20`
3. Confirm: the response shows `"action": "saved"` or `"action": "updated"`.

### list
1. List all saved queries:
   `bzr query list`

### show
1. Show details of a saved query:
   `bzr --json query show <name>`

### run
1. Execute a saved query against the server:
   `bzr --json query run <name>`
   Override limit or fields at runtime:
   `bzr --json query run <name> --limit 10 --fields id,summary,status`

### delete
1. Delete a saved query:
   `bzr query delete <name>`
```

## Composing Multi-Step Skills

Skills can chain multiple bzr commands into a pipeline. Two examples:

### Bug-to-patch review pipeline

This skill searches for bugs with unreviewed patches and builds a review queue:

```yaml
---
name: bzr-review-queue
description: Find bugs with unreviewed patches and present a review queue
argument-hint: [product]
allowed-tools: Bash(bzr *), Bash(jq *), Bash(cat /tmp/bzr-review-*)
---

# Patch Review Queue

Find bugs in **$ARGUMENTS** that have unreviewed patches.

## Steps

1. List open bugs in the product:
   `bzr --json bug list --product "$ARGUMENTS" --status NEW --status ASSIGNED --limit 100`

2. For each bug, check for non-obsolete patch attachments:
   `bzr --json attachment list <BUG_ID> | jq '[.[] | select(.is_patch == true and .is_obsolete == false)]'`

3. Collect bugs that have at least one active patch into a review queue.

4. For each bug in the queue, download the latest patch:
   `bzr attachment download <ATTACHMENT_ID> -o /tmp/bzr-review-<ATTACHMENT_ID>.patch`

5. Present the review queue as a numbered list:
   - Bug ID, summary, patch count, last updated

6. Let the user pick a bug to review, then show the patch content
   and help them write a review comment.
```

### Sprint report

This skill generates a summary of resolved bugs over a date range:

```yaml
---
name: bzr-sprint-report
description: Summarize resolved bugs in a product for a date range
argument-hint: [product]
allowed-tools: Bash(bzr *), Bash(jq *)
---

# Sprint Report

Generate a report of resolved bugs in **$ARGUMENTS**.

## Steps

1. Ask the user for the date range (start and end dates).

2. List resolved bugs:
   `bzr --json bug list --product "$ARGUMENTS" --status RESOLVED --limit 200`

3. Use `jq` to filter bugs by last-change date within the range
   and group by resolution:
   `jq '[.[] | select(.last_change_time >= "START" and .last_change_time <= "END")]
        | group_by(.resolution)
        | map({resolution: .[0].resolution, count: length, bugs: [.[].id]})'`

4. Present a summary:
   - Total bugs resolved
   - Breakdown by resolution (FIXED, WONTFIX, DUPLICATE, etc.)
   - List of bug IDs per resolution category

5. Optionally drill into any category for full bug details.
```

## Tips and Gotchas

- **Use `--json` shorthand**: `--json` is equivalent to `--output json` but shorter. Skills can also set `BZR_OUTPUT=json` in the environment to avoid repeating the flag.
- **Auto-detection**: When bzr's stdout is not a TTY (piped, redirected, or captured with `$(...)`), bzr outputs JSON automatically. At an interactive TTY, use `--json` or set `BZR_OUTPUT=json`.
- **Flag positioning**: `--json` and `--server` go *before* the subcommand. `bzr --json bug list`, not `bzr bug list --json`.
- **Exit codes**: bzr uses distinct exit codes 0–13 (e.g. 0=success, 2=usage/not-found, 3=config, 4=API, 5=network, 6=IO, 9=auth, 12=keyring, 13=TLS pin mismatch). See `docs/bzr-cli.md` for the full table. Skills can check `$?` to handle errors without parsing stderr.
- **JSON errors**: When `--json` is active, errors are emitted as JSON on stderr: `{"error":{"type":"api","message":"...","exit_code":4}}`.
- **Mutation responses**: Create/update commands return structured JSON with `--json`: `{"id":123,"resource":"bug","action":"created"}`. No need for regex to extract IDs.
- **Adding comments**: Use `--body "<text>"` in skills — it is explicit and works in all contexts. Alternatively, `echo "text" | bzr comment add 12345` works when stdin is not a TTY. Omitting both at a TTY opens `$EDITOR`, which hangs in non-interactive skill runs.
- **Attachment downloads**: Use `-o /tmp/<name>` to save attachments to a known path the agent can read back.
- **Validate before updating**: Use `bzr field list <field>` to check valid values for status, priority, severity, and resolution before calling `bug update`.
- **Flag syntax**: `review?(user@example.com)` requests review, `review+` grants, `review-` denies. See [Flag Syntax](bzr-cli.md#flag-syntax).
- **Default limit is 50**: `bug list` and `bug search` return at most 50 results by default. Set `--limit` explicitly when you need more (or fewer).
- **`disable-model-invocation: true`**: Use this for skills with side effects (creating bugs, updating configs, admin ops) so Claude only runs them when you explicitly invoke `/skill-name`.
- **Templates**: Save common field sets with `bzr template save <name> --product P --component C --priority Normal --severity normal`, then file bugs with `bzr bug create --template <name> --summary "..."`. Templates are local config, not server state.
- **Saved queries**: Store reusable search filters with `bzr query save <name> --product P --status NEW --limit 50`, then run them with `bzr --json query run <name>`. Supports runtime overrides (`--limit`, `--fields`).
- **Field aliases**: `bzr field aliases` lists all field name aliases (e.g. `status` → `bug_status`, `severity` → `bug_severity`). Use the short names in skills.
- **TLS**: For self-signed or internal Bugzilla servers, set `--tls-insecure` when configuring the server: `bzr config set-server internal --url https://bugzilla.internal --api-key-env INTERNAL_BZ_API_KEY --tls-insecure`. The flag is persisted per-server, not passed on every command.
- **Multi-server**: Pass `--server <name>` to target a non-default server. Works with every command.

## Quick Reference

Common tasks mapped to bzr commands for use in skills:

| Task | Command |
|------|---------|
| List open bugs | `bzr --json bug list --product P --status NEW` |
| Full-text search | `bzr --json bug search "query" --limit 20` |
| View bug details | `bzr --json bug view ID` |
| View bug history | `bzr --json bug history ID` |
| Create a bug | `bzr bug create --product P --component C --summary "S" --description "D"` |
| Update bug status | `bzr bug update ID --status S --resolution R` |
| Set a flag | `bzr bug update ID --flag "review?(user@example.com)"` |
| List comments | `bzr --json comment list BUG_ID` |
| Add a comment | `bzr comment add BUG_ID --body "text"` |
| List attachments | `bzr --json attachment list BUG_ID` |
| Download attachment | `bzr attachment download ID -o /tmp/file` |
| Upload attachment | `bzr attachment upload BUG_ID file.patch --flag "review?(user)"` |
| List products | `bzr --json product list` |
| View product | `bzr --json product view NAME` |
| Look up field values | `bzr --json field list priority` |
| List field aliases | `bzr --json field aliases` |
| Save a template | `bzr template save NAME --product P --component C` |
| Create bug from template | `bzr bug create --template NAME --summary "S"` |
| List templates | `bzr template list` |
| Save a query | `bzr query save NAME --product P --status NEW --limit 50` |
| Run a saved query | `bzr --json query run NAME` |
| List saved queries | `bzr query list` |
| Search users | `bzr --json user search "query"` |
| Check auth | `bzr --json whoami` |
| Server version | `bzr --json server info` |
| Show config | `bzr --json config show` |