mhproto 0.8.0-preview.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 (124) hide show
  1. package/CONTRIBUTING.md +62 -0
  2. package/LICENSE +21 -0
  3. package/README.md +53 -0
  4. package/THIRD_PARTY_NOTICES.md +40 -0
  5. package/bin/mhproto.mjs +248 -0
  6. package/doc/context-design.md +43 -0
  7. package/doc/context-measurements.json +28 -0
  8. package/doc/guide.md +138 -0
  9. package/doc/publishing.md +93 -0
  10. package/doc/release-notes.md +23 -0
  11. package/doc/release-review-2026-10-02.md +127 -0
  12. package/doc/release-review.md +68 -0
  13. package/doc/viewer-design.md +80 -0
  14. package/package.json +69 -0
  15. package/skills/mhproto-discover/SKILL.md +14 -0
  16. package/skills/mhproto-implement/SKILL.md +14 -0
  17. package/skills/mhproto-reconcile/SKILL.md +14 -0
  18. package/skills/mhproto-specify/SKILL.md +16 -0
  19. package/skills/mhproto-specify/references/format.md +20 -0
  20. package/skills/mhproto-verify/SKILL.md +14 -0
  21. package/src/config.mjs +202 -0
  22. package/src/context.mjs +228 -0
  23. package/src/core.mjs +471 -0
  24. package/src/node-reporter.mjs +15 -0
  25. package/src/paths.mjs +51 -0
  26. package/src/server.mjs +290 -0
  27. package/src/verify.mjs +149 -0
  28. package/src/visuals.mjs +189 -0
  29. package/viewer/app.js +1463 -0
  30. package/viewer/diff.js +245 -0
  31. package/viewer/index.html +51 -0
  32. package/viewer/style.css +1003 -0
  33. package/viewer/vendor/LICENSE +21 -0
  34. package/viewer/vendor/NOTICE.txt +3372 -0
  35. package/viewer/vendor/README.md +75 -0
  36. package/viewer/vendor/build-evidence.json +2775 -0
  37. package/viewer/vendor/bundled-audit.json +88 -0
  38. package/viewer/vendor/bundled-packages.json +84 -0
  39. package/viewer/vendor/embedded-notices.txt +33 -0
  40. package/viewer/vendor/license-inventory.json +1456 -0
  41. package/viewer/vendor/licenses/braintree__sanitize-url-7.1.2.txt +21 -0
  42. package/viewer/vendor/licenses/chevrotain-13.2.0.txt +202 -0
  43. package/viewer/vendor/licenses/chevrotain-allstar-0.5.0.txt +16 -0
  44. package/viewer/vendor/licenses/chevrotain__cst-dts-gen-13.2.0.txt +202 -0
  45. package/viewer/vendor/licenses/chevrotain__gast-13.2.0.txt +202 -0
  46. package/viewer/vendor/licenses/chevrotain__regexp-to-ast-13.2.0.txt +202 -0
  47. package/viewer/vendor/licenses/chevrotain__utils-13.2.0.txt +202 -0
  48. package/viewer/vendor/licenses/cose-base-1.0.3.txt +21 -0
  49. package/viewer/vendor/licenses/cose-base-2.2.0.txt +21 -0
  50. package/viewer/vendor/licenses/cytoscape-3.34.3.txt +19 -0
  51. package/viewer/vendor/licenses/cytoscape-cose-bilkent-4.1.0.txt +21 -0
  52. package/viewer/vendor/licenses/cytoscape-fcose-2.2.0.txt +19 -0
  53. package/viewer/vendor/licenses/d3-7.9.0.txt +13 -0
  54. package/viewer/vendor/licenses/d3-array-2.12.1.txt +27 -0
  55. package/viewer/vendor/licenses/d3-array-3.2.4.txt +13 -0
  56. package/viewer/vendor/licenses/d3-axis-3.0.0.txt +13 -0
  57. package/viewer/vendor/licenses/d3-brush-3.0.0.txt +13 -0
  58. package/viewer/vendor/licenses/d3-chord-3.0.1.txt +13 -0
  59. package/viewer/vendor/licenses/d3-color-3.1.0.txt +13 -0
  60. package/viewer/vendor/licenses/d3-contour-4.0.2.txt +13 -0
  61. package/viewer/vendor/licenses/d3-delaunay-6.0.4.txt +14 -0
  62. package/viewer/vendor/licenses/d3-dispatch-3.0.1.txt +13 -0
  63. package/viewer/vendor/licenses/d3-drag-3.0.0.txt +13 -0
  64. package/viewer/vendor/licenses/d3-dsv-3.0.1.txt +13 -0
  65. package/viewer/vendor/licenses/d3-ease-3.0.1.txt +28 -0
  66. package/viewer/vendor/licenses/d3-fetch-3.0.1.txt +13 -0
  67. package/viewer/vendor/licenses/d3-force-3.0.0.txt +13 -0
  68. package/viewer/vendor/licenses/d3-format-3.1.2.txt +13 -0
  69. package/viewer/vendor/licenses/d3-geo-3.1.1.txt +34 -0
  70. package/viewer/vendor/licenses/d3-hierarchy-3.1.2.txt +13 -0
  71. package/viewer/vendor/licenses/d3-interpolate-3.0.1.txt +13 -0
  72. package/viewer/vendor/licenses/d3-path-1.0.9.txt +27 -0
  73. package/viewer/vendor/licenses/d3-path-3.1.0.txt +13 -0
  74. package/viewer/vendor/licenses/d3-polygon-3.0.1.txt +13 -0
  75. package/viewer/vendor/licenses/d3-quadtree-3.0.1.txt +13 -0
  76. package/viewer/vendor/licenses/d3-random-3.0.1.txt +13 -0
  77. package/viewer/vendor/licenses/d3-sankey-0.12.3.txt +27 -0
  78. package/viewer/vendor/licenses/d3-scale-4.0.2.txt +13 -0
  79. package/viewer/vendor/licenses/d3-scale-chromatic-3.1.0.txt +28 -0
  80. package/viewer/vendor/licenses/d3-selection-3.0.0.txt +13 -0
  81. package/viewer/vendor/licenses/d3-shape-1.3.7.txt +27 -0
  82. package/viewer/vendor/licenses/d3-shape-3.2.0.txt +13 -0
  83. package/viewer/vendor/licenses/d3-time-3.1.0.txt +13 -0
  84. package/viewer/vendor/licenses/d3-time-format-4.1.0.txt +13 -0
  85. package/viewer/vendor/licenses/d3-timer-3.0.1.txt +13 -0
  86. package/viewer/vendor/licenses/d3-transition-3.0.1.txt +13 -0
  87. package/viewer/vendor/licenses/d3-zoom-3.0.0.txt +13 -0
  88. package/viewer/vendor/licenses/dagre-d3-es-7.0.14.txt +23 -0
  89. package/viewer/vendor/licenses/dayjs-1.11.23.txt +21 -0
  90. package/viewer/vendor/licenses/delaunator-5.1.0.txt +15 -0
  91. package/viewer/vendor/licenses/dompurify-3.4.16.txt +202 -0
  92. package/viewer/vendor/licenses/elk-source-notice.txt +11 -0
  93. package/viewer/vendor/licenses/elkjs-0.9.3.txt +264 -0
  94. package/viewer/vendor/licenses/embedded-and-node-notices.txt +45 -0
  95. package/viewer/vendor/licenses/es-toolkit-1.52.0-1.txt +39 -0
  96. package/viewer/vendor/licenses/es-toolkit-1.52.0.txt +21 -0
  97. package/viewer/vendor/licenses/fastdom-1.0.12.txt +221 -0
  98. package/viewer/vendor/licenses/iconify__utils-3.1.7.txt +21 -0
  99. package/viewer/vendor/licenses/internmap-1.0.1.txt +13 -0
  100. package/viewer/vendor/licenses/internmap-2.0.3.txt +13 -0
  101. package/viewer/vendor/licenses/js-yaml-4.3.2.txt +21 -0
  102. package/viewer/vendor/licenses/katex-0.16.47.txt +21 -0
  103. package/viewer/vendor/licenses/khroma-2.1.0.txt +21 -0
  104. package/viewer/vendor/licenses/langium-4.4.0.txt +16 -0
  105. package/viewer/vendor/licenses/layout-base-1.0.2.txt +21 -0
  106. package/viewer/vendor/licenses/layout-base-2.0.1.txt +21 -0
  107. package/viewer/vendor/licenses/lodash-es-4.18.1.txt +47 -0
  108. package/viewer/vendor/licenses/marked-16.4.2.txt +44 -0
  109. package/viewer/vendor/licenses/mermaid-12.1.0.txt +21 -0
  110. package/viewer/vendor/licenses/mermaid-js__parser-2.0.1.txt +21 -0
  111. package/viewer/vendor/licenses/path-browserify-1.0.1.txt +20 -0
  112. package/viewer/vendor/licenses/robust-predicates-3.0.3.txt +24 -0
  113. package/viewer/vendor/licenses/roughjs-4.6.6.txt +21 -0
  114. package/viewer/vendor/licenses/stylis-4.4.0.txt +21 -0
  115. package/viewer/vendor/licenses/ts-dedent-2.3.0.txt +21 -0
  116. package/viewer/vendor/licenses/upsetjs__venn.js-2.0.0.txt +22 -0
  117. package/viewer/vendor/licenses/uuid-14.0.2.txt +9 -0
  118. package/viewer/vendor/licenses/vscode-jsonrpc-9.0.3.txt +11 -0
  119. package/viewer/vendor/licenses/vscode-languageserver-protocol-3.18.4.txt +11 -0
  120. package/viewer/vendor/licenses/vscode-languageserver-textdocument-1.0.15.txt +11 -0
  121. package/viewer/vendor/licenses/vscode-languageserver-types-3.18.4.txt +11 -0
  122. package/viewer/vendor/licenses/vscode-uri-3.1.0.txt +9 -0
  123. package/viewer/vendor/manifest.json +21 -0
  124. package/viewer/vendor/mermaid.min.js +7729 -0
@@ -0,0 +1,62 @@
1
+ # Contributing to MHProto
2
+
3
+ Use Node 22 or 24 and npm. Install the locked dependencies with `npm ci`.
4
+
5
+ ```sh
6
+ npm run check
7
+ npm run format
8
+ ```
9
+
10
+ `check` runs formatting and the Node/DOM tests. Tests use temporary projects and
11
+ clean them up. They cover actual CLI calls, structured Node test events, path
12
+ containment, schema validation, offline exports, type navigation and comparison.
13
+ JSDOM tests do not establish painted browser layout.
14
+
15
+ For real HTTP and desktop/mobile Chromium flows, install the pinned browser and run:
16
+
17
+ ```sh
18
+ npx playwright install --with-deps chromium
19
+ npm run test:browser
20
+ ```
21
+
22
+ The browser suite starts a loopback viewer, exercises navigation, linked types,
23
+ attachment ownership and persistence, iteration diffs and offline save/reload.
24
+ It writes screenshots and console diagnostics to `test-results/browser/`. Review
25
+ the screenshots for layout; automated assertions do not replace visual judgment.
26
+ GitHub CI uploads these artifacts along with dependency-audit and registry-signature
27
+ reports. The offline Mermaid renderer is source-built with a separate locked dependency
28
+ set. CI verifies a clean byte-identical rebuild, all retained licenses, the
29
+ exact bundled-version advisory audit and the build dependency audit. See
30
+ [the renderer notes](viewer/vendor/README.md).
31
+
32
+ Keep changes scoped. Add regression tests for observable bugs. Preserve the
33
+ single-owner attachment policy and the distinction between failed, stale and
34
+ unchecked evidence. Agent context must retain exact rules and explicit deferred
35
+ references. Add a screenshot for changes to the reading flow.
36
+
37
+ ## Code map
38
+
39
+ | Area | Files |
40
+ | --------------------------------------------------- | ------------------------------------- |
41
+ | Contract input and validation | src/core.mjs, src/config.mjs |
42
+ | Scoped agent context | src/context.mjs |
43
+ | Verification and Node reporter | src/verify.mjs, src/node-reporter.mjs |
44
+ | Contained writes and attachment metadata | src/paths.mjs, src/visuals.mjs |
45
+ | Local HTTP viewer and offline export | src/server.mjs |
46
+ | CLI workflows | bin/mhproto.mjs |
47
+ | Reading, types, attachment ownership and navigation | viewer/app.js |
48
+ | Pure snapshots and semantic comparison | viewer/diff.js |
49
+ | Agent workflows and format reference | skills/ |
50
+
51
+ There is no compilation step. The shared comparison module runs in Node and in
52
+ the browser. Standalone export inlines that module, the viewer and Mermaid.
53
+
54
+ ## Before a public release
55
+
56
+ Read [the publishing steps](doc/publishing.md) and doc/release-review.md. Run `npm run release:prepare` from a clean committed checkout to produce and test
57
+ the preview archive. Preparation does not publish it.
58
+ `npm pack --dry-run --json --ignore-scripts` inspects the planned file list without
59
+ creating an archive. `npm pack` runs the prepack check before creating a package.
60
+ Verify a clean installation of the resulting tarball in a separate project before
61
+ publishing. Do not put local app copies, evidence, screenshots, credentials or
62
+ machine-specific paths in the npm package.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 MHProto contributors
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,53 @@
1
+ # MHProto
2
+
3
+ **A shared contract for humans and coding agents.**
4
+
5
+ MHProto (Machine–Human Protocol) keeps what your app should do alongside its API
6
+ definitions, examples and verification checks. Humans review the contract in a browser; coding agents use
7
+ the same source files to implement and verify it.
8
+
9
+ Everything lives in your repository. No hosted service or AI account is required.
10
+
11
+ ## What it does
12
+
13
+ - **Agree on a feature:** keep Behaviour, Interface, Verification and Examples
14
+ together—the BIVE approach.
15
+ - **Review it:** browse features, endpoints and linked types; attach design
16
+ references and compare iterations.
17
+ - **Work with agents:** install five skills for Codex or Claude and retrieve
18
+ scoped context for an endpoint, rule or type.
19
+ - **Verify it:** link checks to the contract and see passing, failing, unchecked
20
+ and stale evidence.
21
+
22
+ ## Try it locally
23
+
24
+ Development preview. Requires Node 22 or newer; the package is not published to npm.
25
+
26
+ ```sh
27
+ git clone https://github.com/rbsx/mhproto.git
28
+ cd mhproto
29
+ npm ci
30
+ npm run check
31
+ ```
32
+
33
+ Then, from your application's directory:
34
+
35
+ ```sh
36
+ npm install --save-dev /path/to/mhproto
37
+ npx mhproto init --agent codex
38
+ npx mhproto view
39
+ ```
40
+
41
+ Use `--agent claude` or `--agent all` for other skill layouts. Edit the generated
42
+ draft to describe your feature, then run `npx mhproto check`.
43
+
44
+ ## Learn more
45
+
46
+ Visit the **[project website](https://mhproto.dev/)** for the overview,
47
+ demo and [documentation](https://mhproto.dev/docs/). The
48
+ [guide source](doc/guide.md) is also available in this repository.
49
+
50
+ For development, see [CONTRIBUTING.md](CONTRIBUTING.md). Current preview boundaries
51
+ and release gates are recorded in [the release review](doc/release-review.md).
52
+
53
+ MIT-licensed. See [LICENSE](LICENSE) and [third-party notices](THIRD_PARTY_NOTICES.md).
@@ -0,0 +1,40 @@
1
+ # Third-party software
2
+
3
+ MHProto's own source is MIT-licensed; see LICENSE. Third-party components retain
4
+ their respective licenses.
5
+
6
+ ## Offline Mermaid viewer
7
+
8
+ The viewer includes a source rebuild of Mermaid 12.1.0 with patched, locked
9
+ browser dependencies. Complete retained notices are in `viewer/vendor/NOTICE.txt`,
10
+ with original texts in `viewer/vendor/licenses/`. The appendix is embedded in the
11
+ renderer, so standalone HTML exports retain it.
12
+
13
+ `viewer/vendor/license-inventory.json` records 79 package/version entries with
14
+ archive integrity, notice sources and hashes. Coverage follows esbuild inputs and
15
+ 32 compiled parser chunks, including flattened vscode-uri/path-browserify sources.
16
+ Embedded upstream and original Node.js path module attributions are retained.
17
+
18
+ Licenses include MIT, ISC, BSD-3-Clause, Apache-2.0, EPL-2.0 and Unlicense.
19
+ DOMPurify offers MPL-2.0 OR Apache-2.0; this distribution selects Apache-2.0 while
20
+ retaining its complete original dual-license notice. Khroma's MIT terms come from
21
+ its license file; Fastdom's MIT terms come from its README.
22
+
23
+ ELK/elkjs is distributed under EPL-2.0. Copyright (c) 2017 Kiel University and
24
+ others. No changes were made to the supplied elkjs implementation; it is bundled
25
+ and minified by esbuild. JavaScript wrapper/build source for elkjs 0.9.3 is available
26
+ at https://github.com/kieler/elkjs/tree/a8304cf79fde75bc2ab1a89d28320f53f8637436;
27
+ ELK's Java algorithm source and tagged releases are at https://github.com/eclipse/elk.
28
+ The original EPL-2.0 text and source availability notice travel with the bundle.
29
+
30
+ Mermaid's runtime source and official build plugins are unchanged. MHProto uses
31
+ its own committed dependency lock, adds a namespace wrapper and appends notices.
32
+ Repeat the clean source rebuild and original-archive checks with
33
+ `npm run verify:vendor`; repeat the separate bundled security audit with
34
+ `npm run audit:vendor`. See `viewer/vendor/README.md`.
35
+
36
+ ## Separately installed dependencies
37
+
38
+ Runtime npm dependencies (Ajv, ajv-formats and YAML) are installed separately by npm
39
+ with their own licenses. Development and renderer build dependencies are excluded
40
+ from the published runtime package.
@@ -0,0 +1,248 @@
1
+ #!/usr/bin/env node
2
+ import { mkdir, readFile, readdir, writeFile, cp, lstat } from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import { loadProject, validateProject, packageRoot } from '../src/core.mjs';
5
+ import { verifyCapability } from '../src/verify.mjs';
6
+ import { compareModels, exportViewer, model, serve } from '../src/server.mjs';
7
+ import { contextPacket, encodeContext } from '../src/context.mjs';
8
+ import { contractSnapshot } from '../viewer/diff.js';
9
+ import { atomicWrite, writePath } from '../src/paths.mjs';
10
+
11
+ let command = 'help',
12
+ root = process.cwd();
13
+ const options = new Map();
14
+ const option = (name, fallback) => options.get(name) ?? fallback;
15
+ const has = (name) => options.has(name);
16
+ function parseArguments() {
17
+ const args = process.argv.slice(2);
18
+ command = args[0] && !args[0].startsWith('-') ? args.shift() : 'help';
19
+ const allowed = {
20
+ init: ['agent', 'no-skills'],
21
+ skills: ['agent'],
22
+ check: ['json'],
23
+ inspect: [],
24
+ context: [
25
+ 'capability',
26
+ 'operation',
27
+ 'rule',
28
+ 'schema',
29
+ 'example',
30
+ 'check',
31
+ 'visual',
32
+ 'section',
33
+ 'max-chars',
34
+ 'stats',
35
+ ],
36
+ verify: ['capability'],
37
+ view: ['port', 'against'],
38
+ snapshot: ['out', 'label'],
39
+ diff: ['against'],
40
+ build: ['out', 'against'],
41
+ help: [],
42
+ };
43
+ if (!Object.hasOwn(allowed, command)) throw new Error(`Unknown command: ${command}`);
44
+ const flags = new Set(['help', 'json', 'no-skills', 'stats']);
45
+ const valid = new Set(['root', 'help', ...allowed[command]]);
46
+ for (let i = 0; i < args.length; i++) {
47
+ const key = args[i].replace(/^--/, '');
48
+ if (!args[i].startsWith('--') || !valid.has(key))
49
+ throw new Error(`Unknown option for ${command}: ${args[i]}`);
50
+ if (options.has(key)) throw new Error(`Option --${key} was supplied twice`);
51
+ if (flags.has(key)) options.set(key, true);
52
+ else {
53
+ const value = args[++i];
54
+ if (!value || value.startsWith('--')) throw new Error(`Option --${key} requires a value`);
55
+ options.set(key, value);
56
+ }
57
+ }
58
+ if (has('help')) command = 'help';
59
+ root = path.resolve(option('root', process.cwd()));
60
+ }
61
+
62
+ async function skillDestinations(agent) {
63
+ if (!['codex', 'claude', 'all'].includes(agent))
64
+ throw new Error('--agent must be codex, claude or all');
65
+ const directories =
66
+ agent === 'all'
67
+ ? ['.agents/skills', '.claude/skills']
68
+ : [agent === 'claude' ? '.claude/skills' : '.agents/skills'];
69
+ const names = await readdir(path.join(packageRoot, 'skills'));
70
+ const destinations = directories.flatMap((dir) =>
71
+ names.map((name) => ({ name, relative: path.join(dir, name) })),
72
+ );
73
+ for (const { relative } of destinations) {
74
+ const file = await writePath(root, relative);
75
+ try {
76
+ await lstat(file);
77
+ throw new Error(`Refusing to overwrite ${relative}`);
78
+ } catch (error) {
79
+ if (error.code !== 'ENOENT') throw error;
80
+ }
81
+ }
82
+ return destinations;
83
+ }
84
+
85
+ async function installSkills(agent = 'codex') {
86
+ for (const { name, relative } of await skillDestinations(agent)) {
87
+ await cp(path.join(packageRoot, 'skills', name), await writePath(root, relative), {
88
+ recursive: true,
89
+ force: false,
90
+ errorOnExist: true,
91
+ });
92
+ }
93
+ console.log(`Installed MHProto skills for ${agent}`);
94
+ }
95
+
96
+ async function init() {
97
+ await mkdir(root, { recursive: true });
98
+ if (!has('no-skills')) await skillDestinations(option('agent', 'codex'));
99
+ const files = {
100
+ 'mhproto.yaml':
101
+ 'version: 1\nname: My app\nsystem: mhproto/system.md\ncapabilities:\n - id: example\n title: Example capability\n spec: mhproto/capabilities/example/spec.md\n interface: mhproto/interfaces/openapi.yaml\n examples: mhproto/capabilities/example/examples.yaml\n checks: mhproto/capabilities/example/checks.yaml\n sources: []\n',
102
+ 'mhproto/system.md':
103
+ '# System map\n\nReplace this with the app’s capabilities, owners and dependencies.\n',
104
+ 'mhproto/capabilities/example/spec.md':
105
+ '# Example capability\n\nStatus: draft — replace this scaffold before implementing.\n\n## Purpose\nDescribe the capability and its boundaries.\n\n## Rules\n- **EXAMPLE-B-1** Reading status returns the current service status.\n\n## States and permissions\nDocument transitions, permissions, failures and recovery.\n',
106
+ 'mhproto/interfaces/openapi.yaml':
107
+ 'openapi: 3.1.0\ninfo:\n title: Example API\n version: "1"\npaths:\n /status:\n get:\n operationId: getStatus\n x-mhproto-rules: [EXAMPLE-B-1]\n responses:\n "200":\n description: Current status\n content:\n application/json:\n schema:\n type: object\n required: [status]\n additionalProperties: false\n properties:\n status: { type: string, enum: [ready] }\n example: { status: ready }\n',
108
+ 'mhproto/capabilities/example/examples.yaml':
109
+ 'examples:\n - id: EXAMPLE-E-1\n title: Read service status\n rules: [EXAMPLE-B-1]\n operations: [getStatus]\n given: The service is ready.\n when: A client reads its status.\n then: The response says ready.\n',
110
+ 'mhproto/capabilities/example/checks.yaml':
111
+ '# Add argv commands and rule/example references. No tests are assumed to exist.\nchecks: []\n',
112
+ };
113
+ // Preflight all destinations; never overwrite an existing contract.
114
+ for (const file of Object.keys(files)) {
115
+ try {
116
+ await lstat(await writePath(root, file));
117
+ throw new Error(`Refusing to overwrite ${file}`);
118
+ } catch (e) {
119
+ if (e.code !== 'ENOENT') throw e;
120
+ }
121
+ }
122
+ for (const [file, contents] of Object.entries(files))
123
+ await writeFile(await writePath(root, file), contents, { flag: 'wx' });
124
+ if (!has('no-skills')) await installSkills(option('agent', 'codex'));
125
+ console.log(
126
+ 'Initialised MHProto. Replace the example capability; run mhproto check and mhproto view.',
127
+ );
128
+ }
129
+
130
+ try {
131
+ parseArguments();
132
+ if (command === 'init') await init();
133
+ else if (command === 'skills') await installSkills(option('agent', 'codex'));
134
+ else if (command === 'check') {
135
+ const project = await loadProject(root),
136
+ issues = await validateProject(project);
137
+ if (has('json')) console.log(JSON.stringify({ name: project.name, issues }, null, 2));
138
+ else {
139
+ console.log(
140
+ `${project.name}: ${project.capabilities.length} capability, ${project.capabilities.reduce((n, c) => n + c.rules.length, 0)} rules, ${project.capabilities.reduce((n, c) => n + c.operations.length, 0)} operations`,
141
+ );
142
+ for (const issue of issues)
143
+ console.log(`${issue.level.toUpperCase()} [${issue.capability}] ${issue.message}`);
144
+ console.log(
145
+ `${issues.filter((i) => i.level === 'error').length} errors, ${issues.filter((i) => i.level === 'warning').length} warnings`,
146
+ );
147
+ }
148
+ if (issues.some((i) => i.level === 'error')) process.exitCode = 1;
149
+ } else if (command === 'context') {
150
+ const options = Object.fromEntries(
151
+ ['capability', 'operation', 'rule', 'schema', 'example', 'check', 'visual', 'section'].map(
152
+ (k) => [k, option(k)],
153
+ ),
154
+ );
155
+ const output = encodeContext(
156
+ contextPacket(await loadProject(root), options),
157
+ Number(option('max-chars', '12000')),
158
+ );
159
+ console.log(output);
160
+ if (has('stats'))
161
+ console.error(
162
+ JSON.stringify({
163
+ characters: output.length,
164
+ bytes: Buffer.byteLength(output),
165
+ note: 'Exact text sizes; model token counts vary.',
166
+ }),
167
+ );
168
+ } else if (command === 'inspect') console.log(JSON.stringify(await model(root), null, 2));
169
+ else if (command === 'verify') {
170
+ const project = await loadProject(root),
171
+ issues = await validateProject(project);
172
+ if (issues.some((i) => i.level === 'error'))
173
+ throw new Error('Contract validation failed; run mhproto check');
174
+ const selected = option('capability');
175
+ const caps = project.capabilities.filter((c) => !selected || c.id === selected);
176
+ if (!caps.length) throw new Error(`Unknown capability: ${selected}`);
177
+ for (const cap of caps) {
178
+ if (!cap.checks.length) {
179
+ console.log(`${cap.id}: no checks configured; evidence remains unchecked`);
180
+ continue;
181
+ }
182
+ console.log(`Running ${cap.checks.length} checks for ${cap.id}`);
183
+ const result = await verifyCapability(project, cap, (r) => {
184
+ console.log(`${r.status.toUpperCase()} ${r.id} (${r.durationMs}ms)`);
185
+ if (r.status === 'failing')
186
+ console.log(
187
+ [
188
+ r.error,
189
+ r.stderr.slice(-1500),
190
+ ...r.missing.map((t) => 'Missing test: ' + t),
191
+ ...r.skipped.map((t) => 'Skipped test: ' + t),
192
+ ...r.todo.map((t) => 'TODO test: ' + t),
193
+ ]
194
+ .filter(Boolean)
195
+ .join('\n'),
196
+ );
197
+ });
198
+ if (result.results.some((r) => r.status === 'failing') || result.changedDuringRun)
199
+ process.exitCode = 1;
200
+ }
201
+ } else if (command === 'view') {
202
+ await loadProject(root);
203
+ const port = Number(option('port', '4317'));
204
+ if (!Number.isInteger(port) || port < 0 || port > 65535) throw new Error('Invalid port');
205
+ const server = await serve(root, port, { against: option('against') });
206
+ console.log(`MHProto viewer: http://127.0.0.1:${server.address().port}`);
207
+ console.log(
208
+ 'Local browser view. Visual attachments save to mhproto/visuals.yaml; source edits refresh automatically.',
209
+ );
210
+ for (const signal of ['SIGINT', 'SIGTERM'])
211
+ process.on(signal, () => server.close(() => process.exit(0)));
212
+ } else if (command === 'snapshot') {
213
+ const destination = path.resolve(root, option('out', '.mhproto/baseline.json'));
214
+ const relative = path.relative(root, destination);
215
+ const data =
216
+ JSON.stringify(
217
+ contractSnapshot(await model(root), { label: option('label', 'Iteration baseline') }),
218
+ null,
219
+ 2,
220
+ ) + '\n';
221
+ if (!relative.startsWith('..' + path.sep) && !path.isAbsolute(relative))
222
+ await atomicWrite(root, relative, data);
223
+ else {
224
+ await mkdir(path.dirname(destination), { recursive: true });
225
+ await atomicWrite(path.dirname(destination), path.basename(destination), data);
226
+ }
227
+ console.log(`Saved baseline: ${destination}`);
228
+ } else if (command === 'diff') {
229
+ const before = JSON.parse(
230
+ await readFile(path.resolve(root, option('against', '.mhproto/baseline.json')), 'utf8'),
231
+ );
232
+ console.log(JSON.stringify(compareModels(before, await model(root)), null, 2));
233
+ } else if (command === 'build') {
234
+ const destination = path.resolve(root, option('out', '.mhproto/viewer'));
235
+ await exportViewer(root, destination, { against: option('against') });
236
+ console.log(
237
+ `Exported viewer: ${destination}. Open viewer.html directly or serve this folder over HTTP.`,
238
+ );
239
+ } else if (command === 'help' || has('help')) {
240
+ const { version } = JSON.parse(await readFile(path.join(packageRoot, 'package.json'), 'utf8'));
241
+ console.log(
242
+ `MHProto ${version}\n\nCommands: init, skills, check, context, inspect, verify, view, snapshot, diff, build\n\nOptions: --root PATH, --json (check), --capability ID (verify/context), --port PORT (view),\n --operation ID|--rule ID|--schema NAME|--example ID|--check ID|--visual ID (context),\n --section request,response,behaviour,errors,examples,checks,visuals,sources (context),\n --max-chars N, --stats (context),\n --agent codex|claude|all (init/skills), --no-skills (init),\n --out PATH (snapshot/build), --label TEXT (snapshot), --against PATH (diff/view/build)`,
243
+ );
244
+ } else throw new Error(`Unknown command: ${command}`);
245
+ } catch (error) {
246
+ console.error(`MHProto: ${error.message}`);
247
+ process.exitCode = 1;
248
+ }
@@ -0,0 +1,43 @@
1
+ # Context design
2
+
3
+ Keep MHProto useful to people in the viewer, and small for agents at its retrieval boundary. Collapsing browser content alone does not reduce tokens: an agent must request a smaller packet.
4
+
5
+ ## Established patterns
6
+
7
+ [Anthropic: Effective context engineering for AI agents](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents) recommends high-signal context, just-in-time retrieval through references, and progressive disclosure. Applied here: a feature index first, then selected endpoint, rule, schema or example detail. The contract remains in authoritative files rather than a giant always-loaded prompt.
8
+
9
+ [Anthropic: Code execution with MCP](https://www.anthropic.com/engineering/code-execution-with-mcp) describes discovering interfaces on demand and filtering/transforming results in code before passing them to a model. Applied here: deterministic CLI packets, deduplicated error schemas, scenario/check summaries and image metadata. No model call is needed to assemble them.
10
+
11
+ [OpenAI: Harness engineering](https://openai.com/index/harness-engineering/) describes short agent instructions as a map into structured repository documentation, with progressive disclosure and mechanical validation. Applied here: concise installable skills, explicit deferred references, linked checks and revision-bound evidence.
12
+
13
+ These are architecture patterns. Provider examples are not measurements of MHProto or a guarantee of our savings.
14
+
15
+ ## Retrieval flow
16
+
17
+ 1. `mhproto context` identifies the feature and endpoint.
18
+ 2. `mhproto context --capability daily --operation tap` supplies the endpoint contract.
19
+ 3. Fetch needed `--schema`, `--rule`, `--example` or `--check` detail. Read deferred groups before changing their behaviour.
20
+ 4. Fetch `--visual ID` metadata and open its image/design only if it helps the task.
21
+ 5. Inspect authoritative implementation/docs and run required checks for the change.
22
+
23
+ Optional `--section` narrows a packet. The default 12,000-character output budget raises an actionable error rather than dropping trailing rules. `--stats` writes character and byte counts to stderr. No token count is assumed.
24
+
25
+ Root structures preserve constraints, required fields, nullability and refs. Nested schemas are retrieved by name; grouped rules retain their IDs and an explicit instruction to fetch them. Exact rule text, semantic preconditions and error codes remain intact. Larger concrete payload examples are available through --example. Check summaries keep stale/failing/unchecked states; verbose runner logs do not enter the endpoint packet. Images are stored separately, never as base64 inside the project model or context output.
26
+
27
+ ## Pilot measurement
28
+
29
+ Measured against the same fresh Impostor daily project on 2026-10-02. Compact JSON, excluding its trailing newline. See context-measurements.json.
30
+
31
+ | Read | Characters | Bytes |
32
+ | --------------------------------- | ---------: | ------: |
33
+ | Complete normalized project model | 129,642 | 129,766 |
34
+ | Feature/operation index | 980 | 980 |
35
+ | Tap endpoint packet | 8,501 | 8,505 |
36
+ | Tap request/response only | 1,914 | 1,914 |
37
+ | Ask endpoint packet | 9,279 | 9,281 |
38
+
39
+ The tap packet is 93.44% smaller in characters than the complete model because it retrieves a different, relevant scope. This is not equivalent-content compression or a measured billing reduction. Model tokenization, follow-up reads, implementation files, retries and any opened images affect total consumption. Fetching every reference may approach or exceed a full read. Avoid summarizing away constraints just to improve this metric.
40
+
41
+ ## Current boundary
42
+
43
+ This version supplies an on-demand CLI boundary and retrieval instructions. It does not intercept every agent tool call, enforce a model session token budget or implement provider prompt caching. Contract text still changes through repository files. Image interpretation remains an explicit agent action; no image analysis service runs automatically.
@@ -0,0 +1,28 @@
1
+ {
2
+ "fullModel": {
3
+ "characters": 129642,
4
+ "bytes": 129766
5
+ },
6
+ "packets": {
7
+ "index": {
8
+ "characters": 980,
9
+ "bytes": 980,
10
+ "reductionPercent": 99.24
11
+ },
12
+ "tap": {
13
+ "characters": 8501,
14
+ "bytes": 8505,
15
+ "reductionPercent": 93.44
16
+ },
17
+ "tapInterface": {
18
+ "characters": 1914,
19
+ "bytes": 1914,
20
+ "reductionPercent": 98.52
21
+ },
22
+ "ask": {
23
+ "characters": 9279,
24
+ "bytes": 9281,
25
+ "reductionPercent": 92.84
26
+ }
27
+ }
28
+ }
package/doc/guide.md ADDED
@@ -0,0 +1,138 @@
1
+ # MHProto guide
2
+
3
+ Detailed usage and reference documentation for the [project website](https://mhproto.dev/docs/).
4
+
5
+ ## Start locally
6
+
7
+ This is a development preview, not an npm registry release. Node 22+ is required.
8
+ The hosted CI matrix covers Node 22/24 on Linux and macOS and [has passed](https://github.com/rbsx/mhproto/actions/runs/37059758163). Windows is unverified.
9
+
10
+ From a checkout of this repository:
11
+
12
+ ```sh
13
+ npm ci
14
+ npm run check
15
+ ```
16
+
17
+ In your application, install the checkout and create a draft contract:
18
+
19
+ ```sh
20
+ npm install --save-dev /path/to/mhproto
21
+ npx mhproto init --agent codex
22
+ npx mhproto check
23
+ npx mhproto snapshot
24
+ npx mhproto view
25
+ ```
26
+
27
+ Replace the example with your feature. `init` refuses to overwrite existing
28
+ contracts or skills. `skills --agent codex|claude|all` installs repository-local
29
+ skills in `.agents/skills` or `.claude/skills`; global agent settings stay unchanged.
30
+ The isolated Impostor pilot is a development fixture, not a package prerequisite.
31
+
32
+ ## Commands
33
+
34
+ | Command | Result |
35
+ | --------------- | ------------------------------------------------------------------------ |
36
+ | init | Scaffold a draft capability and install skills |
37
+ | skills | Install the bundled agent skills separately |
38
+ | check | Validate references, schemas, payload examples and check bindings |
39
+ | context | Retrieve a compact index or scoped endpoint/rule/schema packet |
40
+ | inspect | Emit the normalised project model as JSON |
41
+ | verify | Run linked argv commands, store revision-bound evidence |
42
+ | view | Serve a local viewer; save visual attachments and refresh source changes |
43
+ | snapshot / diff | Save a baseline and inspect contract changes |
44
+ | build | Export viewer assets, model.json and a self-contained viewer.html |
45
+
46
+ Use `--root PATH` for another app. See `mhproto help` for command options and `skills/mhproto-specify/references/format.md` for the data format.
47
+
48
+ ## Viewer
49
+
50
+ The sidebar lists the project and its features. A feature opens one page: title, product/logic description, relative app URL, visible API request/response signatures, play-state diagrams and a Checks section. Search stays at the top; Sources is a secondary link in the sidebar.
51
+
52
+ Each endpoint opens its own page with a stable `#/features/:feature/api/:operation` URL. Behaviour, errors, examples and checks are attached to that endpoint. Named types are clickable inside their signatures. Each type opens a shareable definition page with links to feature overviews, every endpoint using it and referencing type pages. Nested objects still expand in place; there is no separate type catalogue or modal navigation. The Copy page link action preserves direct navigation to the endpoint.
53
+
54
+ The visual system uses white backgrounds, near-black text, neutral dividers and blue/purple links. HTTP method badges retain restrained colour coding. See `doc/viewer-design.md` for the flows and acceptance criteria.
55
+
56
+ Optional capability `url` identifies the app route. `presentation.operationOrder` orders endpoints by use. `presentation.operations[operationId]` accepts `description`, a concise `behaviour` summary, additional `rules`, optional `ruleGroups` (`title`, `rules`) and `diagrams` (`title`, Mermaid `source`). `ruleTitles` supplies concise labels in search and check gaps. These are navigation and context; full source clauses remain authoritative. Operation and rule references are validated.
57
+
58
+ Mermaid fences in the behaviour/system document and endpoint diagrams render as monochrome SVG. The bundled Mermaid runtime also works offline in the exported HTML. Diagram source stays available on demand; invalid diagrams show an error without blocking the rest of the page. The CLI validates diagram metadata, not Mermaid syntax; renderer tests and preview review establish diagram validity.
59
+
60
+ `mhproto build --out ./mhproto-preview` creates a portable `viewer.html` that can be opened without a server. In the live viewer, attachments save to `mhproto/visuals.yaml` and `mhproto/assets`. In an exported snapshot, attachments stay in that preview; **Save preview** downloads a self-contained copy with them. Edit the source files to change normative contract text.
61
+
62
+ Portable exports include check status, timing and observed test names, but omit captured stdout/stderr, failure messages, executed command records and the generated project-root path. Authored contracts, configured check commands/environment values, examples and attachments are retained. Review those files before sharing; export is not a secret scanner.
63
+
64
+ ## Verification semantics
65
+
66
+ Unchecked, passing, failing and stale are distinct. Node checks require exact expected test names and structured results; missing/skipped/TODO tests fail. Evidence includes commands, exit status, timings, observed tests and a SHA-256 digest of the project configuration, system document, capability files, explicitly tracked sources and declared check files. Failures are recorded. Checks execute sequentially, with a timeout. They inherit the environment and execute the configured commands without a shell; they are not sandboxed. Run verification only for check commands you trust. Structured Node reporter output is bounded to 1 MB and fails closed if malformed or oversized.
67
+
68
+ MHProto validates payload schemas and examples and its own cross-references; this is a bounded contract validator, not a complete OpenAPI standards validator. V0 supports OpenAPI 3.1 with local refs. Interfaces can originate in Zod, Protobuf tooling or handwritten OpenAPI, but only OpenAPI is consumed in this version. Optional type generation remains with the app’s chosen generator.
69
+
70
+ A linked passing test is evidence for a rule, not proof of all its cases. Prompt-text tests do not establish live AI behaviour. Runtime permissions, races and retry behaviour require meaningful app tests. No paid evaluation is invoked by the pilot.
71
+
72
+ Browser editing of normative contract text, type generation, remote schema refs and hosted collaboration are deferred.
73
+
74
+ ## Develop
75
+
76
+ Node 22+. `npm ci`, `npm run check`, `npm run format`. See CONTRIBUTING.md and doc/release-review.md. The preview archive is prepared with `npm run release:prepare`; registry publication is a separate step. The CLI and viewer run directly from source; no build step is needed. Dependencies: yaml, Ajv, ajv-formats. The viewer uses platform DOM APIs and escapes source content.
77
+
78
+ ## Visual references
79
+
80
+ Attach a screenshot, design image/PDF or HTTPS design link using the single `+` after a feature/endpoint description, scenario, rule or check text, or alongside a Request/Response header. The action appears on hover or keyboard focus and opens an inline form. Schema signatures and nested object fields only render types and expansion; they do not create attachment controls. Existing field/schema references appear beneath the matching request/response header. Supported files: PNG, JPEG, WebP, GIF and PDF, up to 8 MB. Design links open their source rather than loading an embedded design app. The metadata format is in the bundled format reference.
81
+
82
+ Collapsed object fields show a pale-yellow `{...}`; optional markers, nullability, arrays and constraints remain visible. Expand in place to inspect their fields.
83
+
84
+ ## Compact agent context
85
+
86
+ ```sh
87
+ mhproto context
88
+ mhproto context --capability daily --operation tap --stats
89
+ mhproto context --capability daily --operation tap --section request,response
90
+ mhproto context --capability daily --rule DAILY-PLAY-4
91
+ mhproto context --capability daily --schema DailyPlayState
92
+ ```
93
+
94
+ Packets are assembled in code, not summarised by a model. Rule text and failure semantics remain exact. Nested types and grouped rules are explicit references, payload examples are fetched separately, and check summaries retain freshness. Image bytes, Mermaid's runtime, repeated OpenAPI examples and raw execution logs never enter these packets. The default 12,000-character budget fails visibly if exceeded; it never silently truncates rules. This reduces input context size; actual tokens and billed cost depend on the model and subsequent reads. See [context-design.md](context-design.md) for research, limitations and measurements.
95
+
96
+ ## Linked type entities
97
+
98
+ Signatures label declared component types by their existing OpenAPI names: `DailyTodayResponse { ... }`, `case: DailyCaseView {...} | null`, and `play: DailyPlayState {...} | null`. Type names link to `#/features/:feature/types/:type-id`. Fields remain inline and expandable. Following the type link opens its page; selecting the yellow placeholder expands the object.
99
+
100
+ The type page shows the definition and a Used in section containing feature overview and endpoint links. Backlinks include nested/transitive uses, all declared response statuses, and direct references from other type pages. A type name can also be found through project search. Nothing is added to the sidebar or to object attachment controls.
101
+
102
+ Unnamed query/path/header/cookie structures, inline bodies/responses and nested object items receive deterministic viewer labels, such as `GetTodayQuery` and `DailyRoundAnswersItem`. These pages explain where the structure comes from; labels do not create new application types or change the contract. Declared names take priority, and generated name collisions remain separate. Types shared through the same interface file link across features; equally named types from different interfaces stay distinct. Cycles are bounded.
103
+
104
+ The index is built once per loaded model in the viewer and cached until that model changes. It is not serialized into the project model, snapshots or scoped agent packets, and does not duplicate the authoritative schemas. Type pages remain compatible with the standalone export.
105
+
106
+ ## Review an iteration
107
+
108
+ Open **Changes** in the sidebar. Choose an earlier snapshot JSON or exported MHProto preview HTML, or **Use current spec as baseline** before editing. Changes lists added, changed and removed items by feature. Open an item for its changed fields with Before/Now values, then follow **Open current** to see it in context. Comparison links retain `?compare=1`; **Hide highlights** returns to normal reading. Changed type names and added/changed/removed fields are marked inline. Removed definitions remain reviewable on their change page.
109
+
110
+ ```sh
111
+ mhproto snapshot --label "Before case history" --out .mhproto/iterations/before-history.json
112
+ # Edit the source contract, then:
113
+ mhproto view --against .mhproto/iterations/before-history.json
114
+ mhproto build --against .mhproto/iterations/before-history.json --out ./review
115
+ mhproto diff --against .mhproto/iterations/before-history.json
116
+ ```
117
+
118
+ Without `--against`, the viewer uses `.mhproto/baseline.json`. The live **Use current spec as baseline** action replaces that local baseline with the current contract. When using `--against`, this action is disabled by the server so an explicit saved iteration is retained. **Download current snapshot** exports a named JSON baseline. In a standalone preview, save the amended preview to retain its selected/new baseline. Imported files stay in the viewer; importing an HTML preview reads its model without executing its scripts. Shared URLs require the same current spec and baseline to produce the same comparison; the exported HTML carries both.
119
+
120
+ The comparison is one pure module shared by CLI, server and browser. It covers feature/system text, API operations and global settings, named schemas, attached behaviour/presentation, examples, check definitions and visual metadata. Object key order and unordered sets (required fields, enums and rule references) do not count as changes. Runtime paths, digests, evidence timestamps, test output and renderer code are excluded. Snapshot data is detached from current data and carries no execution logs. This is a spec delta, not an automatic breaking-change assessment or a code diff. Visual asset bytes are not compared when their metadata/path stays unchanged. Agent context packets remain unchanged.
121
+
122
+ ## Release status and boundaries
123
+
124
+ The `0.8.0-preview.0` release candidate is prepared for npm's `next` channel;
125
+ publication is pending. Its renderer is rebuilt with patched dependencies and
126
+ verified notices. See [the release review](release-review.md) for evidence and
127
+ platform limits, and [publishing steps](publishing.md) for the final registry step.
128
+
129
+ The validator is intentionally bounded: JSON Schema 2020-12 payloads, local JSON
130
+ pointer references and linked metadata. It does not implement the whole OpenAPI
131
+ standard. The viewer primarily renders application/json structures. Agent context
132
+ is scoped retrieval, not equivalent-content compression or guaranteed token savings.
133
+ Visual metadata writes are serialized within one process; concurrent writers
134
+ from separate viewer processes are not coordinated. Revision-bound evidence
135
+ tracks files, not every external service or environmental change.
136
+
137
+ MHProto source is MIT-licensed. See LICENSE and THIRD_PARTY_NOTICES.md for the
138
+ separately licensed viewer dependency.