moth-cli 0.1.0 → 0.3.0

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 (2) hide show
  1. package/README.md +54 -111
  2. package/package.json +6 -6
package/README.md CHANGED
@@ -1,177 +1,120 @@
1
1
  # moth
2
2
 
3
- An opinionated issue tracker that lives in your repository. Tickets are markdown files with an enforced schema — no account, no server, no sign-up.
3
+ [![ci](https://github.com/nikolasgioannou/moth/actions/workflows/ci.yml/badge.svg)](https://github.com/nikolasgioannou/moth/actions/workflows/ci.yml) [![npm](https://img.shields.io/npm/v/moth-cli)](https://www.npmjs.com/package/moth-cli) [![license](https://img.shields.io/github/license/nikolasgioannou/moth)](LICENSE)
4
4
 
5
- Built for coding agents and the people who use them.
5
+ An issue tracker that lives in your repository. Tickets are markdown files with a schema the CLI enforces no account, no server, no sign-up.
6
6
 
7
7
  ```
8
8
  $ moth list
9
9
  backlog
10
- 003 Ship the first binary high
11
- 002 Handle quoted strings none ↳ 001
12
-
13
- in-progress
14
- 001 Parse the frontmatter none
10
+ 280f4d Ship the binary high
11
+ 8e0642 Parse the frontmatter none
15
12
  ```
16
13
 
17
- ## Why it exists
18
-
19
- A folder of markdown files is free, but it is a convention rather than a tool, and nothing enforces it. Session one's agent writes `status: todo`. Session three's agent, having never seen that file, writes `state: in_progress`. By session ten the folder is unqueryable, and answering "what's blocked?" means re-deriving a grep every time.
20
-
21
- moth's value is the constraint. It refuses writes a bare filesystem would accept: an unrecognised status, a field nobody declared, a parent that would create a cycle. An agent cannot invent `status: blocked` on a whim, because the write fails and tells it what is legal. And it can ask: `moth schema --json` returns every legal field and value for the repository, so a session with no memory of previous sessions can discover the rules in one call.
22
-
23
- Because the shape of the data is known, querying it is a command rather than a grep somebody has to get right.
24
-
25
- ## What it deliberately does not do
26
-
27
- The refusals are the design, not gaps waiting to be filled:
28
-
29
- - **No assignees, and no accounts.** Moving a ticket into a started status is how you claim it.
30
- - **No custom statuses outside six fixed categories.** You name your own statuses; every one belongs to `backlog`, `unstarted`, `started`, `completed`, `canceled`, or `duplicate`. Queries against categories work in any repository; queries against your status names work in yours.
31
- - **No undeclared fields.** Custom fields are allowed, but they must be declared in config first, so an agent can never introduce one.
32
- - **No comments and no activity log.** `git log -p` on a ticket file is already a complete, attributed, tamper-evident history. Notes append to the body.
33
- - **No cycles, sprints, estimates, projects, or manual ordering.**
34
- - **No web UI, and no TUI.** The CLI is the interface.
35
-
36
- The full list, each with its reasoning, is in [the spec](docs/spec-v1.md#out-of-scope).
37
-
38
- ## Installing
39
-
40
- ### Homebrew
14
+ ## Install
41
15
 
42
16
  ```sh
43
17
  brew install nikolasgioannou/tap/moth
44
18
  ```
45
19
 
46
- ### Shell
47
-
48
20
  ```sh
49
21
  curl -fsSL https://raw.githubusercontent.com/nikolasgioannou/moth/main/install.sh | sh
50
22
  ```
51
23
 
52
- Installs to `~/.local/bin` by default. Set `MOTH_INSTALL_DIR` to change that, or `MOTH_VERSION` to pin a release. The download is checked against the release's published checksums.
53
-
54
- ### npm
55
-
56
24
  ```sh
57
25
  npm install -g moth-cli
58
26
  ```
59
27
 
60
- Or run it without installing: `npx moth-cli list`. Only your platform's binary is downloaded, not all five.
28
+ Or grab a binary from [releases](https://github.com/nikolasgioannou/moth/releases). macOS, Linux and Windows.
61
29
 
62
- ### From a release
63
-
64
- Binaries for macOS, Linux and Windows are attached to every [release](https://github.com/nikolasgioannou/moth/releases), alongside a `SHA256SUMS` file. Download one, `chmod +x` it, and put it on your `PATH`.
65
-
66
- ### From source
30
+ ## Use it
67
31
 
68
32
  ```sh
69
- git clone https://github.com/nikolasgioannou/moth.git
70
- cd moth
71
- bun install
72
- bun run build
33
+ moth init # one question per status, Enter accepts each
34
+ moth new "Parse the frontmatter" # prints the id it assigned
35
+ moth new "Ship the binary" --body "Needs the parser first."
36
+ moth edit 280f4d --blocked-by 8e0642 --priority high --label release
73
37
  ```
74
38
 
75
- ## A worked example
39
+ Then ask what you can actually start, rather than what merely exists:
76
40
 
77
- Starting from a repository with no tickets:
78
-
79
- ```sh
80
- $ moth init
81
- Statuses in 'backlog' [backlog]
82
- Statuses in 'unstarted' [todo]
83
- Statuses in 'started' [in-progress]
84
- Statuses in 'completed' [done]
85
- Statuses in 'canceled' [canceled]
86
- Statuses in 'duplicate' [duplicate]
41
+ ```
42
+ $ moth list --unblocked
43
+ backlog
44
+ 8e0642 Parse the frontmatter none
87
45
  ```
88
46
 
89
- One question per status category, and Enter accepts each default. That writes `moth.config.yml` at the root and creates `.moth/` for the tickets. Then file some work:
47
+ `280f4d` is missing because it is waiting on `8e0642`.
90
48
 
91
- ```sh
92
- $ moth new "Parse the frontmatter"
93
- 001 Parse the frontmatter
49
+ Name a ticket however you remember it. `moth show 280f4d`, `moth show 280` and `moth show "ship the binary"` all find the same one, and an ambiguous reference lists the candidates rather than guessing.
94
50
 
95
- $ moth new "Handle quoted strings" --parent 1
96
- 002 Handle quoted strings
51
+ `moth schema --json` reports exactly what this repository considers a legal ticket, which is how an agent learns the rules in one call.
97
52
 
98
- $ moth new "Ship the first binary" --body "Blocked on the parser landing."
99
- 003 Ship the first binary
100
- ```
53
+ ## Commands
101
54
 
102
- Relate and prioritise it:
55
+ Ten, and that is the whole surface:
103
56
 
104
- ```sh
105
- $ moth edit 3 --blocked-by 1 --priority high --label release
106
- 003 Ship the first binary
57
+ - `init` — set up a repository
58
+ - `new` file a ticket
59
+ - `list` — the default view, priority then age
60
+ - `show` — one ticket in full
61
+ - `move` — change status, which is how you claim work
62
+ - `edit` — change any field, the body included
63
+ - `delete` — remove a ticket
64
+ - `board` — a markdown board, grouped by status
65
+ - `check` — validate every ticket against the schema
66
+ - `schema` — this repository's rules, as JSON
107
67
 
108
- $ moth move 1 in-progress
109
- 001 Parse the frontmatter in-progress
110
- ```
68
+ Each one's `--help` carries its flags and a worked example, and `--json` is available on everything that returns a ticket.
111
69
 
112
- Then ask what is actually startable — work that has been committed to and is not waiting on anything:
70
+ ## Why it exists
113
71
 
114
- ```sh
115
- $ moth list --unblocked --category backlog
116
- backlog
117
- 002 Handle quoted strings none ↳ 001
118
- ```
72
+ A folder of markdown files is free, but nothing enforces it. Session one's agent writes `status: todo`. Session three's agent, having never seen that file, writes `state: in_progress`. By session ten the folder is unqueryable, and "what's blocked?" means re-deriving a grep every time.
119
73
 
120
- And look at one ticket:
74
+ moth refuses writes a bare filesystem would accept: an unrecognised status, a field nobody declared, a parent that would form a cycle. An agent cannot invent `status: blocked`, because the write fails and says what is legal. Because the shape is known, querying it is a command rather than a grep somebody has to get right.
121
75
 
122
- ```sh
123
- $ moth show 3
124
- 003 Ship the first binary
125
- status backlog
126
- priority high
127
- labels release
128
- blocked by 001
129
- created 2026-08-31T00:35:11.462Z
130
- updated 2026-08-31T00:35:11.484Z
76
+ ## What it refuses to do
131
77
 
132
- Blocked on the parser landing.
133
- ```
78
+ The refusals are the design, not gaps:
134
79
 
135
- A ticket is referred to by its number, padded or not, or by words from its title: `moth show 3`, `moth show 003`, and `moth show "quoted strings"` all work. An ambiguous reference lists the candidates rather than guessing.
80
+ - **No assignees, no accounts.** Moving a ticket into a started status is how you claim it.
81
+ - **No statuses outside six fixed categories.** Name your own; each belongs to `backlog`, `unstarted`, `started`, `completed`, `canceled` or `duplicate`. Queries by category work in any repository.
82
+ - **No undeclared fields.** Custom fields are allowed, but must be declared in config first, so an agent can never introduce one.
83
+ - **No comments, no activity log.** `git log -p` on a ticket is already a complete, attributed history.
84
+ - **No cycles, sprints, estimates, projects or manual ordering. No web UI, no TUI.**
136
85
 
137
- ## How it is stored
86
+ Every rejection, with its reasoning, is in [the spec](docs/spec-v1.md#out-of-scope).
138
87
 
139
- ```
140
- moth.config.yml statuses, custom fields, where tickets live
141
- .moth/
142
- 001-parse-the-frontmatter.md
143
- 002-handle-quoted-strings.md
144
- ```
88
+ ## Storage
145
89
 
146
- One markdown file per ticket, flat, with YAML frontmatter for structured fields and the body for the description. Nothing central that every write touches, so two branches creating tickets merge without conflict. Commit them with your code and they travel through branches, clones and pull requests.
90
+ `moth.config.yml` at the root, and one markdown file per ticket in `.moth/`, named for its title so a directory listing reads like a backlog `fix-the-login-redirect-280f4d.md`:
147
91
 
148
92
  ```markdown
149
93
  ---
150
- id: 3
94
+ id: "280f4d"
151
95
  title: Ship the first binary
152
96
  status: backlog
153
97
  priority: high
154
98
  labels:
155
99
  - release
156
- created_at: 2026-08-31T00:35:11.462Z
157
- updated_at: 2026-08-31T00:35:11.484Z
100
+ created_at: 2026-08-31T02:31:59.759Z
101
+ updated_at: 2026-08-31T02:31:59.787Z
158
102
  blocked_by:
159
- - 1
103
+ - "8e0642"
160
104
  ---
161
105
 
162
106
  Blocked on the parser landing.
163
107
  ```
164
108
 
165
- ## Commands
166
-
167
- Run `moth --help` for the list, and `moth <command> --help` for a worked example of any one of them. `moth schema --json` reports what this repository considers a legal ticket.
109
+ Flat, with nothing central that every write touches, so two branches creating tickets merge cleanly. Commit them with your code and they travel through branches, clones and pull requests.
168
110
 
169
- ## Design notes
111
+ ## Design
170
112
 
171
113
  - [The v1 spec](docs/spec-v1.md) — what was built, and every rejected alternative
172
- - [Architecture decisions](docs/adr/) — including two reversals, with the reasoning that changed
114
+ - [Architecture decisions](docs/adr/) — four decisions, each with the alternatives that lost
115
+ - [Contributing](CONTRIBUTING.md)
173
116
 
174
- moth tracks its own development in moth: the backlog is in [`.moth/`](.moth/).
117
+ moth tracks its own development in moth: the backlog is [`.moth/`](.moth/).
175
118
 
176
119
  ## Licence
177
120
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "moth-cli",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "An opinionated issue tracker that lives in your repo. Tickets are markdown files with an enforced schema.",
5
5
  "keywords": [
6
6
  "issue-tracker",
@@ -22,10 +22,10 @@
22
22
  "bin"
23
23
  ],
24
24
  "optionalDependencies": {
25
- "moth-cli-darwin-arm64": "0.1.0",
26
- "moth-cli-darwin-x64": "0.1.0",
27
- "moth-cli-linux-arm64": "0.1.0",
28
- "moth-cli-linux-x64": "0.1.0",
29
- "moth-cli-windows-x64": "0.1.0"
25
+ "moth-cli-darwin-arm64": "0.3.0",
26
+ "moth-cli-darwin-x64": "0.3.0",
27
+ "moth-cli-linux-arm64": "0.3.0",
28
+ "moth-cli-linux-x64": "0.3.0",
29
+ "moth-cli-windows-x64": "0.3.0"
30
30
  }
31
31
  }