agentic-mermaid 0.1.2 → 0.2.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 (52) hide show
  1. package/AGENT_NATIVE.md +671 -0
  2. package/CHANGELOG.md +19 -0
  3. package/Instructions_for_agents.md +89 -0
  4. package/README.md +8 -8
  5. package/assets/hero.png +0 -0
  6. package/dist/agent-core.d.ts +2 -2
  7. package/dist/agent-core.js +2 -2
  8. package/dist/agent.d.ts +2 -2
  9. package/dist/agent.js +4 -4
  10. package/dist/agentic-mermaid-mcp.js +5 -5
  11. package/dist/am.js +8 -15
  12. package/dist/{chunk-QKDLMOJJ.js → chunk-2P5FKUQC.js} +7 -9
  13. package/dist/{chunk-WN3YDOBG.js → chunk-2S3VSS6I.js} +4 -4
  14. package/dist/{chunk-CDPKJ2BQ.js → chunk-2SILJDW2.js} +2 -2
  15. package/dist/{chunk-ZYMMKQ3I.js → chunk-BJYMBT4I.js} +299 -973
  16. package/dist/{chunk-WI35L7IR.js → chunk-FDM43XU7.js} +2 -2
  17. package/dist/{chunk-4QECACIA.js → chunk-MYPDVZCO.js} +19 -19
  18. package/dist/{index-D54dqSdC.d.ts → index-DWPa2MJs.d.ts} +7 -4
  19. package/dist/index.d.ts +1 -1
  20. package/dist/index.js +1 -1
  21. package/dist/mcp-cli-5J47WEY3.js +17 -0
  22. package/docs/README.md +34 -34
  23. package/docs/agent-api-cookbook.md +317 -0
  24. package/docs/agent-mutation-policy.md +104 -0
  25. package/docs/agent-workflow-examples.md +46 -0
  26. package/docs/api.md +418 -0
  27. package/docs/ascii.md +113 -0
  28. package/docs/code-mode-impact.md +214 -0
  29. package/docs/comparison.md +106 -0
  30. package/docs/computational-aesthetics-prototype-plan.md +252 -0
  31. package/docs/config.md +121 -0
  32. package/docs/custom-fonts.md +265 -0
  33. package/docs/custom-style-cookbook.md +275 -0
  34. package/docs/diagram-families.md +218 -0
  35. package/docs/features.md +154 -0
  36. package/docs/fork-differences.md +133 -0
  37. package/docs/getting-started.md +182 -0
  38. package/docs/issue-derived-test-cases.md +163 -0
  39. package/docs/mcp-code-mode-rationale.md +108 -0
  40. package/docs/mcp-http-transport.md +230 -0
  41. package/docs/mermaid-layout-complaints.md +851 -0
  42. package/docs/mutation-testing.md +285 -0
  43. package/docs/quality.md +224 -0
  44. package/docs/react.md +97 -0
  45. package/docs/style-authoring.md +336 -0
  46. package/docs/svg-semantic-contract.md +49 -0
  47. package/docs/testing-strategy.md +443 -0
  48. package/docs/theming.md +149 -0
  49. package/package.json +21 -6
  50. package/server.json +2 -2
  51. package/skills/agentic-mermaid-live-editor/SKILL.md +1 -1
  52. package/dist/mcp-cli-SBQSTJFC.js +0 -17
@@ -0,0 +1,104 @@
1
+ # Agent mutation policy: structured vs source-level
2
+
3
+ This note records why the agent surface exposes structured mutation only for modeled syntax, while preserving unmodeled syntax as opaque/source-level bodies even inside otherwise supported families.
4
+
5
+ ## Goal
6
+
7
+ The agent-native goal is not "make every diagram editable somehow." The goal is:
8
+
9
+ 1. preserve source-provided meaning;
10
+ 2. never silently drop syntax we do not model;
11
+ 3. expose typed mutation only when the parser, IR, serializer, and verifier can preserve that meaning;
12
+ 4. make unsupported structured edits explicit instead of pretending they are safe.
13
+
14
+ So the rule is:
15
+
16
+ > Structured mutation is allowed only for modeled syntax. Unknown or lossy syntax must stay source-level/opaque and round-trip through preserved source.
17
+
18
+ This policy applies to **editing existing diagrams**. For a brand-new diagram, direct Mermaid source authoring is the native path: write source, parse it, verify it, then render or return it. Mutation is a preservation tool, not a required creation ritual.
19
+
20
+ ## What "mutation exposure" means
21
+
22
+ A family has mutation exposure when public agent surfaces advertise typed structural edits for it, such as:
23
+
24
+ - library narrowers like `asFlowchart(d)` and `mutate(flow, op)`;
25
+ - CLI support through `am mutate --op ...`;
26
+ - MCP / Code Mode methods in the SDK declaration;
27
+ - `am capabilities` entries with `editPolicy: "structured-when-narrowed"`, `hasMutate: true`, and `mutationOps`;
28
+ - docs/examples telling agents which ops to call.
29
+
30
+ When a particular body does not narrow, agents are not told it can be safely edited through typed ops. The diagram may still parse, render, verify, describe, and serialize; that body just does not get structured mutation.
31
+
32
+ ## Current split
33
+
34
+ Structured mutation is exposed for every built-in renderable family when its modeled subset narrows:
35
+
36
+ - flowchart/state;
37
+ - sequence (segment-preserving: `alt`/`opt`/`loop`/`par` are typed fragments with read-back and mutation ops; Note/box/critical/activate/autonumber/title ride along verbatim as opaque-block segments. Top-level message indices stay separate from fragment-message indices. Only un-segmentable input, e.g. an unbalanced `end`, falls back to whole-body opaque);
38
+ - timeline;
39
+ - class;
40
+ - ER;
41
+ - journey (simple title/section/task bodies; BUILD-15);
42
+ - architecture (modeled groups/services/junctions/edges; BUILD-17);
43
+ - xychart (modeled title/axes/series; BUILD-16);
44
+ - pie (title/showData/slices);
45
+ - quadrant (title/axes/quadrant labels/points);
46
+ - gantt (title/sections/tasks, with calendar directives and click/comment/accessibility lines preserved as opaque segments).
47
+
48
+ Opaque/source-level bodies:
49
+
50
+ - any known-family diagram that falls back to an opaque body because it contains unmodeled syntax (e.g. architecture `{group}` boundary modifiers, accTitle/accDescr, malformed pie entries, out-of-range quadrant coordinates, or un-segmentable sequence/gantt syntax).
51
+
52
+ For source-level bodies, the safe loop is:
53
+
54
+ 1. preserve `body.source`;
55
+ 2. if an edit is explicitly requested, edit the Mermaid text intentionally;
56
+ 3. re-parse;
57
+ 4. verify;
58
+ 5. only then return or serialize.
59
+
60
+ `am mutate` should return `UNSUPPORTED_FAMILY` for those bodies.
61
+
62
+ ## Why not every syntax construct?
63
+
64
+ Because "structured mutation" is a much stronger promise than parsing enough to render.
65
+
66
+ To expose one safe mutation op for a family, we need all of this:
67
+
68
+ - a parser that fully understands the syntax subset it accepts;
69
+ - an IR that stores all semantic details needed for edits;
70
+ - stable identifiers for edited elements;
71
+ - a serializer that can re-emit equivalent Mermaid without dropping constructs;
72
+ - verification that can inspect labels/emptiness/structure for both structured and opaque paths;
73
+ - tests proving parse → serialize → parse stays stable;
74
+ - CLI/MCP/docs/capability declarations that match the implementation.
75
+
76
+ Many Mermaid families are not one grammar. They are a mix of family syntax, directives, frontmatter, comments, accessibility blocks, style/config overlays, renderer conveniences, aliases, and syntax that Mermaid accepts but normalizes internally. Some constructs are also semantically important but hard to preserve if the IR does not model them exactly.
77
+
78
+ A partial structured parser is dangerous: it can make unsupported syntax disappear. For example, if we parse only the pieces we know and serialize from that partial IR, we can drop source-provided meaning. That is worse than refusing typed mutation, because the agent would produce a plausible-looking but semantically changed diagram.
79
+
80
+ External AST libraries do not automatically solve this. A render-oriented AST may canonicalize, normalize, omit comments/directives, or fail to preserve byte/source fidelity. We specifically need an **editing AST**, not just a render AST.
81
+
82
+ ## What we have achieved
83
+
84
+ We have achieved the safety goal for the current surface:
85
+
86
+ - opaque fallback bodies round-trip through preserved source instead of lossy structured IR;
87
+ - public capabilities match the implementation: every built-in renderable family reports `structured-when-narrowed`, with source-level editing reserved for opaque fallback bodies;
88
+ - Code Mode, CLI, docs, MCP SDK declarations, and tests agree on the same public surface;
89
+ - the registry, live editor examples, eval manifest, generated `llms.txt`, and generated `am init-agent` snippets are now checked together so new family support cannot silently skip an agent-facing surface.
90
+
91
+ That is a success for semantic preservation, even though it is less convenient than pretending every Mermaid construct has a typed edit op.
92
+
93
+ ## How an opaque path graduates
94
+
95
+ An opaque fallback path can become structurally mutable only when a scoped implementation satisfies the same bar:
96
+
97
+ 1. define the syntax subset to model;
98
+ 2. reject/fall back to opaque for everything outside that subset;
99
+ 3. add typed body types and mutation ops;
100
+ 4. serialize without semantic loss;
101
+ 5. prove round-trip stability with tests and corpus examples;
102
+ 6. update CLI/MCP/capabilities/docs together.
103
+
104
+ Until then, opaque/source-level editing is the honest behavior for that body.
@@ -0,0 +1,46 @@
1
+ # Agent workflow examples
2
+
3
+ These examples are runnable and covered by tests so they do not drift from the agent/CLI/MCP contracts.
4
+
5
+ ## Create a complicated diagram through MCP and CLI
6
+
7
+ Run:
8
+
9
+ ```bash
10
+ bun run examples/mcp-vs-cli-complex-diagrams.ts
11
+ ```
12
+
13
+ What it demonstrates:
14
+
15
+ - MCP Code Mode path: `tools/call execute` runs `parseRegisteredMermaid → asFlowchart → mutate[] → verifyMermaid → serializeMermaid` in one sandboxed call.
16
+ - CLI path: `am mutate auth-flow.mmd --ops ops.json --json` applies the same mutation batch and verifies before emitting source.
17
+ - The example asserts both channels produce byte-identical Mermaid source for multiple non-trivial cases: an Auth Flow with decisions/feedback loops and an Order Domain ER diagram.
18
+
19
+ This is the intended local equivalence story: MCP Code Mode and CLI/library can create the same diagram. The local non-Code-Mode helpers remain narrow (`describe_sdk`, `render_png`, `describe`); `describe_sdk` returns one family's version-matched mutation schema on demand. The hosted `/mcp` endpoint additionally offers direct pure render/verify/describe tools plus declarative `mutate`/`build` for bounded structured edits.
20
+
21
+ ## Improve a diagram through an agent loop
22
+
23
+ Run:
24
+
25
+ ```bash
26
+ bun run examples/agent-improve-auth-flow.ts
27
+ # or choose a stable output location
28
+ bun run examples/agent-improve-auth-flow.ts --out-dir /tmp/auth-flow-improved
29
+ ```
30
+
31
+ What it demonstrates:
32
+
33
+ 1. The agent creates a draft Auth Flow via typed mutations.
34
+ 2. It assesses the draft with `verifyMermaid(..., { labelCharCap: 28 })` and layout bounds.
35
+ 3. It spots problems: long decision labels and wide LR layout.
36
+ 4. It applies a second mutation batch (`set_label`) to improve readability while preserving structure.
37
+ 5. It reassesses impact: warnings and longest-label length decrease, and bounds shrink.
38
+ 6. It writes final render artifacts. SVG/ASCII come from Code Mode; PNG is rendered by the host from the verified final source, matching the local MCP helper rationale that binary output should stay a narrow helper/host responsibility. On the hosted endpoint, direct `render_svg`/`render_ascii`/`render_png` tools cover the same artifact path without a Code Mode isolate.
39
+ - `auth-flow-before.mmd`
40
+ - `auth-flow-improved.mmd`
41
+ - `auth-flow-improved.svg`
42
+ - `auth-flow-improved.txt` (ASCII)
43
+ - `auth-flow-improved.png`
44
+ - `assessment.json`
45
+
46
+ The point is not that `verify.ok` alone proves visual quality. The example records concrete assessment signals before and after mutation, then emits human-reviewable render artifacts.
package/docs/api.md ADDED
@@ -0,0 +1,418 @@
1
+ # API reference
2
+
3
+ Agentic Mermaid exposes these library surfaces:
4
+
5
+ - `agentic-mermaid` — runtime-neutral renderer API for SVG, ASCII/Unicode,
6
+ and host-injected browser PNG output.
7
+ - `agentic-mermaid/agent` — agent-native API with
8
+ parse/narrow/mutate/verify/serialize plus SVG, native Node/Bun PNG, and ASCII
9
+ output helpers.
10
+ - `agentic-mermaid/agent/core` — the same structured-edit, SVG, and ASCII
11
+ surface without the native PNG dependency; use this entry in browser and
12
+ workerd bundles.
13
+
14
+ Capability reports, the pinned upstream manifest, and trusted Node-host
15
+ resource resolution remain repository audit/host tooling rather than published
16
+ runtime entry points.
17
+
18
+ Use `agentic-mermaid/agent` when you want one import path for agents.
19
+ Use `agentic-mermaid/agent/core` when the target runtime cannot load Node native
20
+ addons.
21
+
22
+ ### Canonical requests and comparable receipts
23
+
24
+ Every first-party renderer enters through the same immutable internal request
25
+ boundary: source wrappers/config, the Style stack, colors, font, security, and
26
+ shared options are normalized once. Receipt-bearing variants make that boundary
27
+ observable without exporting its executable implementation types or changing
28
+ the existing convenience return types:
29
+
30
+ ```ts
31
+ import {
32
+ renderMermaidASCIIWithReceipt,
33
+ renderMermaidPNGWithReceipt,
34
+ renderMermaidSVGWithReceipt,
35
+ } from 'agentic-mermaid/agent'
36
+
37
+ const options = { style: 'hand-drawn', seed: 7, embedFontImport: false }
38
+ const svg = renderMermaidSVGWithReceipt(source, options)
39
+ const png = renderMermaidPNGWithReceipt(source, options)
40
+ const text = renderMermaidASCIIWithReceipt(source, { ...options, colorMode: 'none' })
41
+
42
+ console.assert(svg.receipt.sharedRequestDigest === png.receipt.sharedRequestDigest)
43
+ console.assert(svg.receipt.appearanceDigest === text.receipt.appearanceDigest)
44
+ ```
45
+
46
+ Each `RenderRequestReceipt` contains `version`, `output`,
47
+ `sharedRequestDigest`, output-specific `requestDigest`, and
48
+ `appearanceDigest`. Its `diagnostics` array records stable request-resolution,
49
+ compatibility, applicability, projection, and output-policy decisions. In
50
+ particular, `RENDER_OPTION_NOT_APPLICABLE` makes an authored family-scoped
51
+ option that the selected family does not consume observable instead of letting
52
+ it change request identity silently. CLI JSON results and local/hosted MCP
53
+ render results expose the same receipt. Use `validateSerializableRenderOptions(value)` and
54
+ `sharedRenderOptionsJsonSchema()` for untrusted advanced option objects, or
55
+ `styleInputJsonSchema()` for a standalone convenience `style` field; unknown
56
+ fields, `null`, functions, prototype keys, and non-finite values are rejected.
57
+
58
+ ## Output helpers
59
+
60
+ ### SVG
61
+
62
+ ```ts
63
+ import { renderMermaidSVG } from 'agentic-mermaid/agent'
64
+
65
+ const svg = renderMermaidSVG(`flowchart TD
66
+ A --> B`, { security: 'strict' })
67
+ ```
68
+
69
+ `renderMermaidSVG(input, options?)` accepts a Mermaid source string or any open
70
+ `ParsedDiagram` envelope returned by `parseRegisteredMermaid` and returns an SVG
71
+ string.
72
+
73
+ ### PNG
74
+
75
+ ```ts
76
+ import { writeFileSync } from 'node:fs'
77
+ import { renderMermaidPNG } from 'agentic-mermaid/agent'
78
+
79
+ const png = renderMermaidPNG(`flowchart TD
80
+ A --> B`, {
81
+ fitTo: { width: 1200 },
82
+ background: '#fff',
83
+ })
84
+
85
+ writeFileSync('diagram.png', png)
86
+ ```
87
+
88
+ `renderMermaidPNG(input, options?)` accepts a Mermaid source string or any open
89
+ `ParsedDiagram` envelope returned by `parseRegisteredMermaid` and returns
90
+ `Uint8Array` PNG bytes. SVG, ASCII/Unicode, layout, native PNG, and browser PNG
91
+ accept the same parsed-or-source input contract; an unregistered preserved
92
+ envelope round-trips exactly and returns its stable capability diagnostic rather
93
+ than falling through to Flowchart.
94
+
95
+ `PngOptions` extends the shared `RenderOptions` contract used by SVG. The
96
+ canonical machine-readable field set is returned by
97
+ `sharedRenderOptionsJsonSchema()`; the table below contains only PNG-specific
98
+ controls:
99
+
100
+ | Option | Type | Default | Availability and meaning |
101
+ |---|---|---:|---|
102
+ | `scale` | `number` | `2` | Portable: native/browser library, CLI, and local/hosted MCP. Zoom multiplier when `fitTo` is not set. |
103
+ | `background` | `string` | artifact background, then white | Portable on the same surfaces. Safe explicit PNG background color. |
104
+ | `fitTo` | `{ width?: number; height?: number }` | — | Portable on the same surfaces. Constrain output to exactly one positive width or height. |
105
+ | `fontDirs` | `string[]` | — | Trusted native-host input: Node/Bun library, CLI, and local MCP only. Extra font directories for unbundled families and scripts the bundled fonts do not cover. CLI: `--font-dirs <dirs>` (comma-separated). |
106
+ | `loadSystemFonts` | `boolean` | `false` | Trusted native-host input on the same native surfaces. Trades cross-machine determinism for glyph coverage. CLI: `--system-fonts`. |
107
+ | `onWarning` | `(w: PngFontWarning) => void` | stderr | Native library callback only. Receives `PNG_FONT_COVERAGE` warnings; callbacks never enter serializable requests or receipts. |
108
+
109
+ PNG rasterization uses offline `@resvg/resvg-js` with bundled fonts for
110
+ deterministic same-machine output: Inter (the default face — the same family
111
+ the SVG requests and the family `src/text-metrics.ts` is calibrated for, so
112
+ rasterized labels match their measured boxes), DejaVu Sans as a per-glyph
113
+ fallback for symbols Inter lacks, plus the faces the built-in styles
114
+ reference (Caveat, EB Garamond, Architects Daughter, Share Tech Mono — see
115
+ `assets/fonts/FONT-LICENSES.md`). A style whose `font` is neither bundled
116
+ nor supplied via `fontDirs` rasterizes with Inter. Characters no loaded font
117
+ covers (CJK, most emoji) draw as tofu boxes and raise a `PNG_FONT_COVERAGE`
118
+ warning naming the script and the escape hatches (`fontDirs` /
119
+ `loadSystemFonts`).
120
+ Note for third-party rasterizers: the SVG declares fonts as
121
+ `font-family: var(--font, 'Face')`, and static rasterizers (resvg, librsvg)
122
+ do not resolve CSS custom properties — `renderMermaidPNG` inlines the
123
+ resolved family before rasterizing; do the same if you feed the raw SVG to
124
+ your own pipeline.
125
+
126
+ For complete custom-Style recipes using `font`, `fontDirs`, browser faces, and
127
+ SVG font declarations, see [Fonts in custom styles](./custom-fonts.md).
128
+
129
+ PNG output declares the shared sRGB policy with `sRGB` and `cICP` metadata,
130
+ places `cICP` before image data, and deliberately emits no conflicting ICC
131
+ profile. SVG and PNG consume the same resolved graphical colors before
132
+ rasterization.
133
+
134
+ #### Trusted host-selected graphical backends
135
+
136
+ Executable backends are bound by the host, never selected by `RenderOptions` or
137
+ serialized Style data. These factories apply the same canonical request,
138
+ Scene-admission, SVG-security, receipt, PNG-output-policy, and color-profile
139
+ contracts as their default counterparts:
140
+
141
+ ```ts
142
+ import {
143
+ createMermaidBrowserPNGRenderer,
144
+ createMermaidRenderer,
145
+ } from 'agentic-mermaid'
146
+ import { createMermaidPNGRenderer } from 'agentic-mermaid/agent'
147
+
148
+ const backendPolicy = { selectBackend: () => 'backend:acme/renderer' }
149
+ const svgRenderer = createMermaidRenderer({ backendPolicy })
150
+ const nodePngRenderer = createMermaidPNGRenderer({ backendPolicy })
151
+ const browserPngRenderer = createMermaidBrowserPNGRenderer({
152
+ backendPolicy,
153
+ rasterize: async (securedSvg, context) => ({
154
+ png: await rasterizeWithCanvas(securedSvg, context.outputPolicy),
155
+ }),
156
+ })
157
+ ```
158
+
159
+ Register and conformance-check the named backend before constructing these
160
+ renderers. The Node/Bun factory reuses the built-in `@resvg/resvg-js` adapter;
161
+ the browser factory wraps a trusted injected rasterizer, which receives only
162
+ the admitted and secured SVG plus the complete resolved portable output policy.
163
+ Its rasterizer must apply `fitTo` and `background`, not only `scale`.
164
+ `renderMermaidSVG`, `renderMermaidPNG`, and
165
+ `renderMermaidPNGInBrowserWithReceipt` remain the compatible default-backend
166
+ entry points.
167
+
168
+ ### ASCII / Unicode
169
+
170
+ ```ts
171
+ import { renderMermaidASCII } from 'agentic-mermaid/agent'
172
+
173
+ const unicode = renderMermaidASCII(`flowchart LR
174
+ A --> B`)
175
+ const ascii = renderMermaidASCII(`flowchart LR
176
+ A --> B`, { useAscii: true })
177
+ ```
178
+
179
+ `renderMermaidASCII(input, options?)` accepts a Mermaid source string or any open
180
+ `ParsedDiagram` envelope returned by `parseRegisteredMermaid` and returns terminal
181
+ text.
182
+
183
+ `AsciiRenderOptions` also extends the same shared `RenderOptions` contract.
184
+ Terminal-only controls and the explicit losses involved in projecting a
185
+ graphical appearance onto terminal cells are documented in
186
+ [`ascii.md`](./ascii.md).
187
+ `colorMode: 'html'` returns an escaped terminal projection through this same
188
+ function; it is not a separate CLI output format or a `renderMermaidHTML` API.
189
+
190
+ `AsciiRenderOptions`:
191
+
192
+ | Option | Type | Default | Meaning |
193
+ |---|---|---:|---|
194
+ | `useAscii` | `boolean` | `false` | Use 7-bit ASCII instead of Unicode box drawing. |
195
+ | `paddingX` | `number` | `5` | Horizontal spacing. |
196
+ | `paddingY` | `number` | `5` | Vertical spacing. |
197
+ | `boxBorderPadding` | `number` | `1` | Inner box padding. |
198
+ | `colorMode` | `string` | `'auto'` | `'none'`, `'auto'`, `'ansi16'`, `'ansi256'`, `'truecolor'`, or `'html'`. |
199
+ | `theme` | `Partial<AsciiTheme>` | — | Override ASCII colors. |
200
+ | `targetWidth` | `number` | unset | Hard maximum line width in terminal display cells. Uses grapheme-safe fitting; impossible geometry throws `AsciiWidthError`. |
201
+ | `maxWidth` | `number` | unset | Deprecated best-effort label wrapping. It does **not** guarantee the output width. Do not combine with `targetWidth`. |
202
+ | `onProjectionDiagnostic` | `(diagnostic: TerminalProjectionDiagnostic) => void` | — | Host callback for explicit graphical-to-terminal projection losses; non-serializable and excluded from receipts. |
203
+
204
+ `AsciiWidthError` has code `ASCII_TARGET_WIDTH_IMPOSSIBLE` plus
205
+ `requestedWidth`, `requiredWidth`, `family`, and `reason` (`MINIMUM_GEOMETRY`,
206
+ `UNBREAKABLE_GRAPHEME`, or `INVALID_WIDTH`). The same fields are returned by
207
+ CLI JSON and hosted MCP errors. CLI: `am render diagram.mmd --format unicode
208
+ --target-width 80`; hosted `render_ascii`: `{ source, targetWidth: 80 }`.
209
+ Omitting both width options preserves the unconstrained output path.
210
+
211
+ ## Shared render options
212
+
213
+ SVG, PNG, ASCII, and Unicode adapters accept this serializable `RenderOptions`
214
+ field set. The built-in-family column exposes family applicability; the
215
+ terminal column records whether text output consumes a field, projects it with
216
+ an explicit diagnostic, or declares it inapplicable. Output-specific controls
217
+ remain in their respective sections.
218
+
219
+ <!-- BEGIN GENERATED SHARED RENDER OPTIONS -->
220
+ | Option | Type | Effective default | Meaning | Built-in families | Terminal |
221
+ |---|---|---|---|---|---|
222
+ | `bg` | `string` | `#FFFFFF` | Background color or CSS variable. | all | consumed |
223
+ | `fg` | `string` | `#27272A` | Primary foreground and text color. | all | consumed |
224
+ | `line` | `string` | derived | Connector and secondary-line color. | all | consumed |
225
+ | `accent` | `string` | derived | Arrowhead, highlight, and data accent color. | all | consumed |
226
+ | `muted` | `string` | derived | Secondary text and label color. | all | projected — terminal themes have no dedicated muted-text role |
227
+ | `surface` | `string` | derived | Node and group surface color. | all | projected — terminal cells do not paint graphical surfaces |
228
+ | `border` | `string` | derived | Node and group border color. | all | consumed |
229
+ | `font` | `string` | `Inter` | CSS font family or stack. | all | projected — the host terminal owns the font face |
230
+ | `style` | `StyleInput \| StyleInput[]` | `crisp` | Registered Style/Palette name, inline StyleSpec, or left-to-right stack. | all | consumed |
231
+ | `padding` | `number` | `40` | Canvas padding in SVG user units. | flowchart, state, architecture | not-applicable — terminal output uses paddingX, paddingY, and boxBorderPadding |
232
+ | `nodeSpacing` | `number` | `24` | Horizontal spacing between sibling nodes. | flowchart, state, class, er, architecture | not-applicable — terminal layout has a cell-grid spacing contract |
233
+ | `layerSpacing` | `number` | `40` | Vertical spacing between graph layers. | flowchart, state, class, er, architecture | not-applicable — terminal layout has a cell-grid spacing contract |
234
+ | `wrappingWidth` | `number` | unset | Flowchart measured-label wrapping budget in pixels. | flowchart | not-applicable — terminal output uses maxWidth or targetWidth |
235
+ | `componentSpacing` | `number` | extension-defined | Spacing between disconnected graph components for compatible extension families; no built-in family currently consumes it. | none — extension-defined | not-applicable — terminal layout has a cell-grid spacing contract |
236
+ | `transparent` | `boolean` | `false` | Omit the painted SVG canvas background. | all | projected — terminal output has no painted canvas background |
237
+ | `interactive` | `boolean` | `false` | Enable hover tooltips for supported chart data points. | xychart, pie, quadrant | projected — terminal output is a static semantic projection |
238
+ | `shadow` | `boolean` | `false` | Paint explicit drop shadows on node shapes. | flowchart, state, sequence, timeline, class, er, journey, xychart, pie, quadrant, gantt, mindmap, gitgraph | projected — elevation projects to borders and labels |
239
+ | `class` | `{ hierarchicalNamespaces?: boolean }` | `hierarchicalNamespaces: true` | Class-diagram rendering controls. | class | not-applicable — this option configures graphical class layout |
240
+ | `architecture` | `{ visual?: ArchitectureVisualOverrides }` | built-in metrics | Sparse architecture renderer visual metric and paint overrides. | architecture | not-applicable — this option configures graphical architecture rendering |
241
+ | `timeline` | `{ maxWidth?: number }` | `maxWidth`: unset | Timeline layout controls. | timeline | not-applicable — terminal output uses maxWidth or targetWidth |
242
+ | `journey` | `{ experienceCurve?: boolean }` | `experienceCurve: true` | User-journey graphical controls. | journey | not-applicable — experience curves are graphical-only |
243
+ | `gantt` | `{ dependencyArrows?: boolean; criticalPath?: boolean }` | both `false` | Gantt dependency and critical-path overlays. | gantt | not-applicable — graphical Gantt connector emphasis is not represented in cells |
244
+ | `mermaidConfig` | `MermaidRuntimeConfig` | source config | Mermaid-style recursive runtime configuration. | all | consumed |
245
+ | `embedFontImport` | `boolean` | `false` | Embed the Google Fonts import in SVG styles; PNG forces this off for offline rasterization. | all | not-applicable — terminal output embeds no web-font import |
246
+ | `compact` | `boolean` | `false` | Compact SVG serialization while preserving agent hooks. | all | not-applicable — compact controls SVG serialization |
247
+ | `idPrefix` | `string` | unset | Non-empty namespace for generated SVG definition IDs and local references. | all | not-applicable — terminal output has no SVG definition ids |
248
+ | `security` | `'default' \| 'strict'` | `default` | Active SVG content is rejected in every mode; strict additionally rejects every external reference. Raw Mermaid themeCSS is rejected in both modes. | all | not-applicable — terminal text has its own control-character and HTML-color safety projection |
249
+ | `ganttToday` | `string` | unset | Explicit deterministic date for the Gantt today marker. | gantt | consumed |
250
+ | `seed` | `number` | `0` | Deterministic re-roll seed for stochastic Styles. | all | not-applicable — terminal glyph geometry is deterministic and has no stochastic ink |
251
+ <!-- END GENERATED SHARED RENDER OPTIONS -->
252
+
253
+ `Built-in families: all` means the field is family-neutral. `none —
254
+ extension-defined` means no built-in currently consumes it. An external
255
+ `FamilyDescriptor` opts into any family-scoped field it consumes through its
256
+ frozen `applicableRenderOptions` array; an omitted or empty declaration means
257
+ none, and authored values receive `RENDER_OPTION_NOT_APPLICABLE` in the render
258
+ receipt.
259
+
260
+ `onConfigDiagnostic?: (diagnostic: ConfigDiagnostic) => void` is deliberately
261
+ outside the serializable field set. Library callers can collect qualified
262
+ `INEFFECTIVE_CONFIG` warnings without changing output bytes; CLI, MCP, editor,
263
+ and JSON Schema surfaces return diagnostics as data instead of accepting a
264
+ function.
265
+
266
+ ### SVG semantic identity and accessibility
267
+
268
+ All built-in families expose the same inspectable element contract:
269
+
270
+ - every source-semantic Scene mark has a deterministic `data-id` and closed
271
+ `data-role`; identity is unique within one SVG (layout furniture retains typed
272
+ Scene identity without bloating the DOM);
273
+ - source relations use `data-from` and `data-to`; source `className` tokens stay
274
+ on the identified element's `class` attribute;
275
+ - typed relations expose `role="graphics-symbol"`,
276
+ `aria-roledescription="relation"`, and an `aria-label` derived from endpoints
277
+ plus the authored relation label;
278
+ - public Scene types expose `SvgSemanticIdentity`,
279
+ `SvgSemanticAccessibility`, and `SvgRelationSemantics`;
280
+ - `idPrefix` rewrites local DOM `id` references, not source-facing `data-id`.
281
+
282
+ Built-in concrete palettes are contrast-normalized at render time: normal text
283
+ roles meet WCAG AA 4.5:1 and meaningful relation lines/markers meet 3:1 against
284
+ the page background. Unresolved runtime CSS variables cannot be statically
285
+ certified and pass through unchanged. See
286
+ [`svg-semantic-contract.md`](./svg-semantic-contract.md) for the complete contract.
287
+
288
+ For JSON files, use
289
+ [`docs/schemas/style-spec.schema.json`](./schemas/style-spec.schema.json). The
290
+ same schema is exported from the npm package as
291
+ `agentic-mermaid/style-spec.schema.json`; see
292
+ [`custom-style-cookbook.md`](./custom-style-cookbook.md) for complete style
293
+ files and screenshots, and [`custom-fonts.md`](./custom-fonts.md) for font
294
+ resolution across output surfaces.
295
+
296
+ ## Agent edit API
297
+
298
+ ```ts
299
+ import {
300
+ parseRegisteredMermaid,
301
+ asFlowchart,
302
+ mutate,
303
+ verifyMermaid,
304
+ analyzeMermaid,
305
+ analyzeMermaidSource,
306
+ describeMermaidFacts,
307
+ checkMermaid,
308
+ serializeMermaid,
309
+ } from 'agentic-mermaid/agent'
310
+ ```
311
+
312
+ Core functions:
313
+
314
+ | Function | Purpose |
315
+ |---|---|
316
+ | `parseRegisteredMermaid(source)` | Parse Mermaid source to `Result<ValidDiagram, ParseError[]>`. |
317
+ | Family narrower | Narrow to a mutable family or return `null`; obtain the current generated name from `am capabilities --json`. |
318
+ | `mutate(d, op)` | Apply a kind-discriminated typed mutation. |
319
+ | `verifyMermaid(d)` | Return structural warnings and layout evidence. |
320
+ | `analyzeMermaid(d)` / `analyzeMermaidSource(source)` | Return deterministic non-rendering analysis: feedback edges, source-only action records, and Gantt critical-path/slack summary when available. |
321
+ | `describeMermaidFacts(d)` / `checkMermaid(d, spec)` | Return deterministic semantic fact lines, or check required/forbidden facts such as `edge Processing -> [*] : done`, `member Duck +quack()`, `task Docs start after core`. |
322
+ | `serializeMermaid(d)` | Emit source only after verifying. |
323
+ | `layoutMermaid(d)` | Return layout JSON for quality/inspection; `layoutMermaid(d, { debug: true })` includes graph route certificates, family edge-route certificates (class/ER/architecture/sequence), region-containment certificates (timeline/charts), and semantic region/action sidecars (`cluster`, `lane`, `band`, `compartment`, `plot`, `ring`). Edge certificates include exact ports plus side/slot/role port assignments where applicable. |
324
+ | `renderMermaidWithActions(d, request)` | Render SVG, PNG, ASCII, or Unicode and return one inert action/hit-region sidecar for admitted Flowchart/Class/Gantt interactions and Sequence actor-menu links. An SVG href is `embedded-inert` only when matching inert metadata is present in the returned SVG; PNG/terminal actions, strict-mode hrefs, and all callbacks are `sidecar-only` and never execute. Terminal artifacts also return projection `warnings`, and terminal render failure throws instead of returning an empty success artifact. |
325
+ | `measureQuality(layout, colors?)` / `checkQuality(layout, bounds?, colors?)` | Perceptual quality metrics, including fail-closed contrast (`null` when requested paints are unresolved), nearest-node spacing, and element density. Rendered audits can supply exact foreground/background associations through `textPairs`. |
326
+ | `describeMermaid(d, { format })` | Prose, AX-tree, or facts summary (`format: "text" | "json" | "facts"`). |
327
+
328
+ The family registry is the operation authority. Use `am capabilities --json`
329
+ for the current roster and field schemas, or call `describeOps(family)` and
330
+ `opSignatures(family)` at runtime. The generated SDK declaration projects the
331
+ same descriptors; this reference deliberately does not copy an exhaustive
332
+ family/operation table.
333
+
334
+ Opaque fallback bodies (any unmodeled syntax) are source-level-only: edit source deliberately, then parse and verify again.
335
+
336
+ ## Capability and extension discovery
337
+
338
+ Repository audit tooling can import `createSectionACapabilityReport()` from
339
+ `src/section-a-capability-report.ts`. It returns the JSON-safe, registry-derived
340
+ request/backend/output/family/Scene matrix. `am capabilities --json` →
341
+ `sectionA` intentionally exposes only its version, pin, digest, counts,
342
+ no-absent status, and directions to this full report. Validate a stored snapshot with
343
+ `validateSectionACapabilityReport(report)`. The generated human projection is
344
+ [`project/section-a-capability-report.md`](./project/section-a-capability-report.md).
345
+ Keeping this audit surface out of the package prevents the full characterization
346
+ and upstream syntax corpora from entering renderer/browser bundles.
347
+
348
+ Canonical extension identities are kind-qualified (`look:`, `palette:`,
349
+ `backend:`, `family:`, `role:`, and `resource:`), versioned, provenance-bearing,
350
+ and collision-safe. New graphical backends declare feature/operation-level
351
+ Scene primitive capability claims; the registry rejects an empty, duplicate,
352
+ cross-target, or otherwise invalid claim set. Every external backend, and every
353
+ external family that supplies `lowerScene`, must also declare an explicit
354
+ compatible `identity.compatibility.scene` range (Scene v2: `^2.0.0`). The host
355
+ checks that range before running backend conformance or other executable
356
+ witnesses; only the internal built-in enrollment path receives compatibility
357
+ defaults.
358
+
359
+ ### Current customization and extension inventory
360
+
361
+ This is the current authoritative inventory. Field-level `RenderOptions` and
362
+ `StyleSpec` details remain in their generated tables above rather than being
363
+ copied here.
364
+
365
+ | Level | Public seam | What it can change | Boundary and availability |
366
+ |---|---|---|---|
367
+ | Mermaid-authored appearance | frontmatter/init config, theme variables, family style statements such as classes and link styles | Syntax-defined colors, labels, family geometry, and interaction metadata where the family advertises support | Source-level and family-dependent. Raw `themeCSS` is recognized but diagnosed at the render boundary because its selectors and markup can escape an imported SVG; use `StyleSpec` instead. |
368
+ | One-off render overrides | `RenderOptions` | Palette channels, font family, spacing/geometry controls, deterministic seed, security, accessibility-related output options, and a Style stack | The generated field×surface matrix marks each serializable shared field `forwarded`, `host-enforced`, or `unavailable`. Hosted SVG and editor SVG enforce strict security with external font imports disabled; effective receipts reflect those constraints. Host callbacks are library-only and never enter receipts. |
369
+ | One-off declarative style | inline `StyleSpec` or a left-to-right `StyleInput[]` stack | Safe palette, font, stroke/fill treatment, backdrop, exact semantic-role defaults, named semantic slots, V1 `category` bindings, non-color cues, and inspect-only contrast/accent-area/mono-role constraints | JSON-safe and executable-code-free. Bindings supply defaults beneath authored family paint and semantics; constraints diagnose final effective paint without repainting or relayout. This is the lowest-complexity custom Style path. |
370
+ | Named Palette/Look | `registerStyle`, `getStyle`, `knownStyleDescriptors` | Installs a versioned `palette:` or `look:` name backed by exactly the same `StyleSpec` accepted inline | Descriptors expose one `kind` (`look` or `palette`), explicit `isDefault`, and one stable `inputName`. In-process host registry. A CLI/MCP/server sees a registration only when that host installs it at startup. |
371
+ | Theme conversion | `fromShikiTheme` | Converts a Shiki-compatible editor theme into diagram colors | Pure library helper; the result is ordinary declarative color input. |
372
+ | Live host retheming | CSS custom-property values in graphical color/font inputs | Lets a host page switch SVG palette and font values without re-rendering | SVG/browser-only and limited to safe property values; this is not a raw CSS rule or selector hook. Static outputs need values resolved under their rasterization environment to remain reproducible. |
373
+ | Terminal output projection | `AsciiRenderOptions` (`useAscii`, `paddingX`, `paddingY`, `boxBorderPadding`, `colorMode`, `theme`, `targetWidth`/`maxWidth`, `onProjectionDiagnostic`) | Selects Unicode/ASCII encoding, cell spacing, width policy, ANSI/HTML colors, terminal-only theme overrides, and projection-loss reporting | Output-adapter customization, not a second shared Style system. Serializable fields have transport-specific availability; the diagnostic callback is host-only and remains outside receipts. |
374
+ | Fonts and installed resources | `font`, Node PNG `fontDirs`/`loadSystemFonts`/`onWarning`, browser `BrowserPngRasterizer`, `ResourceManifest`, and repository host tooling via `NodeResourceResolver` | Selects a safe font stack, supplies host-dependent raster fonts, reports missing glyph coverage, or verifies bounded installed bytes | Font family names do not install fonts. Browser and warning callbacks remain outside serializable options and every digest. Node `fontDirs`/`loadSystemFonts` are trusted host inputs outside shared `RenderOptions` and the shared/appearance digests, but their resolved PNG output policy is included in the output-specific request digest; runtime provenance still marks host-dependent resources explicitly. Manifests require path, size, media-type, digest, and licence evidence and never fall back to network access. |
375
+ | Graphical backend | `registerBackend`, `runBackendConformance`, `createMermaidRenderer`, `createMermaidPNGRenderer`, `createMermaidBrowserPNGRenderer` (each with a host-only `backendPolicy`) | Serializes the typed Scene contract with a different drawing implementation for SVG, native Node/Bun PNG, and injected-rasterizer browser PNG | Trusted in-process host only. Host registrations must explicitly declare compatible core and Scene ranges; identity/compatibility admission precedes executable conformance. Registration then must pass bounded, deterministic, semantic, well-formed, secure SVG conformance plus an exact witness for every first-party core primitive/feature/operation claim; namespaced extension claims without a core witness remain explicitly unverified. All listed factories use the same admitted and secured graphical request; PNG adapters do not reparse or rerender source. Serializable styles and `RenderOptions` cannot select arbitrary executable backends. |
376
+ | Diagram family | `registerFamily`, `getFamilyConformanceReport`, `parseRegisteredMermaid`, `projectPositionedView` | Adds a namespaced language with detection, parse/preservation, verification, layout, Scene/SVG, terminal, and discovery claims | Every versioned `family:<owner/name>` descriptor declares a compatible core range and supplies one bounded canonical `example`. It also lists consumed family-scoped shared fields in `applicableRenderOptions`; omission means none, unknown or duplicate fields fail registration, and the frozen declaration appears in the capability report. Registration stages the frozen candidate, runs native claims twice through canonical parse/serialize, non-empty positive-bounds layout, strict SVG, portable PNG pre-raster, terminal, Scene and verify paths, and rolls back on failure, reentrancy or nondeterminism. Discovery reports `native` only beside a passed per-capability witness. Native tuples still require layout + `projectPositioned`, Scene requires layout + `lowerScene`, and extension verification requires its hook plus executable SVG. An external Scene family additionally declares a compatible Scene range, and its example witnesses every positive role/primitive cell. Built-in-only unions stay closed; extension bodies use the open envelope. Remote transports gain the family only when their trusted host installs it. |
377
+ | Scene semantics | `SceneDoc`, typed connectors/markers/hit geometry, namespaced `SceneRole` | Lets a family/backend exchange identity, relationship, accessibility, geometry, and terminal-projection intent | This is a versioned typed contract, not a raw SVG hook. Unknown namespaced roles deliberately receive inert identity-only traits and cannot acquire core behavior by local-name collision. There is no public arbitrary primitive/trait mutation registry. |
378
+ | Browser PNG host adapter | `renderMermaidPNGInBrowserWithReceipt(..., rasterize)` or reusable `createMermaidBrowserPNGRenderer({ rasterize, backendPolicy? })` | Supplies Canvas/OffscreenCanvas rasterization and reports font provenance | Trusted callback receives only the admitted, secured canonical SVG; the library re-applies the PNG color-profile gate and retains the same logical receipt as the native PNG path. |
379
+ | Identity plumbing | `canonicalExtensionId`, `parseExtensionId`, `createExtensionIdentity`, `registerExtension`, `ExtensionCollisionError` | Gives kind-specific registries stable names, parsing, versions, provenance, compatibility ranges, and collision rejection | Low-level plumbing, not a stand-alone extension registry or rendering hook. Stable short inputs belong to kind-specific descriptors. |
380
+
381
+ There is currently no BrandPack registry, public role-trait registration,
382
+ arbitrary SVG/CSS hook, or Treatment hook. Semantic slots and the closed V1
383
+ `category` binding API are ordinary `StyleSpec` fields; other Scene channels are
384
+ not publicly bindable without new executable family witnesses. B4 remains the
385
+ unpromoted, evidence-gated BrandPack distribution envelope only. A future
386
+ Treatment seam is a separate decision and is not implied by B4.
387
+
388
+ ## CLI
389
+
390
+ ```bash
391
+ am render diagram.mmd --format svg > diagram.svg
392
+ am render diagram.mmd --format png --output diagram.png --fit-width 1200 --bg '#fff'
393
+ am render diagram.mmd --format ascii > diagram.txt
394
+ am render diagram.mmd --format layout --certificates > layout-with-routes.json
395
+ am verify diagram.mmd
396
+ am describe diagram.mmd --format facts
397
+ am mutate diagram.mmd --op '{"kind":"add_node","id":"Cache","label":"Cache"}' --json
398
+ am capabilities --json
399
+ am init-agent --dir . --json
400
+ ```
401
+
402
+ PNG is single-input and requires `--output` so binary bytes are never accidentally printed to a terminal. Portable controls are `--scale`, `--bg`, and the mutually exclusive `--fit-width`/`--fit-height`; native-host font controls are `--font-dirs` and `--system-fonts`. `am init-agent` writes a non-clobbering agent-agnostic onboarding bundle (`AGENTS.md`, root `skills/`, and `.mcp.json`) into a consumer repo.
403
+
404
+ ## MCP
405
+
406
+ The published package exposes Node-runnable bins: `am`, the package-runner
407
+ alias `agentic-mermaid`, and `agentic-mermaid-mcp`.
408
+
409
+ Local `agentic-mermaid-mcp` is Code Mode-first and exposes:
410
+
411
+ - `execute(code)` — primary Code Mode tool with global `mermaid.*` SDK.
412
+ - `describe_sdk({ family, detail })` — version-matched compact signatures or exact mutation fields for one family.
413
+ - `render_png` — narrow helper returning base64 PNG bytes, or managed file/URL artifacts via `output: "file"|"url"`; accepts portable `scale`/`background`/`fitTo`, plus local-only `fontDirs`/`loadSystemFonts`, and returns configuration/font-coverage warnings with every output mode.
414
+ - `describe` — narrow summary helper; pass `format: "facts"` for deterministic semantic fact lines.
415
+
416
+ Use Code Mode for multi-step parse/narrow/mutate/verify/serialize loops. Use `render_png` or host/library code for binary PNG output. The default transport is stdio; `agentic-mermaid-mcp --transport http --host 127.0.0.1 --port 3000` starts the HTTP/SSE transport. HTTP mode serves managed artifacts from `/artifacts/<name>` with MIME type, byte count, and SHA-256 metadata in tool responses. Non-loopback HTTP binding requires `--auth-token`; that bearer token protects `/rpc`, `/sse`, `/message`, and `/artifacts/*`.
417
+
418
+ A hosted Streamable HTTP endpoint also runs at `https://agentic-mermaid.dev/mcp`. It is MCP JSON-RPC only (not REST), stateless, public/unauthenticated, and capped at 64 KB inputs. Hosted tools are `execute`, `describe_sdk`, `render_svg`, `render_ascii`, `render_png`, `verify`, `describe`, `mutate`, and `build`; `describe_sdk` returns compact signatures or exact mutation fields for one family, hosted `execute` uses a Cloudflare Dynamic Worker isolate with no network, and hosted `render_png` returns base64 only while retaining portable `scale`/`background`/`fitTo`. Prefer local CLI/library/MCP for sensitive diagrams, offline work, larger inputs, native font controls, or file/URL PNG artifacts. See [`mcp-http-transport.md`](./mcp-http-transport.md) for JSON-RPC examples and option details.