claude code plugin · v0.1.0 · apache-2.0

HTML as canonical LLM memory and inter-agent comms.

A Claude Code plugin (and MCP server) that teaches AI agents to write and read single-file HTML as persistent memory across sessions. Anchor-signed. Schema-validated. Sanitized before any LLM reads it. Three independent audit loops. Zero runtime dependencies.

4
skills
5
slash commands
3
audit loops
0
runtime deps

section · 1

Why HTML, why now

The "HTML is the new Markdown for LLM I/O" thesis crystallized in May 2026 after Thariq Shihipar's Unreasonable Effectiveness of HTML and Simon Willison's permalink endorsement. The defensible reading isn't "HTML beats Markdown everywhere" — it's bifurcated by direction:

DirectionBest formatWhy
Agent → human (outputs, decisions, artifacts)HTMLDiagrams, tables, hierarchy, links, interactivity — Markdown flattens all of it.
Agent → agent (context, retrieval, RAG)HTML with structured data islandsHtmlRAG (Tan et al., Nov 2024) shows HTML beats plain-text on six QA benchmarks because heading and table structure survive.
System → agent (tables, configs)Markdown-KV or YAMLImproving Agents 2025 benchmarks show MD-KV at 60.7 % vs HTML at 53.6 % on tabular tasks.

htmem is built for the first two. For the third (config files, table input), keep using Markdown.

section · 2

Install

1. Add the marketplace

/plugin marketplace add droggy992/htmem@v0.1.0

Always pin by tag, never bare main. The plugin code runs on your machine; you should be able to read every line you're trusting.

2. Install the plugin

/plugin install htmem@htmem-plugins --scope user

User scope writes to ~/.claude/settings.json.

3. Create your first memory

/htmem:htm-new memory "Why we picked Redis"

Claude scaffolds, fills in body, anchors with SHA-256.

4. View it safely in a browser

/htmem:htm-render htmem/memory-why-we-picked-redis-2026-05-15.html

Opens via a CSP-hardened localhost server inside a sandboxed iframe.

section · 3

Architecture — one file, two pipelines

A single htmem file feeds two physically separate pipelines: one for LLMs (sanitize + verify + sentinel-wrap), one for humans (CSP-hardened iframe sandbox). They never share rendering code, so a bypass in one pipeline can't compromise the other. This is a direct response to CamoLeak (CVE-2025-59145) and CVE-2026-22813.

htmem file (.html) single self-contained, anchor-signed LLM-read pipeline read_memory.py 1. sanitize (default-deny allow-list) 2. NFKC + strip Cf + tag-block U+E0000-U+E007F 3. anchor verify (sha256 canonical) 4. JSON-Schema validate (manifest) 5. wrap <untrusted_content> sentinels → structured JSON to the model Human-render pipeline render_server.py 1. bind 127.0.0.1 only · random high port 2. 128-bit URL token (secrets.compare_digest) 3. strict CSP + COOP + COEP headers 4. <iframe sandbox> without allow-scripts 5. Host header allow-list · idle exit 15 min → rendered page in the user's browser Same file. Two pipelines. Two threat models. No shared rendering code.

section · 4

Security defenses — what's protected, by what

ThreatAdversaryPrimary defense
Indirect prompt injection via free-text fieldsrepo-fork attackerschema-level zero-width reject, sanitizer Cf+tag-block strip, <untrusted_content> sentinel wrap
Indirect prompt injection via HTML comments / hidden metaartifact authorsanitizer drops every comment; meta name allow-list of 10; audit A07 flags instruction-shaped comments at CRITICAL
Forged manifest smuggled inside <applet>/<embed>/<base>artifact authorsanitizer refuses to capture data islands when any DANGEROUS_TAG is seen; validator counts manifest scripts
Local XSS via inline script / on*= / javascript: URLartifact authordefault-deny tag allow-list; on*= strip; URL-scheme allow-list; iframe sandbox without allow-scripts
CSS-based exfiltration (url(), @import, expression())artifact authorsanitizer drops <style> body if dangerous tokens; audit A05 scan
Anchor tamperingrepo-fork attackerSHA-256 canonicalization zeroes meta content + literal hashes + manifest anchor field
Render-server token leak in logslocal co-tenantregex redact ?t=<token> → t=REDACTED before write
Render-server path traversal via symlinkrepo-fork attackercross-platform .. and \ normalization; explicit is_symlink() refusal in render server and MCP server
Skill auto-trigger coercionprompt-injection attackernarrow trigger description: only /htm-* or literal "htmem"; no Bash in htmem-write; no Read in htmem-read
Hook RCE via plugin updatesupply-chain attackerhooks ship OFF by default; opt-in only; CODEOWNERS gates hooks/; CI fails on malformed hooks.json
Allocator DoS via giant data islandartifact author10 MB file cap; 1 MB per-island cap; 10000-file walk cap

Full threat model: docs/threat-model.md. Vulnerability disclosure policy: SECURITY.md (72-hour ack, 30-day fix SLA for HIGH/CRITICAL).

section · 5

What ships in v0.1.0

4 skills

htmem-write · htmem-read · htmem-render · htmem-audit. Narrow auto-trigger only on explicit /htm-*, literal "htmem", or referenced paths.

5 slash commands

/htmem:htm-new · /htm-read · /htmem:htm-render · /htm-audit · /htm-hub. Each enforces $ARGUMENTS single-quoting and refuses shell metachars.

3 HTML templates

memory · decision · thread. Modern CSS (@layer, light-dark()). Inert JSON / JSON-LD / text-plain data islands. No JS.

5 JSON schemas

memory · decision · thread · identity · llm-onboarding. $defs.safeText rejects BMP zero-width / RTL-override / format / BOM chars.

8 Python scripts

anchor · sanitize · schema_validator · validate · read_memory · audit · new_memory · render_server. Python 3.10+ stdlib only.

1 MCP server

Stdio JSON-RPC bridge. Exposes htmem://<path> resources + htmem_read / htmem_audit / htmem_list tools.

Opt-in hooks

hooks/hooks.json ships empty. Three vetted recipes: PostToolUse snapshot · SessionStart digest · PreToolUse signed-decision gate.

2 regression tests

G01 forged-manifest-under-dropped-subtree (7 vectors) · V18 multi-manifest-smuggling. Stdlib only, wired into CI.

CI stack

gitleaks · CodeQL · Semgrep (OWASP Top 10 + python + security-audit) · trufflehog · plugin-validate · end-to-end smoke + regression tests. Dependabot weekly.

section · 6

What's in the repo

htmem/
├── .claude-plugin/      marketplace.json + plugin.json
├── .github/             CODEOWNERS, dependabot, workflows/ci.yml
├── commands/            5 slash commands
├── docs/                format-spec · threat-model · design-rationale · index.html
├── examples/            3 anchor-verified artifacts (memory, decision, thread)
├── hooks/               empty hooks.json + README + 3 opt-in script recipes
├── mcp/                 stdio MCP server
├── schemas/             5 JSON Schemas
├── scripts/             anchor · sanitize · schema_validator · validate · read · audit · new · render
├── skills/              4 narrow-trigger SKILL.md files
├── templates/           memory · decision · thread
├── tests/               2 regression tests, no framework
├── .gitignore  .gitleaks.toml  .mcp.json
├── CHANGELOG.md  CONTRIBUTING.md  LICENSE
├── README.md  SECURITY.md

section · 7

Roadmap

VersionThemeStatus
0.1.0Skills + commands + templates + MCP + opt-in hooks + CIshipped
0.2.0Anthropic + OpenAI MCP Apps Extension compatibility — htmem artifacts as ui:// resources renderable in Claude desktop and ChatGPT side-paneplanned
0.3.0Cosign signed releases + provenance attestation + automated security advisoriesplanned
0.4.0Local sqlite full-text index over htmem artifacts (no embedding model required)planned
0.5.0First-party browser-agent integration (Stagehand / browser-use accessibility-tree extraction of htmem artifacts)exploratory

Suggest a feature: open an issue.

if this saves you a design

hit ⭐ on the repo — it's the only signal the maintainer reads