constant-docs 0.7.0__tar.gz → 0.9.1__tar.gz

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 (46) hide show
  1. {constant_docs-0.7.0 → constant_docs-0.9.1}/PKG-INFO +103 -66
  2. {constant_docs-0.7.0 → constant_docs-0.9.1}/README.md +95 -58
  3. {constant_docs-0.7.0 → constant_docs-0.9.1}/pyproject.toml +8 -8
  4. {constant_docs-0.7.0 → constant_docs-0.9.1}/pyproject.toml.orig +8 -8
  5. {constant_docs-0.7.0 → constant_docs-0.9.1}/src/constant_docs/api.py +161 -24
  6. {constant_docs-0.7.0 → constant_docs-0.9.1}/src/constant_docs/auto.py +51 -5
  7. constant_docs-0.9.1/src/constant_docs/budget.py +58 -0
  8. {constant_docs-0.7.0 → constant_docs-0.9.1}/src/constant_docs/cli.py +96 -16
  9. {constant_docs-0.7.0 → constant_docs-0.9.1}/src/constant_docs/config.py +218 -8
  10. constant_docs-0.9.1/src/constant_docs/guides/quickstart.md +178 -0
  11. constant_docs-0.9.1/src/constant_docs/guides/readme.md +184 -0
  12. constant_docs-0.9.1/src/constant_docs/house-style.md +143 -0
  13. {constant_docs-0.7.0 → constant_docs-0.9.1}/src/constant_docs/index.py +146 -33
  14. {constant_docs-0.7.0 → constant_docs-0.9.1}/src/constant_docs/kinds.py +30 -1
  15. {constant_docs-0.7.0 → constant_docs-0.9.1}/src/constant_docs/paths.py +20 -4
  16. constant_docs-0.9.1/src/constant_docs/prompts/architecture.md +36 -0
  17. constant_docs-0.9.1/src/constant_docs/prompts/cli-reference.md +27 -0
  18. constant_docs-0.9.1/src/constant_docs/prompts/config-reference.md +26 -0
  19. constant_docs-0.9.1/src/constant_docs/prompts/errors.md +34 -0
  20. constant_docs-0.9.1/src/constant_docs/prompts/log.md +11 -0
  21. constant_docs-0.9.1/src/constant_docs/prompts/manual-page.md +35 -0
  22. constant_docs-0.9.1/src/constant_docs/prompts/module.md +30 -0
  23. constant_docs-0.9.1/src/constant_docs/prompts/spec.md +46 -0
  24. constant_docs-0.9.1/src/constant_docs/writing-core.md +37 -0
  25. constant_docs-0.7.0/src/constant_docs/guides/quickstart.md +0 -384
  26. constant_docs-0.7.0/src/constant_docs/guides/readme.md +0 -458
  27. constant_docs-0.7.0/src/constant_docs/house-style.md +0 -331
  28. constant_docs-0.7.0/src/constant_docs/prompts/architecture.md +0 -71
  29. constant_docs-0.7.0/src/constant_docs/prompts/cli-reference.md +0 -50
  30. constant_docs-0.7.0/src/constant_docs/prompts/config-reference.md +0 -49
  31. constant_docs-0.7.0/src/constant_docs/prompts/errors.md +0 -60
  32. constant_docs-0.7.0/src/constant_docs/prompts/log.md +0 -32
  33. constant_docs-0.7.0/src/constant_docs/prompts/module.md +0 -66
  34. constant_docs-0.7.0/src/constant_docs/prompts/spec.md +0 -90
  35. {constant_docs-0.7.0 → constant_docs-0.9.1}/LICENSE +0 -0
  36. {constant_docs-0.7.0 → constant_docs-0.9.1}/src/constant_docs/__init__.py +0 -0
  37. {constant_docs-0.7.0 → constant_docs-0.9.1}/src/constant_docs/__main__.py +0 -0
  38. {constant_docs-0.7.0 → constant_docs-0.9.1}/src/constant_docs/checks.py +0 -0
  39. {constant_docs-0.7.0 → constant_docs-0.9.1}/src/constant_docs/completeness.py +0 -0
  40. {constant_docs-0.7.0 → constant_docs-0.9.1}/src/constant_docs/coverage.py +0 -0
  41. {constant_docs-0.7.0 → constant_docs-0.9.1}/src/constant_docs/decisions.py +0 -0
  42. {constant_docs-0.7.0 → constant_docs-0.9.1}/src/constant_docs/document.py +0 -0
  43. {constant_docs-0.7.0 → constant_docs-0.9.1}/src/constant_docs/fingerprint.py +0 -0
  44. {constant_docs-0.7.0 → constant_docs-0.9.1}/src/constant_docs/globs.py +0 -0
  45. {constant_docs-0.7.0 → constant_docs-0.9.1}/src/constant_docs/state.py +0 -0
  46. {constant_docs-0.7.0 → constant_docs-0.9.1}/src/constant_docs/vcs.py +0 -0
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: constant-docs
3
- Version: 0.7.0
3
+ Version: 0.9.1
4
4
  Summary: Self-maintaining documentation for agentic codebases
5
5
  Keywords: documentation,docs,staleness,drift,ci,codegen,agents,llm
6
- Author: Ashborn Systems
6
+ Author: Daemon Agent
7
7
  License-Expression: Apache-2.0
8
8
  License-File: LICENSE
9
9
  Classifier: Development Status :: 3 - Alpha
@@ -19,12 +19,12 @@ Classifier: Operating System :: OS Independent
19
19
  Classifier: Typing :: Typed
20
20
  Requires-Dist: pyyaml>=6.0.3
21
21
  Requires-Python: >=3.11
22
- Project-URL: Homepage, https://github.com/ashborn-systems/constant-docs
23
- Project-URL: Repository, https://github.com/ashborn-systems/constant-docs
24
- Project-URL: Documentation, https://github.com/ashborn-systems/constant-docs/blob/main/README.md
25
- Project-URL: Changelog, https://github.com/ashborn-systems/constant-docs/blob/main/docs/CHANGELOG.md
26
- Project-URL: Issues, https://github.com/ashborn-systems/constant-docs/issues
27
- Project-URL: Specification, https://github.com/ashborn-systems/constant-docs/blob/main/docs/SPEC.md
22
+ Project-URL: Homepage, https://github.com/daemon-systems/constant-docs
23
+ Project-URL: Repository, https://github.com/daemon-systems/constant-docs
24
+ Project-URL: Documentation, https://github.com/daemon-systems/constant-docs/blob/main/README.md
25
+ Project-URL: Changelog, https://github.com/daemon-systems/constant-docs/blob/main/docs/CHANGELOG.md
26
+ Project-URL: Issues, https://github.com/daemon-systems/constant-docs/issues
27
+ Project-URL: Specification, https://github.com/daemon-systems/constant-docs/blob/main/docs/SPEC.md
28
28
  Description-Content-Type: text/markdown
29
29
 
30
30
  <!-- constant-docs
@@ -51,20 +51,29 @@ constant_docs:
51
51
  - src/constant_docs/api.py
52
52
  - src/constant_docs/cli.py
53
53
  - src/constant_docs/kinds.py
54
- source_hash: sha256:99017f4b3440779659af6e13a51d12da0e37146fd449a934a42751f6f6f8d50b
54
+ source_hash: sha256:aeb0c87c1ea90b23e657543f1eb6c39707733d7def1a6f05096158295d76cec8
55
55
  hash_method: sha256-over-sorted-path-and-content
56
56
  hash_covers: source_files
57
- timestamp: '2026-09-05T13:18:40Z'
58
- generator: constant-docs/0.7.0
59
- generator_spec: https://github.com/ashborn-systems/constant-docs/blob/main/SPEC.md
57
+ timestamp: '2026-09-19T13:07:50Z'
58
+ generator: constant-docs/0.9.1
59
+ generator_spec: https://github.com/daemon-systems/constant-docs/blob/main/SPEC.md
60
60
  -->
61
61
 
62
62
 
63
+
64
+
65
+
66
+
67
+
68
+
69
+
70
+
63
71
  # constant-docs
64
72
 
65
73
  Documentation that fails the build when it drifts.
66
74
 
67
- A Python command-line tool for codebases written with a coding agent. Each
75
+ A Python command-line tool and coding-agent plugin for maintaining source
76
+ documents. Each
68
77
  document records a hash of the source files it describes, and `constant-docs
69
78
  verify` exits 1 the moment the two disagree. The check is a hash comparison, so
70
79
  it needs no model client and no network. Your agent writes the documents. The
@@ -94,8 +103,9 @@ Your coding agent writes every word, because it already holds the source and a
94
103
  model connection. constant-docs names the documents that moved and takes the
95
104
  new text back.
96
105
 
97
- That one command is also the whole CI integration. It exits 1 on drift, so a
98
- change that alters behaviour and leaves its document behind does not merge:
106
+ That one command is also the whole continuous-integration check. It exits 1 on
107
+ drift, so a change that alters behaviour and leaves its document behind does
108
+ not merge:
99
109
 
100
110
  ```yaml
101
111
  - run: constant-docs verify
@@ -167,13 +177,15 @@ clean report on no evidence. `plan --json` considers every module whatever the
167
177
  marks say. `verify` hashes everything and exits 1 on drift. Keep `verify` as
168
178
  the gate.
169
179
 
170
- Claude Code gets a plugin. Install it and two hooks run those commands for you:
171
- `PostToolUse` runs `mark`, `Stop` runs `settle --hook`. Edit a file, stop the
172
- turn, and its document is up to date. Any harness that can run a command on
173
- write and at turn end does the same job.
180
+ Codex and Claude Code can load the plugin. Its two document hooks run these
181
+ commands:
182
+ `PostToolUse` runs `mark` after each edit, and `Stop` runs `settle --hook` when
183
+ the turn ends. The agent reads the returned plan and updates the affected documents before
184
+ verification. Any
185
+ harness that can run a command on write and at turn end does the same job.
174
186
 
175
- Regeneration happens at quiescence, never mid-edit, so the generator and the
176
- coding loop never write the same file at once. The dirty set lives in
187
+ Regeneration happens at the end of a turn, never mid-edit, so the generator and
188
+ the coding loop never write the same file at once. The dirty set lives in
177
189
  `.constant-docs/dirty.json`, which is gitignored, so a crashed session is
178
190
  picked up on the next run.
179
191
 
@@ -181,9 +193,9 @@ The [harness guide](guides/harness-integration.md) walks through each route.
181
193
 
182
194
  ## Kinds
183
195
 
184
- A document is not always a module explainer. Its kind decides which sections it
185
- must carry, which prompt its generator is handed, and whether a regeneration
186
- replaces the body or appends to it.
196
+ Every document has a kind. The kind decides which sections its body must carry,
197
+ which prompt its generator is handed, and whether a regeneration replaces the
198
+ body or appends an entry.
187
199
 
188
200
  | Kind | For | Mode |
189
201
  |---|---|---|
@@ -191,9 +203,10 @@ replaces the body or appends to it.
191
203
  | `spec` | What a subsystem promises, and why | replace |
192
204
  | `log` | A changelog or build log | **append** |
193
205
  | `architecture` | The module map, with a diagram | replace |
194
- | `errors` | Every message the tool can emit | replace |
206
+ | `errors` | Every message the covered code can raise | replace |
195
207
  | `config-reference` | Every configuration key | replace |
196
208
  | `cli-reference` | Every command and flag | replace |
209
+ | `manual-page` | One user task, written for the person doing it | replace |
197
210
 
198
211
  ```yaml
199
212
  modules:
@@ -212,8 +225,25 @@ An append never rewrites or reorders what is already there. Pass a whole body
212
225
  to a log, or a single entry to a module document, and the tool refuses it. A
213
226
  configuration that has never heard of kinds behaves exactly as it did.
214
227
 
215
- One house style governs every generated document. It lives in a single file
216
- that all seven built-in prompts receive, so the rules cannot drift apart.
228
+ One shared writing register governs documents written from built-in prompts. It
229
+ lives in a single file that all eight built-in prompts receive, and is checked
230
+ against the canonical technical-writing skill. The smaller shared core can also
231
+ be consumed by other agents through a pinned import.
232
+ The [writing-register guide](guides/writing-register.md) describes the exports.
233
+
234
+ ## User manuals
235
+
236
+ A user manual is an ordered collection of small task pages. Each page is a
237
+ normal tracked document, so a product change makes only the affected pages
238
+ stale. Constant-Docs assembles the navigation without a model call.
239
+
240
+ Manuals declare input and output token ceilings. A page already above its input
241
+ ceiling appears under `blocked` and is never handed to the supplied generation
242
+ workflow. Split that page by user task, narrow its source, or change the budget
243
+ deliberately.
244
+
245
+ This repository uses the feature itself. Start with the [Constant-Docs user
246
+ manual](docs/user-manual/index.md).
217
247
 
218
248
  ## Finding what is undocumented
219
249
 
@@ -223,17 +253,18 @@ constant-docs coverage # source no module covers, by directory
223
253
  constant-docs completeness # kinds of document the contents warrant
224
254
  ```
225
255
 
226
- `verify` can only check what has been declared, so a repository could otherwise
227
- drift to a large fraction undocumented while every check passed. `coverage`
228
- does one thing: a set difference. Declare the directories that should carry no
229
- document in the configuration, with a reason each. An exclusion nobody
230
- justified is one nobody decided.
256
+ `verify` can only check what has been declared, so a repository can drift a
257
+ long way undocumented while every check passes. `coverage` does one thing: a
258
+ set difference. It reports the files no declared glob matches and no exclusion
259
+ names. Declare the directories that should carry no document in the
260
+ configuration, with a reason each. An exclusion nobody justified is one nobody
261
+ decided.
231
262
 
232
263
  Coverage answers whether a file has a document. It cannot answer whether the
233
- set of documents is complete: a document that was never written cannot drift,
234
- and a module document covers its files, so a repository with a document per
235
- module and no specification passes everything. `completeness` proposes the
236
- kinds your contents warrant, each with the fact behind it:
264
+ set of documents is complete. A document that was never written cannot drift,
265
+ and a repository with a document per module and no specification passes every
266
+ coverage check. `completeness` proposes the kinds your contents warrant, each
267
+ with the fact behind it:
237
268
 
238
269
  ```
239
270
  Warranted and not written (2):
@@ -247,11 +278,11 @@ Warranted and not written (2):
247
278
  It proposes from evidence in the repository, such as a console script or an
248
279
  exception hierarchy. The existence of a kind is not itself evidence. A library
249
280
  with no command line is not offered a CLI reference, because a document nobody
250
- needs still has to be kept true and still refuses a commit when it drifts.
281
+ needs still has to be kept true and still fails the build when it drifts.
251
282
  Nothing warrants a changelog: every repository could keep one, so the signal
252
283
  fires everywhere and says nothing.
253
284
 
254
- Write the document, or decline the kind under `unwarranted:` with a reason and
285
+ Write the document, or decline the kind under `unwarranted:` with a reason, and
255
286
  it stops being proposed.
256
287
 
257
288
  `verify --coverage` and `verify --completeness` fold the two into the gate,
@@ -261,13 +292,14 @@ document, and `prune` deletes it.
261
292
  ## Files it will not touch
262
293
 
263
294
  Pointing the tool at a `docs/` folder the repository already has is safe. Every
264
- document this tool writes carries a block naming the tool, and, when you
265
- declare a `project` id, the project that wrote it. A markdown file without that
266
- block belongs to somebody else, and three commands act on the difference:
295
+ document this tool writes carries a block naming the tool and, when you declare
296
+ a `project` id, the project that wrote it. A markdown file without that block
297
+ belongs to somebody else, and three commands act on the difference:
267
298
 
268
299
  - `apply` refuses to write over one. It names the file and changes no byte
269
300
  - `prune` refuses to delete one, and names every file it left alone
270
- - `verify` lists them under a heading of their own, and they fail nothing
301
+ - `verify` lists them under a heading of their own, and none of them fails the
302
+ check
271
303
 
272
304
  Take one over when you want it maintained:
273
305
 
@@ -288,7 +320,7 @@ rewrite it. Every body your agent generates still carries those headings, and
288
320
  `apply` checks before it writes a byte.
289
321
 
290
322
  A glob that matches no file gets the same restraint. `verify` names the module
291
- and exits 1, `apply` refuses to record a digest over nothing, and the document
323
+ and exits 1, `apply` refuses to record a hash over nothing, and the document
292
324
  stays where it is. A mistyped glob costs you a failing check and nothing else.
293
325
 
294
326
  ## Documents outside the repository
@@ -309,12 +341,14 @@ real directory on this machine: where to open the file.
309
341
 
310
342
  The variable must resolve when the configuration loads. Unset, empty, relative,
311
343
  or naming a directory that is not there, each refuses the configuration and
312
- says which. A store landing inside `.ssh`, `Secret/`, a cache or any other
313
- directory on the deny list is refused too. The tool declines to read those
314
- directories, so it declines to write documents into them. Plain `${NAME}` is
315
- the whole syntax. A default value would let a machine without the vault write
316
- documents into the repository and report success. The Stop hook blocks on the
317
- same failure, so a missing variable cannot switch the gate off quietly.
344
+ says which. A store landing inside `.ssh`, `Secret/`, a cache, or any other
345
+ directory on the deny list is refused too: the tool declines to read those
346
+ directories, so it declines to write documents into them.
347
+
348
+ Plain `${NAME}` is the whole syntax. A default value would let a machine
349
+ without the vault write documents into the repository and report success. The
350
+ Stop hook blocks on the same failure, so a missing variable cannot switch the
351
+ gate off quietly.
318
352
 
319
353
  Deletion changes as well. A repository's documents ride the branch, and `git
320
354
  checkout` brings one back. A store stands still while the checkout moves, so
@@ -334,12 +368,14 @@ auto:
334
368
  budget: 5
335
369
  ```
336
370
 
337
- The tool still calls no model. constant-docs splits your command with `shlex`
338
- and runs it directly, so an agent CLI, a script and a Makefile target all work.
339
- No credential goes in it. The command's success is checked: `auto` re-runs
340
- `verify` afterwards. It exits 0 when everything is clean, 1 when something is
341
- still stale, and 2 when the command could not run or exited non-zero. Three
342
- outcomes, because a scheduler that confuses the last two retries the wrong one.
371
+ constant-docs itself calls no model. It splits your command with `shlex` and
372
+ runs it directly, so an agent CLI, a script, and a Makefile target all work. No
373
+ credential goes in it. The command's success is checked: `auto` re-runs
374
+ `verify` afterwards.
375
+
376
+ It exits 0 when everything is clean, 1 when something is still stale, and 2
377
+ when the command could not run or exited non-zero. Three outcomes, because a
378
+ scheduler that confuses the last two retries the wrong one.
343
379
 
344
380
  ## Three things it checks that a hash cannot
345
381
 
@@ -354,9 +390,10 @@ document, with a date.
354
390
  in those modules' files by name, so it goes stale when their boundary moves.
355
391
 
356
392
  **An error catalogue agrees with the source, both ways.** Every message the
357
- code raises appears in the catalogue, and every entry still exists in the code.
358
- Neither needs parsing beyond a string scan, so it costs nothing, and it is the
359
- one document here the tool can actually guarantee. The rest are only fresh.
393
+ code raises appears in the catalogue, and every entry listed is still raised in
394
+ the code. The check needs no parsing beyond a string scan, so it costs nothing,
395
+ and it is the one document here the tool can guarantee. The rest are only
396
+ fresh.
360
397
 
361
398
  ## What a document looks like
362
399
 
@@ -381,8 +418,8 @@ constant_docs:
381
418
  hash_method: sha256-over-sorted-path-and-content
382
419
  hash_covers: source_files
383
420
  timestamp: '2026-08-19T09:14:00Z'
384
- generator: constant-docs/0.7.0
385
- generator_spec: https://github.com/ashborn-systems/constant-docs/blob/main/SPEC.md
421
+ generator: constant-docs/0.8.0
422
+ generator_spec: https://github.com/daemon-systems/constant-docs/blob/main/SPEC.md
386
423
  ---
387
424
  ## Purpose
388
425
 
@@ -404,7 +441,7 @@ report records that it happened.
404
441
 
405
442
  The frontmatter stands alone. An agent that has never run this tool can see
406
443
  what the document describes, where its source lives, and how to recompute the
407
- digest. `project` answers the question asked before every overwrite and every
444
+ hash. `project` answers the question asked before every overwrite and every
408
445
  deletion: whose document is this. The tool keeps everything it owns under one
409
446
  `constant_docs` key, an Open Knowledge Format producer extension. `type`,
410
447
  `title`, `tags` and the two dates stay yours, and unknown keys survive a write.
@@ -424,11 +461,11 @@ prune() # deletes orphans; under a store, lists them
424
461
 
425
462
  ## What it does not do
426
463
 
427
- A module names a glob, and the tool digests the bytes of the files that glob
428
- matches. Nothing in that step knows a language, which is what makes yours work:
429
- no model client, no network call, no AST, no import graph. The cost is that any
430
- byte moves the hash. Fixing a typo in a comment reports the module stale, and
431
- your agent rewrites a document the edit never touched.
464
+ A module names a glob, and the tool hashes the bytes of the files that glob
465
+ matches. Nothing in that step knows a language, which is what makes it work on
466
+ yours: no model client, no network call, no syntax tree, no import graph. The
467
+ cost is that any byte moves the hash. Fixing a typo in a comment reports the
468
+ module stale, and your agent rewrites a document the edit never touched.
432
469
 
433
470
  It watches files and nothing else. A document quoting a queue depth or a
434
471
  production URL stays fresh for ever, because nobody edited anything. Hash what
@@ -22,20 +22,29 @@ constant_docs:
22
22
  - src/constant_docs/api.py
23
23
  - src/constant_docs/cli.py
24
24
  - src/constant_docs/kinds.py
25
- source_hash: sha256:99017f4b3440779659af6e13a51d12da0e37146fd449a934a42751f6f6f8d50b
25
+ source_hash: sha256:aeb0c87c1ea90b23e657543f1eb6c39707733d7def1a6f05096158295d76cec8
26
26
  hash_method: sha256-over-sorted-path-and-content
27
27
  hash_covers: source_files
28
- timestamp: '2026-09-05T13:18:40Z'
29
- generator: constant-docs/0.7.0
30
- generator_spec: https://github.com/ashborn-systems/constant-docs/blob/main/SPEC.md
28
+ timestamp: '2026-09-19T13:07:50Z'
29
+ generator: constant-docs/0.9.1
30
+ generator_spec: https://github.com/daemon-systems/constant-docs/blob/main/SPEC.md
31
31
  -->
32
32
 
33
33
 
34
+
35
+
36
+
37
+
38
+
39
+
40
+
41
+
34
42
  # constant-docs
35
43
 
36
44
  Documentation that fails the build when it drifts.
37
45
 
38
- A Python command-line tool for codebases written with a coding agent. Each
46
+ A Python command-line tool and coding-agent plugin for maintaining source
47
+ documents. Each
39
48
  document records a hash of the source files it describes, and `constant-docs
40
49
  verify` exits 1 the moment the two disagree. The check is a hash comparison, so
41
50
  it needs no model client and no network. Your agent writes the documents. The
@@ -65,8 +74,9 @@ Your coding agent writes every word, because it already holds the source and a
65
74
  model connection. constant-docs names the documents that moved and takes the
66
75
  new text back.
67
76
 
68
- That one command is also the whole CI integration. It exits 1 on drift, so a
69
- change that alters behaviour and leaves its document behind does not merge:
77
+ That one command is also the whole continuous-integration check. It exits 1 on
78
+ drift, so a change that alters behaviour and leaves its document behind does
79
+ not merge:
70
80
 
71
81
  ```yaml
72
82
  - run: constant-docs verify
@@ -138,13 +148,15 @@ clean report on no evidence. `plan --json` considers every module whatever the
138
148
  marks say. `verify` hashes everything and exits 1 on drift. Keep `verify` as
139
149
  the gate.
140
150
 
141
- Claude Code gets a plugin. Install it and two hooks run those commands for you:
142
- `PostToolUse` runs `mark`, `Stop` runs `settle --hook`. Edit a file, stop the
143
- turn, and its document is up to date. Any harness that can run a command on
144
- write and at turn end does the same job.
151
+ Codex and Claude Code can load the plugin. Its two document hooks run these
152
+ commands:
153
+ `PostToolUse` runs `mark` after each edit, and `Stop` runs `settle --hook` when
154
+ the turn ends. The agent reads the returned plan and updates the affected documents before
155
+ verification. Any
156
+ harness that can run a command on write and at turn end does the same job.
145
157
 
146
- Regeneration happens at quiescence, never mid-edit, so the generator and the
147
- coding loop never write the same file at once. The dirty set lives in
158
+ Regeneration happens at the end of a turn, never mid-edit, so the generator and
159
+ the coding loop never write the same file at once. The dirty set lives in
148
160
  `.constant-docs/dirty.json`, which is gitignored, so a crashed session is
149
161
  picked up on the next run.
150
162
 
@@ -152,9 +164,9 @@ The [harness guide](guides/harness-integration.md) walks through each route.
152
164
 
153
165
  ## Kinds
154
166
 
155
- A document is not always a module explainer. Its kind decides which sections it
156
- must carry, which prompt its generator is handed, and whether a regeneration
157
- replaces the body or appends to it.
167
+ Every document has a kind. The kind decides which sections its body must carry,
168
+ which prompt its generator is handed, and whether a regeneration replaces the
169
+ body or appends an entry.
158
170
 
159
171
  | Kind | For | Mode |
160
172
  |---|---|---|
@@ -162,9 +174,10 @@ replaces the body or appends to it.
162
174
  | `spec` | What a subsystem promises, and why | replace |
163
175
  | `log` | A changelog or build log | **append** |
164
176
  | `architecture` | The module map, with a diagram | replace |
165
- | `errors` | Every message the tool can emit | replace |
177
+ | `errors` | Every message the covered code can raise | replace |
166
178
  | `config-reference` | Every configuration key | replace |
167
179
  | `cli-reference` | Every command and flag | replace |
180
+ | `manual-page` | One user task, written for the person doing it | replace |
168
181
 
169
182
  ```yaml
170
183
  modules:
@@ -183,8 +196,25 @@ An append never rewrites or reorders what is already there. Pass a whole body
183
196
  to a log, or a single entry to a module document, and the tool refuses it. A
184
197
  configuration that has never heard of kinds behaves exactly as it did.
185
198
 
186
- One house style governs every generated document. It lives in a single file
187
- that all seven built-in prompts receive, so the rules cannot drift apart.
199
+ One shared writing register governs documents written from built-in prompts. It
200
+ lives in a single file that all eight built-in prompts receive, and is checked
201
+ against the canonical technical-writing skill. The smaller shared core can also
202
+ be consumed by other agents through a pinned import.
203
+ The [writing-register guide](guides/writing-register.md) describes the exports.
204
+
205
+ ## User manuals
206
+
207
+ A user manual is an ordered collection of small task pages. Each page is a
208
+ normal tracked document, so a product change makes only the affected pages
209
+ stale. Constant-Docs assembles the navigation without a model call.
210
+
211
+ Manuals declare input and output token ceilings. A page already above its input
212
+ ceiling appears under `blocked` and is never handed to the supplied generation
213
+ workflow. Split that page by user task, narrow its source, or change the budget
214
+ deliberately.
215
+
216
+ This repository uses the feature itself. Start with the [Constant-Docs user
217
+ manual](docs/user-manual/index.md).
188
218
 
189
219
  ## Finding what is undocumented
190
220
 
@@ -194,17 +224,18 @@ constant-docs coverage # source no module covers, by directory
194
224
  constant-docs completeness # kinds of document the contents warrant
195
225
  ```
196
226
 
197
- `verify` can only check what has been declared, so a repository could otherwise
198
- drift to a large fraction undocumented while every check passed. `coverage`
199
- does one thing: a set difference. Declare the directories that should carry no
200
- document in the configuration, with a reason each. An exclusion nobody
201
- justified is one nobody decided.
227
+ `verify` can only check what has been declared, so a repository can drift a
228
+ long way undocumented while every check passes. `coverage` does one thing: a
229
+ set difference. It reports the files no declared glob matches and no exclusion
230
+ names. Declare the directories that should carry no document in the
231
+ configuration, with a reason each. An exclusion nobody justified is one nobody
232
+ decided.
202
233
 
203
234
  Coverage answers whether a file has a document. It cannot answer whether the
204
- set of documents is complete: a document that was never written cannot drift,
205
- and a module document covers its files, so a repository with a document per
206
- module and no specification passes everything. `completeness` proposes the
207
- kinds your contents warrant, each with the fact behind it:
235
+ set of documents is complete. A document that was never written cannot drift,
236
+ and a repository with a document per module and no specification passes every
237
+ coverage check. `completeness` proposes the kinds your contents warrant, each
238
+ with the fact behind it:
208
239
 
209
240
  ```
210
241
  Warranted and not written (2):
@@ -218,11 +249,11 @@ Warranted and not written (2):
218
249
  It proposes from evidence in the repository, such as a console script or an
219
250
  exception hierarchy. The existence of a kind is not itself evidence. A library
220
251
  with no command line is not offered a CLI reference, because a document nobody
221
- needs still has to be kept true and still refuses a commit when it drifts.
252
+ needs still has to be kept true and still fails the build when it drifts.
222
253
  Nothing warrants a changelog: every repository could keep one, so the signal
223
254
  fires everywhere and says nothing.
224
255
 
225
- Write the document, or decline the kind under `unwarranted:` with a reason and
256
+ Write the document, or decline the kind under `unwarranted:` with a reason, and
226
257
  it stops being proposed.
227
258
 
228
259
  `verify --coverage` and `verify --completeness` fold the two into the gate,
@@ -232,13 +263,14 @@ document, and `prune` deletes it.
232
263
  ## Files it will not touch
233
264
 
234
265
  Pointing the tool at a `docs/` folder the repository already has is safe. Every
235
- document this tool writes carries a block naming the tool, and, when you
236
- declare a `project` id, the project that wrote it. A markdown file without that
237
- block belongs to somebody else, and three commands act on the difference:
266
+ document this tool writes carries a block naming the tool and, when you declare
267
+ a `project` id, the project that wrote it. A markdown file without that block
268
+ belongs to somebody else, and three commands act on the difference:
238
269
 
239
270
  - `apply` refuses to write over one. It names the file and changes no byte
240
271
  - `prune` refuses to delete one, and names every file it left alone
241
- - `verify` lists them under a heading of their own, and they fail nothing
272
+ - `verify` lists them under a heading of their own, and none of them fails the
273
+ check
242
274
 
243
275
  Take one over when you want it maintained:
244
276
 
@@ -259,7 +291,7 @@ rewrite it. Every body your agent generates still carries those headings, and
259
291
  `apply` checks before it writes a byte.
260
292
 
261
293
  A glob that matches no file gets the same restraint. `verify` names the module
262
- and exits 1, `apply` refuses to record a digest over nothing, and the document
294
+ and exits 1, `apply` refuses to record a hash over nothing, and the document
263
295
  stays where it is. A mistyped glob costs you a failing check and nothing else.
264
296
 
265
297
  ## Documents outside the repository
@@ -280,12 +312,14 @@ real directory on this machine: where to open the file.
280
312
 
281
313
  The variable must resolve when the configuration loads. Unset, empty, relative,
282
314
  or naming a directory that is not there, each refuses the configuration and
283
- says which. A store landing inside `.ssh`, `Secret/`, a cache or any other
284
- directory on the deny list is refused too. The tool declines to read those
285
- directories, so it declines to write documents into them. Plain `${NAME}` is
286
- the whole syntax. A default value would let a machine without the vault write
287
- documents into the repository and report success. The Stop hook blocks on the
288
- same failure, so a missing variable cannot switch the gate off quietly.
315
+ says which. A store landing inside `.ssh`, `Secret/`, a cache, or any other
316
+ directory on the deny list is refused too: the tool declines to read those
317
+ directories, so it declines to write documents into them.
318
+
319
+ Plain `${NAME}` is the whole syntax. A default value would let a machine
320
+ without the vault write documents into the repository and report success. The
321
+ Stop hook blocks on the same failure, so a missing variable cannot switch the
322
+ gate off quietly.
289
323
 
290
324
  Deletion changes as well. A repository's documents ride the branch, and `git
291
325
  checkout` brings one back. A store stands still while the checkout moves, so
@@ -305,12 +339,14 @@ auto:
305
339
  budget: 5
306
340
  ```
307
341
 
308
- The tool still calls no model. constant-docs splits your command with `shlex`
309
- and runs it directly, so an agent CLI, a script and a Makefile target all work.
310
- No credential goes in it. The command's success is checked: `auto` re-runs
311
- `verify` afterwards. It exits 0 when everything is clean, 1 when something is
312
- still stale, and 2 when the command could not run or exited non-zero. Three
313
- outcomes, because a scheduler that confuses the last two retries the wrong one.
342
+ constant-docs itself calls no model. It splits your command with `shlex` and
343
+ runs it directly, so an agent CLI, a script, and a Makefile target all work. No
344
+ credential goes in it. The command's success is checked: `auto` re-runs
345
+ `verify` afterwards.
346
+
347
+ It exits 0 when everything is clean, 1 when something is still stale, and 2
348
+ when the command could not run or exited non-zero. Three outcomes, because a
349
+ scheduler that confuses the last two retries the wrong one.
314
350
 
315
351
  ## Three things it checks that a hash cannot
316
352
 
@@ -325,9 +361,10 @@ document, with a date.
325
361
  in those modules' files by name, so it goes stale when their boundary moves.
326
362
 
327
363
  **An error catalogue agrees with the source, both ways.** Every message the
328
- code raises appears in the catalogue, and every entry still exists in the code.
329
- Neither needs parsing beyond a string scan, so it costs nothing, and it is the
330
- one document here the tool can actually guarantee. The rest are only fresh.
364
+ code raises appears in the catalogue, and every entry listed is still raised in
365
+ the code. The check needs no parsing beyond a string scan, so it costs nothing,
366
+ and it is the one document here the tool can guarantee. The rest are only
367
+ fresh.
331
368
 
332
369
  ## What a document looks like
333
370
 
@@ -352,8 +389,8 @@ constant_docs:
352
389
  hash_method: sha256-over-sorted-path-and-content
353
390
  hash_covers: source_files
354
391
  timestamp: '2026-08-19T09:14:00Z'
355
- generator: constant-docs/0.7.0
356
- generator_spec: https://github.com/ashborn-systems/constant-docs/blob/main/SPEC.md
392
+ generator: constant-docs/0.8.0
393
+ generator_spec: https://github.com/daemon-systems/constant-docs/blob/main/SPEC.md
357
394
  ---
358
395
  ## Purpose
359
396
 
@@ -375,7 +412,7 @@ report records that it happened.
375
412
 
376
413
  The frontmatter stands alone. An agent that has never run this tool can see
377
414
  what the document describes, where its source lives, and how to recompute the
378
- digest. `project` answers the question asked before every overwrite and every
415
+ hash. `project` answers the question asked before every overwrite and every
379
416
  deletion: whose document is this. The tool keeps everything it owns under one
380
417
  `constant_docs` key, an Open Knowledge Format producer extension. `type`,
381
418
  `title`, `tags` and the two dates stay yours, and unknown keys survive a write.
@@ -395,11 +432,11 @@ prune() # deletes orphans; under a store, lists them
395
432
 
396
433
  ## What it does not do
397
434
 
398
- A module names a glob, and the tool digests the bytes of the files that glob
399
- matches. Nothing in that step knows a language, which is what makes yours work:
400
- no model client, no network call, no AST, no import graph. The cost is that any
401
- byte moves the hash. Fixing a typo in a comment reports the module stale, and
402
- your agent rewrites a document the edit never touched.
435
+ A module names a glob, and the tool hashes the bytes of the files that glob
436
+ matches. Nothing in that step knows a language, which is what makes it work on
437
+ yours: no model client, no network call, no syntax tree, no import graph. The
438
+ cost is that any byte moves the hash. Fixing a typo in a comment reports the
439
+ module stale, and your agent rewrites a document the edit never touched.
403
440
 
404
441
  It watches files and nothing else. A document quoting a queue depth or a
405
442
  production URL stays fresh for ever, because nobody edited anything. Hash what
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "constant-docs"
3
- version = "0.7.0"
3
+ version = "0.9.1"
4
4
  description = "Self-maintaining documentation for agentic codebases"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -32,15 +32,15 @@ classifiers = [
32
32
  dependencies = ["pyyaml>=6.0.3"]
33
33
 
34
34
  [[project.authors]]
35
- name = "Ashborn Systems"
35
+ name = "Daemon Agent"
36
36
 
37
37
  [project.urls]
38
- Homepage = "https://github.com/ashborn-systems/constant-docs"
39
- Repository = "https://github.com/ashborn-systems/constant-docs"
40
- Documentation = "https://github.com/ashborn-systems/constant-docs/blob/main/README.md"
41
- Changelog = "https://github.com/ashborn-systems/constant-docs/blob/main/docs/CHANGELOG.md"
42
- Issues = "https://github.com/ashborn-systems/constant-docs/issues"
43
- Specification = "https://github.com/ashborn-systems/constant-docs/blob/main/docs/SPEC.md"
38
+ Homepage = "https://github.com/daemon-systems/constant-docs"
39
+ Repository = "https://github.com/daemon-systems/constant-docs"
40
+ Documentation = "https://github.com/daemon-systems/constant-docs/blob/main/README.md"
41
+ Changelog = "https://github.com/daemon-systems/constant-docs/blob/main/docs/CHANGELOG.md"
42
+ Issues = "https://github.com/daemon-systems/constant-docs/issues"
43
+ Specification = "https://github.com/daemon-systems/constant-docs/blob/main/docs/SPEC.md"
44
44
 
45
45
  [project.scripts]
46
46
  constant-docs = "constant_docs.cli:main"