# Module design plan

Status: the combined design has been adopted, and all five forms are connected to the new Interface. See the [HTML slice](quality-slice.md) and [built-in forms](native-forms.md) for their scopes. User extension seams apply only to HTML; the other four forms do not accept external extensions. Arbitrary component-library loading and the full SDK are not implemented or finalized. This document uses the codebase-design vocabulary: Module, Interface, Implementation, Depth, Seam, Adapter, Leverage, and Locality. Product requirements are governed by the [project specification](project-spec.md) and [extension design](extensibility.md). The three alternatives below remain as design history; the current scope takes precedence.

An Interface includes more than function parameters: calling order, input invariants, errors, configuration, performance, and result guarantees all count. Few methods still make a shallow interface if the agent must understand the entire layout pipeline.

## Evidence from the existing Implementation

The original assessment below used source at `5ec707b`. These paths describe behavior at that revision, not a proposed directory structure.

| Observed behavior | Design implication |
| --- | --- |
| The [MCP Adapter](../bin/mcp-server.mjs) calls `renderToFiles`, then `renderMermaid`, and decides PNG fallback itself | Display policy leaks into callers; CLI and MCP quality behavior can diverge |
| [Mermaid output](../src/mermaid.mjs) calls `layoutComposition`, reusing custom-diagram normalization and layout | Normalization may be shared, but terminal and other forms should not be forced through SVG layout |
| [File output](../src/render.mjs) combines rendering, directory creation, rasterizer discovery, subprocess execution, and PNG reading | Pure layout, environment dependencies, and artifact storage need clear internal seams; text output should not depend on PNG conversion |
| [Primitive handling](../src/composition.mjs) uses a fixed type set and branches | Adding domain elements should not require editing core type dispatch |
| [Exports](../src/index.mjs) expose validation, compilation, layout, and several output entry points | Preserve compatibility while letting new callers use a deeper Module instead of assembling processing steps |

Immediately splitting the code into more packages will not solve these issues. First concentrate behavior, caller knowledge, and tests at the right seam; decide physical directories and packages afterward.

## Required constraints

- The agent chooses the display form and semantic content; automatic layout repair stays in the Implementation.
- Each of the five forms may use its own content structure. Pseudocode, trees, and diff need not become Card/Relation graphs.
- Built-in and independent user libraries use the same extension seam; names must not trigger core special cases.
- User components participate in measurement and layout but cannot declare overall quality success.
- Do not silently change forms, discard content, or change relations. Capability failures and success must be distinguishable.
- Unverified client relayout has no inherited quality guarantee; results must state verification scope.
- Add seams only where behavior actually varies. Ordinary pure functions need no Adapter wrapper.

## Three independent designs

### A. Minimal caller Interface

```text
createShowMe(hostConfiguration) → showMe.render(request)
```

One request performs resolution, measurement, layout, detection, repair, artifact generation, and verification. None of those pipeline stages is exposed externally.

Depth is high, quality policy is centralized, and MCP and CLI can share behavior. However, configuration, versioned inputs, and element usage remain part of the Interface. Without discovery, complexity merely moves into the knowledge required before calling. One method alone does not establish sufficient Depth.

### B. Extension-first Interface

```text
discoverLibraries(filter) → elements / recipes / form support
render(formNativeIntent, resolvedLibraries) → artifact and evidence
```

Expression libraries declare identity, semantic schemas, and recipes. A Display Adapter produces candidates for a particular form, while the core decides quality using that form's inspection surface. Trees, diff, and graphs are not forced into a universal node model.

The extension seam is clear and Locality is good. The cost is potential growth of the author contract: requiring every author to implement measurement, routing, and rendering protocols shifts complexity out of the core. Geometry reported by a candidate is also not sufficient final acceptance evidence on its own.

### C. Common-call and recipe-first Interface

```text
show({ recipe, form, input }) → artifact and evidence
```

Recipes own content schemas, constraints, and examples, keeping common calls short. A retry recipe might support pseudocode and Mermaid, with the agent explicitly choosing the form. Recipe discovery is therefore needed.

Leverage is high for common scenarios, but requiring a recipe for a simple text tree increases learning cost. Separate `list_*` and `describe_*` operations for every query also enlarge the Interface. Recipes must not replace a form's basic input capability.

| Design | Depth | Locality | Main cost of the Seam |
| --- | --- | --- | --- |
| A | One call hides the full workflow, but discovery knowledge is missing | Quality behavior is centralized | Callers may still assemble configuration and semantic structures manually |
| B | High Leverage for extension capabilities | Domain knowledge stays in its library | An oversized author Interface and leaking inspection details |
| C | Common recipes are easiest to use | Recipes and content constraints are concentrated | Forcing simple content through recipes and multiplying discovery operations |

## Recommendation: A's deep Module, B's extension seam, and C's optional recipes

### Agent-facing Interface

The names and types below are design sketches, not a declaration that every proposed MCP or SDK capability has shipped.

```ts
interface ShowMe {
  describe(query: CatalogQuery): Promise<CatalogPage>;
  render(request: DisplayRequest): Promise<DisplayResult>;
}
```

- `describe`: filter enabled capabilities by form, library, or recipe; return versions, schemas, meanings, examples, and limits with pagination. A single discovery entry point avoids multiple query-forwarding Modules.
- `render`: accept an explicit `form` and its content. Content may use the form's direct structure or, where supported, a discovered recipe and parameters. Inputs do not expose layout-loop stages.
- Call `render` directly when the input contract is known; `describe` is not mandatory before every request. Form selection remains explicit rather than becoming an implicit automatic choice.
- Validate `content` against the selected form or recipe schema; it is not an arbitrary field bag. Custom elements use the namespace and version conventions returned by discovery.

This example illustrates the call shape:

```js
// The host configures libraries, the display environment, and dependencies at startup.
const result = await showMe.render({
  form: "tree",
  content: {
    roots: [{
      label: "Request handling",
      children: [{ label: "Authentication" }, { label: "Execution" }]
    }]
  }
});
```

The agent need not specify font paths, subprocess commands, output directories, iteration counts, or collision algorithms. Invalid semantic content may require correction by the caller; the Implementation should handle layout defects itself.

### Host configuration responsibilities

When assembling `ShowMe`, the Host supplies enabled libraries, available display adaptations, the display environment, and required local tools. The Host may be the MCP process, CLI, or future Pi integration. This configuration is part of the full Interface; a short function signature does not hide its cost.

Widths, fonts, and renderer capabilities come from actual Host environment information, not agent guesses. If the target environment is unknown, provide evidence only for a clearly named test environment rather than claiming the user's current window passed. Defaults can simplify calls, but actual versions and verification scope must be recorded.

Configuration remains consistent within a request, and versions are resolved before execution. Supported sizes, budgets, and cancellation are execution contracts. Quality checks and resource consumption need limits, with specific values determined through vertical-slice validation.

### Results and error contracts

```text
ready       → checked artifact + QualityEvidence
not-ready   → reason + unresolved defects / limits + QualityEvidence
```

Distinguish `not-ready` reasons: invalid input, missing or incompatible extensions, unsupported forms or environments, unavailable dependencies, exhausted repair budget, and cancellation. An unexplained boolean is insufficient, and successful file generation is not equivalent to `ready`.

`QualityEvidence` associates a particular artifact with semantic checks, defect and repair summaries, final checks, library/adaptation/renderer versions, and environment scope. The agent does not need every internal debug event. Unverified previews must be separately labeled rather than occupying the accepted-artifact slot.

Results must not silently switch forms, change relations, or delete text. File formats encode or present artifacts; they are not shortcuts for changing semantics. If another client performs layout again, existing evidence does not automatically cover its new output.

### Work hidden in the Implementation

```text
MCP / CLI / Pi Adapter
          ↓
    ShowMe Interface
          ↓
    Resolve and normalize
          ↓
    Selected form's Implementation
    Measure → layout → check → repair → recheck
          ↓
    Artifact and final verification evidence
```

Semantic constraints, execution contracts, and quality results are shared; layout algorithms need not be. Graphs can use boxes and paths, text trees use hierarchy and display width, and diff uses original lines and hunk semantics. Do not invent a universal Card type for all of them.

Pure computation returns results. Accept file or external-tool dependencies at an internal seam. Prefer returning text or artifact content for the Host's delivery Adapter to save or display; tools that require file intermediates may use controlled temporary directories inside the Implementation. Verify the content actually delivered, and do not leave failed partial artifacts marked as successful.

## Interface for user extension authors

Authors should not register libraries through agent-call configuration. Separate expression declarations from display adaptation:

1. **Expression declarations**: namespaces, versions, element/recipe schemas, semantic constraints, examples, and supported forms. Prefer declarations and composition of existing elements for data-oriented extensions.
2. **Display adaptation**: measurements, anchors, resources, and adjustable capabilities needed when users supply components. Authors should not implement the entire document rendering, repair, and acceptance loop.

The core owns the loop and quality gates. Extensions may produce candidates, add constraints, and supply specialized checks, but cannot bypass core checks by reporting `passed`. Initial measurements must be checked against actual resources and artifacts; component declarations are not independent acceptance evidence.

Use the default library and an example outside the core source to establish two real Adapters before extracting a minimal author contract. Do not freeze a complete executable SDK, loading lifecycle, or public geometry protocol prematurely. Adding a display form does not automatically imply an installable renderer-plugin mechanism.

## Seams justified by actual variation

This table records the assessment at the original design stage; current implementation progress is described in the slice guides.

| Dependency / variation | Classification and handling | Verification |
| --- | --- | --- |
| Validation, normalization, pure layout | In-process; direct functions, not an Adapter per step | Observable outcomes through the ShowMe Interface |
| MCP and CLI callers | Two existing callers; protocol Adapters do not own quality policy | Equivalent input should produce equivalent quality decisions |
| Default and user libraries | An extension seam is required; the second real Adapter was still pending at design time | Add/remove an independent example without editing core source |
| Layout across display forms | Behavior genuinely varies; start with private Implementations and extract internal seams from real forms | At least one relation diagram and one text tree must work without sharing a forced node model |
| File storage | Local-substitutable; use real temporary directories first rather than forcing a public FileSystem Interface for tests | Real reads, writes, and cleanup; abstract when a second storage use appears |
| Fonts, librsvg, client rendering | External local tools/environment capabilities; resolve or invoke only on paths that need them, with dependencies supplied by the Host | Actual integrations prove success; mocks prove only failure handling such as timeout or absence |
| Remote network services | No current dependency | Do not predefine remote ports or split services |

“One adapter means a hypothetical seam” applies here too: more folders and Interfaces do not automatically improve extensibility. Prefer one package for the initial implementation unless two actual use cases justify independent distribution.

## Testing Depth

Tests and callers cross the same ShowMe Interface, asserting output semantics and quality decisions rather than internal processing order.

- An input whose label obscures an arrow is repaired by one `render` call, without a second agent revision.
- Text, endpoints, grouping, and reading order survive wrapping and avoidance.
- Built-in and custom elements undergo the same checks; extensions cannot skip quality gates.
- Missing libraries, unsupported forms, unavailable fonts, and exhausted budgets cannot yield `ready`.
- Tree output does not depend on PNG conversion; simple text does not execute graph layout.
- The same content is checked separately in different Host environments; unsuitable dimension evidence cannot be reused.

Use replace-don't-layer testing: migrate existing regressions to the new Interface and verify they catch the same defect before removing equivalent tests that only constrain internal implementation shape. Keep unmigrated regressions, format-validity tests, real PNG/Unicode checks, and protocol integrations. Do not delete the old suite wholesale.

## Minimal validation sequence

1. Use an existing failing diagram to implement a complete single-call quality loop for one form and a defined environment, rather than scaffolding five empty implementations.
2. Add both the default library and an independent user example through the same call to prove domain changes do not modify the core.
3. Add a minimal text-tree path to prove the Interface needs neither PNG nor tree-to-graph conversion.
4. Refine the sketch using actual repairs and extensions before freezing the first Interface and author contract.

Preserve `render_visual` and existing exports for compatibility. Do not replace existing Pi calls with an unverified Interface. A transitional Adapter translates old inputs and results rather than duplicating new layout policy.

### Deletion test

Removing the ShowMe Module would redistribute version resolution, environment selection, defect repair, and acceptance logic across MCP, CLI, Pi, and test callers: it should therefore provide real Depth. If removing an internal forwarding wrapper reduces complexity instead, do not retain it merely for a tidy directory structure.
