honestdocs 0.0.0-stage → 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 +340 -2
- package/bin/honestdocs.mjs +55 -0
- package/guide/METHOD.md +93 -0
- package/guide/agents-snippet.md +22 -0
- package/guide/before-you-build.md +44 -0
- package/guide/docs-readme.md +29 -0
- package/guide/skill/SKILL.md +71 -0
- package/package.json +41 -4
- package/src/cli.mjs +67 -0
- package/src/commands/brief.mjs +78 -0
- package/src/commands/check.mjs +163 -0
- package/src/commands/done.mjs +53 -0
- package/src/commands/guide.mjs +29 -0
- package/src/commands/index.mjs +62 -0
- package/src/commands/init.mjs +166 -0
- package/src/commands/new.mjs +91 -0
- package/src/commands/promote.mjs +55 -0
- package/src/commands/rules.mjs +51 -0
- package/src/commands/search.mjs +88 -0
- package/src/commands/status.mjs +43 -0
- package/src/config.mjs +146 -0
- package/src/docs.mjs +139 -0
- package/src/frontmatter.mjs +90 -0
- package/src/git.mjs +181 -0
- package/src/render.mjs +84 -0
- package/src/rules.mjs +52 -0
- package/src/templates.mjs +26 -0
- package/templates/decision.md +17 -0
- package/templates/design.md +28 -0
- package/templates/plan.md +31 -0
- package/templates/postmortem.md +21 -0
- package/templates/reference.md +8 -0
- package/templates/research.md +20 -0
- package/templates/rule.md +20 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Glivo
|
|
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
CHANGED
|
@@ -1,3 +1,341 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/logo-light.svg#gh-light-mode-only" alt="honestdocs" width="422">
|
|
3
|
+
<img src="assets/logo-dark.svg#gh-dark-mode-only" alt="honestdocs" width="422">
|
|
4
|
+
</p>
|
|
2
5
|
|
|
3
|
-
|
|
6
|
+
<h3 align="center">Development documents that stay true.</h3>
|
|
7
|
+
|
|
8
|
+
<p align="center">
|
|
9
|
+
Decisions, designs, plans, research, postmortems and standing rules —<br>
|
|
10
|
+
kept honest for the people on your team and the AI agents working beside them.
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
<p align="center">
|
|
14
|
+
<a href="LICENSE"><img alt="MIT license" src="https://img.shields.io/badge/license-MIT-16a34a"></a>
|
|
15
|
+
<img alt="Node 20+ or Bun" src="https://img.shields.io/badge/node-%E2%89%A520%20%C2%B7%20bun-1f2328">
|
|
16
|
+
<img alt="Zero dependencies" src="https://img.shields.io/badge/dependencies-0-1f2328">
|
|
17
|
+
<img alt="Windows, macOS, Linux" src="https://img.shields.io/badge/os-windows%20%C2%B7%20macos%20%C2%B7%20linux-1f2328">
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
A project's development documents are its long-term memory — for the colleague who joins
|
|
23
|
+
next year, for you in three months, for the AI agent that starts every session knowing
|
|
24
|
+
nothing. And they rot. A plan says *in progress* a year after it shipped. A design that was
|
|
25
|
+
replaced still reads as current. The "related files" list stopped being true the week it
|
|
26
|
+
was written. Someone builds from the wrong one.
|
|
27
|
+
|
|
28
|
+
**honestdocs** is a small CLI and a ten-rule method that stop that. People write only what
|
|
29
|
+
people know. The tool works out the rest, and fails CI the moment the set starts to lie.
|
|
30
|
+
|
|
31
|
+
<p align="center">
|
|
32
|
+
<img src="assets/how-it-works-light.svg#gh-light-mode-only" alt="People write title, status, supersedes, related and the reasoning. honestdocs derives progress from the checklist, files from commit trailers, updated from git history, superseded-by from the newer document. check fails CI when the set lies." width="880">
|
|
33
|
+
<img src="assets/how-it-works-dark.svg#gh-dark-mode-only" alt="People write title, status, supersedes, related and the reasoning. honestdocs derives progress from the checklist, files from commit trailers, updated from git history, superseded-by from the newer document. check fails CI when the set lies." width="880">
|
|
34
|
+
</p>
|
|
35
|
+
|
|
36
|
+
Plain Markdown in your repository. No server, no database, no dependencies.
|
|
37
|
+
|
|
38
|
+
## Quick start
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
npx honestdocs init --agents
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
That creates `.honestdocs/` — its config, a README, a first rule document and an index —
|
|
45
|
+
and adds a short section to `AGENTS.md` so your AI agents follow the method too. Nothing
|
|
46
|
+
else in your project is touched.
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
npx honestdocs new general token-rotation --type plan --title "Token rotation"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Do the work. When you commit it, add one line naming the document:
|
|
53
|
+
|
|
54
|
+
```sh
|
|
55
|
+
git commit -m "Rotate tokens on refresh" -m "Doc: 2026-11-02-token-rotation"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Then let the tool keep the record straight:
|
|
59
|
+
|
|
60
|
+
```sh
|
|
61
|
+
npx honestdocs index # work out progress, files, superseded-by, updated; rebuild INDEX.md
|
|
62
|
+
npx honestdocs check # exit 1 if anything in the set lies
|
|
63
|
+
npx honestdocs done 2026-11-02-token-rotation
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## What you get back
|
|
67
|
+
|
|
68
|
+
**Where things stand, in one page** — what a person back from a week away, or an agent
|
|
69
|
+
with an empty context, reads first:
|
|
70
|
+
|
|
71
|
+
```text
|
|
72
|
+
$ honestdocs brief
|
|
73
|
+
Development documents — 41 documents
|
|
74
|
+
|
|
75
|
+
In progress
|
|
76
|
+
🔧 2026-11-02-token-rotation — Token rotation (3/5)
|
|
77
|
+
- [ ] Revoke old tokens after the grace period
|
|
78
|
+
- [ ] Document the rotation endpoint
|
|
79
|
+
|
|
80
|
+
Planned — re-check against the code before building
|
|
81
|
+
📋 2026-10-20-audit-log — Audit log for admin actions
|
|
82
|
+
|
|
83
|
+
Rules in force — read the ones a change touches before building
|
|
84
|
+
.honestdocs/rules/2026-09-01-before-you-build.md — Before you build: B1…B4 (4)
|
|
85
|
+
.honestdocs/rules/2026-09-14-security.md — Security rules: SEC1…SEC9 (9)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**What was already tried, and why it lost** — superseded and abandoned documents included,
|
|
89
|
+
because that is where the rejected ideas live:
|
|
90
|
+
|
|
91
|
+
```text
|
|
92
|
+
$ honestdocs search redis --section alternatives
|
|
93
|
+
🔧 .honestdocs/billing/2026-10-03-rate-limits.md — Rate limits
|
|
94
|
+
§ Alternatives considered: Redis counters were rejected: one more service to run…
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**A document whose bookkeeping does itself:**
|
|
98
|
+
|
|
99
|
+
```markdown
|
|
100
|
+
---
|
|
101
|
+
id: 2026-11-02-token-rotation
|
|
102
|
+
title: Token rotation
|
|
103
|
+
area: auth
|
|
104
|
+
type: plan
|
|
105
|
+
status: in-progress
|
|
106
|
+
created: 2026-11-02
|
|
107
|
+
updated: 2026-11-05 ← from git
|
|
108
|
+
completed:
|
|
109
|
+
progress: 3/5 ← from the checklist
|
|
110
|
+
supersedes: [2026-06-10-long-lived-tokens]
|
|
111
|
+
superseded-by: ← from the newer document
|
|
112
|
+
related: [2026-10-20-audit-log]
|
|
113
|
+
files: [src/auth/refresh.ts, src/auth/tokens.ts] ← from commits naming this document
|
|
114
|
+
---
|
|
115
|
+
# Token rotation
|
|
116
|
+
|
|
117
|
+
## Context
|
|
118
|
+
## Goals / Non-goals
|
|
119
|
+
## Decision
|
|
120
|
+
## Alternatives considered ← what lost, and why
|
|
121
|
+
## Checklist
|
|
122
|
+
## Verification
|
|
123
|
+
## Log ← the hand-over to the next session
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## The method
|
|
127
|
+
|
|
128
|
+
Ten rules, short enough to remember. `honestdocs guide` prints them in full.
|
|
129
|
+
|
|
130
|
+
| | |
|
|
131
|
+
|---|---|
|
|
132
|
+
| **D1** The code is the truth | Where a document and the code disagree, believe the code — then correct the document. |
|
|
133
|
+
| **D2** Derive what can be derived | People write `title`, `status`, `supersedes`, `related`. A field someone must remember to update will be wrong. |
|
|
134
|
+
| **D3** Write it down before building | Non-trivial work starts with a design, plan or research document. |
|
|
135
|
+
| **D4** Commits name their document | `Doc: <id>` — the one link between documents and code that cannot drift. |
|
|
136
|
+
| **D5** Write down what was rejected | *Alternatives considered* stops the same argument — and the same AI suggestion — coming back. |
|
|
137
|
+
| **D6** Replace from the newer side | `supersedes:` in the new document; the old one is marked for you. |
|
|
138
|
+
| **D7** Close honestly | Unticked boxes are explained, not ignored. Abandoned work keeps its reasons. |
|
|
139
|
+
| **D8** Living documents change in place | References and rules are edited, never contradicted by a second copy. |
|
|
140
|
+
| **D9** A rule that can be a test is one | Numbered rules name their tests; `check` fails when a test disappears. |
|
|
141
|
+
| **D10** Documents change with the work | A change is not done while its documents describe the old behaviour. |
|
|
142
|
+
|
|
143
|
+
### Two kinds of document
|
|
144
|
+
|
|
145
|
+
| Kind | Types | Lifecycle |
|
|
146
|
+
|---|---|---|
|
|
147
|
+
| **Work** — gets done, then is finished | `research` `design` `plan` `decision` `postmortem` | `draft → planned → in-progress → done` · `abandoned` · `superseded` |
|
|
148
|
+
| **Living** — true now, kept true | `reference` `rule` | `draft → current → retired` · `superseded` |
|
|
149
|
+
|
|
150
|
+
A standing rule is never "done". Forced through a work lifecycle, it sits in `draft` forever
|
|
151
|
+
while everyone follows it — so living documents get their own.
|
|
152
|
+
|
|
153
|
+
### Rules that prove themselves
|
|
154
|
+
|
|
155
|
+
`.honestdocs/rules/` holds what every change must keep: security, public APIs, migrations —
|
|
156
|
+
whatever your project forgets when nobody is looking. Rules are numbered so a review can
|
|
157
|
+
cite them, and each names the test that proves it:
|
|
158
|
+
|
|
159
|
+
```markdown
|
|
160
|
+
- **SEC3** Every route checks the item it names, not just the caller.
|
|
161
|
+
Test: `tests/routes/item-scope.test.ts`
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
If that test file disappears, `honestdocs check` fails. `init` starts you with a *before you
|
|
165
|
+
build* checklist that sends each kind of change to the rules that govern it.
|
|
166
|
+
|
|
167
|
+
## Built for AI agents
|
|
168
|
+
|
|
169
|
+
The documents matter most to the reader with the least memory. `init --agents` writes a
|
|
170
|
+
section into `AGENTS.md` (or `--agents-file CLAUDE.md`), and `init --skill` installs the
|
|
171
|
+
same instructions as a skill. An agent that follows them:
|
|
172
|
+
|
|
173
|
+
1. runs `honestdocs brief` when a session starts;
|
|
174
|
+
2. `search`es before proposing a design — with `--section alternatives`, so it does not
|
|
175
|
+
bring back what was rejected — and reads the rules a change touches;
|
|
176
|
+
3. opens a document for non-trivial work and puts `Doc: <id>` in its commits;
|
|
177
|
+
4. never writes the derived fields; closes with `done` and `check`.
|
|
178
|
+
|
|
179
|
+
Every query takes `--json`. Data goes to stdout, everything else to stderr.
|
|
180
|
+
|
|
181
|
+
> **Memory or documents?** Agents and people keep notes of their own. Preferences and habits
|
|
182
|
+
> belong there. Decisions about the project belong in the documents, where every person and
|
|
183
|
+
> every future session reads the same thing — a memory entry about the project should point
|
|
184
|
+
> to the document, not copy it.
|
|
185
|
+
|
|
186
|
+
## Commands
|
|
187
|
+
|
|
188
|
+
| Command | |
|
|
189
|
+
|---|---|
|
|
190
|
+
| `init` | Set up `.honestdocs/`. `--agents` writes the AGENTS.md section, `--skill` installs the skill; both refresh in place when run again. |
|
|
191
|
+
| `new <area> <slug> --title …` | Start a document from its type's template. Prints the path. |
|
|
192
|
+
| `index` | Work out the derived fields and rebuild `INDEX.md`. |
|
|
193
|
+
| `check` | Validate everything; exit 1 on errors. `--fix` corrects the mechanical ones. |
|
|
194
|
+
| `done <id>` | Close a work document. Refuses unticked items unless `--force`; `--abandoned` for dropped work. |
|
|
195
|
+
| `status <id> <status>` | Move a document — a rule to `current`, a reference to `retired`. |
|
|
196
|
+
| `brief` | One page: in progress with next items, planned, recently changed, rules in force. |
|
|
197
|
+
| `search <words…>` | Every document, superseded and abandoned included. `--section alternatives` for what was rejected. |
|
|
198
|
+
| `rules [prefix]` | The numbered rules in force, with their tests. |
|
|
199
|
+
| `promote <id> --to <path>` | Start a public document from a development one — headings only, on purpose. |
|
|
200
|
+
| `guide [method\|agents\|skill]` | Print the method, the agents section or the skill. |
|
|
201
|
+
|
|
202
|
+
<details>
|
|
203
|
+
<summary><b>What <code>check</code> treats as an error</b></summary>
|
|
204
|
+
|
|
205
|
+
- frontmatter missing; an id that does not match its filename; two documents with one id
|
|
206
|
+
- an area, type or status outside the config — or a status the type's lifecycle lacks
|
|
207
|
+
- a document in one area's folder claiming another area
|
|
208
|
+
- `supersedes` or `related` pointing at nothing
|
|
209
|
+
- a superseded document that still claims to be in force
|
|
210
|
+
- a checklist count, or `superseded-by`, never recomputed
|
|
211
|
+
- a rule naming a test that does not exist; two rules with one id
|
|
212
|
+
- `INDEX.md` not rebuilt since the frontmatter changed
|
|
213
|
+
|
|
214
|
+
A commit that names a document moves that document's `files` and `updated` by definition,
|
|
215
|
+
so those are warnings, settled by the next `index` — never a reason for CI to fail.
|
|
216
|
+
|
|
217
|
+
</details>
|
|
218
|
+
|
|
219
|
+
<details>
|
|
220
|
+
<summary><b>How git is used</b></summary>
|
|
221
|
+
|
|
222
|
+
Two of the derived fields come from history, because history is the one record nobody
|
|
223
|
+
edits after the fact:
|
|
224
|
+
|
|
225
|
+
- **`files`** — every commit whose message carries `Doc: <id>` contributes the files it
|
|
226
|
+
changed. Several ids per commit are fine, comma-separated or one per line. The match is on
|
|
227
|
+
the whole id, and paths follow later renames, so a file is listed by the name it has now.
|
|
228
|
+
- **`updated`** — the last commit that changed the document's content. Moving a folder of
|
|
229
|
+
documents is not an edit and does not restamp them.
|
|
230
|
+
|
|
231
|
+
Everything else — progress, superseded-by, every check — works from the files alone.
|
|
232
|
+
Outside a repository, or in a shallow clone, honestdocs says so and leaves the two git
|
|
233
|
+
fields as they are rather than writing a wrong answer.
|
|
234
|
+
|
|
235
|
+
</details>
|
|
236
|
+
|
|
237
|
+
## Layouts
|
|
238
|
+
|
|
239
|
+
<details>
|
|
240
|
+
<summary><b>Same repository</b> — the default</summary>
|
|
241
|
+
|
|
242
|
+
`.honestdocs/` sits next to your code and is committed with it. Its config is
|
|
243
|
+
`.honestdocs/config.json`.
|
|
244
|
+
|
|
245
|
+
</details>
|
|
246
|
+
|
|
247
|
+
<details>
|
|
248
|
+
<summary><b>A private documents repository inside public code</b></summary>
|
|
249
|
+
|
|
250
|
+
When the code is open and the design discussion is not: add `.honestdocs/` to the code's
|
|
251
|
+
`.gitignore` and `git init` inside it. Dates then come from the documents' repository, and
|
|
252
|
+
`files` from the code's (`"codeRepos": [".."]` is not needed — paths are read from the
|
|
253
|
+
project folder that holds `.honestdocs/`).
|
|
254
|
+
|
|
255
|
+
</details>
|
|
256
|
+
|
|
257
|
+
<details>
|
|
258
|
+
<summary><b>Several code repositories, one set of documents</b></summary>
|
|
259
|
+
|
|
260
|
+
For a workspace of sibling repositories:
|
|
261
|
+
|
|
262
|
+
```json
|
|
263
|
+
{ "codeRepos": ["app", "web", "plugins"] }
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Files are then listed as `app/src/x.ts`, `web/src/x.ts`.
|
|
267
|
+
|
|
268
|
+
</details>
|
|
269
|
+
|
|
270
|
+
<details>
|
|
271
|
+
<summary><b>Documents somewhere else</b></summary>
|
|
272
|
+
|
|
273
|
+
`honestdocs init --root docs/dev` keeps them in `docs/dev/` and puts the config at the top
|
|
274
|
+
of the project as `honestdocs.config.json`. `init` refuses a folder that already holds
|
|
275
|
+
Markdown, so your own documents are never overwritten.
|
|
276
|
+
|
|
277
|
+
</details>
|
|
278
|
+
|
|
279
|
+
## Configuration
|
|
280
|
+
|
|
281
|
+
<details>
|
|
282
|
+
<summary><code>.honestdocs/config.json</code></summary>
|
|
283
|
+
|
|
284
|
+
```jsonc
|
|
285
|
+
{
|
|
286
|
+
"title": "Development documents", // heading of INDEX.md
|
|
287
|
+
"areas": { // folder → what belongs there
|
|
288
|
+
"general": "Anything not yet in a narrower area",
|
|
289
|
+
"rules": "Standing rules every change must keep"
|
|
290
|
+
},
|
|
291
|
+
"trailer": "Doc", // the commit trailer key
|
|
292
|
+
"codeRepos": ["."], // where trailer commits are read from
|
|
293
|
+
"templates": ".honestdocs/_templates", // optional: your own <type>.md templates
|
|
294
|
+
"types": { // optional: add or remove types
|
|
295
|
+
"rfc": { "lifecycle": "work", "description": "A proposal for review" },
|
|
296
|
+
"postmortem": false
|
|
297
|
+
},
|
|
298
|
+
"recent": 25, // rows in INDEX.md's "Recently changed"
|
|
299
|
+
"root": ".honestdocs" // where the documents live (with a top-level config)
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
Templates may use `{{title}}`, `{{id}}` and `{{date}}`. Write the bodies in any language;
|
|
304
|
+
filenames and frontmatter stay plain ASCII so every tool can read them.
|
|
305
|
+
|
|
306
|
+
</details>
|
|
307
|
+
|
|
308
|
+
## In CI
|
|
309
|
+
|
|
310
|
+
`files` and `updated` need history, so check out all of it:
|
|
311
|
+
|
|
312
|
+
```yaml
|
|
313
|
+
- uses: actions/checkout@v4
|
|
314
|
+
with:
|
|
315
|
+
fetch-depth: 0
|
|
316
|
+
- uses: actions/setup-node@v4
|
|
317
|
+
with:
|
|
318
|
+
node-version: 22
|
|
319
|
+
- run: npx honestdocs check
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## How it relates to other tools
|
|
323
|
+
|
|
324
|
+
- **ADR tools** — adr-tools, log4brains, the MADR template. honestdocs's `decision`
|
|
325
|
+
template follows MADR, so ADRs fit in as one type among several. It adds the other kinds of
|
|
326
|
+
document, two lifecycles, and fields that are worked out instead of maintained.
|
|
327
|
+
- **Spec-driven kits** — Spec Kit, OpenSpec and others shape what an agent is told *before*
|
|
328
|
+
it writes code. honestdocs keeps the record true *after*: what was decided, what was
|
|
329
|
+
rejected, what shipped, what was replaced. They work side by side.
|
|
330
|
+
- **RFC, PEP and KEP processes** — the same idea at project scale, without the metadata
|
|
331
|
+
somebody has to keep in sync by hand.
|
|
332
|
+
|
|
333
|
+
## Where it comes from
|
|
334
|
+
|
|
335
|
+
honestdocs was built while making [Glivo](https://github.com/glivo-dev), a desktop automation
|
|
336
|
+
app developed alongside AI coding agents, where a few hundred development documents had to
|
|
337
|
+
stay trustworthy for people and agents alike. This is that system, made general.
|
|
338
|
+
|
|
339
|
+
## License
|
|
340
|
+
|
|
341
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// honestdocs — development documents that stay true.
|
|
3
|
+
|
|
4
|
+
import { Failure, UsageError, c } from "../src/cli.mjs";
|
|
5
|
+
import { packageFile } from "../src/templates.mjs";
|
|
6
|
+
|
|
7
|
+
const COMMANDS = ["init", "new", "index", "check", "done", "status", "brief", "search", "rules", "promote", "guide"];
|
|
8
|
+
|
|
9
|
+
const load = (name) => import(`../src/commands/${name}.mjs`);
|
|
10
|
+
|
|
11
|
+
async function usage() {
|
|
12
|
+
const lines = [
|
|
13
|
+
"honestdocs — development documents that stay true",
|
|
14
|
+
"",
|
|
15
|
+
" honestdocs <command> [options] honestdocs <command> --help for more",
|
|
16
|
+
"",
|
|
17
|
+
];
|
|
18
|
+
for (const name of COMMANDS) lines.push(` ${name.padEnd(9)} ${(await load(name)).summary}`);
|
|
19
|
+
lines.push("", "The method: honestdocs guide · Docs: https://github.com/glivo-dev/honestdocs");
|
|
20
|
+
return lines.join("\n");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function main(argv) {
|
|
24
|
+
const [cmd, ...rest] = argv;
|
|
25
|
+
if (!cmd || cmd === "--help" || cmd === "-h" || cmd === "help") {
|
|
26
|
+
console.log(await usage());
|
|
27
|
+
if (!cmd) process.exitCode = 2;
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (cmd === "--version" || cmd === "-v") {
|
|
31
|
+
console.log(JSON.parse(packageFile("package.json")).version);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (!COMMANDS.includes(cmd)) throw new UsageError(`unknown command "${cmd}"`);
|
|
35
|
+
const mod = await load(cmd);
|
|
36
|
+
if (rest.includes("--help") || rest.includes("-h")) {
|
|
37
|
+
console.log(mod.help.trimEnd());
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
await mod.run(rest);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
main(process.argv.slice(2)).catch((e) => {
|
|
44
|
+
if (e instanceof UsageError) {
|
|
45
|
+
console.error(c.red("✗ ") + e.message);
|
|
46
|
+
console.error(c.dim(" see: honestdocs " + (process.argv[2] && !process.argv[2].startsWith("-") ? process.argv[2] + " " : "") + "--help"));
|
|
47
|
+
process.exitCode = 2;
|
|
48
|
+
} else if (e instanceof Failure) {
|
|
49
|
+
console.error(c.red("✗ ") + e.message);
|
|
50
|
+
process.exitCode = 1;
|
|
51
|
+
} else {
|
|
52
|
+
console.error(e);
|
|
53
|
+
process.exitCode = 1;
|
|
54
|
+
}
|
|
55
|
+
});
|
package/guide/METHOD.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# The honestdocs method
|
|
2
|
+
|
|
3
|
+
Development documents are a project's long-term memory: why it is built this way, what
|
|
4
|
+
was tried and rejected, what went wrong, what is under way, and which rules every change
|
|
5
|
+
must keep. They are read by people coming back after a month, by new colleagues, and —
|
|
6
|
+
more and more — by AI agents that start every session with an empty context.
|
|
7
|
+
|
|
8
|
+
A memory that is wrong is worse than none: someone builds from it. These ten rules are
|
|
9
|
+
what keep it right. The `honestdocs` command enforces the ones a machine can check.
|
|
10
|
+
|
|
11
|
+
## The rules
|
|
12
|
+
|
|
13
|
+
- **D1 The code is the truth.** A document records what was decided at the time. When it
|
|
14
|
+
and the code disagree, believe the code — then come back and correct the document's
|
|
15
|
+
status. A replaced document that still says it is in force is the most expensive thing
|
|
16
|
+
in a docs folder.
|
|
17
|
+
|
|
18
|
+
- **D2 A field someone has to remember to update will be wrong.** So people write four
|
|
19
|
+
fields — `title`, `status`, `supersedes`, `related` — and everything else is derived:
|
|
20
|
+
`progress` from the checklist, `files` from git, `superseded-by` from the newer
|
|
21
|
+
document, `updated` from git. `honestdocs index` derives; nobody types those.
|
|
22
|
+
|
|
23
|
+
- **D3 Write it down before building.** Non-trivial work starts with a document: a design
|
|
24
|
+
for "how should this work", a plan for "what are the steps", research for "what is
|
|
25
|
+
true". A small change needs none. The test is whether someone will later ask "why is it
|
|
26
|
+
like this?"
|
|
27
|
+
|
|
28
|
+
- **D4 Commits name the document they serve.** A trailer line in the commit message —
|
|
29
|
+
`Doc: 2026-11-02-token-rotation` — is the only link between a document and the code
|
|
30
|
+
that cannot drift. A hand-kept "related files" list is out of date by the second week.
|
|
31
|
+
|
|
32
|
+
- **D5 Write down what was rejected.** Every template has *Alternatives considered*. The
|
|
33
|
+
option that lost, and why, is what stops the same argument three months later — and
|
|
34
|
+
stops an AI agent from proposing it again as if it were new. Before proposing a design,
|
|
35
|
+
search for it: `honestdocs search <words> --section alternatives`.
|
|
36
|
+
|
|
37
|
+
- **D6 One document replaces another from the newer side.** Write
|
|
38
|
+
`supersedes: [<old id>]` in the new document; the old one is marked automatically.
|
|
39
|
+
Never edit the old one to point forward — one source cannot contradict itself.
|
|
40
|
+
|
|
41
|
+
- **D7 Close honestly.** A plan with unticked boxes is not done. Tick them, or write in
|
|
42
|
+
the Log what happened to them. Work dropped on purpose is `abandoned`, and the reason it
|
|
43
|
+
was dropped is as worth keeping as the reason anything was built.
|
|
44
|
+
|
|
45
|
+
- **D8 Living documents change in place.** References and rules are never finished; they
|
|
46
|
+
are true now. When one changes, edit it and add a dated line to its Log. A second
|
|
47
|
+
document beside it that says something different is how a project ends up with two
|
|
48
|
+
truths.
|
|
49
|
+
|
|
50
|
+
- **D9 A rule that can be a test is one.** Rules are numbered (`R1`, `R2`, …) so they can
|
|
51
|
+
be cited in a review. A rule names the test that proves it, and `honestdocs check`
|
|
52
|
+
fails when that test file is gone. A rule that lives only in prose is the one that gets
|
|
53
|
+
forgotten.
|
|
54
|
+
|
|
55
|
+
- **D10 Documents change with the work.** A change is not finished while the documents
|
|
56
|
+
and rules it affects still describe the old behaviour. Check both before saying a batch
|
|
57
|
+
is done.
|
|
58
|
+
|
|
59
|
+
## Two kinds of document
|
|
60
|
+
|
|
61
|
+
| Kind | Types | Lifecycle |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| **Work** — something gets done, then it is finished | `research`, `design`, `plan`, `decision`, `postmortem` | `draft → planned → in-progress → done`, or `abandoned`; `superseded` when replaced |
|
|
64
|
+
| **Living** — true now, kept true in place | `reference`, `rule` | `draft → current → retired`; `superseded` when replaced |
|
|
65
|
+
|
|
66
|
+
`planned` means decided but not started. Re-check a planned document against the code
|
|
67
|
+
before building from it: the code may have moved since it was written.
|
|
68
|
+
|
|
69
|
+
## Ids never change
|
|
70
|
+
|
|
71
|
+
A document's id is its filename: `YYYY-MM-DD-<slug>`. Other documents, commits and
|
|
72
|
+
conversations refer to it, so it is never renamed. A document that turns out to be about
|
|
73
|
+
something else is superseded by a new one, not renamed.
|
|
74
|
+
|
|
75
|
+
## Memory, documents and agents
|
|
76
|
+
|
|
77
|
+
People and AI agents both keep notes of their own — an agent's memory file, a personal
|
|
78
|
+
to-do list. Draw the line like this:
|
|
79
|
+
|
|
80
|
+
- **Preferences and habits** of one person (how they like reports, which commands they
|
|
81
|
+
avoid) belong in that person's or agent's own memory.
|
|
82
|
+
- **Decisions about the project** — what was chosen, what was rejected, what broke and
|
|
83
|
+
why — belong in the documents, where everyone, and every future session, reads the same
|
|
84
|
+
thing.
|
|
85
|
+
- A memory entry about the project should *point* to the document, not repeat it. Two
|
|
86
|
+
copies drift; a pointer does not.
|
|
87
|
+
|
|
88
|
+
## Areas
|
|
89
|
+
|
|
90
|
+
Documents live in area folders (`engine/`, `billing/`, `rules/` …) listed in the config.
|
|
91
|
+
The folder is the area; a document cannot claim one area while sitting in another.
|
|
92
|
+
`rules/` holds the rules every change must keep, and its first document is a checklist —
|
|
93
|
+
*before you build* — that sends each kind of change to the rules that govern it.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
## Development documents (honestdocs)
|
|
2
|
+
|
|
3
|
+
This project keeps its decisions, plans, research, postmortems and standing rules in
|
|
4
|
+
`{{root}}/`, managed by `honestdocs`. The code is the truth: where a document and the code
|
|
5
|
+
disagree, believe the code and correct the document's status.
|
|
6
|
+
|
|
7
|
+
- **Starting a session:** run `honestdocs brief` — what is in progress, its next unticked
|
|
8
|
+
items, what changed lately, which rules are in force.
|
|
9
|
+
- **Before building anything non-trivial:** run `honestdocs search <words>` (add
|
|
10
|
+
`--section alternatives` to see what was already rejected, and why), read the rules a
|
|
11
|
+
change touches (`honestdocs rules`), then open a document:
|
|
12
|
+
`honestdocs new <area> <slug> --type design|plan|research --title "…"`.
|
|
13
|
+
- **While building:** put `{{trailer}}: <id>` on its own line at the end of every commit
|
|
14
|
+
message that does the work. Tick the document's checklist as items land; add dated
|
|
15
|
+
notes to its Log — they are the hand-over to the next session.
|
|
16
|
+
- **Never type** `progress`, `files`, `superseded-by` or `updated` — `honestdocs index`
|
|
17
|
+
derives them. To replace a document, write `supersedes: [<old id>]` in the new one.
|
|
18
|
+
- **Finishing:** `honestdocs done <id>` (or `--abandoned`, with the reason in the Log),
|
|
19
|
+
then `honestdocs check`. A change is not finished while a document or rule it affects
|
|
20
|
+
still describes the old behaviour.
|
|
21
|
+
- Ids are filenames and never change. Add `--json` to any query command for
|
|
22
|
+
machine-readable output. The full method: `honestdocs guide`.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Before you build: the checklist every change goes through
|
|
2
|
+
|
|
3
|
+
_Rules that every change must keep. Edit them here, in place, when they change, and add a
|
|
4
|
+
line to the Log. Never a second document beside this one._
|
|
5
|
+
|
|
6
|
+
## Scope
|
|
7
|
+
|
|
8
|
+
This folder, `{{root}}/rules/`, holds the rules that belong to no single feature but that
|
|
9
|
+
every change has to keep — the ones that, forgotten, fail silently. Each concern gets one
|
|
10
|
+
rule document with its own letter (`SEC` for security, `API` for public interfaces, …).
|
|
11
|
+
This one is the entry point: go down it before starting, and again before saying a batch
|
|
12
|
+
is finished.
|
|
13
|
+
|
|
14
|
+
## Rules
|
|
15
|
+
|
|
16
|
+
- **B1** Non-trivial work has a document before it has code, and its commits carry
|
|
17
|
+
`{{trailer}}: <id>`.
|
|
18
|
+
- **B2** A change is not finished while a document or rule it affects still describes the
|
|
19
|
+
old behaviour.
|
|
20
|
+
- **B3** A rule that can be checked by a test names that test on a `Test:` line, so
|
|
21
|
+
`honestdocs check` notices when it disappears.
|
|
22
|
+
|
|
23
|
+
## The checklist
|
|
24
|
+
|
|
25
|
+
_Add a group per kind of change your project has — a route, a database migration, a
|
|
26
|
+
public API, a setting — each pointing at the rule document that governs it. Start small;
|
|
27
|
+
add a line the first time something is forgotten._
|
|
28
|
+
|
|
29
|
+
**Any change**
|
|
30
|
+
- ☐ Searched for earlier decisions: `honestdocs search <words> --section alternatives`.
|
|
31
|
+
- ☐ The documents and rules it affects are updated in the same batch (B2).
|
|
32
|
+
|
|
33
|
+
**Before saying it works**
|
|
34
|
+
- ☐ The project's tests pass.
|
|
35
|
+
- ☐ `honestdocs index && honestdocs check` passes.
|
|
36
|
+
|
|
37
|
+
## Keeping this folder right
|
|
38
|
+
|
|
39
|
+
- A rule changes ⇒ edit its document here, in place, and add a line to its Log.
|
|
40
|
+
- A new cross-cutting concern ⇒ a new rule document
|
|
41
|
+
(`honestdocs new rules <slug> --type rule --status current --title "…"`), its rules
|
|
42
|
+
numbered with a fresh letter, and its lines added to the checklist above.
|
|
43
|
+
|
|
44
|
+
## Log
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Development documents
|
|
2
|
+
|
|
3
|
+
Decisions, designs, plans, research, postmortems and standing rules for this project,
|
|
4
|
+
kept true by [honestdocs](https://github.com/glivo-dev/honestdocs).
|
|
5
|
+
|
|
6
|
+
**The code is the truth.** A document records what was decided at the time. Where it and
|
|
7
|
+
the code disagree, believe the code — then come back and correct the document's status.
|
|
8
|
+
|
|
9
|
+
- `INDEX.md` — every document, newest first and by area. Generated; do not edit.
|
|
10
|
+
- `rules/` — the rules every change must keep. Start with *before you build*.
|
|
11
|
+
- `<area>/YYYY-MM-DD-<slug>.md` — one document each. The filename is the id; it never
|
|
12
|
+
changes.
|
|
13
|
+
|
|
14
|
+
## Working with them
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
honestdocs brief # what is under way
|
|
18
|
+
honestdocs new <area> <slug> --type plan --title "…"
|
|
19
|
+
git commit -m "…" -m "{{trailer}}: <id>" # link the work to its document
|
|
20
|
+
honestdocs done <id> # close it
|
|
21
|
+
honestdocs index && honestdocs check # derive, regenerate, validate
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Write by hand only `title`, `status`, `supersedes` and `related`. The rest is derived —
|
|
25
|
+
`progress` from the checklist, `files` from commits carrying `{{trailer}}: <id>`,
|
|
26
|
+
`superseded-by` from the newer document, `updated` from git — because a field someone has
|
|
27
|
+
to remember to update will be wrong.
|
|
28
|
+
|
|
29
|
+
The method in full: `honestdocs guide`.
|