๐๏ธ Architecture โ
WCI separates what the agent sees, what the site allows, and how actions execute into three cooperating layers.

Layer 1 โ Semantic HTML (@webcontextinterface/spec) โ
Standard DOM nodes carry machine-readable metadata:
- Identity โ
data-wci-id - Role โ
action,form,display,nav,status,landmark - Intent โ
data-wci-desc,data-wci-action - State โ
data-wci-state(JSON snapshot) - Guards โ
data-wci-precondition,data-wci-required
readWciNodeSpec(element) maps attributes to the WciNodeSpec TypeScript interface.
Layer 2 โ Distiller (@webcontextinterface/distiller) โ
The distiller walks the DOM, collects annotated nodes, sorts by priority, and emits a compact WciView (JSON) or Markdown string suitable for LLM context windows.
Design goals:
- Drop decorative/layout nodes (
data-wci-hidden) - Scope to a landmark (
scopeoption) - Cap node count (
maxNodes) for token budgets - Optionally attach site summary metadata
Layer 3 โ Bridge (@webcontextinterface/bridge) โ
The bridge translates agent decisions into real DOM interactions:
| Action | DOM effect |
|---|---|
click | .click(), updates state |
fill | Native value setter + input/change events |
select | <select>.value + change |
check | checkbox checked + change |
focus | .focus() |
clear | Clears input value |
submit | form.requestSubmit() |
navigate | window.location.href |
Every dispatch returns a typed ActionResult: success flag, before/after state, optional side effects on sibling nodes, and structured errors (NODE_NOT_FOUND, PRECONDITION_UNMET, etc.).
State changes also emit wci:state-change on document for observers.
Site context (@webcontextinterface/context) โ
Before touching a page, agents can load site policy. WciContextLoader resolves URLs in priority order: <meta name="wci:*"> tags, then X-WCI-Directives / X-WCI-Manifest / X-WCI-Context headers, then root /wci.txt, /wci.json, /wci.md. Well-known /.well-known/wci/* paths are fetched only as a fallback when no explicit URL was set.
PolicyEngine enforces allow/deny scopes, auth requirements, and human-confirmation scopes. Attach it to WciBridge via setPolicy so every dispatch is validated before DOM mutation.
Typical agent loop โ
WciContextLoader.load()โ system prompt + policyWciDistiller.distilJSON()โ page tool context- LLM chooses
{ nodeId, action, value } WciBridge.dispatch()โActionResult- Re-distil or read
sideEffectsโ next turn
Size and deployment โ
Packages are tree-shakeable ESM/CJS builds. Use only the layers you need:
- Read-only crawlers:
@webcontextinterface/distiller+@webcontextinterface/spec - In-page agents: add
@webcontextinterface/bridge - Multi-page flows: add
@webcontextinterface/context
