---
title: @memhtml/html
---

`@memhtml/html` is the memory file format: parse, serialize, hash, fence-language detection, the surgical head editors, the template that writes a new file, and the closed vocabulary all of them read. The format is semantic HTML5 over that vocabulary and this package is its only implementation, so a memory file stays a document a browser renders with no server, and the index stays derivable from the tree alone. Every element in the vocabulary earns its place by carrying indexer semantics, which is why the parse output is named for what the indexer stores rather than for the markup it came from: `gist` is the one `<mark>`, `eventAt` is the first `<time>`, `facets` are the `<dl>` pairs. The package sits on `parse5`, `effect`, a pinned `highlight.js`, and `@memhtml/contracts` for the closed edge, type and error vocabularies.

`vocabulary.ts` is the bottom of the stack and holds no logic, because the vocabulary IS the policy: there is no sanitizer library here and no allow/deny engine, only data. Both metadata planes use the same hyphenated prefix (`META_PREFIX`, `LINK_REL_PREFIX`) because HTML5 metadata names are a flat token space and a `rel` token cannot hold a colon at all. `REQUIRED_META` is the four facts no pure function can invent, a type, a status, and the two write stamps; `memhtml-confidence`, `memhtml-importance` and `memhtml-author` are deliberately absent because the `files` table documents a default for each, so a hand-authored file missing them is completed rather than refused. `META_ORDER` is the emit order and a diff-stability contract: a new scalar goes at the end of the scalar block and a new repeatable at the end of the repeatable block, so two agents stamping different keys leave each other's lines in place. `REPEATABLE_META` names the three keys that may appear more than once, one element per value so correcting one tag is a one-line diff, and `isMemoryMetaName` and `isRepeatableMeta` are the predicates over both lists. The element tables split by role: `DOCUMENT_ELEMENTS` is the skeleton that carries no indexer semantics, `ARTICLE_ELEMENTS` is one entry per row of the format's element table (with `tr` added, because a `<table>` cannot hold a cell without a row), `PERSON_ELEMENTS` is the `<address>` a person file adds, `FIGURE_SCOPED_ELEMENTS` is `<div>` and `<span>` permitted only inside a `<figure>` where a pasted sample carries its own containers, and `KNOWN_ELEMENTS` is their union. The rest are serialization and scoping facts the writer and the hash need: `VOID_ELEMENTS`, `GIST_EXCLUDED_ELEMENTS` (a command line is body text and searchable, and it is not the claim), `FORBIDDEN_ELEMENTS` and `FORBIDDEN_ATTRIBUTES`.

`tree.ts` is parse5 navigation narrowed to what the format needs, pure, total, and ignorant of the vocabulary. Source locations are always on, because the head editors splice by byte offset and a second parse to obtain them would let two views of the same bytes disagree. `parseArticleFragment` parses article inner HTML in `<article>` context on purpose: fragment parsing without a context element runs in `<template>` content, where table-scoped elements are foster-parented out and their text would vanish from the digest, so parsing in the element the markup came from is what makes `contentHash` agree on a doc and on the whole file. The walks are iterative rather than recursive so a pathologically deep hand-authored file cannot overflow the stack. `markup.ts` is the writer, and it exists because parse5's own serializer is unusable here for two reasons. The costlier one is `<pre>`: the parser swallows one newline after the start tag and parse5 does not re-emit it, so a file loses one newline on every write, and `<pre>` whitespace is inside the hash scope verbatim, so that drift would move a memory's dedup key on a pass that edited nothing. The second is attribute order, which parse5 preserves, leaving two files differing only in attribute order as different bytes forever; sorting by name canonicalizes them. `escapeText` writes U+00A0 as `&nbsp;` because an invisible character in a claim is a trap, and `escapeAttribute` turns line breaks into character references so an emitted `<meta>` or `<link>` is always one source line, which is what the line-splicing editors depend on.

`hash.ts` owns the one value in the system that must be invariant under head edits. The content hash is `sha256` over the whitespace-normalized text content of `<article>`, except inside `<pre>` where whitespace passes through byte for byte, so meta and `<link>` edits are outside the scope by construction and confidence decay, access bookkeeping and the sleep phases' own stamping never look like content changes. Without that invariance a corpus-wide decay pass would present the whole corpus as new content and dedup would collapse. Only ASCII whitespace collapses; U+00A0 is content, because a non-breaking space inside a claim is a typographic decision worth preserving. A block element contributes a collapsible space at each edge, so the digest is a function of the article's words and not of its indentation, and the outer trim applies only to a leading or trailing collapsible segment, since trimming the whole result would let `<pre>  a</pre>` and `<pre>a</pre>` hash identically. `canonicalText` takes `CanonicalTextOptions`, whose `excludeCode` omits `<pre>` and `<code>` per the gist rule, `canonicalArticleText` is the same fold with code kept, and `contentHash` accepts a parsed doc, an article node, a `HashableArticle`, or raw HTML, locating `<article>` first so head content never reaches the digest and hashing a string with no article as article-inner-HTML rather than failing, because refusing malformed input is `parseMemory`'s job and not the digest's. `HASH_ALGORITHM` is the prefix that makes a stored digest self-describing and `isContentHash` recognizes the `sha256:<64 hex>` form.

`constraints.ts` is the six format constraints as pure predicates over a parsed document. Constraints 1 through 5 are violations and the file is not a memory; constraint 6 is a warning, because an element outside the vocabulary still indexes and the format has to degrade gracefully on a file a human hand-wrote in a hurry. Nothing here throws and nothing repairs: a checker that silently fixed a violation would make `memhtml doctor` report a clean corpus that the next hand-edit breaks again. `isValidDatetime` admits exactly two forms, an ISO date and a canonical UTC instant, and is narrower than HTML's own `datetime` grammar because `files.event_at`, `files.due_at` and `files.valid_until` are compared and ordered as raw strings, so every admitted value has to sort lexicographically as it sorts chronologically; a space separator, a non-UTC offset, or optional seconds each break that, and range is checked too so `2026-13-45` is refused rather than stored as an unsortable date. `isRootRelativeHref` requires the document-reference form, repo-root-relative with a leading slash and no scheme, host or `..` segment, since a relative href breaks on the first `git mv` of the source file and a protocol-relative one silently leaves the repo. The `<mark>` rules are the format's center: exactly one, non-empty, leading the article's first `<p>` or `<li>`, and never inside an `<aside>` or `<details>`, so a recall line cannot quote a caveat or something the author chose to hide. Emptiness is tested with the real gist rule (`canonicalText` with `excludeCode`, then trimmed) rather than a convenient approximation, because `parse.ts` derives `gist` from exactly that text, so `<mark><code>drain --vip</code></mark>` indexes with no gist and is refused. `checkDocument` collects rather than short-circuits, so one parse tells an author everything wrong with the file, and returns a `CheckResult` of violations and warnings in constraint order then document order, with warnings deduplicated by element name so forty stray `<div>`s produce one actionable line. `VIOLATION_SEPARATOR` is how that list is joined into the single string `InvalidMemory.reason` carries.

`parse.ts` implements the extraction table one element at a time, and the interesting part is what it refuses versus what it drops. A malformed optional meta is dropped and left for `memhtml doctor`: `memhtml-confidence="high"` means the file stated no confidence and the `files` default applies, and a blank value is malformed rather than zero, since `Number("")` is `0` and a blank confidence must not index as `0.00`. The datetime metas and the task metas are refusals instead, because a drop is only safe where the `files` table owns a default and an instant has none: dropping an unsortable `memhtml-valid-until` WIDENS the window to always-valid, so the file would answer an as-of query for instants it said the fact was already dead, and a `task` with no `memhtml-task-status` has no lifecycle position at all, so it would be invisible to the surface that exists to show it. `parseMemory` fails with `InvalidMemory` and no partial doc, and `checkMemory` is the total variant that returns the structured violation and warning lists without building one. `document.ts` holds the shapes, as Effect schemas paired with the interfaces they decode to, and they live here rather than in `@memhtml/contracts` because they are format types: the extraction fields exist only because the HTML has those elements. `MemoryMetas` states each field's coordinate space on the field, and an absent value means the file did not state it, with no default substituted, so a hand-authored omission stays distinguishable from a deliberate assertion. `ArticleExtractions` is what the indexer reads out of `<article>`, with `html` a serialization fixed point, `bodyText` the FTS and embedding input including asides, details bodies, captions and `<pre>`, `gist` the one span nothing derives, `eventAt` the world time the recency arm coalesces with the write stamp, and the document-order lists (`facets`, `citations`, `definedTerms`, `summaryTexts`, `asideTexts`, `captions`, `codeLangs`, `abbreviations`) each feeding their own table or entity promotion. `MemoryLink` carries an unprefixed rel from the closed edge vocabulary with the href as the file spells it, `Facet` pairs a `<dt>` with each of its `<dd>`s and carries a `numericValue` only when a `<data value>` parses as a finite number, deliberately unitless because the unit lives in the human phrasing, and `Citation` is a `<cite>` or a `<q>` with its optional source URI.

`serialize.ts` is the inverse: `parseMemory(serializeMemory(doc))` yields the doc again, which is the property that lets sleep read, adjust and write a file back without touching content it did not mean to touch. The output is deterministic, one `<meta>` per line in `META_ORDER` with no head indentation, so stamping `memhtml-updated` produces a one-line git diff a human actually reviews, and `article.html` is re-parsed and re-serialized rather than interpolated so a hand-assembled doc still gets the canonical fixed-point markup. `metaPairs` is the ordered `[name, content]` expansion, repeatable keys one pair per value, confidence rendered to two decimals and every other number as an integer. `editors.ts` is the alternative to that round trip for a bookkeeping pass: byte-level splices that change exactly one line and provably do not touch the article. The sleep phases stamp `memhtml-updated`, decay `memhtml-confidence`, bump `memhtml-reprieves` and set `memhtml-needs-revision` on files they otherwise leave alone, and re-serializing the whole document for that would make the pass look like a content change in `git diff` and risk moving the dedup key. Splicing by source offset keeps the hash invariant by construction, so `contentHash(setMeta(html, name, value))` equals `contentHash(html)` for every name. `setMeta` replaces the first meta of a name or inserts a line in `META_ORDER` position and refuses an unknown name by returning the input unchanged, `addMeta` appends another value of a repeatable name and is a no-op on a value already present so a re-run of a phase cannot grow the head, `addLink` is idempotent on the `(rel, href)` pair because the conflict phase promotes the same corroborated edge on each run and a duplicated `<link>` would become a duplicated `edges` row, `removeMeta` and `removeLink` cut whole lines (omitting `href` drops every link of that rel), and `readMeta` and `readLinks` are the deliberately tolerant read halves: the document is parsed and nothing is validated, so a caller holding raw bytes can ask what a file points at without the file having to be a well-formed memory.

`fences.ts` owns the fenced-code grammar and only the grammar: what opens a fence, what closes it, and what language its info string names. There is one copy because the template renders a block and the write doors split prose into paragraphs, and two answers to "is this line a fence?" would let the splitter keep a block intact that the template then fails to recognize. Backtick fences only, per CommonMark: three or more open, a run at least as long closes, and the info string may hold no backtick; tilde fences are deliberately absent because agents write backticks. `LANG_TOKEN` is the language-token grammar, wide enough for `ts`, `c++`, `c#` and `objective-c` and closed to whitespace and markup characters, so a `data-lang` value is always safe in view-source and safe to promote to a `lang:` entity. `fenceOpeningOf` and `closesFence` are the line-level predicates, and `fencedBlockOf` returns a `FencedBlock` only when the whole paragraph is the fence: prose sharing a paragraph with a fence is not a fence, and an unterminated fence is `undefined`, because rendering either as code would commit markup the author may not have finished while escaping it as text keeps the file saying what the author typed.

`detect.ts` is a port of a measured detector, not a fresh design, because an unlabeled fence carries no language and wrong metadata costs more than none. A private evaluation corpus swept two candidates, `flourite` and highlight.js `highlightAuto`, over 332 real fences and file slices and picked the operating point where measured precision first reaches a 95% floor: highlight.js won at threshold 0.28685957116771854 with precision 95.18% at 25.0% coverage, where `flourite` reached 100% precision at only 3.0% coverage, abstaining exactly where this one stamps. `DEPLOY_THRESHOLD` is 0.30, a conservative rounding up of that point, safe because confidence is monotone in evidence: re-measured on the same corpus it stamped 81 snippets, 77 correctly, for 95.06% precision at 24.4% coverage, and both numbers are recorded because the measured one is the evidence and the deployed one is the decision. `detect` returns a `Detection` with the threshold not yet applied, scoring `1 - exp(-(top - runnerUp) / lines)`, the per-line evidence margin between the winning grammar and its closest real competitor, where a runner-up normalizing to the same canonical token is not disagreement and so charges no penalty, and where hljs runs its full grammar set deliberately: restricting it to the twelve-name vocabulary measured 0.9% coverage against 25%, because with the true language's grammar absent a runner-up wins unopposed and wins confidently. `detectLang` applies both independent gates, in-vocabulary and at or above the threshold, since a confident detection of a language outside `CANONICAL_LANGS` is still nothing, and the corpus has hljs naming `smali` at 0.86 and `autohotkey` at 0.55 for snippets that are really bash and TypeScript. `CANONICAL_LANGS` is one lowercase token per language because `data-lang` promotes to a `lang:` entity by exact string match, and `normalizeLang` folds the aliases seen in detector output, info strings and file extensions (highlight.js names its HTML grammar "xml", ships no TOML grammar, and SQL dialects collapse because a dialect distinction is noise at entity granularity). Three operational decisions come with the port. highlight.js is pinned exactly, no caret, because relevance scores are grammar-dependent and a bump silently moves every confidence and therefore which fences get stamped; measured against 11.12.0, one snippet fell from 0.5406 to 0.1993 and stopped stamping `toml`, so a bump is a deliberate decision that re-runs the eval and re-derives the threshold. The library loads lazily on the first detection, because eagerly imported its 192 grammars cost roughly 100ms and 12MB in every process that touches the format layer, including the read path, which detects nothing. Fences longer than 4096 characters abstain without running hljs at all, since `highlightAuto` is super-linear in input size (5KB is about 450ms and 100KB about 122s of blocking CPU on the pinned build) and the MCP server is one single-threaded process, so an uncapped detector would let one large unlabeled fence wedge every other request. Detection is also write-time only: the stamp goes into the file, which is the system of record, and rebuild reads `data-lang` back through `parse.ts` and never re-detects, so a dropped and rebuilt index stays a pure function of the tree instead of a function of the installed hljs version. Author strings are untouched throughout, since this vocabulary gates detector output alone.

`template.ts` is what the write path calls instead of the serializer, because an agent supplies a title, a claim and prose, and something has to turn that into the `<mark>`-led first paragraph the format requires: an agent hand-authoring that placement would violate constraint 1 regularly, and a template that places it always places it correctly. `NewMemoryInput` mirrors the write tool's parameters, with `claim` required because a memory with no claim has nothing to disclose at Tier 1, `body` one string per paragraph, and `articleHtml` the escape hatch for a correction carrying its own `<dl>` or `<figure>`, where the caller then owns constraint 1. `articleHtmlFor` joins the first body paragraph onto the claim's own paragraph as its tail, drops empty paragraphs, and renders a body paragraph that is a fenced block as `<figure><pre><code data-lang>` rather than a `<p>`, never joined onto the claim, so the claim still leads the article and code stays out of the sentence; the language rides on `data-lang` because `class` is a constraint-3 violation and `lang` is a human-language attribute, and the info string wins outright, so `detectLang` runs only on an unlabeled fence and no detector opinion overrides what a human wrote. `DEFAULT_TASK_STATUS` is `todo`, defaulted rather than required of the caller because `parseMemory` refuses a task with no `memhtml-task-status` and it is stamped only for a task, since a non-task carrying one is a file git holds and the indexer skips. `newMemoryDoc` builds the doc with `memhtml-content-hash` already stamped from the article the template just built, so the file reaching disk is self-consistent and the indexer's own recomputation agrees with it on the first read, and `renderTemplate` is the one function the write path calls for bytes.

The package publishes one import path, `@memhtml/html`, which re-exports the eleven modules below, so the reference on this page is the whole exported surface. `tree.ts` is internal: it reaches consumers only as the parse5 node types the other modules accept and return.

| Module           | What it contributes                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `constraints.ts` | `checkDocument` and its `CheckResult`, `VIOLATION_SEPARATOR`, and the two value grammars `isValidDatetime` and `isRootRelativeHref`.                                                                                                                                                                                                                                                                                                                                          |
| `detect.ts`      | `CANONICAL_LANGS` and `CanonicalLang`, `normalizeLang`, `DEPLOY_THRESHOLD`, `detect` with its `Detection`, and `detectLang`.                                                                                                                                                                                                                                                                                                                                                  |
| `document.ts`    | `MemoryDoc`, `MemoryMetas`, `ArticleExtractions`, `MemoryLink`, `Facet` and `Citation`, each a schema paired with the interface it decodes to.                                                                                                                                                                                                                                                                                                                                |
| `editors.ts`     | The write half (`setMeta`, `addMeta`, `removeMeta`, `addLink`, `removeLink`) and the tolerant read half (`readMeta`, `readLinks`).                                                                                                                                                                                                                                                                                                                                            |
| `fences.ts`      | `LANG_TOKEN`, `fenceOpeningOf`, `closesFence`, and `fencedBlockOf` with its `FencedBlock`.                                                                                                                                                                                                                                                                                                                                                                                    |
| `hash.ts`        | `HASH_ALGORITHM`, `canonicalText` with `CanonicalTextOptions`, `canonicalArticleText`, `contentHash` with `HashableArticle`, and `isContentHash`.                                                                                                                                                                                                                                                                                                                             |
| `markup.ts`      | `escapeText`, `escapeAttribute`, `writeChildren` and `writeOuter`.                                                                                                                                                                                                                                                                                                                                                                                                            |
| `parse.ts`       | `parseMemory` (the doc or `InvalidMemory`) and `checkMemory` (the total violation and warning lists).                                                                                                                                                                                                                                                                                                                                                                         |
| `serialize.ts`   | `serializeMemory` and `metaPairs`.                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `template.ts`    | `NewMemoryInput`, `articleHtmlFor`, `newMemoryDoc`, `renderTemplate` and `DEFAULT_TASK_STATUS`.                                                                                                                                                                                                                                                                                                                                                                               |
| `tree.ts`        | Nothing on the package surface: the parse5 navigation and the two parsers the modules above share.                                                                                                                                                                                                                                                                                                                                                                            |
| `vocabulary.ts`  | The naming conventions (`META_PREFIX`, `LINK_REL_PREFIX`), the metadata lists (`REQUIRED_META`, `META_ORDER`, `MemoryMetaName`, `isMemoryMetaName`, `REPEATABLE_META`, `RepeatableMeta`, `isRepeatableMeta`), the element tables (`DOCUMENT_ELEMENTS`, `ARTICLE_ELEMENTS`, `PERSON_ELEMENTS`, `FIGURE_SCOPED_ELEMENTS`, `KNOWN_ELEMENTS`), and the serialization and scoping facts (`VOID_ELEMENTS`, `GIST_EXCLUDED_ELEMENTS`, `FORBIDDEN_ELEMENTS`, `FORBIDDEN_ATTRIBUTES`). |

## Interfaces

### ArticleExtractions

The parsed shape `ArticleExtractions` decodes to, named so a signature can refer to it.

#### Extends

- `ArticleExtractionsShape`

#### Properties

##### abbreviations

```ts
readonly abbreviations: readonly string[];
```

`<abbr title>` expansions in document order. FTS-visible.

###### Inherited from

`ArticleExtractionsShape.abbreviations`

##### asideTexts

```ts
readonly asideTexts: readonly string[];
```

`<aside>` texts in document order. In `bodyText` and therefore searchable, and left out of
a recall index line. An aside is a scope caveat, so quoting it as the memory
would present the exception as the rule.

###### Inherited from

`ArticleExtractionsShape.asideTexts`

##### bodyText

```ts
readonly bodyText: string = Schema.String;
```

All article text, whitespace-collapsed. The FTS body and the embedding input. Includes
`<aside>`, `<details>` bodies, `<figcaption>`, and `<pre>`, so everything is searchable.

###### Inherited from

`ArticleExtractionsShape.bodyText`

##### captions

```ts
readonly captions: readonly string[];
```

`<figcaption>` texts in document order. FTS-visible; the `<pre>` body is not gist-visible.

###### Inherited from

`ArticleExtractionsShape.captions`

##### citations

```ts
readonly citations: readonly object[];
```

`<cite>` and `<q>` in document order, one row each in `file_citations`.

###### Inherited from

`ArticleExtractionsShape.citations`

##### codeLangs

```ts
readonly codeLangs: readonly string[];
```

`data-lang` values of `<code>` elements, lowercased, in document order. Each promotes to a
`lang:<value>` entity the way a `<dfn>` promotes to `concept:`. A memory carrying a
TypeScript snippet is findable by `--entity lang:ts` without the author restating the
language in a `memhtml-entity` meta the fence's info string already carried.

###### Inherited from

`ArticleExtractionsShape.codeLangs`

##### definedTerms

```ts
readonly definedTerms: readonly string[];
```

`<dfn>` terms, in document order. Each promotes to a `concept:<term>` entity, so a
semantic memory that defines a term is findable by the term without the author also
writing a `memhtml-entity` meta.

###### Inherited from

`ArticleExtractionsShape.definedTerms`

##### eventAt?

```ts
readonly eventAt?: string;
```

The FIRST `<time datetime>` value, as authored (ISO date or ISO datetime, so `2026-07-28`
and `2026-07-28T14:03:11Z` both occur). This is when the remembered fact HAPPENED, so it is
world time and not write time. The recency arm ranks by `coalesce(event_at, updated_at)`, so an
episodic memory backdates correctly. Absent when the article names no time.

###### Inherited from

`ArticleExtractionsShape.eventAt`

##### facets

```ts
readonly facets: readonly object[];
```

`<dt>`/`<dd>` pairs in document order, one row each in `file_facets`.

###### Inherited from

`ArticleExtractionsShape.facets`

##### gist

```ts
readonly gist: string = Schema.String;
```

The ONE `<mark>` span's text, the claim and only the claim. It is the span the author chose,
the Tier-1 disclosure line, and the span a correction targets. Nothing derives it, so it is
not a summary and not the first sentence.

###### Inherited from

`ArticleExtractionsShape.gist`

##### html

```ts
readonly html: string = Schema.String;
```

The article's inner HTML, trimmed. A serialization fixed point: re-parsing and
re-serializing it yields the same bytes, which is what makes the round-trip property hold.

###### Inherited from

`ArticleExtractionsShape.html`

##### summaryTexts

```ts
readonly summaryTexts: readonly string[];
```

`<summary>` texts in document order. Always disclosed in recall, as Tier 2 of the fold.
The matching `<details>` body is Tier 3 and reaches an agent only through `memory_read`.

###### Inherited from

`ArticleExtractionsShape.summaryTexts`

***

### BlockTagInArticle

Which element's text holds a block tag, and the tag as the text reads.

#### Properties

##### element

```ts
readonly element: "mark" | "p";
```

##### tag

```ts
readonly tag: string;
```

***

### BlockTagInRun

Where a block tag sits in a text: the position it starts at, and the tag as written.

#### Properties

##### offset

```ts
readonly offset: number;
```

##### tag

```ts
readonly tag: string;
```

***

### CanonicalTextOptions

What [canonicalText](/api/html/#canonicaltext) may skip.

#### Properties

##### excludeCode?

```ts
readonly excludeCode?: boolean;
```

Omit `<pre>` and `<code>` subtrees, per the gist rule. A command line is body text and it
is searchable, and it is not part of the claim.

***

### CheckResult

The outcome of checking a document. Both lists are in constraint order, then document order.

#### Properties

##### violations

```ts
readonly violations: readonly string[];
```

##### warnings

```ts
readonly warnings: readonly string[];
```

***

### Citation

The parsed shape `Citation` decodes to, named so a signature can refer to it.

#### Extends

- `CitationShape`

#### Properties

##### href?

```ts
readonly href?: string;
```

###### Inherited from

`CitationShape.href`

##### text

```ts
readonly text: string = Schema.String;
```

###### Inherited from

`CitationShape.text`

***

### Detection

What the detector concluded, threshold not yet applied. Exported for tests and for the sweep.

#### Properties

##### confidence

```ts
readonly confidence: number;
```

Monotone evidence score in [0, 1). NOT a calibrated probability, and meaningful only against [DEPLOY\_THRESHOLD](/api/html/#deploy_threshold).

##### lang

```ts
readonly lang: 
  | "html"
  | "javascript"
  | "typescript"
  | "python"
  | "bash"
  | "json"
  | "sql"
  | "yaml"
  | "toml"
  | "css"
  | "go"
  | "rust"
  | undefined;
```

Canonical language, or `undefined` when hljs abstained or named a language outside the vocabulary.

***

### Facet

The parsed shape `Facet` decodes to, named so a signature can refer to it.

#### Extends

- `FacetShape`

#### Properties

##### name

```ts
readonly name: string = Schema.String;
```

###### Inherited from

`FacetShape.name`

##### numericValue?

```ts
readonly numericValue?: number;
```

###### Inherited from

`FacetShape.numericValue`

##### value

```ts
readonly value: string = Schema.String;
```

###### Inherited from

`FacetShape.value`

***

### FencedBlock

One recognized fenced block: its code verbatim, and the info string's language when it names one.

#### Properties

##### code

```ts
readonly code: string;
```

The lines between the fences, joined verbatim, with indentation and blank lines preserved.

##### lang?

```ts
readonly lang?: string;
```

The first info-string token, lowercased, when it matches [LANG\_TOKEN](/api/html/#lang_token).

***

### HashableArticle

What [contentHash](/api/html/#contenthash-1) accepts. A caller that already holds a parsed article passes the
node; the store and indexer, which hold bytes, pass a string or the article HTML.

#### Properties

##### article

```ts
readonly article: object;
```

###### html

```ts
readonly html: string;
```

***

### MemoryDoc

The parsed shape `MemoryDoc` decodes to, named so a signature can refer to it.

#### Extends

- `MemoryDocShape`

#### Properties

##### aliases

```ts
readonly aliases: readonly string[];
```

`memhtml-alias` values as authored, in document order. The other names this file's subject is
recorded under — a person file's declaration that `laura` and `l.desabelin` are the same person
as its own `person:` entity.

Meant as EVIDENCE for entity resolution, which can merge an alias-backed pair whatever
the name similarity says. That is why the field is a bare string list rather than a parsed
`type:name`: the declaring file's own `memhtml-entity` already carries the type, and an alias
that restated it could disagree with it.

###### Inherited from

`MemoryDocShape.aliases`

##### article

```ts
readonly article: object = ArticleExtractions;
```

###### abbreviations

```ts
readonly abbreviations: readonly string[];
```

`<abbr title>` expansions in document order. FTS-visible.

###### asideTexts

```ts
readonly asideTexts: readonly string[];
```

`<aside>` texts in document order. In `bodyText` and therefore searchable, and left out of
a recall index line. An aside is a scope caveat, so quoting it as the memory
would present the exception as the rule.

###### bodyText

```ts
readonly bodyText: string = Schema.String;
```

All article text, whitespace-collapsed. The FTS body and the embedding input. Includes
`<aside>`, `<details>` bodies, `<figcaption>`, and `<pre>`, so everything is searchable.

###### captions

```ts
readonly captions: readonly string[];
```

`<figcaption>` texts in document order. FTS-visible; the `<pre>` body is not gist-visible.

###### citations

```ts
readonly citations: readonly object[];
```

`<cite>` and `<q>` in document order, one row each in `file_citations`.

###### codeLangs

```ts
readonly codeLangs: readonly string[];
```

`data-lang` values of `<code>` elements, lowercased, in document order. Each promotes to a
`lang:<value>` entity the way a `<dfn>` promotes to `concept:`. A memory carrying a
TypeScript snippet is findable by `--entity lang:ts` without the author restating the
language in a `memhtml-entity` meta the fence's info string already carried.

###### definedTerms

```ts
readonly definedTerms: readonly string[];
```

`<dfn>` terms, in document order. Each promotes to a `concept:<term>` entity, so a
semantic memory that defines a term is findable by the term without the author also
writing a `memhtml-entity` meta.

###### eventAt?

```ts
readonly eventAt?: string;
```

The FIRST `<time datetime>` value, as authored (ISO date or ISO datetime, so `2026-07-28`
and `2026-07-28T14:03:11Z` both occur). This is when the remembered fact HAPPENED, so it is
world time and not write time. The recency arm ranks by `coalesce(event_at, updated_at)`, so an
episodic memory backdates correctly. Absent when the article names no time.

###### facets

```ts
readonly facets: readonly object[];
```

`<dt>`/`<dd>` pairs in document order, one row each in `file_facets`.

###### gist

```ts
readonly gist: string = Schema.String;
```

The ONE `<mark>` span's text, the claim and only the claim. It is the span the author chose,
the Tier-1 disclosure line, and the span a correction targets. Nothing derives it, so it is
not a summary and not the first sentence.

###### html

```ts
readonly html: string = Schema.String;
```

The article's inner HTML, trimmed. A serialization fixed point: re-parsing and
re-serializing it yields the same bytes, which is what makes the round-trip property hold.

###### summaryTexts

```ts
readonly summaryTexts: readonly string[];
```

`<summary>` texts in document order. Always disclosed in recall, as Tier 2 of the fold.
The matching `<details>` body is Tier 3 and reaches an agent only through `memory_read`.

###### Inherited from

`MemoryDocShape.article`

##### entities

```ts
readonly entities: readonly string[];
```

`memhtml-entity` values as authored, e.g. `service:checkout-api`, in document order.

###### Inherited from

`MemoryDocShape.entities`

##### links

```ts
readonly links: readonly object[];
```

###### Inherited from

`MemoryDocShape.links`

##### metas

```ts
readonly metas: object = MemoryMetas;
```

###### archivedAt?

```ts
readonly archivedAt?: string;
```

When eviction moved it under `archive/<YYYY>/`. Present iff `status` is `archived`.

###### author?

```ts
readonly author?: string;
```

Who wrote it, as `agent:<model>` or `human:<name>`.

###### confidence?

```ts
readonly confidence?: number;
```

Unitless in `[0, 1]`. 1.0 is an unqualified assertion.

###### contentHash?

```ts
readonly contentHash?: string;
```

The `sha256:<hex>` the file claims for its own article. Advisory: the parser reports it
verbatim and leaves it alone, so a stale value is visible to `memhtml doctor` rather than
silently corrected into agreement.

###### createdAt

```ts
readonly createdAt: string = Schema.String;
```

###### dueAt?

```ts
readonly dueAt?: string;
```

When a task is due. An ISO date or datetime, ordered as a string exactly as `event_at` is,
so `due_at < now` is a lexicographic comparison rather than a parse per row.

A wall-clock DEADLINE. `validUntil` says when a remembered fact stops being true, and this
says when work is late, so neither a write time nor a validity bound belongs here.

###### importance?

```ts
readonly importance?: number;
```

1-10 inclusive, a display ordinal. The retention scorer divides by 10 before using it.

###### memoryType

```ts
readonly memoryType: 
  | "episodic"
  | "semantic"
  | "procedural"
  | "agent_insight"
  | "user_preference"
  | "error_pattern"
  | "verdict"
  | "precedent"
  | "arc"
  | "task" = MemoryType;
```

###### needsRevision?

```ts
readonly needsRevision?: boolean;
```

A curation pass flagged the claim as stale or contested and wants an agent to revisit it.

###### promptId?

```ts
readonly promptId?: string;
```

The prompt within that session. Joins `trace_prompts.prompt_id`.

###### reprieves?

```ts
readonly reprieves?: number;
```

How many times a retention pass spared this memory from eviction. A count, monotonically
non-decreasing, `>= 0`.

###### sessionId?

```ts
readonly sessionId?: string;
```

The Claude Code session that produced it. Joins `traces.session_id`.

###### status

```ts
readonly status: "active" | "archived" = MemoryStatus;
```

###### supersededBy?

```ts
readonly supersededBy?: string;
```

The path that replaced it, repo-root-relative with a leading `/` (the document-reference
form). The inverse of a `memhtml-supersedes` link on the newer file.

###### taskStatus?

```ts
readonly taskStatus?: "todo" | "doing" | "blocked" | "done";
```

A task's own lifecycle position, present iff `memoryType` is `task`. The parser reports a
violation either way round. A separate axis from [MemoryMetas.status](/api/html/#memorymetas), which stays
`active`/`archived` for a task as for anything else.

###### turnUuid?

```ts
readonly turnUuid?: string;
```

The turn within that session. Joins `trace_prompts.turn_uuid`.

###### updatedAt

```ts
readonly updatedAt: string = Schema.String;
```

###### validFrom?

```ts
readonly validFrom?: string;
```

Bitemporal validity of the *fact*, not of the row. Absent means always-valid.

###### validUntil?

```ts
readonly validUntil?: string;
```

###### Inherited from

`MemoryDocShape.metas`

##### tags

```ts
readonly tags: readonly string[];
```

`memhtml-tag` values as authored, in document order. Open vocabulary.

###### Inherited from

`MemoryDocShape.tags`

##### title

```ts
readonly title: string = Schema.String;
```

The `<title>` text. The human name of the memory and the slug's source.

###### Inherited from

`MemoryDocShape.title`

##### warnings

```ts
readonly warnings: readonly string[];
```

Vocabulary warnings, such as an element outside the closed vocabulary or a `<div>` outside
a `<figure>`. Format constraint 6: the file still parses and still indexes, so a
hand-authored file degrades gracefully instead of being refused.

###### Inherited from

`MemoryDocShape.warnings`

***

### MemoryLink

The parsed shape `MemoryLink` decodes to, named so a signature can refer to it.

#### Extends

- `MemoryLinkShape`

#### Properties

##### href

```ts
readonly href: string = Schema.String;
```

###### Inherited from

`MemoryLinkShape.href`

##### rel

```ts
readonly rel: 
  | "supersedes"
  | "contradicts"
  | "caused_by"
  | "leads_to"
  | "part_of"
  | "relates_to"
  | "example_of"
  | "supports"
  | "laterally_related"
  | "about_person"
  | "authored_by"
  | "from_session"
  | "blocks"
  | "subtask_of" = EdgeRel;
```

###### Inherited from

`MemoryLinkShape.rel`

***

### MemoryMetas

The parsed shape `MemoryMetas` decodes to, named so a signature can refer to it.

#### Extends

- `MemoryMetasShape`

#### Properties

##### archivedAt?

```ts
readonly archivedAt?: string;
```

When eviction moved it under `archive/<YYYY>/`. Present iff `status` is `archived`.

###### Inherited from

`MemoryMetasShape.archivedAt`

##### author?

```ts
readonly author?: string;
```

Who wrote it, as `agent:<model>` or `human:<name>`.

###### Inherited from

`MemoryMetasShape.author`

##### confidence?

```ts
readonly confidence?: number;
```

Unitless in `[0, 1]`. 1.0 is an unqualified assertion.

###### Inherited from

`MemoryMetasShape.confidence`

##### contentHash?

```ts
readonly contentHash?: string;
```

The `sha256:<hex>` the file claims for its own article. Advisory: the parser reports it
verbatim and leaves it alone, so a stale value is visible to `memhtml doctor` rather than
silently corrected into agreement.

###### Inherited from

`MemoryMetasShape.contentHash`

##### createdAt

```ts
readonly createdAt: string = Schema.String;
```

###### Inherited from

`MemoryMetasShape.createdAt`

##### dueAt?

```ts
readonly dueAt?: string;
```

When a task is due. An ISO date or datetime, ordered as a string exactly as `event_at` is,
so `due_at < now` is a lexicographic comparison rather than a parse per row.

A wall-clock DEADLINE. `validUntil` says when a remembered fact stops being true, and this
says when work is late, so neither a write time nor a validity bound belongs here.

###### Inherited from

`MemoryMetasShape.dueAt`

##### importance?

```ts
readonly importance?: number;
```

1-10 inclusive, a display ordinal. The retention scorer divides by 10 before using it.

###### Inherited from

`MemoryMetasShape.importance`

##### memoryType

```ts
readonly memoryType: 
  | "episodic"
  | "semantic"
  | "procedural"
  | "agent_insight"
  | "user_preference"
  | "error_pattern"
  | "verdict"
  | "precedent"
  | "arc"
  | "task" = MemoryType;
```

###### Inherited from

`MemoryMetasShape.memoryType`

##### needsRevision?

```ts
readonly needsRevision?: boolean;
```

A curation pass flagged the claim as stale or contested and wants an agent to revisit it.

###### Inherited from

`MemoryMetasShape.needsRevision`

##### promptId?

```ts
readonly promptId?: string;
```

The prompt within that session. Joins `trace_prompts.prompt_id`.

###### Inherited from

`MemoryMetasShape.promptId`

##### reprieves?

```ts
readonly reprieves?: number;
```

How many times a retention pass spared this memory from eviction. A count, monotonically
non-decreasing, `>= 0`.

###### Inherited from

`MemoryMetasShape.reprieves`

##### sessionId?

```ts
readonly sessionId?: string;
```

The Claude Code session that produced it. Joins `traces.session_id`.

###### Inherited from

`MemoryMetasShape.sessionId`

##### status

```ts
readonly status: "active" | "archived" = MemoryStatus;
```

###### Inherited from

`MemoryMetasShape.status`

##### supersededBy?

```ts
readonly supersededBy?: string;
```

The path that replaced it, repo-root-relative with a leading `/` (the document-reference
form). The inverse of a `memhtml-supersedes` link on the newer file.

###### Inherited from

`MemoryMetasShape.supersededBy`

##### taskStatus?

```ts
readonly taskStatus?: "todo" | "doing" | "blocked" | "done";
```

A task's own lifecycle position, present iff `memoryType` is `task`. The parser reports a
violation either way round. A separate axis from [MemoryMetas.status](/api/html/#memorymetas), which stays
`active`/`archived` for a task as for anything else.

###### Inherited from

`MemoryMetasShape.taskStatus`

##### turnUuid?

```ts
readonly turnUuid?: string;
```

The turn within that session. Joins `trace_prompts.turn_uuid`.

###### Inherited from

`MemoryMetasShape.turnUuid`

##### updatedAt

```ts
readonly updatedAt: string = Schema.String;
```

###### Inherited from

`MemoryMetasShape.updatedAt`

##### validFrom?

```ts
readonly validFrom?: string;
```

Bitemporal validity of the *fact*, not of the row. Absent means always-valid.

###### Inherited from

`MemoryMetasShape.validFrom`

##### validUntil?

```ts
readonly validUntil?: string;
```

###### Inherited from

`MemoryMetasShape.validUntil`

***

### NewMemoryInput

What `memory_write` supplies. Mirrors the tool's parameters, with the format's own additions.

#### Properties

##### aliases?

```ts
readonly aliases?: readonly string[];
```

Other names this file's subject is recorded under, as `memhtml-alias` metas. A person file's
identity declaration, meant as merge evidence for entity resolution.

##### articleHtml?

```ts
readonly articleHtml?: string;
```

Pre-authored article markup, used verbatim in place of `claim`/`body`. The escape hatch for
a correction that carries a `<dl>` or a `<figure>`. It must already contain its own
`<mark>`, so the caller owns constraint 1 when it uses this.

##### at

```ts
readonly at: string;
```

ISO-8601 UTC instant of write time. Stamps both `memhtml-created` and `memhtml-updated`.

##### author?

```ts
readonly author?: string;
```

##### body?

```ts
readonly body?: readonly string[];
```

Prose after the claim, one paragraph per element. The claim's own paragraph is the first
one, so `body[0]` becomes the claim paragraph's tail rather than a second `<p>`.

##### claim

```ts
readonly claim: string;
```

The claim: exactly the text that becomes the one `<mark>` span and therefore `files.gist`.
Required, because a memory with no claim has nothing to disclose at Tier 1.

##### confidence?

```ts
readonly confidence?: number;
```

##### dueAt?

```ts
readonly dueAt?: string;
```

When a task is due. An ISO date or datetime, string-ordered.

##### entities?

```ts
readonly entities?: readonly string[];
```

`type:name` entity references, e.g. `service:checkout-api`.

##### importance?

```ts
readonly importance?: number;
```

##### links?

```ts
readonly links?: readonly object[];
```

##### memoryType

```ts
readonly memoryType: 
  | "episodic"
  | "semantic"
  | "procedural"
  | "agent_insight"
  | "user_preference"
  | "error_pattern"
  | "verdict"
  | "precedent"
  | "arc"
  | "task";
```

##### promptId?

```ts
readonly promptId?: string;
```

##### sessionId?

```ts
readonly sessionId?: string;
```

##### tags?

```ts
readonly tags?: readonly string[];
```

##### taskStatus?

```ts
readonly taskStatus?: "todo" | "doing" | "blocked" | "done";
```

A task's lifecycle position. Absent on a `task` defaults to [DEFAULT\_TASK\_STATUS](/api/html/#default_task_status);
absent on any other type stays absent, because only a task carries one.

##### title

```ts
readonly title: string;
```

The `<title>`, and the slug's source.

##### turnUuid?

```ts
readonly turnUuid?: string;
```

##### validFrom?

```ts
readonly validFrom?: string;
```

Bitemporal validity of the fact. Absent means always-valid.

##### validUntil?

```ts
readonly validUntil?: string;
```

## Type Aliases

### CanonicalLang

```ts
type CanonicalLang = typeof CANONICAL_LANGS[number];
```

***

### MemoryMetaName

```ts
type MemoryMetaName = typeof META_ORDER[number];
```

***

### ProseParagraph

```ts
type ProseParagraph = 
  | {
  claim?: string;
  index?: number;
  kind: "p";
  text?: string;
}
  | {
  block: FencedBlock;
  index: number;
  kind: "figure";
};
```

One paragraph of the article the prose path renders, before escaping: a `<p>` holding text, or
a `<figure>` holding a fenced block. `index` is the body paragraph it came from.

#### Union Members

##### Type Literal

```ts
{
  claim?: string;
  index?: number;
  kind: "p";
  text?: string;
}
```

###### claim?

```ts
readonly claim?: string;
```

The claim, on the first paragraph only: the text of its `<mark>`.

###### index?

```ts
readonly index?: number;
```

###### kind

```ts
readonly kind: "p";
```

###### text?

```ts
readonly text?: string;
```

The body paragraph's text, absent on a claim that stands alone.

***

##### Type Literal

```ts
{
  block: FencedBlock;
  index: number;
  kind: "figure";
}
```

***

### RepeatableMeta

```ts
type RepeatableMeta = typeof REPEATABLE_META[number];
```

## Variables

### ARTICLE\_ELEMENTS

```ts
const ARTICLE_ELEMENTS: readonly ["article", "mark", "time", "dl", "dt", "dd", "data", "cite", "q", "dfn", "figure", "figcaption", "details", "summary", "aside", "section", "abbr", "pre", "code", "kbd", "samp", "var", "table", "caption", "thead", "tbody", "tr", "th", "td", "p", "ul", "ol", "li", "a", "strong", "em"];
```

The body vocabulary, one entry per row of the format's element table.

`tr` is here although the table lists only `caption/thead/tbody/th/td`: a `<table>` cannot
hold a cell without a row, so refusing `tr` would make every real table warn. Nothing else
is added by inference. An element the format does not name is a warning, which is the
graceful-degradation rule for hand-authored files.

***

### ArticleExtractions

```ts
const ArticleExtractions: Struct<{
  abbreviations: $Array<String>;
  asideTexts: $Array<String>;
  bodyText: String;
  captions: $Array<String>;
  citations: $Array<Struct<{
     href: optional<String>;
     text: String;
  }>>;
  codeLangs: $Array<String>;
  definedTerms: $Array<String>;
  eventAt: optional<String>;
  facets: $Array<Struct<{
     name: String;
     numericValue: optional<Number>;
     value: String;
  }>>;
  gist: String;
  html: String;
  summaryTexts: $Array<String>;
}>;
```

What the indexer reads out of `<article>`. Field names are the indexer's own, so the indexing
pipeline consumes this struct without a translation layer.

***

### CANONICAL\_LANGS

```ts
const CANONICAL_LANGS: readonly ["typescript", "javascript", "python", "bash", "json", "sql", "yaml", "html", "toml", "css", "go", "rust"];
```

The languages a DETECTION may name. One canonical lowercase token each, because `data-lang`
promotes to a `lang:` entity by exact string match, so two spellings of TypeScript would be
two entities. Anything outside this list is "do not stamp".

***

### Citation

```ts
const Citation: Struct<{
  href: optional<String>;
  text: String;
}>;
```

One `<cite>` or `<q>`. `href` is the `<q cite>` URI when present, an absolute or
root-relative source URI, not necessarily a memory path.

***

### DEFAULT\_TASK\_STATUS

```ts
const DEFAULT_TASK_STATUS: TaskStatus = "todo";
```

The status a new task starts in.

Defaulted rather than required of the caller because `parseMemory` REFUSES a task with no
`memhtml-task-status`. A template that omitted it would render a file the format rejects, and
every `memhtml task add` would have to restate the obvious opening state.

***

### DEPLOY\_THRESHOLD

```ts
const DEPLOY_THRESHOLD: 0.3 = 0.3;
```

The confidence at or above which a detection is stamped: 0.30.

See the module header for provenance. This is the measured 0.28685957116771854 rounded in the
safe direction, not a guess and not a round number chosen for looking tidy.

***

### DOCUMENT\_ELEMENTS

```ts
const DOCUMENT_ELEMENTS: readonly ["html", "head", "body", "title", "meta", "link"];
```

The document skeleton. These carry no indexer semantics of their own; they exist so the
file is a valid HTML5 document a browser renders with no server.

***

### Facet

```ts
const Facet: Struct<{
  name: String;
  numericValue: optional<Number>;
  value: String;
}>;
```

One `<dt>`/`<dd>` pair. `name` is the `<dt>` text, `value` the `<dd>` text.

`numericValue` is present only when the `<dd>` holds a `<data value>` whose attribute parses
as a finite number. It is unitless here on purpose: the unit lives in the human phrasing
(`<data value="120">about two minutes</data>` is seconds because the prose says so), so a
consumer cannot read a unit off the number alone.

***

### FIGURE\_SCOPED\_ELEMENTS

```ts
const FIGURE_SCOPED_ELEMENTS: readonly ["div", "span"];
```

`<div>` and `<span>` are permitted only inside a `<figure>`, where a pasted code sample
legitimately carries its own markup. Outside a figure they are the generic-container habit
the closed vocabulary exists to refuse.

***

### FORBIDDEN\_ATTRIBUTES

```ts
const FORBIDDEN_ATTRIBUTES: ReadonlySet<string>;
```

Attributes forbidden anywhere: presentation is the stylesheet's job, not the memory's.

***

### FORBIDDEN\_ELEMENTS

```ts
const FORBIDDEN_ELEMENTS: ReadonlySet<string>;
```

Elements forbidden anywhere: a memory file is data, and data does not execute.

Beyond the script/style pair, the list bans every element that embeds a browsing context or
foreign resource (`iframe`, `frame`, `frameset`, `object`, `embed`, `applet`), rewrites the
document's own URL space (`base`), or submits data to a target (`form`). These are violations
rather than constraint-6 warnings because the corpus is published as a static site: a file
carrying one would execute, embed, or navigate in every reader's browser under the corpus's
own origin. `link`/`meta` need attribute-level rules instead (the scheme check and the
`http-equiv` refusal in `constraints.ts`), since both are required skeleton elements.

***

### GIST\_EXCLUDED\_ELEMENTS

```ts
const GIST_EXCLUDED_ELEMENTS: ReadonlySet<string>;
```

Elements whose text the gist must not absorb. A command line is body text and it is
searchable. The claim is prose in the `<mark>` span.

***

### HASH\_ALGORITHM

```ts
const HASH_ALGORITHM: "sha256" = "sha256";
```

The digest's algorithm prefix. A hash is self-describing so a stored value can be re-verified.

***

### KNOWN\_ELEMENTS

```ts
const KNOWN_ELEMENTS: ReadonlySet<string>;
```

Every element name the vocabulary knows, at any position.

***

### LANG\_TOKEN

```ts
const LANG_TOKEN: RegExp;
```

The language token grammar. Covers the identifiers real info strings carry, such as `ts`,
`c++`, `c#`, `objective-c`, and `python3`, while refusing whitespace and markup characters, so
a `data-lang` value is always safe in view-source and safe to promote to a `lang:` entity.

***

### LINK\_REL\_PREFIX

```ts
const LINK_REL_PREFIX: "memhtml-" = "memhtml-";
```

***

### MemoryDoc

```ts
const MemoryDoc: Struct<{
  aliases: $Array<String>;
  article: Struct<{
     abbreviations: $Array<String>;
     asideTexts: $Array<String>;
     bodyText: String;
     captions: $Array<String>;
     citations: $Array<Struct<{
        href: optional<String>;
        text: String;
     }>>;
     codeLangs: $Array<String>;
     definedTerms: $Array<String>;
     eventAt: optional<String>;
     facets: $Array<Struct<{
        name: String;
        numericValue: optional<Number>;
        value: String;
     }>>;
     gist: String;
     html: String;
     summaryTexts: $Array<String>;
  }>;
  entities: $Array<String>;
  links: $Array<Struct<{
     href: String;
     rel: Literals<readonly ["supersedes", "contradicts", "caused_by", "leads_to", "part_of", "relates_to", "example_of", "supports", "laterally_related", "about_person", "authored_by", "from_session", "blocks", "subtask_of"]>;
  }>>;
  metas: Struct<{
     archivedAt: optional<String>;
     author: optional<String>;
     confidence: optional<Number>;
     contentHash: optional<String>;
     createdAt: String;
     dueAt: optional<String>;
     importance: optional<Int>;
     memoryType: Literals<readonly ["episodic", "semantic", "procedural", "agent_insight", "user_preference", "error_pattern", "verdict", "precedent", "arc", "task"]>;
     needsRevision: optional<Boolean>;
     promptId: optional<String>;
     reprieves: optional<Number>;
     sessionId: optional<String>;
     status: Literals<readonly ["active", "archived"]>;
     supersededBy: optional<String>;
     taskStatus: optional<Literals<readonly ["todo", "doing", "blocked", "done"]>>;
     turnUuid: optional<String>;
     updatedAt: String;
     validFrom: optional<String>;
     validUntil: optional<String>;
  }>;
  tags: $Array<String>;
  title: String;
  warnings: $Array<String>;
}>;
```

A parsed memory file. Frozen: a consumer that wants a changed doc builds a new one, so a
shared doc cannot be mutated out from under the hash a caller already computed.

***

### MemoryLink

```ts
const MemoryLink: Struct<{
  href: String;
  rel: Literals<readonly ["supersedes", "contradicts", "caused_by", "leads_to", "part_of", "relates_to", "example_of", "supports", "laterally_related", "about_person", "authored_by", "from_session", "blocks", "subtask_of"]>;
}>;
```

One `<link rel="memhtml-*">`. `rel` is the unprefixed rel from the closed edge vocabulary; the
`memhtml-`-prefixed hyphenated token is the wire form and is re-derived on serialize.

`href` is the document-reference form, repo-root-relative *with* a leading slash, as it
appears in the file. The git-tree form the `edges` table stores drops that slash;
`@memhtml/contracts`'s `normalizePath` is the conversion, applied at the store boundary.

***

### MemoryMetas

```ts
const MemoryMetas: Struct<{
  archivedAt: optional<String>;
  author: optional<String>;
  confidence: optional<Number>;
  contentHash: optional<String>;
  createdAt: String;
  dueAt: optional<String>;
  importance: optional<Int>;
  memoryType: Literals<readonly ["episodic", "semantic", "procedural", "agent_insight", "user_preference", "error_pattern", "verdict", "precedent", "arc", "task"]>;
  needsRevision: optional<Boolean>;
  promptId: optional<String>;
  reprieves: optional<Number>;
  sessionId: optional<String>;
  status: Literals<readonly ["active", "archived"]>;
  supersededBy: optional<String>;
  taskStatus: optional<Literals<readonly ["todo", "doing", "blocked", "done"]>>;
  turnUuid: optional<String>;
  updatedAt: String;
  validFrom: optional<String>;
  validUntil: optional<String>;
}>;
```

The head's typed metadata. Absent means the file did not state it, and no default is
substituted. The `files` table owns the defaults, and a parser that invented `confidence:
1.0` would make a hand-authored omission indistinguishable from a deliberate assertion.

Timestamps are ISO-8601 UTC instants of *write* time. `createdAt` is when the memory was
first written and `updatedAt` when it last changed. When the remembered fact happened is
`article.eventAt` instead.

***

### META\_ORDER

```ts
const META_ORDER: readonly ["memhtml-type", "memhtml-status", "memhtml-created", "memhtml-updated", "memhtml-confidence", "memhtml-importance", "memhtml-content-hash", "memhtml-author", "memhtml-session", "memhtml-prompt", "memhtml-turn", "memhtml-valid-from", "memhtml-valid-until", "memhtml-reprieves", "memhtml-archived", "memhtml-superseded-by", "memhtml-needs-revision", "memhtml-task-status", "memhtml-due", "memhtml-entity", "memhtml-tag", "memhtml-alias"];
```

Every metadata name in the closed vocabulary, in the order the serializer emits them.
A stable order is what makes a meta-only edit a one-line git diff, so two writers stamping
different keys leave each other's lines in place.

***

### META\_PREFIX

```ts
const META_PREFIX: "memhtml-" = "memhtml-";
```

The memory file format's naming conventions. HTML5 metadata names are a flat token
space where colons are reserved-ish, and `rel` tokens cannot hold a colon at all,
so both planes use the same hyphenated prefix.

***

### PERSON\_ELEMENTS

```ts
const PERSON_ELEMENTS: readonly ["address"];
```

`<address>` is the contact surface a person file adds. Permitted everywhere rather than
only under `resources/people/`, because this module sees HTML and no path, and a warning
keyed on a directory would belong to `memhtml doctor`, not to the parser.

***

### REPEATABLE\_META

```ts
const REPEATABLE_META: readonly ["memhtml-entity", "memhtml-tag", "memhtml-alias"];
```

Meta keys that may appear more than once. Each value is its own `<meta>` element
rather than a comma-joined string, so correcting one tag is a one-line diff.

`memhtml-alias` is the third: a person file declares the other names the same person is recorded
under, so `laura de-sabelin` can state that `laura` is them. Entity resolution can read it as
EVIDENCE and merge an alias-backed pair whatever the character distance says, which no
string similarity can supply — `laura` against `laura de-sabelin` scores 0.476, below even the
review band. One meta per alias, for the same one-line-diff reason.

***

### REQUIRED\_META

```ts
const REQUIRED_META: readonly ["memhtml-type", "memhtml-status", "memhtml-created", "memhtml-updated"];
```

The metas a file must carry. Each of the five is a fact no pure function can invent: a
type cannot be guessed from prose, a status cannot be inferred, and a timestamp cannot be
synthesized without a clock. `memhtml-confidence`, `memhtml-importance`, and `memhtml-author` are
deliberately absent, because the `files` table documents a default for each (1.0, 5, `agent`),
so a hand-authored file missing them is completed rather than refused.

***

### VIOLATION\_SEPARATOR

```ts
const VIOLATION_SEPARATOR: "; " = "; ";
```

How violations are joined into `InvalidMemory.reason`, which carries a single string.

***

### VOID\_ELEMENTS

```ts
const VOID_ELEMENTS: ReadonlySet<string>;
```

Elements with no end tag, per the HTML serialization algorithm. The serializer emits
these as a start tag alone; emitting `</meta>` would make the file invalid HTML5.

## Functions

### addLink()

```ts
function addLink(
   html, 
   rel, 
   href
): string;
```

Append a `<link rel="memhtml-…">` edge. Idempotent on the `(rel, href)` pair, in any spelling of
the rel the reader accepts, because a caller can add the same edge on every run, as a session's
`link` op can, and a duplicated `<link>` would become a duplicated `edges` row.

#### Parameters

##### html

`string`

##### rel

  \| `"supersedes"`
  \| `"contradicts"`
  \| `"caused_by"`
  \| `"leads_to"`
  \| `"part_of"`
  \| `"relates_to"`
  \| `"example_of"`
  \| `"supports"`
  \| `"laterally_related"`
  \| `"about_person"`
  \| `"authored_by"`
  \| `"from_session"`
  \| `"blocks"`
  \| `"subtask_of"`

##### href

`string`

#### Returns

`string`

***

### addMeta()

```ts
function addMeta(
   html, 
   name, 
   value
): string;
```

Append another `<meta>` of a repeatable name, a new `memhtml-entity` or `memhtml-tag`, after the
last one already present. Adding a value that is already there is a no-op, so the operation
is idempotent and a re-run of a bookkeeping pass cannot grow the head.

#### Parameters

##### html

`string`

##### name

`string`

##### value

`string`

#### Returns

`string`

***

### articleHtmlFor()

```ts
function articleHtmlFor(input): string;
```

The article markup for an input: `articleHtml` verbatim when it is supplied, and otherwise the
paragraphs [proseParagraphs](/api/html/#proseparagraphs) plans for the claim and body.

#### Parameters

##### input

[`NewMemoryInput`](/api/html/#newmemoryinput)

#### Returns

`string`

***

### blockTagInArticle()

```ts
function blockTagInArticle(html): BlockTagInArticle | undefined;
```

The first `<p>`, or `<mark>` outside any `<p>`, in a memory file's article whose text holds a
block tag outside code, or `undefined` when none does.

A `<p>` is read whole, its `<mark>` included, because that is the paragraph the prose path
rendered: the claim, a space, and the first body paragraph. A `<mark>` outside a `<p>` (the
first `<li>` of authored markup) is read on its own. The text is what a reader sees, so
`&lt;p&gt;` in the file reads as `<p>` here.

#### Parameters

##### html

`string`

#### Returns

[`BlockTagInArticle`](/api/html/#blocktaginarticle) \| `undefined`

***

### blockTagInRun()

```ts
function blockTagInRun(text): BlockTagInRun | undefined;
```

The first block tag in a paragraph's text outside a backtick span, or `undefined` when there is
none. The text is read as the HTML parser will hold it in a `<p>`: line breaks in all three
spellings, NULs dropped. A backtick span opens and closes on one line, so a tag on a line of its
own is prose even when the lines around it carry backticks.

`offset` is the tag's position in `text` as given, and `tag` is the tag sliced from the line as
the parser reads it (backticks kept, NULs dropped), cut to TAG\_SHOWN characters.

#### Parameters

##### text

`string`

#### Returns

[`BlockTagInRun`](/api/html/#blocktaginrun) \| `undefined`

***

### canonicalArticleText()

```ts
function canonicalArticleText(root): string;
```

The digest's input. `canonicalText` with `<pre>`/`<code>` kept, so everything is hashed.

#### Parameters

##### root

`Node`

#### Returns

`string`

***

### canonicalText()

```ts
function canonicalText(root, options?): string;
```

The exact string the digest is taken over: article text with runs of ASCII whitespace
collapsed to one space, `<pre>` descendants passed through byte for byte.

Block-element edges contribute a collapsible space, so the hash is a function of the article's
*words* and not of its indentation: `<li>one</li><li>two</li>` and the same list pretty-printed
across lines yield one digest. Without that edge space the flat form would canonicalize to
`onetwo`, so reformatting a file would move its dedup key while changing nothing a reader can
see.

The outer trim is applied only to a leading or trailing *collapsible* segment. Trimming the
whole result would let `<pre>  a</pre>` and `<pre>a</pre>` hash identically, and the leading
whitespace of a code sample is exactly the kind of difference a `<pre>` exists to keep.

#### Parameters

##### root

`Node`

##### options?

[`CanonicalTextOptions`](/api/html/#canonicaltextoptions) = `{}`

#### Returns

`string`

***

### checkDocument()

```ts
function checkDocument(document): CheckResult;
```

Check a parsed document against all six constraints. Violations are collected rather than
short-circuited, so one parse tells an author everything wrong with the file.

#### Parameters

##### document

`Document`

#### Returns

[`CheckResult`](/api/html/#checkresult)

***

### checkMemory()

```ts
function checkMemory(html): object;
```

Check a file without building a doc: the structured `{ violations, warnings }` `memhtml doctor`
reports. Total, so a completely malformed string yields violations instead of throwing.

#### Parameters

##### html

`string`

#### Returns

`object`

##### violations

```ts
readonly violations: readonly string[];
```

##### warnings

```ts
readonly warnings: readonly string[];
```

***

### closesFence()

```ts
function closesFence(line, opening): boolean;
```

True when a line closes a fence opened by `opening`: same-or-longer backtick run, nothing else.

#### Parameters

##### line

`string`

##### opening

`string`

#### Returns

`boolean`

***

### contentHash()

```ts
function contentHash(input): string;
```

The content hash of an article, from a parsed document, an article node, or the article's
inner HTML. Passing whole-file HTML works too: the `<article>` element is located first, so
head content does not reach the digest.

#### Parameters

##### input

`string` \| `Node` \| [`HashableArticle`](/api/html/#hashablearticle)

#### Returns

`string`

***

### detect()

```ts
function detect(code): Detection;
```

hljs's own evidence, squeezed into the sweepable scalar the eval calibrated.

`confidence = 1 - exp(-(top - runnerUp) / lines)`, the per-line evidence MARGIN between the
best language and its closest REAL competitor. Two refinements carry their weight, and a grid
search over the alternatives (relative margin, top score alone, saturating absolute margin) put
all of them at ≤9% coverage against this shape's 25%:

 - Canonical-aware runner-up: when the runner-up normalizes to the SAME token as the winner
   (`pgsql` vs `n1ql`, `xml` vs `xhtml`), the margin is the FULL top score. A dialect duel is
   not disagreement about what to stamp, and charging it as one would abstain on the cases the
   detector is most right about.
 - Per-line normalization: absolute relevance grows with snippet length, so a raw margin
   conflates "confident" with "long". Margin per line does not.

hljs runs its FULL grammar set deliberately. Restricting `highlightAuto` to the 12-name
vocabulary measured 0.9% coverage against 25% at the precision floor: with the true language's
grammar absent, a runner-up wins unopposed and wins CONFIDENTLY, so the false positives land
exactly where the threshold cannot see them.

#### Parameters

##### code

`string`

#### Returns

[`Detection`](/api/html/#detection)

***

### detectLang()

```ts
function detectLang(code): 
  | "html"
  | "javascript"
  | "typescript"
  | "python"
  | "bash"
  | "json"
  | "sql"
  | "yaml"
  | "toml"
  | "css"
  | "go"
  | "rust"
  | undefined;
```

The canonical language to stamp on an unlabeled fence, or `undefined` to stamp nothing.

Both gates are independent and both must pass: the detection must be IN the vocabulary, and its
confidence must reach [DEPLOY\_THRESHOLD](/api/html/#deploy_threshold). A confident detection of a language outside the
vocabulary is still `undefined`. Measured on the corpus, hljs names `smali` at confidence 0.86
and `autohotkey` at 0.55 for snippets that are really bash and TypeScript. Confidence says only
"this grammar won by a wide margin", never "this grammar is one we stamp".

Pure and synchronous: hljs is synchronous, so the write path calls this inline with no Effect.

#### Parameters

##### code

`string`

#### Returns

  \| `"html"`
  \| `"javascript"`
  \| `"typescript"`
  \| `"python"`
  \| `"bash"`
  \| `"json"`
  \| `"sql"`
  \| `"yaml"`
  \| `"toml"`
  \| `"css"`
  \| `"go"`
  \| `"rust"`
  \| `undefined`

***

### escapeAttribute()

```ts
function escapeAttribute(value): string;
```

Escape an attribute value. Double quotes are the fixed quote style, so `<` and `>` need no
escape. Line breaks become character references so an emitted `<meta>` or `<link>` is always
one source line: the head editors splice by line boundaries, so a literal newline inside an
attribute would split one head entry across two of their lines. `\r` is referenced too,
because the HTML preprocessor folds a literal one into `\n` on re-parse.

#### Parameters

##### value

`string`

#### Returns

`string`

***

### escapeText()

```ts
function escapeText(text): string;
```

Escape a text run. U+00A0 becomes `&nbsp;` because a literal no-break space is invisible in
an editor and reads as an ordinary space in review. An invisible character in a memory's
claim is a trap, so the file names it.

#### Parameters

##### text

`string`

#### Returns

`string`

***

### fencedBlockOf()

```ts
function fencedBlockOf(paragraph): FencedBlock | undefined;
```

Parse a paragraph as a fenced block, or `undefined` when it is not one.

The whole paragraph must be the fence: an opening line, the code, a closing line. Prose sharing
a paragraph with a fence is not a fence. The paragraph splitter keeps a block intact as its own
paragraph, so a mixed paragraph means the author did not blank-line-separate their fence, and
escaping it as text is the graceful reading of that.

An unterminated fence (opener, no closer) is also `undefined`. Rendering it as code would commit
markup the author may not have finished. Rendering it as escaped text keeps the backticks
visible, so the file says what the author typed.

#### Parameters

##### paragraph

`string`

#### Returns

[`FencedBlock`](/api/html/#fencedblock) \| `undefined`

***

### fenceOpeningOf()

```ts
function fenceOpeningOf(line): string | undefined;
```

The backtick run of a fence-opening line, or `undefined` when the line opens no fence.
The run's length is what a closing line must meet or exceed.

#### Parameters

##### line

`string`

#### Returns

`string` \| `undefined`

***

### isContentHash()

```ts
function isContentHash(value): boolean;
```

True when a value is a well-formed `sha256:<64 hex>` digest.

#### Parameters

##### value

`string`

#### Returns

`boolean`

***

### isMemoryMetaName()

```ts
function isMemoryMetaName(name): name is "memhtml-entity" | "memhtml-tag" | "memhtml-alias" | "memhtml-type" | "memhtml-status" | "memhtml-created" | "memhtml-updated" | "memhtml-confidence" | "memhtml-importance" | "memhtml-content-hash" | "memhtml-author" | "memhtml-session" | "memhtml-prompt" | "memhtml-turn" | "memhtml-valid-from" | "memhtml-valid-until" | "memhtml-reprieves" | "memhtml-archived" | "memhtml-superseded-by" | "memhtml-needs-revision" | "memhtml-task-status" | "memhtml-due";
```

True when a `memhtml-`-prefixed metadata name is in the closed vocabulary.

#### Parameters

##### name

`string`

#### Returns

name is "memhtml-entity" \| "memhtml-tag" \| "memhtml-alias" \| "memhtml-type" \| "memhtml-status" \| "memhtml-created" \| "memhtml-updated" \| "memhtml-confidence" \| "memhtml-importance" \| "memhtml-content-hash" \| "memhtml-author" \| "memhtml-session" \| "memhtml-prompt" \| "memhtml-turn" \| "memhtml-valid-from" \| "memhtml-valid-until" \| "memhtml-reprieves" \| "memhtml-archived" \| "memhtml-superseded-by" \| "memhtml-needs-revision" \| "memhtml-task-status" \| "memhtml-due"

***

### isRepeatableMeta()

```ts
function isRepeatableMeta(name): name is "memhtml-entity" | "memhtml-tag" | "memhtml-alias";
```

True when a metadata name may legitimately appear more than once in one head.

#### Parameters

##### name

`string`

#### Returns

name is "memhtml-entity" \| "memhtml-tag" \| "memhtml-alias"

***

### isRootRelativeHref()

```ts
function isRootRelativeHref(href): boolean;
```

True when a `<link>` href is the document-reference form the format requires:
repo-root-relative with a leading slash, no scheme, no host, no `..` segment.

A relative href would break on the first `git mv` of the *source* file and a protocol-relative
`//host/x` would silently leave the repo, so both are refused rather than normalized.

#### Parameters

##### href

`string`

#### Returns

`boolean`

***

### isValidDatetime()

```ts
function isValidDatetime(value): boolean;
```

True when a `datetime` value is one this format accepts: a calendar date, or a date with a
UTC time. Narrower than HTML's own `datetime` grammar (which admits durations, weeks, bare
times, offsets, and variable precision) because `files.event_at` and `files.due_at` are
compared and ordered as strings. A value that does not sort lexicographically alongside the
others would corrupt the recency arm and the overdue query alike.

Range is checked too, so `2026-13-45` is refused rather than stored as an unsortable date.

#### Parameters

##### value

`string`

#### Returns

`boolean`

***

### metaPairs()

```ts
function metaPairs(doc): readonly (readonly [
  | "memhtml-entity"
  | "memhtml-tag"
  | "memhtml-alias"
  | "memhtml-type"
  | "memhtml-status"
  | "memhtml-created"
  | "memhtml-updated"
  | "memhtml-confidence"
  | "memhtml-importance"
  | "memhtml-content-hash"
  | "memhtml-author"
  | "memhtml-session"
  | "memhtml-prompt"
  | "memhtml-turn"
  | "memhtml-valid-from"
  | "memhtml-valid-until"
  | "memhtml-reprieves"
  | "memhtml-archived"
  | "memhtml-superseded-by"
  | "memhtml-needs-revision"
  | "memhtml-task-status"
  | "memhtml-due", string])[];
```

The metas of a doc as `[name, content]` pairs in [META\_ORDER](/api/html/#meta_order), repeatable keys expanded
to one pair per value. A meta whose value is absent contributes nothing, so the file states
what it knows and the `files` defaults cover the rest.

#### Parameters

##### doc

[`MemoryDoc`](/api/html/#memorydoc)

#### Returns

readonly (readonly \[
  \| `"memhtml-entity"`
  \| `"memhtml-tag"`
  \| `"memhtml-alias"`
  \| `"memhtml-type"`
  \| `"memhtml-status"`
  \| `"memhtml-created"`
  \| `"memhtml-updated"`
  \| `"memhtml-confidence"`
  \| `"memhtml-importance"`
  \| `"memhtml-content-hash"`
  \| `"memhtml-author"`
  \| `"memhtml-session"`
  \| `"memhtml-prompt"`
  \| `"memhtml-turn"`
  \| `"memhtml-valid-from"`
  \| `"memhtml-valid-until"`
  \| `"memhtml-reprieves"`
  \| `"memhtml-archived"`
  \| `"memhtml-superseded-by"`
  \| `"memhtml-needs-revision"`
  \| `"memhtml-task-status"`
  \| `"memhtml-due"`, `string`\])[]

***

### newMemoryDoc()

```ts
function newMemoryDoc(input): MemoryDoc;
```

A fresh `MemoryDoc` for an input, with `memhtml-content-hash` already stamped from the article the
template just built, so the file that reaches disk is self-consistent and the indexer's own
recomputation agrees with it on the first read.

#### Parameters

##### input

[`NewMemoryInput`](/api/html/#newmemoryinput)

#### Returns

[`MemoryDoc`](/api/html/#memorydoc)

***

### normalizeLang()

```ts
function normalizeLang(raw): 
  | "html"
  | "javascript"
  | "typescript"
  | "python"
  | "bash"
  | "json"
  | "sql"
  | "yaml"
  | "toml"
  | "css"
  | "go"
  | "rust"
  | undefined;
```

Canonical token for a raw language name, or `undefined` when it is outside the vocabulary.

#### Parameters

##### raw

`string`

#### Returns

  \| `"html"`
  \| `"javascript"`
  \| `"typescript"`
  \| `"python"`
  \| `"bash"`
  \| `"json"`
  \| `"sql"`
  \| `"yaml"`
  \| `"toml"`
  \| `"css"`
  \| `"go"`
  \| `"rust"`
  \| `undefined`

***

### parseMemory()

```ts
function parseMemory(html): Effect<MemoryDoc, InvalidMemory>;
```

Parse a memory file. Fails with `InvalidMemory` whose `reason` is every violation joined by
[VIOLATION\_SEPARATOR](/api/html/#violation_separator). The error type carries one string, so the list is joined rather
than smuggled through a field the frozen contract does not have. A caller that wants the
structured list calls [checkMemory](/api/html/#checkmemory).

#### Parameters

##### html

`string`

#### Returns

`Effect`\<[`MemoryDoc`](/api/html/#memorydoc), `InvalidMemory`\>

***

### proseParagraphs()

```ts
function proseParagraphs(claim, body): readonly ProseParagraph[];
```

The paragraphs the prose path renders for a claim and body, in order: the claim's `<p>`, with
the first body paragraph joined onto it as its tail, then each remaining paragraph. Empty
paragraphs are dropped rather than emitted, so a trailing blank in the tool payload does not
become an empty element.

A body paragraph that is a fenced code block, whole, becomes a `<figure><pre><code>` instead of
a `<p>`, the one way the prose path can author real code markup. A fence is not joined onto the
claim's paragraph. When the first body paragraph is a fence, the claim stands alone in its `<p>`
and the figure follows, so the claim still leads the article (constraint 1) and code stays out
of the sentence.

Exported because the doors judge a body by what it renders to: the text of each `<p>` here,
read by `blockTagInRun`, is the text `blockTagInArticle` reads from the file.

#### Parameters

##### claim

`string`

##### body

readonly `string`[]

#### Returns

readonly [`ProseParagraph`](/api/html/#proseparagraph)[]

***

### proseParagraphText()

```ts
function proseParagraphText(paragraph): string;
```

The text a rendered `<p>` holds once read: its claim, a space, and its body paragraph.

#### Parameters

##### paragraph

[`ProseParagraph`](/api/html/#proseparagraph) & `object`

#### Returns

`string`

***

### readLinks()

```ts
function readLinks(html): readonly MemoryLink[];
```

Every `<link rel="memhtml-*">` edge in the head, in document order. The read half of
[addLink](/api/html/#addlink)/[removeLink](/api/html/#removelink), tolerant the way [readMeta](/api/html/#readmeta) is: the document is
parsed but nothing is validated — no `MemoryDoc`, no constraint check — so a caller holding raw
bytes can ask what a file points at without the file having to be a well-formed memory. An
unknown rel token is dropped exactly as `parseMemory`'s own reader drops it.

#### Parameters

##### html

`string`

#### Returns

readonly [`MemoryLink`](/api/html/#memorylink)[]

***

### readMeta()

```ts
function readMeta(html, name): string | undefined;
```

The value of a head meta, or `undefined`. The read half of [setMeta](/api/html/#setmeta), no parse needed.

#### Parameters

##### html

`string`

##### name

`string`

#### Returns

`string` \| `undefined`

***

### removeLink()

```ts
function removeLink(
   html, 
   rel, 
   href?
): string;
```

Drop a `<link rel="memhtml-…">` edge, in every spelling of the rel the reader accepts. Omitting
`href` drops every link of that rel; naming one drops just that pair, which is what the
integrity phase does when it replaces a dangling href with the target's new path.

#### Parameters

##### html

`string`

##### rel

  \| `"supersedes"`
  \| `"contradicts"`
  \| `"caused_by"`
  \| `"leads_to"`
  \| `"part_of"`
  \| `"relates_to"`
  \| `"example_of"`
  \| `"supports"`
  \| `"laterally_related"`
  \| `"about_person"`
  \| `"authored_by"`
  \| `"from_session"`
  \| `"blocks"`
  \| `"subtask_of"`

##### href?

`string`

#### Returns

`string`

***

### removeMeta()

```ts
function removeMeta(
   html, 
   name, 
   value?
): string;
```

Drop a `<meta>` of a name, one whole line each. Omitting `value` drops every meta of that name;
naming one drops just the metas carrying it, which is how a session's `unlabel` op takes one
`memhtml-entity` off a file and leaves its other entities alone. A name or value that is absent
is a no-op. Like [removeLink](/api/html/#removelink), the cut is outside the article, so the content hash is
unchanged.

#### Parameters

##### html

`string`

##### name

`string`

##### value?

`string`

#### Returns

`string`

***

### renderTemplate()

```ts
function renderTemplate(input): string;
```

A fresh memory file as bytes. The one function the write path calls. The extraction fields on
the intermediate doc are empty because serialization reads only `article.html`, and the real
extractions come back from `parseMemory` on the next read.

#### Parameters

##### input

[`NewMemoryInput`](/api/html/#newmemoryinput)

#### Returns

`string`

***

### serializeMemory()

```ts
function serializeMemory(doc): string;
```

Serialize a doc to a whole file. Inverse of `parseMemory` on the fields the format carries:
`parseMemory(serializeMemory(doc))` yields `doc` again, which is the property that lets a caller
read, adjust, and write a file back without touching content it did not mean to touch.

`article.html` is re-parsed and re-serialized rather than interpolated, so a caller that
hand-assembled a doc still gets the canonical, fixed-point markup the round-trip needs.

#### Parameters

##### doc

[`MemoryDoc`](/api/html/#memorydoc)

#### Returns

`string`

***

### setMeta()

```ts
function setMeta(
   html, 
   name, 
   value
): string;
```

Set a head meta to one value, replacing the first `<meta>` of that name in place or inserting
a line in [META\_ORDER](/api/html/#meta_order) position. Exactly one line changes, and the article stays outside
the edited range, so `contentHash(setMeta(html, name, value)) === contentHash(html)` holds
for every name, repeatable ones included.

On a repeatable key this sets the FIRST value. [addMeta](/api/html/#addmeta) is the append. An unknown name
is refused by returning the input unchanged rather than writing a meta `memhtml doctor` would
immediately flag.

#### Parameters

##### html

`string`

##### name

`string`

##### value

`string`

#### Returns

`string`

***

### writeChildren()

```ts
function writeChildren(parent): string;
```

The inner markup of a parent node: its children, the node itself excluded.

#### Parameters

##### parent

`ParentNode`

#### Returns

`string`

***

### writeOuter()

```ts
function writeOuter(node): string;
```

A node and its subtree, the node included.

#### Parameters

##### node

`Node`

#### Returns

`string`