bmo 0.2.2

Local-first SQLite-backed CLI issue tracker for AI agents
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
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
# bmo

![bmo logo](https://raw.githubusercontent.com/erewok/bmo/main/assets/bmo-full.png)

![CI](https://github.com/erewok/bmo/actions/workflows/ci.yaml/badge.svg)
`bmo` is a local-first command-line issue tracker backed by a single SQLite file, designed for use by both human developers and AI agents operating in a terminal. It requires no server, no network dependency, and no external services. Issues are identified by `BMO-N` IDs.

## Attribution

`bmo` was inspired by and adapted from [docket](https://github.com/ALT-F4-LLC/docket), an issue tracker for AI agents written by **ALT-F4-LLC**. The design, data model, and command structure of BMO all owe a direct debt to that project, and all credit for the underlying ideas belongs there.

In addition, the code in this repository was written by [Claude Code](https://claude.ai/claude-code), Anthropic's AI coding assistant. The repo owner directed this work.

## Installation

**From crates.io (recommended):**

```bash
cargo install bmo
```

**From source:**

```bash
cargo install --path .
```

**Pre-built binaries:**

Download the latest binary for your platform from [GitHub Releases](https://github.com/erewok/bmo/releases).

## Quickstart

```bash
bmo init
bmo issue create --title "First issue" --priority medium --kind task
bmo issue list
bmo board
bmo web
```

## Commands

### Global Flags

These flags are accepted by every command.

| Flag | Type | Default | Description |
|---|---|---|---|
| `--json` | bool | false | Output results as JSON |
| `--db <PATH>` | string | auto | Override database path (also reads `BMO_DB` env var) |

---

### Issue Management

#### bmo issue create

Create a new issue.

```sh
bmo issue create --title <title> [options]
```

| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
| `--title` | `-t` | string | required | Issue title |
| `--description` | `-d` | string | `""` | Issue description |
| `--status` | `-s` | string | `backlog` | Initial status |
| `--priority` | `-p` | string | `medium` | Priority level |
| `--kind` | `-T` | string | `task` | Issue kind |
| `--assignee` | `-a` | string | none | Assignee name |
| `--parent` | | string | none | Parent issue ID |
| `--label` | `-l` | string | none | Label name (repeatable) |
| `--file` | `-f` | string | none | File path to attach (repeatable) |

#### bmo issue list

List issues with optional filters.

```sh
bmo issue list [options]
```

| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
| `--status` | `-s` | string | none | Filter by status (repeatable) |
| `--priority` | `-p` | string | none | Filter by priority (repeatable) |
| `--kind` | `-T` | string | none | Filter by kind (repeatable) |
| `--assignee` | `-a` | string | none | Filter by assignee |
| `--label` | `-l` | string | none | Filter by label, AND semantics (repeatable) |
| `--parent` | | string | none | Filter by parent ID |
| `--search` | | string | none | Search in title and description |
| `--limit` | | integer | `50` | Maximum number of results |
| `--sort` | | string | none | Sort field |
| `--all` | | bool | false | Include done issues |

#### bmo issue show

Show full detail for a single issue.

```sh
bmo issue show <id>
```

#### bmo issue edit

Edit issue fields. Only supplied flags are updated.

```sh
bmo issue edit <id> [options]
```

| Flag | Short | Type | Description |
|---|---|---|---|
| `--title` | `-t` | string | New title |
| `--description` | `-d` | string | New description |
| `--status` | `-s` | string | New status |
| `--priority` | `-p` | string | New priority |
| `--kind` | `-T` | string | New kind |
| `--assignee` | `-a` | string | New assignee |
| `--parent` | | string | New parent issue ID |

#### bmo issue move

Change the status of an issue.

```sh
bmo issue move <id> --status <status>
```

| Flag | Short | Type | Description |
|---|---|---|---|
| `--status` | `-s` | string | New status value |

#### bmo issue close

Close an issue by setting its status to `done`.

```sh
bmo issue close <id>
```

#### bmo issue reopen

Reopen a closed issue.

```sh
bmo issue reopen <id>
```

#### bmo issue delete

Delete an issue permanently.

```sh
bmo issue delete <id> [--yes]
```

| Flag | Type | Description |
|---|---|---|
| `--yes` | bool | Skip confirmation prompt |

#### bmo issue comment add

Add a comment to an issue.

```sh
bmo issue comment add <id> --body <text> [--author <name>]
```

| Flag | Short | Type | Description |
|---|---|---|---|
| `--body` | `-b` | string | Comment text |
| `--author` | `-a` | string | Comment author name |

#### bmo issue comment list

List all comments on an issue.

```sh
bmo issue comment list <id>
```

#### bmo issue label add

Add a label to an issue. Creates the label if it does not exist.

```sh
bmo issue label add <id> <name> [--color <hex>]
```

| Flag | Type | Description |
|---|---|---|
| `--color` | string | Label color as a hex string (e.g. `#ff0000`) |

#### bmo issue label rm

Remove a label from an issue. Accepts `rm` or `remove`.

```sh
bmo issue label rm <id> <name>
```

#### bmo issue label list

List all labels attached to an issue.

```sh
bmo issue label list <id>
```

#### bmo issue label delete

Delete a label globally, removing it from all issues.

```sh
bmo issue label delete <name>
```

#### bmo issue link add

Add a directional relation between two issues.

```sh
bmo issue link add <from-id> <relation> <to-id>
```

Valid relation values: `blocks`, `blocked-by`, `depends-on`, `dependency-of`, `relates-to`, `duplicates`, `duplicate-of`.

#### bmo issue link remove

Remove a relation by its numeric relation ID.

```sh
bmo issue link remove <link-id>
```

#### bmo issue link list

List all relations for an issue.

```sh
bmo issue link list <id>
```

#### bmo issue file add

Attach a file path to an issue.

```sh
bmo issue file add <id> <path>
```

#### bmo issue file rm

Remove a file attachment from an issue. Accepts `rm` or `remove`.

```sh
bmo issue file rm <id> <path>
```

#### bmo issue file list

List all file attachments for an issue.

```sh
bmo issue file list <id>
```

#### bmo issue log

Show the activity log for an issue.

```sh
bmo issue log <id> [--limit <n>]
```

| Flag | Type | Default | Description |
|---|---|---|---|
| `--limit` | integer | `10` | Maximum number of log entries to show |

#### bmo issue graph

Show the dependency graph for an issue.

```sh
bmo issue graph <id>
```

Issue IDs accept both `42` and `BMO-42` everywhere.

---

### Board and Planning

#### bmo board

Show a Kanban board of all issues grouped by status.

```sh
bmo board [options]
```

| Flag | Short | Type | Description |
|---|---|---|---|
| `--label` | `-l` | string | Filter by label (repeatable) |
| `--priority` | `-p` | string | Filter by priority (repeatable) |
| `--assignee` | `-a` | string | Filter by assignee |

#### bmo next

Show the next work-ready issues. An issue is work-ready when it has no unresolved blocking dependencies.

```sh
bmo next [options]
```

| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
| `--assignee` | `-a` | string | none | Filter by assignee |
| `--limit` | | integer | `10` | Maximum number of results |

#### bmo plan

Show a phased execution plan ordered by dependency relationships.

```sh
bmo plan [options]
```

| Flag | Short | Type | Description |
|---|---|---|---|
| `--assignee` | `-a` | string | Filter by assignee |

---

### Statistics and Export

#### bmo stats

Show issue counts grouped by status, priority, and kind.

```sh
bmo stats
```

#### bmo export

Export all issues, comments, labels, relations, activity, and file attachments as a JSON bundle.

```
bmo export [--output <file>]
```

| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
| `--output` | `-o` | string | stdout | Output file path |

#### bmo import

Import a JSON export bundle. Use `--from-docket` when importing from a docket export.

```
bmo import <file> [--from-docket]
```

| Flag | Type | Description |
|---|---|---|
| `--from-docket` | bool | Remap `DKT-` IDs to `BMO-` IDs during import |

---

### Web Interface

#### bmo web

`bmo web` starts a local HTTP server at `http://127.0.0.1:7777` by default and opens a browser window automatically. The web interface provides a read-friendly view of all issues, their statuses, comments, labels, and relationships.

To start without opening a browser:

```bash
bmo web --no-open
```

To bind to a different port:

```bash
bmo web --port 8080
```

The bmo server will use server-sent-events to update the web view.

---

### BMO Basics

#### bmo init

Initialize a new bmo project in the current directory. Creates `.bmo/issues.db` and `.bmo/config.toml`. Safe to run on an existing project; it is idempotent.

```bash
bmo init [--name <project-name>]
```

| Flag | Type | Description |
|---|---|---|
| `--name` | string | Project name written to config |

#### bmo config

Project-level settings will be stored in the file `.bmo/config.toml`:

```toml
project_name = "my-project"
default_assignee = "me"
web_port = 7777
web_host = "127.0.0.1"
```

Read and write these values with the command `bmo config`:

```bash
bmo config                          # print all values
bmo config --get project_name
bmo config --set default_assignee=alice
```

With no flags, `bmo config` prints all current values.

```sh
bmo config [--get <key>] [--set <key>=<value>]
```

Valid keys are: `project_name`, `default_assignee`, `web_port`, `web_host`.

| Flag | Type | Description |
|---|---|---|
| `--get <key>` | string | Print the value of a single key |
| `--set <key>=<value>` | string | Set a key to a value |

#### bmo version

Print the current bmo version.

```sh
bmo version
```

---

## JSON Output

Every command accepts `--json` and returns a consistent envelope.

Success:

```json
{"ok": true, "data": <payload>, "message": "<human summary>"}
```

Error:

```json
{"ok": false, "error": "<description>", "code": "<code>"}
```

Error codes and exit statuses:

| Code | Exit | Meaning |
|---|---|---|
| `general` | 1 | Unclassified error |
| `not-found` | 2 | Requested resource does not exist |
| `validation` | 3 | Invalid input |
| `conflict` | 4 | State conflict (e.g. duplicate relation) |

The `--json` flag is designed for programmatic consumption by AI agents and other tools. All structured data in the `data` field is stable across patch releases within a major version.

---

## Enumerations

Valid string values for enumerated fields. All values are case-insensitive. Agents should use these exact strings to construct valid commands without trial and error.

**Status:** `backlog`, `todo`, `in-progress`, `review`, `done`

`in-progress` also accepts `in_progress` and `inprogress` as aliases.

**Priority:** `none`, `low`, `medium`, `high`, `critical`

**Kind:** `bug`, `feature`, `task`, `epic`, `chore`

**Relation kinds:** `blocks`, `blocked-by`, `depends-on`, `dependency-of`, `relates-to`, `duplicates`, `duplicate-of`

---

## For AI Agents

`bmo` is built for agent-driven workflows. This section documents the recommended integration pattern.

**Session initialization.** At the start of a session, run:

```bash
bmo init          # idempotent — safe to run every session
bmo board --json  # get a Kanban overview of all issues
bmo next --json   # get work-ready issues sorted by dependency order
```

**Finding work.** Use `bmo next --json` to retrieve the issues an agent should act on next. Issues returned by `bmo next` have no unresolved blocking dependencies and are not yet done.

**Creating issues.** Use `-d` to provide a rich description so that any agent or human reading the issue later has full context:

```bash
bmo issue create -t "Implement retry logic" -d "Add exponential backoff to the HTTP client. Max 3 retries. See src/client.rs." -p high -T task
```

**Tracking progress.** Move issues through the workflow as work proceeds:

```bash
bmo issue move BMO-7 --status in-progress
bmo issue move BMO-7 --status done
# or equivalently:
bmo issue close BMO-7
```

**Adding context.** Comment on issues to record findings, decisions, and discoveries:

```bash
bmo issue comment add BMO-7 --body "Completed: rewrote retry loop. Added unit tests in src/client_test.rs."
```

**Attaching files.** Record which files are relevant to an issue for traceability and collision detection:

```bash
bmo issue file add BMO-7 src/client.rs
```

**Reading machine-readable output.** Always pass `--json` when the output will be consumed by code:

```bash
bmo issue show BMO-7 --json
bmo issue list --status in-progress --json
bmo next --json
```

---

## Data Storage

All data is stored in `.bmo/issues.db` in the directory where `bmo init` was run. `bmo` walks up the directory tree from the current working directory to find the nearest `.bmo/` directory, so you can run `bmo` commands from any subdirectory of your project.

To use a database at an explicit path, set the `BMO_DB` environment variable or pass `--db <path>`:

```bash
BMO_DB=/path/to/issues.db bmo issue list
bmo --db /path/to/issues.db issue list
```

---

## Migration from docket

See [docs/migration-from-docket.md](https://github.com/erewok/bmo/blob/main/docs/migration-from-docket.md) for the full migration guide.

Quick start:

```bash
docket export -f export.json && bmo init && bmo import --from-docket export.json
```

---

## Development

We use [`just`](https://github.com/casey/just) to run common recipes for this project:

```bash
just test    # run all tests
just check   # fmt check + clippy
just fmt     # run cargo fmt
just build   # release build
just clean   # remove build artifacts
```

---

## License

MIT License. See [LICENSE](LICENSE) file.

`bmo` was inspired by [docket](https://github.com/ALT-F4-LLC/docket) by **ALT-F4-LLC**. Please credit that project for the ideas in this project.