Guide / current binding

Use IA² with HTML

Publish identities, relationships, provenance, and constraints in the same HTML a person reads. No JSON-LD payload, remote context, inherited parser state, or script execution is needed to extract the graph. In the complementary direction, RDF/HTML describes a parsed DOM in Turtle or TriG and derives an inert, inspectable HTML document.

  • One elementcarries one complete statement.
  • Native HTMLcarries literal and IRI objects.
  • Local extractionyields a complete RDF 1.2 dataset.
  • Reverse renderingderives HTML while preserving unused RDF.

This is the friendly tour. For exact processing, conformance, recovery, and RDF 1.2 rules, use the normative HTML/RDF model.

Add statements, not a second document.

Any element with rdf-predicate is a statement carrier. That element locally determines a subject, predicate, object, and optional graph name. Nesting is useful HTML, but it never supplies hidden RDF state.

Subject
The element itself by default, or an explicit IRI or local blank-node key.
Predicate
A full IRI reference in rdf-predicate.
Object
Visible text, a native HTML value, a native IRI, a local key, or a direct child template.
Graph
The default graph unless rdf-graph or rdf-graph-key is present.

Use full IRI references. Core 0.1 has no prefix declarations or compact-IRI expansion. Write https://schema.org/name, not schema:name, in an HTML attribute.

Publish two facts in ordinary HTML.

Declare the binding on html, give the document a stable canonical location, and annotate the elements already carrying the information.

HTML
<!doctype html>
<html lang="en" rdf-version="1.2">
  <head>
    <link rel="canonical" href="https://example.com/notes">
  </head>
  <body>
    <article id="note-7">
      <h1
        rdf-subject="#note-7"
        rdf-predicate="https://schema.org/headline"
      >A field note</h1>

      <time
        datetime="2026-07-15"
        rdf-subject="#note-7"
        rdf-predicate="https://schema.org/dateCreated"
        rdf-datatype="http://www.w3.org/2001/XMLSchema#date"
      >July 15, 2026</time>
    </article>
  </body>
</html>
Yields <https://example.com/notes#note-7> <https://schema.org/headline> "A field note" ; <https://schema.org/dateCreated> "2026-07-15"^^<http://www.w3.org/2001/XMLSchema#date> .

The article is addressable because it has an id. It does not assert anything by itself. Each child statement explicitly names #note-7, so moving either child elsewhere in the same document cannot silently change what it describes.

Let the carrier describe itself, until it should not.

Subject construction follows one fixed order. An explicit rdf-subject wins, then rdf-subject-key, then the carrier’s own non-empty id. With none of those, the carrier gets a fresh blank node for that extraction.

Self-subject
<h1
  id="alice"
  rdf-predicate="https://schema.org/name"
>Alice</h1>
<#alice> <https://schema.org/name> "Alice" .
Describe another element
<article id="alice">
  <h1
    rdf-subject="#alice"
    rdf-predicate="https://schema.org/name"
  >Alice</h1>
</article>
<#alice> <https://schema.org/name> "Alice" .

There is no subject inheritance. A parent id makes the parent referable; it does not become the child’s RDF subject unless the child says so.

Use the HTML value that already means the thing.

IA² does not add a general rdf-object mini-language. The object comes from one native carrier on the statement element.

Object kindAuthoring formTypical use
Visible literalElement textNames, descriptions, labels
Exact literalmeta[content], data[value], time[datetime]Dates, codes, machine-exact values
IRINative href, src, cite, or other allowed single-IRI carrierLinks to people, artifacts, sources
Reusable blank noderdf-object-keyStructured anonymous resources
RDF 1.2 triple termOne direct child templateClaims about an unasserted proposition

IRI objects stay native links

HTML
<a
  href="https://orcid.org/0000-0002-1825-0097"
  rdf-subject="#alice"
  rdf-predicate="https://schema.org/sameAs"
>Alice’s ORCID</a>
<#alice> <https://schema.org/sameAs> <https://orcid.org/0000-0002-1825-0097> .

Keys correlate anonymous structure

HTML
<span
  rdf-subject="#ticket-42"
  rdf-predicate="https://schema.org/location"
  rdf-object-key="location"
></span>

<span
  rdf-subject-key="location"
  rdf-predicate="https://schema.org/name"
>Lab 3</span>
<#ticket-42> <https://schema.org/location> _:location . _:location <https://schema.org/name> "Lab 3" .

The source key is only an extraction-local correlation handle. A serializer chooses its own blank-node label.

Put datatype, language, and direction where they apply.

rdf-datatype gives a literal datatype. Native lang and dir give language and base direction, but only when directly present on the statement carrier.

HTML
<time
  datetime="2026-07-15"
  rdf-subject="#release"
  rdf-predicate="https://schema.org/datePublished"
  rdf-datatype="http://www.w3.org/2001/XMLSchema#date"
>15 July 2026</time>

<p
  lang="fr"
  rdf-subject="#release"
  rdf-predicate="https://schema.org/name"
>Architecture de l’information</p>
<#release> <https://schema.org/datePublished> "2026-07-15"^^<http://www.w3.org/2001/XMLSchema#date> ; <https://schema.org/name> "Architecture de l’information"@fr .

Literal metadata never inherits for RDF. An ancestor’s lang still affects HTML presentation and accessibility, but it does not silently change an extracted literal. Datatype and language are mutually exclusive.

Name graphs locally. Quote propositions without asserting them.

Named graphs

Put rdf-graph or rdf-graph-key directly on every statement that belongs to that graph. A non-statement element carrying the attribute declares an empty named graph.

HTML
<data
  value="approved"
  rdf-subject="#decision-9"
  rdf-predicate="https://schema.org/status"
  rdf-graph="#audit"
></data>

<span hidden rdf-graph="#empty-review-queue"></span>

RDF 1.2 triple terms

A direct child template can carry one unasserted statement as the outer statement’s object. Template contents live in a separate DocumentFragment, so the inner proposition is not accidentally asserted by a document-wide DOM query.

HTML
<div
  rdf-subject="#review"
  rdf-predicate="https://example.com/quotes"
>
  <template>
    <a
      href="https://example.com/bob"
      rdf-subject="https://example.com/alice"
      rdf-predicate="https://schema.org/knows"
    >Bob</a>
  </template>
</div>
<#review> <https://example.com/quotes> << <https://example.com/alice> <https://schema.org/knows> <https://example.com/bob> >> .

Extract the document you actually mean.

A downloaded HTML document is an inert observation. An application-mutated DOM is a runtime observation. IA² permits both. Each extraction is a snapshot of the supplied Document or DocumentFragment; extraction itself executes nothing.

Add the document navigator

The browser bundle mounts one navigator, extracts the current DOM, and refreshes after semantic mutations. This guide includes it, so its own RDF is available from the launcher on this page.

HTML
<script
  type="module"
  src="https://ia2.dev/packages/html-rdf-navigator/dist/html-rdf-navigator.js"
></script>
  • Inert acquisition: parse downloaded HTML and extract without running its scripts.
  • Live acquisition: extract the current light DOM after the host application changes it.
  • Separate fragments: pass a template’s content explicitly when that inert fragment is the intended root.

Describe the document as a graph, then render it.

RDF/HTML is the complementary direction to HTML/RDF. Turtle or TriG describes parsed document nodes, element classes, attributes, text, and enough child-order constraints to derive a sibling sequence. A renderer derives faithful ordinary HTML and can also publish RDF statements not used structurally inside an augmented HTML/RDF result.

Why describe HTML in RDF?

HTML is an excellent finished document format, but its tree is often the end of a pipeline. RDF/HTML is useful when the document should remain a view of a larger graph. Giving document nodes RDF identity lets the same dataset describe what a node renders, what domain resource it concerns, where it came from, and how it relates to evidence or decisions outside the page.

  • Graph-native views: derive a human-readable document from RDF without reducing the source graph to template variables or an opaque HTML string.
  • Independent composition: let separate graphs or tools contribute named nodes, annotations, and ordering constraints before one document is materialized.
  • Meaning survives rendering: consume the structural statements needed to build the DOM, then carry the remaining domain and provenance statements into the result as HTML/RDF.

It is not a replacement for ordinary HTML authoring. Use HTML directly when the page is the primary artifact and no graph-native composition, node identity, or preserved RDF context is needed.

HTML/RDF
Start with an HTML host and extract its RDF 1.2 dataset.
RDF/HTML
Start with an RDF 1.2 dataset and derive one or more HTML documents.
Fidelity
The graph describes the parsed DOM, including explicit text and comment nodes, not the original source bytes.
Safety
The public renderer and extension use inert previews. Description never grants execution.

Declare the vocabulary snapshot

Every renderable document identifies the dated vocabulary it was authored against. The renderer recognizes supported snapshots locally; it does not fetch the vocabulary during rendering.

Turtle
@prefix dcterms: <http://purl.org/dc/terms/> .

doc:page
  a rdfhtml:Document ;
  rdfhtml:base <https://example.com/page/> ;
  dcterms:conformsTo <https://ia2.dev/spec/rdf-html/vocabulary/rdf-html-2026-07-18.ttl> .

A dataset may contain partial RDF/HTML descriptions assembled by several sources. Materialization begins only when the selected document has one complete, unambiguous tree. The renderer reports incomplete membership or ordering instead of inventing missing structure.

Write known attributes directly

Each indexed HTML attribute has a generated RDF property. Use that property directly and preserve the exact DOM value as a string. Present boolean attributes use the empty string.

Turtle
@prefix rdfhtml: <https://ia2.dev/spec/rdf-html#> .

doc:save
  a rdfhtml:Button ;
  rdfhtml:id "save-draft" ;
  rdfhtml:accessKey "S" ;
  rdfhtml:disabled "" .

Use an expanded rdfhtml:Attribute occurrence for an unknown or extension attribute, or when the occurrence itself needs identity, provenance, or annotations. Known attributes can also use the expanded form with rdfhtml:attributeDefinition, but the direct property is the ordinary authoring form.

Extension attribute
doc:save rdfhtml:attribute [
  a rdfhtml:Attribute ;
  rdfhtml:attributeName "data-review-state" ;
  rdfhtml:attributeValue "pending"
] .

Use a collection for a complete child sequence

rdfhtml:children is the compact default when one description owns a parent's complete sequence. Its RDF Collection states membership and immediate order together. Anonymous [] nodes remain convenient for children that need no identity outside that description, and converters emit this form.

Turtle
doc:body rdfhtml:children (
  [ a rdfhtml:H1 ; rdfhtml:children (
    [ a rdfhtml:Text ; rdfhtml:data "Welcome" ]
  ) ]
  [ a rdfhtml:P ; rdfhtml:children (
    [ a rdfhtml:Text ; rdfhtml:data "Hello world!" ]
  ) ]
) .

Use flat relations for independent contributions

A collection is intentionally complete and changing its middle means changing the shared RDF list spine. Use named children, rdfhtml:hasChild, and ord: relations when different graphs or tools contribute nodes independently, when a child is annotated elsewhere, or when only relative order is meaningful. One rdfhtml:hasChild assertion anchors a connected ordering chain; normalization derives the other child memberships. The vocabulary supplies the ordering types, so authors do not repeat them.

Independently extensible Turtle
@prefix ord: <https://ontology.inferal.com/modules/ordering/> .

doc:body rdfhtml:hasChild doc:heading .

doc:heading
  a rdfhtml:H1 ;
  ord:precedes doc:status .

doc:status
  a rdfhtml:P ;
  ord:precedes doc:actions .

doc:actions
  a rdfhtml:Nav .

Use ord:immediatelyPrecedes only when adjacency is part of the assertion. If the important fact is merely that one child comes before another, ord:precedes, or inverse ord:follows, is usually more accurate and remains valid if another contributor inserts a child between them. A renderable parent must still have enough combined constraints to yield one sequence; the renderer does not invent a tie-break. The inverse forms rdfhtml:childOf and ord:follows are equivalent when that direction reads more naturally.

Keep mixed content explicit. Do not use an aggregate textContent value. Represent text as rdfhtml:Text nodes and order those nodes beside elements, so Hello <em>world</em>! remains three distinct children.

Convert an existing HTML document

The package can walk a parsed HTML DOM and emit the same compact RDF/HTML structure. It preserves document type, elements, attributes, text, comments, and template contents. The result describes the parsed DOM, so it does not preserve source whitespace choices or other byte-level formatting.

Command line
npx @ia2-dev/rdf-html describe page.html \
  --output page.ttl \
  --document-iri https://example.com/page#document \
  --base https://example.com/page/

The same command accepts an HTTP or HTTPS URL. In the other direction, npx @ia2-dev/rdf-html render page.ttl writes the faithful described HTML to standard output. Add --publication to retain unconsumed RDF in an HTML/RDF island. Use --document for one document in a multi-document Turtle or TriG source, or --workspace for the inert selector workspace.

Renderability is not complete HTML validation. Generated categories, attribute applicability, and value syntax are inspectable metadata. RDF/HTML validates that one DOM can be derived; a separate reviewed profile or HTML validator checks whether that DOM follows all WHATWG authoring rules.

Open a public Turtle or TriG document

The URL renderer fetches at most 2 MiB from a public HTTP or HTTPS location, blocks private-network destinations and unsafe redirects, then renders a single declared document without visible renderer chrome. When a source describes several documents, a compact selector remains outside the sandboxed document frame. The IA² browser extension applies the package's inert workspace renderer to browser-opened .ttl and .trig documents.

Carry a graph and its resources in one HTML document.

HARE, the proposed HTML Agent Resource Envelope, packages a manifest, relationships, and inspectable representations in a browser-openable file. Semantic HTML can live directly in the document as template DOM. The manifest is HTML/RDF, not a parallel JSON document, so agents can extract it without running code.

Use HARE when a handoff must preserve meaning and the resources that meaning describes. Keep the graph as the primary model. Give DOM representations logical paths so they receive virtual document URLs; paths remain optional for other representations. Use byte representations only when exact octets, downloads, or hashes matter. The envelope remains useful as HTML even when no viewer runs.

HARE reuses dcterms:hasPart for membership, dcterms:identifier for logical paths, and dc:format for media types. It defines only the envelope mechanics that those vocabularies do not provide, including the manifest graph, virtual document base, representation link, carrier, and optional runtime. Byte representations additionally use cred:digestSRI for digests and HARE's decoded byte length.

Envelope
The self-contained HTML artifact and its source document identity.
Manifest
One named RDF graph describing resources, representations, relationships, and policy.
Resource
A conceptual item in the handoff, such as a brief, dataset, image, or decision.
Representation
A semantic or byte realization of a resource, with a media type and an HTML carrier.

Build the smallest declarative envelope

This complete envelope carries a small HTML resource as parsed, directly inspectable template DOM. The logical path is a useful alias, not the identity or source of truth for the resource.

HARE 0.1
<!doctype html>
<html lang="en" rdf-version="1.2">
  <head>
    <meta charset="utf-8">
    <link rel="canonical" href="https://example.com/hello.hare.html">
  </head>
  <body>
    <main>
      <h1>Hello handoff</h1>
      <section id="manifest" aria-label="Bundle manifest">
        <a hidden href="https://ia2.dev/spec/resource-envelope#Envelope"
          rdf-subject="" rdf-predicate="http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
          rdf-graph="#manifest"></a>
        <a hidden href="https://ia2.dev/spec/resource-envelope#HARE-0.1" rdf-subject=""
          rdf-predicate="http://purl.org/dc/terms/conformsTo"
          rdf-graph="#manifest"></a>
        <a hidden href="https://ia2.dev/spec/resource-envelope#DeclarativeProfile" rdf-subject=""
          rdf-predicate="http://purl.org/dc/terms/conformsTo"
          rdf-graph="#manifest"></a>
        <a hidden href="#manifest" rdf-subject=""
          rdf-predicate="https://ia2.dev/spec/resource-envelope#manifestGraph"
          rdf-graph="#manifest"></a>
        <a hidden href="https://hello.hare.invalid/" rdf-subject=""
          rdf-predicate="https://ia2.dev/spec/resource-envelope#virtualBase"
          rdf-graph="#manifest"></a>
        <a href="#greeting" rdf-subject=""
          rdf-predicate="http://purl.org/dc/terms/hasPart"
          rdf-graph="#manifest">Greeting resource</a>

        <a hidden href="#greeting-representation" rdf-subject="#greeting"
          rdf-predicate="https://ia2.dev/spec/resource-envelope#representation"
          rdf-graph="#manifest"></a>
        <a id="greeting-representation" hidden
          href="https://ia2.dev/spec/resource-envelope#DOMRepresentation"
          rdf-subject="#greeting-representation"
          rdf-predicate="http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
          rdf-graph="#manifest"></a>
        <data value="/hello.html" rdf-subject="#greeting-representation"
          rdf-predicate="http://purl.org/dc/terms/identifier"
          rdf-graph="#manifest">/hello.html</data>
        <data hidden value="text/html" rdf-subject="#greeting-representation"
          rdf-predicate="http://purl.org/dc/elements/1.1/format"
          rdf-graph="#manifest"></data>
        <a hidden href="#greeting-content" rdf-subject="#greeting-representation"
          rdf-predicate="https://ia2.dev/spec/resource-envelope#carrier"
          rdf-graph="#manifest"></a>
      </section>
    </main>
    <template id="greeting-content">
      <article>
        <h1>Hello, agent</h1>
        <p>This semantic HTML is readable directly in the envelope.</p>
        <a href="/">Return to the envelope document</a>
      </article>
    </template>
  </body>
</html>

The declared hare:virtualBase gives the host envelope the virtual URL https://hello.hare.invalid/. The greeting's logical path gives it https://hello.hare.invalid/hello.html. Inside the template, href="/" returns to the host document, and ordinary relative paths can address other bundled representations. These virtual URLs are routing addresses, not retrievable locations or RDF identity.

When exact bytes are part of the handoff contract, use a hare:ByteRepresentation instead. Its carrier is an inert base64 <script type="application/octet-stream"> and its byte length and SRI digest describe the decoded octets. One resource may have both semantic and byte representations.

Materialize a small site without inventing an origin

Template HTML can use ordinary relative URLs for passive resources. A materializing viewer resolves each reference against the containing document's virtual URL, finds the matching byte representation, verifies it, and rewrites only the derived view to a local Blob URL. The template stays readable and unchanged.

Inspectable HTML with bundled dependencies
<template id="report-content">
  <link rel="stylesheet" href="../styles/report.css">
  <article>
    <img src="../images/verified.svg" alt="Verified">
    <a href="details.html">Details</a>
  </article>
</template>

Navigation and materialization deliberately differ. The anchor routes to another virtual document when activated; the image and stylesheet are passive fetch destinations and may be materialized immediately. Stylesheet imports and CSS url() references can recurse through the same verified process. External, missing, incompatible, and executable destinations stay inert; a viewer does not use the live network as fallback.

Verified Markdown bytes can use the same virtual address space. For example, a brief at /docs/brief.md may contain ![Verified result](../assets/verified.svg). A safe renderer resolves that reference to /assets/verified.svg, verifies the declared image representation, and gives only the rendered image a temporary Blob URL. The Markdown bytes and reference remain unchanged; unmatched images are never fetched from the network.

The optional @ia2-dev/hare-viewer runtime includes a small dependency-free Markdown renderer for headings, emphasis, links, images, quotations, lists, task items, tables, and code. It creates DOM nodes directly, treats raw HTML as text, routes links through HARE, and delegates images to verified resource lookup. It is intentionally not advertised as CommonMark conformant until it is tested against that specification's corpus. Self-viewing envelopes can inline the renderer with the rest of their runtime.

A safe viewer also makes links inert in its derived iframe before showing it, retains the original href as routing data, and resolves that value through the HARE virtual URL space when the user activates the link. This prevents a timing gap from turning a virtual .invalid address into a browser navigation. The readable links in the authored template are not changed.

The authored host document can refer to a bundled passive resource too. Keep its virtual URL in an inert data-hare-src attribute so the browser does not try the non-retrievable address before verification. A supporting viewer retains that declarative reference and supplies the verified Blob URL to src at runtime.

Verified image in the host document
<figure>
  <img
    data-hare-src="https://hello.hare.invalid/images/verified.svg"
    alt="Verified bundle"
  >
  <figcaption>Image carried by this envelope.</figcaption>
</figure>

Keep the host policy compatible. A srcdoc preview inherits the envelope's Content Security Policy, and its inner policy can only restrict it further. If browser viewers are intended to work, permit about: and blob: frames plus blob:/data: for the passive style, image, media, and font destinations the viewer materializes. Continue to deny scripts, workers, plugins, and network fallback.

DevTools, test runners, and other extensions sometimes inject inspection code into the preview. The browser may report that attempt as blocked script execution even though the derived document is script-free. That is the sandbox working. Confirm the derived document contains no script; do not add allow-scripts to silence the message.

Enhance it only when a viewer helps

A declarative envelope needs no executable code. During development, @ia2-dev/hare-viewer can generate a file browser when the body has no authored interface, or add Document and Files tabs when authored content is present. A compatible browser extension can add those modes automatically, including the full file browser for a bare envelope, without requiring or executing envelope-supplied code.

Development convenience
<script
  type="module"
  src="https://ia2.dev/packages/hare-viewer/dist/hare-viewer.js"
></script>

Keep transport self-contained. The package URL is convenient while authoring. Inline the built runtime into an exported self-viewing envelope, and never execute bundled HTML or scripts by default.

Give an agent the model, not a pasted prompt.

The IA² repository packages HTML/RDF and HARE as two portable Agent Skills. Each skill keeps its working instructions in SKILL.md, then loads detailed references or the HARE byte-commitment helper only when the task needs them.

ia2-html-rdf
Author, extract, and review locally complete RDF 1.2 statements in HTML.
ia2-hare
Create and verify HARE manifests, representations, byte commitments, routing, and viewer security.
plugins/ia2
The distributable package, with thin Codex and Claude Code manifests around the same skill folders.

Get the portable source

Clone the repository once. The directories under plugins/ia2/skills/ are the cross-client source of truth.

Shell
git clone --depth 1 https://github.com/ia2-dev/ia2.git
cd ia2
Codex / project skills
mkdir -p .agents/skills
cp -R plugins/ia2/skills/ia2-html-rdf .agents/skills/
cp -R plugins/ia2/skills/ia2-hare .agents/skills/
Invoke $ia2-html-rdf $ia2-hare
Claude Code / development plugin
claude --plugin-dir ./plugins/ia2
Invoke /ia2:ia2-html-rdf /ia2:ia2-hare

Install at the scope you mean

The Codex example installs repository-scoped skills. Copy the same two directories to ~/.agents/skills/ when they should be available to Codex across repositories. For persistent Claude Code project skills, copy them to .claude/skills/; use ~/.claude/skills/ for personal scope. Skills copied directly into Claude Code use /ia2-html-rdf and /ia2-hare without the plugin namespace.

Other Agent Skills compatible clients can install either skill directory in their supported skills location. The portable contract is the folder containing SKILL.md, its references, and optional scripts. The agents/openai.yaml files add Codex interface metadata but do not change the instructions.

Deploy the wrapper, maintain the core. The package includes both .codex-plugin/plugin.json and .claude-plugin/plugin.json for marketplace or team distribution. Keep edits in the shared skill folders so every host receives the same IA² and HARE behavior.

Check the statement at the carrier.

  • Declare rdf-version="1.2" on the document element.
  • Publish exactly one valid, fragmentless canonical link when a stable public identity is available and differs from the retrieval URL.
  • Use a full predicate IRI on every statement carrier.
  • Make every carrier determine exactly one object form.
  • Use explicit subjects for statements about another element or resource.
  • Put graph membership, datatype, language, and direction directly on the statement where they apply.
  • Inspect diagnostics, then verify the resulting Turtle and its DOM correlation.
Common mistakes

Expecting nesting to chain subjects. It never does.

Using prefixed names in attributes. Core resolves IRI references; it does not expand prefixes.

Combining object carriers. Do not put a native IRI, exact literal, local object key, and object template on the same statement.

Treating local keys as persistent IDs. They correlate blank nodes only within one extraction.

Assuming extraction validates or executes SHACL. Shapes and rules are extracted as RDF data; validation and execution are separate operations.

Move from the tour to the working artifacts.