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.
- package/CONTRIBUTING.md +62 -0
- package/LICENSE +21 -0
- package/README.md +53 -0
- package/THIRD_PARTY_NOTICES.md +40 -0
- package/bin/mhproto.mjs +248 -0
- package/doc/context-design.md +43 -0
- package/doc/context-measurements.json +28 -0
- package/doc/guide.md +138 -0
- package/doc/publishing.md +93 -0
- package/doc/release-notes.md +23 -0
- package/doc/release-review-2026-10-02.md +127 -0
- package/doc/release-review.md +68 -0
- package/doc/viewer-design.md +80 -0
- package/package.json +69 -0
- package/skills/mhproto-discover/SKILL.md +14 -0
- package/skills/mhproto-implement/SKILL.md +14 -0
- package/skills/mhproto-reconcile/SKILL.md +14 -0
- package/skills/mhproto-specify/SKILL.md +16 -0
- package/skills/mhproto-specify/references/format.md +20 -0
- package/skills/mhproto-verify/SKILL.md +14 -0
- package/src/config.mjs +202 -0
- package/src/context.mjs +228 -0
- package/src/core.mjs +471 -0
- package/src/node-reporter.mjs +15 -0
- package/src/paths.mjs +51 -0
- package/src/server.mjs +290 -0
- package/src/verify.mjs +149 -0
- package/src/visuals.mjs +189 -0
- package/viewer/app.js +1463 -0
- package/viewer/diff.js +245 -0
- package/viewer/index.html +51 -0
- package/viewer/style.css +1003 -0
- package/viewer/vendor/LICENSE +21 -0
- package/viewer/vendor/NOTICE.txt +3372 -0
- package/viewer/vendor/README.md +75 -0
- package/viewer/vendor/build-evidence.json +2775 -0
- package/viewer/vendor/bundled-audit.json +88 -0
- package/viewer/vendor/bundled-packages.json +84 -0
- package/viewer/vendor/embedded-notices.txt +33 -0
- package/viewer/vendor/license-inventory.json +1456 -0
- package/viewer/vendor/licenses/braintree__sanitize-url-7.1.2.txt +21 -0
- package/viewer/vendor/licenses/chevrotain-13.2.0.txt +202 -0
- package/viewer/vendor/licenses/chevrotain-allstar-0.5.0.txt +16 -0
- package/viewer/vendor/licenses/chevrotain__cst-dts-gen-13.2.0.txt +202 -0
- package/viewer/vendor/licenses/chevrotain__gast-13.2.0.txt +202 -0
- package/viewer/vendor/licenses/chevrotain__regexp-to-ast-13.2.0.txt +202 -0
- package/viewer/vendor/licenses/chevrotain__utils-13.2.0.txt +202 -0
- package/viewer/vendor/licenses/cose-base-1.0.3.txt +21 -0
- package/viewer/vendor/licenses/cose-base-2.2.0.txt +21 -0
- package/viewer/vendor/licenses/cytoscape-3.34.3.txt +19 -0
- package/viewer/vendor/licenses/cytoscape-cose-bilkent-4.1.0.txt +21 -0
- package/viewer/vendor/licenses/cytoscape-fcose-2.2.0.txt +19 -0
- package/viewer/vendor/licenses/d3-7.9.0.txt +13 -0
- package/viewer/vendor/licenses/d3-array-2.12.1.txt +27 -0
- package/viewer/vendor/licenses/d3-array-3.2.4.txt +13 -0
- package/viewer/vendor/licenses/d3-axis-3.0.0.txt +13 -0
- package/viewer/vendor/licenses/d3-brush-3.0.0.txt +13 -0
- package/viewer/vendor/licenses/d3-chord-3.0.1.txt +13 -0
- package/viewer/vendor/licenses/d3-color-3.1.0.txt +13 -0
- package/viewer/vendor/licenses/d3-contour-4.0.2.txt +13 -0
- package/viewer/vendor/licenses/d3-delaunay-6.0.4.txt +14 -0
- package/viewer/vendor/licenses/d3-dispatch-3.0.1.txt +13 -0
- package/viewer/vendor/licenses/d3-drag-3.0.0.txt +13 -0
- package/viewer/vendor/licenses/d3-dsv-3.0.1.txt +13 -0
- package/viewer/vendor/licenses/d3-ease-3.0.1.txt +28 -0
- package/viewer/vendor/licenses/d3-fetch-3.0.1.txt +13 -0
- package/viewer/vendor/licenses/d3-force-3.0.0.txt +13 -0
- package/viewer/vendor/licenses/d3-format-3.1.2.txt +13 -0
- package/viewer/vendor/licenses/d3-geo-3.1.1.txt +34 -0
- package/viewer/vendor/licenses/d3-hierarchy-3.1.2.txt +13 -0
- package/viewer/vendor/licenses/d3-interpolate-3.0.1.txt +13 -0
- package/viewer/vendor/licenses/d3-path-1.0.9.txt +27 -0
- package/viewer/vendor/licenses/d3-path-3.1.0.txt +13 -0
- package/viewer/vendor/licenses/d3-polygon-3.0.1.txt +13 -0
- package/viewer/vendor/licenses/d3-quadtree-3.0.1.txt +13 -0
- package/viewer/vendor/licenses/d3-random-3.0.1.txt +13 -0
- package/viewer/vendor/licenses/d3-sankey-0.12.3.txt +27 -0
- package/viewer/vendor/licenses/d3-scale-4.0.2.txt +13 -0
- package/viewer/vendor/licenses/d3-scale-chromatic-3.1.0.txt +28 -0
- package/viewer/vendor/licenses/d3-selection-3.0.0.txt +13 -0
- package/viewer/vendor/licenses/d3-shape-1.3.7.txt +27 -0
- package/viewer/vendor/licenses/d3-shape-3.2.0.txt +13 -0
- package/viewer/vendor/licenses/d3-time-3.1.0.txt +13 -0
- package/viewer/vendor/licenses/d3-time-format-4.1.0.txt +13 -0
- package/viewer/vendor/licenses/d3-timer-3.0.1.txt +13 -0
- package/viewer/vendor/licenses/d3-transition-3.0.1.txt +13 -0
- package/viewer/vendor/licenses/d3-zoom-3.0.0.txt +13 -0
- package/viewer/vendor/licenses/dagre-d3-es-7.0.14.txt +23 -0
- package/viewer/vendor/licenses/dayjs-1.11.23.txt +21 -0
- package/viewer/vendor/licenses/delaunator-5.1.0.txt +15 -0
- package/viewer/vendor/licenses/dompurify-3.4.16.txt +202 -0
- package/viewer/vendor/licenses/elk-source-notice.txt +11 -0
- package/viewer/vendor/licenses/elkjs-0.9.3.txt +264 -0
- package/viewer/vendor/licenses/embedded-and-node-notices.txt +45 -0
- package/viewer/vendor/licenses/es-toolkit-1.52.0-1.txt +39 -0
- package/viewer/vendor/licenses/es-toolkit-1.52.0.txt +21 -0
- package/viewer/vendor/licenses/fastdom-1.0.12.txt +221 -0
- package/viewer/vendor/licenses/iconify__utils-3.1.7.txt +21 -0
- package/viewer/vendor/licenses/internmap-1.0.1.txt +13 -0
- package/viewer/vendor/licenses/internmap-2.0.3.txt +13 -0
- package/viewer/vendor/licenses/js-yaml-4.3.2.txt +21 -0
- package/viewer/vendor/licenses/katex-0.16.47.txt +21 -0
- package/viewer/vendor/licenses/khroma-2.1.0.txt +21 -0
- package/viewer/vendor/licenses/langium-4.4.0.txt +16 -0
- package/viewer/vendor/licenses/layout-base-1.0.2.txt +21 -0
- package/viewer/vendor/licenses/layout-base-2.0.1.txt +21 -0
- package/viewer/vendor/licenses/lodash-es-4.18.1.txt +47 -0
- package/viewer/vendor/licenses/marked-16.4.2.txt +44 -0
- package/viewer/vendor/licenses/mermaid-12.1.0.txt +21 -0
- package/viewer/vendor/licenses/mermaid-js__parser-2.0.1.txt +21 -0
- package/viewer/vendor/licenses/path-browserify-1.0.1.txt +20 -0
- package/viewer/vendor/licenses/robust-predicates-3.0.3.txt +24 -0
- package/viewer/vendor/licenses/roughjs-4.6.6.txt +21 -0
- package/viewer/vendor/licenses/stylis-4.4.0.txt +21 -0
- package/viewer/vendor/licenses/ts-dedent-2.3.0.txt +21 -0
- package/viewer/vendor/licenses/upsetjs__venn.js-2.0.0.txt +22 -0
- package/viewer/vendor/licenses/uuid-14.0.2.txt +9 -0
- package/viewer/vendor/licenses/vscode-jsonrpc-9.0.3.txt +11 -0
- package/viewer/vendor/licenses/vscode-languageserver-protocol-3.18.4.txt +11 -0
- package/viewer/vendor/licenses/vscode-languageserver-textdocument-1.0.15.txt +11 -0
- package/viewer/vendor/licenses/vscode-languageserver-types-3.18.4.txt +11 -0
- package/viewer/vendor/licenses/vscode-uri-3.1.0.txt +9 -0
- package/viewer/vendor/manifest.json +21 -0
- package/viewer/vendor/mermaid.min.js +7729 -0
package/CONTRIBUTING.md
ADDED
|
@@ -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.
|
package/bin/mhproto.mjs
ADDED
|
@@ -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.
|