moth-cli 0.1.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.
- package/LICENSE +21 -0
- package/README.md +178 -0
- package/bin/moth.cjs +27 -0
- package/package.json +31 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nikolas Ioannou
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# moth
|
|
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.
|
|
4
|
+
|
|
5
|
+
Built for coding agents and the people who use them.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
$ moth list
|
|
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
|
|
15
|
+
```
|
|
16
|
+
|
|
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
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
brew install nikolasgioannou/tap/moth
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Shell
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
curl -fsSL https://raw.githubusercontent.com/nikolasgioannou/moth/main/install.sh | sh
|
|
50
|
+
```
|
|
51
|
+
|
|
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
|
+
```sh
|
|
57
|
+
npm install -g moth-cli
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Or run it without installing: `npx moth-cli list`. Only your platform's binary is downloaded, not all five.
|
|
61
|
+
|
|
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
|
|
67
|
+
|
|
68
|
+
```sh
|
|
69
|
+
git clone https://github.com/nikolasgioannou/moth.git
|
|
70
|
+
cd moth
|
|
71
|
+
bun install
|
|
72
|
+
bun run build
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## A worked example
|
|
76
|
+
|
|
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]
|
|
87
|
+
```
|
|
88
|
+
|
|
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:
|
|
90
|
+
|
|
91
|
+
```sh
|
|
92
|
+
$ moth new "Parse the frontmatter"
|
|
93
|
+
001 Parse the frontmatter
|
|
94
|
+
|
|
95
|
+
$ moth new "Handle quoted strings" --parent 1
|
|
96
|
+
002 Handle quoted strings
|
|
97
|
+
|
|
98
|
+
$ moth new "Ship the first binary" --body "Blocked on the parser landing."
|
|
99
|
+
003 Ship the first binary
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Relate and prioritise it:
|
|
103
|
+
|
|
104
|
+
```sh
|
|
105
|
+
$ moth edit 3 --blocked-by 1 --priority high --label release
|
|
106
|
+
003 Ship the first binary
|
|
107
|
+
|
|
108
|
+
$ moth move 1 in-progress
|
|
109
|
+
001 Parse the frontmatter in-progress
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Then ask what is actually startable — work that has been committed to and is not waiting on anything:
|
|
113
|
+
|
|
114
|
+
```sh
|
|
115
|
+
$ moth list --unblocked --category backlog
|
|
116
|
+
backlog
|
|
117
|
+
002 Handle quoted strings none ↳ 001
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
And look at one ticket:
|
|
121
|
+
|
|
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
|
|
131
|
+
|
|
132
|
+
Blocked on the parser landing.
|
|
133
|
+
```
|
|
134
|
+
|
|
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.
|
|
136
|
+
|
|
137
|
+
## How it is stored
|
|
138
|
+
|
|
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
|
+
```
|
|
145
|
+
|
|
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.
|
|
147
|
+
|
|
148
|
+
```markdown
|
|
149
|
+
---
|
|
150
|
+
id: 3
|
|
151
|
+
title: Ship the first binary
|
|
152
|
+
status: backlog
|
|
153
|
+
priority: high
|
|
154
|
+
labels:
|
|
155
|
+
- release
|
|
156
|
+
created_at: 2026-08-31T00:35:11.462Z
|
|
157
|
+
updated_at: 2026-08-31T00:35:11.484Z
|
|
158
|
+
blocked_by:
|
|
159
|
+
- 1
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
Blocked on the parser landing.
|
|
163
|
+
```
|
|
164
|
+
|
|
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.
|
|
168
|
+
|
|
169
|
+
## Design notes
|
|
170
|
+
|
|
171
|
+
- [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
|
|
173
|
+
|
|
174
|
+
moth tracks its own development in moth: the backlog is in [`.moth/`](.moth/).
|
|
175
|
+
|
|
176
|
+
## Licence
|
|
177
|
+
|
|
178
|
+
[MIT](LICENSE)
|
package/bin/moth.cjs
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
// Finds the binary npm installed for this platform and runs it. Only the
|
|
4
|
+
// matching platform package is downloaded, so nobody pays for five binaries.
|
|
5
|
+
const { spawnSync } = require("node:child_process");
|
|
6
|
+
|
|
7
|
+
const platform = process.platform === "win32" ? "windows" : process.platform;
|
|
8
|
+
const name = "moth-cli-" + platform + "-" + process.arch;
|
|
9
|
+
const binary = process.platform === "win32" ? "moth.exe" : "moth";
|
|
10
|
+
|
|
11
|
+
let executable;
|
|
12
|
+
try {
|
|
13
|
+
executable = require.resolve(name + "/" + binary);
|
|
14
|
+
} catch {
|
|
15
|
+
console.error(
|
|
16
|
+
"moth: no prebuilt binary for " + process.platform + "-" + process.arch + ".\n" +
|
|
17
|
+
"Install from https://github.com/nikolasgioannou/moth instead."
|
|
18
|
+
);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const result = spawnSync(executable, process.argv.slice(2), { stdio: "inherit" });
|
|
23
|
+
if (result.error) {
|
|
24
|
+
console.error("moth: " + result.error.message);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
process.exit(result.status === null ? 1 : result.status);
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "moth-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "An opinionated issue tracker that lives in your repo. Tickets are markdown files with an enforced schema.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"issue-tracker",
|
|
7
|
+
"cli",
|
|
8
|
+
"tickets",
|
|
9
|
+
"markdown",
|
|
10
|
+
"agents"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/nikolasgioannou/moth.git"
|
|
16
|
+
},
|
|
17
|
+
"homepage": "https://github.com/nikolasgioannou/moth",
|
|
18
|
+
"bin": {
|
|
19
|
+
"moth": "./bin/moth.cjs"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"bin"
|
|
23
|
+
],
|
|
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"
|
|
30
|
+
}
|
|
31
|
+
}
|