SurfDoc Format Specification

The definitive reference for the .surf document format. Version 0.5.0.

SurfDoc is a typed document format designed for AI/human collaboration. It uses structured block directives, embedded data, and presentation hints — while remaining readable as plain text in any editor. A SurfDoc without a renderer degrades gracefully to readable plain text. With a renderer, it becomes an interactive, visually polished document with structured data, conversations, task tracking, and cross-references.

This specification defines 41 block types across 8 categories, the front matter schema, the rendering model, graceful degradation behavior, and the security architecture. The reference parser is surf-parse, a Rust crate with 378+ tests.

1. Design Principles

  1. Backward-compatible. Every standard Markdown document is a valid SurfDoc. SurfDoc adds typed block directives; it never breaks existing files.
  2. Three-layer architecture. Every document has a content layer (prose), a data layer (structured, typed, queryable), and a presentation layer (layout, styling). Each layer is accessible independently.
  3. Graceful degradation. A SurfDoc opened in a plain text editor, GitHub, or any markdown renderer is fully readable. Blocks degrade to fenced content with visible labels. No information is lost.
  4. AI-native. An AI agent can read, write, and modify a SurfDoc without special tooling. The format is text-based, the syntax is simple, and the block types are semantic.
  5. File-based and portable. A SurfDoc is a .surf file. It lives on disk, in git, in any filesystem. It is not a database row, not a cloud-only format, not proprietary.
  6. Schema-validated. Block types have defined attributes. A renderer or linter can validate that a ::data block has a format, a ::turn block has a participant, etc.
  7. Renderable at multiple fidelities. Plain text → styled markdown → rich interactive → print/PDF. Same source, four fidelity levels.

2. File Format

PropertyValue
Extension.surf (preferred) or .md (compatible)
MIME typetext/surf (proposed), falls back to text/markdown
EncodingUTF-8, no BOM
Line endingsLF (Unix). CRLF accepted, normalized to LF on parse.

A .surf file signals to tooling that it should be rendered with SurfDoc block support. Renaming .surf to .md produces a fully readable markdown file (graceful degradation).

3. Front Matter

SurfDoc uses YAML front matter delimited by ---. Front matter is optional but recommended.

.surf
---
title: "Document Title"
type: doc
version: 1
created: 2026-02-10
updated: 2026-02-10
author: "Brady Davis"
status: draft
scope: workspace
tags: [architecture, surfdoc]
---

Required Fields by Document Type

TypeRequired Fields
doctitle, type
guidetitle, type, confidence, updated
conversationtitle, type, status, participants
plantitle, type, status, created
agenttitle, type
preferencetitle, type

4. Block Syntax

SurfDoc blocks use the :: directive syntax. Container blocks open with ::blocktype[attrs] and close with ::. Leaf directives fit on a single line.

Container Block (multi-line)

.surf
::blocktype[attr1=value attr2="quoted value"]
Content inside the block.
Multiple lines allowed.
::

Leaf Directive (single-line)

.surf
::blocktype[attr1=value]{Inline content}

Nesting

Blocks can nest. Inner blocks use additional colons. Maximum nesting depth: 4 levels.

.surf
::columns[count=2]

:::column
Left column content.
:::

:::column
Right column content.
:::

::

Attribute Syntax

SyntaxMeaning
[key=value]Unquoted value (no spaces)
[key="quoted value"]Quoted value (spaces allowed)
[key=true]Boolean
[key=42]Number
[flag]Boolean flag (presence = true)

5. Core Blocks

The foundation blocks for structured content: callouts, decisions, summaries, figures, quotes, and code.

::callout
Core Container Implemented

Styled callout box for important information with type-based theming.

Attributes

AttributeValuesDefault
typeinfo, warning, danger, success, tip, noteinfo
titleStringAuto from type
collapsibleBooleanfalse

Source

.surf
::callout[type=warning]
This deployment will cause 5 minutes of downtime.
::

Rendered

Warning

This deployment will cause 5 minutes of downtime.

Degrades to

> **Warning:** This deployment will cause 5 minutes of downtime.
::decision
Core Container Implemented

Highlighted decision record with status tracking.

Attributes

AttributeValuesDefault
statusproposed, accepted, rejected, supersededproposed
dateISO dateNone
decidersComma-separated namesNone

Source

.surf
::decision[status=accepted date=2026-02-10]
**GTK4 native** — 5MB binary, native look and feel.
::

Rendered

Accepted 2026-02-10

GTK4 native — 5MB binary, native look and feel.

Degrades to

> **Decision (accepted, 2026-02-10):** GTK4 native — 5MB binary, native look and feel.
::summary
Core Container Implemented

Token-efficient summary for AI loading. Renderers may show this collapsed with an expand affordance.

Attributes

AttributeValuesDefault
No attributes

Source

.surf
::summary
This document covers the GTK vs Electron decision for desktop.
We chose GTK4 for binary size and native feel.
::

Rendered

This document covers the GTK vs Electron decision for desktop. We chose GTK4 for binary size and native feel.

Degrades to

*This document covers the GTK vs Electron decision for desktop. We chose GTK4 for binary size and native feel.*
::figure
Core Leaf Implemented

Image or diagram with caption and optional source attribution.

Attributes

AttributeValuesDefault
srcFile path or URLRequired
captionStringNone
altStringCaption or empty
widthCSS value100%

Source

.surf
::figure[src=brand/diagrams/ecosystem.png caption="Product Ecosystem" alt="Diagram showing product relationships"]
::

Rendered

[Image: ecosystem.png]

Product Ecosystem

Degrades to

![Diagram showing product relationships](brand/diagrams/ecosystem.png)
*Product Ecosystem*
::quote
Core Container Implemented

Attributed quotation with source citation.

Attributes

AttributeAliasesDefault
byattribution, authorNone
citesourceNone

Source

.surf
::quote[by="Peter Thiel" cite="Zero to One"]
Every moment in business happens only once.
::

Rendered

Every moment in business happens only once.
— Peter Thiel, Zero to One

Degrades to

> Every moment in business happens only once.
>
> — Peter Thiel, *Zero to One*
::code
Core Container Implemented

Enhanced code block with language, file path, and highlighting metadata.

Attributes

AttributeValuesDefault
langLanguage identifierNone
fileSource file pathNone
highlightLine numbers/rangesNone
linesLine rangeNone
titleDisplay titleNone
runnableBooleanfalse
diffBooleanfalse

Source

.surf
::code[lang=rust file=src/sync/mod.rs]
pub fn run_sync(opts: &SyncOpts) -> Result<SyncReport> {
    let repo_root = find_repo_root()?;
    let config = config::load_config(&repo_root)?;
}
::

Rendered

src/sync/mod.rs — rust
pub fn run_sync(opts: &SyncOpts) -> Result<SyncReport> {
    let repo_root = find_repo_root()?;
    let config = config::load_config(&repo_root)?;
}

Degrades to

```rust
pub fn run_sync(opts: &SyncOpts) -> Result<SyncReport> {
    let repo_root = find_repo_root()?;
    let config = config::load_config(&repo_root)?;
}
```

6. Data Blocks

Blocks that embed structured, queryable data inside documents.

::data
Data Container Implemented

Structured data with schema, supporting table, CSV, and JSON formats.

Attributes

AttributeValuesDefault
idUnique identifierAuto-generated
formattable, csv, jsontable
sortableBooleanfalse
filterableBooleanfalse
chartbar, line, pie, nonenone
sourceFile pathNone

Source

.surf
::data[id=competitors format=table sortable]
| Company | Funding | Users  | Threat |
|---------|---------|--------|--------|
| Linear  | $52M    | 10K+   | High   |
| Jira    | Public  | 250K+  | Medium |
::

Rendered

CompanyFundingUsersThreat
Linear$52M10K+High
JiraPublic250K+Medium

Degrades to

| Company | Funding | Users  | Threat |
|---------|---------|--------|--------|
| Linear  | $52M    | 10K+   | High   |
| Jira    | Public  | 250K+  | Medium |
::metric
Data Leaf Implemented

Single metric display with label, value, trend, and optional change indicator.

Attributes

AttributeValuesDefault
labelStringRequired
valueStringRequired
trendup, down, flatNone
unitStringNone
changeString (percentage or absolute)None
periodStringNone

Source

.surf
::metric[label="MRR" value="$2,400" trend=up]

Rendered

$2,400
MRR

Degrades to

**MRR:** $2,400
::timeline
Data Container Spec only

Chronological sequence of events with dates and descriptions.

Attributes

AttributeValuesDefault
No attributes

Source

.surf
::timeline
- 2026-01: Beta launch
- 2026-02: First paying customers
- 2026-03: Angel round
::

Rendered

2026-01 — Beta launch
2026-02 — First paying customers
2026-03 — Angel round

Degrades to

- 2026-01: Beta launch
- 2026-02: First paying customers
- 2026-03: Angel round
::chart
Data Container Spec only

Data visualization with bar, line, pie, area, and scatter chart types.

Attributes

AttributeValuesDefault
typebar, line, pie, area, scatterRequired
titleStringNone
xColumn name for x-axisFirst column
yColumn name(s) for y-axisRemaining columns
stackedBooleanfalse

Source

.surf
::chart[type=bar title="Revenue by Quarter"]
| Quarter | Revenue |
|---------|---------|
| Q1 2026 | $3,000  |
| Q2 2026 | $8,000  |
::

Rendered

[Chart: Revenue by Quarter — bar chart]

Degrades to

*[Chart: Revenue by Quarter]*

| Quarter | Revenue |
|---------|---------|
| Q1 2026 | $3,000  |
| Q2 2026 | $8,000  |

7. Conversation Blocks

Blocks that structure multi-party discussions and decision alternatives.

::turn
Conversation Container Spec only

A single participant's contribution in a threaded conversation.

Attributes

AttributeValuesDefault
participantStringRequired
timeISO timestampNone
rolehuman, ai, systemInferred
modelModel identifierNone

Source

.surf
::turn[participant=brady time=2026-02-10T05:00Z]
Should we go native per platform?
::

Rendered

B
brady · 2026-02-10 05:00

Should we go native per platform?

Degrades to

### Brady &mdash; 2026-02-10 05:00

Should we go native per platform?
::alternatives
Conversation Container Spec only

Structured comparison of options considered, with pros, cons, and verdict.

Attributes

AttributeValuesDefault
No attributes

Source

.surf
::alternatives
| Option   | Pros            | Cons          | Verdict     |
|----------|-----------------|---------------|-------------|
| GTK4     | 5MB, native     | Linux-first   | **Selected**|
| Electron | Cross-platform  | 150MB, heavy  | Rejected    |
::

Rendered

OptionProsConsVerdict
GTK45MB, nativeLinux-firstSelected
ElectronCross-platform150MB, heavyRejected

Degrades to

| Option   | Pros            | Cons          | Verdict     |
|----------|-----------------|---------------|-------------|
| GTK4     | 5MB, native     | Linux-first   | **Selected**|
| Electron | Cross-platform  | 150MB, heavy  | Rejected    |

8. Task Blocks

Actionable task lists and progress indicators embedded in documents.

::tasks
Task Container Implemented

Actionable task list with assignees, status tags, and dependency tracking.

Attributes

AttributeValuesDefault
sourceinline, surfdoc, githubinline
projectExternal project IDNone
filterQuery stringNone

Source

.surf
::tasks[source=inline]
- [x] Build parser crate @brady #done
- [ ] Add chart rendering @brady #in-progress
- [ ] Publish to crates.io @brady
::

Rendered

Build parser crate @brady
☐ Add chart rendering @brady
☐ Publish to crates.io @brady

Degrades to

- [x] Build parser crate @brady #done
- [ ] Add chart rendering @brady #in-progress
- [ ] Publish to crates.io @brady
::progress
Task Leaf Spec only

Visual progress indicator with label, value, and maximum.

Attributes

AttributeValuesDefault
valueNumberRequired
labelStringNone
maxNumber100

Source

.surf
::progress[value=65 label="Sprint 3 completion" max=100]

Rendered

Sprint 3 completion — 65%

Degrades to

**Sprint 3 completion:** 65%

9. Reference Blocks

Cross-references, embeds, and citations that link documents together.

::embed
Reference Leaf Implemented

Embed content from another SurfDoc or external file with optional section targeting.

Attributes

AttributeValuesDefault
srcFile pathRequired
sectionHeading to extractEntire file
modefull, preview, linkpreview
linesLine rangeNone

Source

.surf
::embed[src=.context/docs/architecture.md section="## Stack" mode=preview]

Degrades to

See: [architecture.md &mdash; Stack](.context/docs/architecture.md)
::footnote
Reference Container Spec only

Document-level footnote with citation for evidence-tagged claims.

Attributes

AttributeValuesDefault
idFootnote identifierRequired

Source

.surf
::footnote[id=1]
Gartner, "Magic Quadrant for PM Tools," 2025. Tier 1 source.
::

Degrades to

[^1]: Gartner, "Magic Quadrant for PM Tools," 2025. Tier 1 source.

10. Layout Blocks

Blocks that control content arrangement: columns, tabs, collapsibles, and dividers.

::columns
Layout Container Implemented

Multi-column layout with nested :::column children or --- separators.

Attributes

AttributeValuesDefault
count2–42
gapsm, md, lgmd
ratioRatios like 2:1 or 1:1:1Equal

Source

.surf
::columns

:::column
Left column content.
:::

:::column
Right column content.
:::

::

Rendered

Left column content.
Right column content.

Degrades to

Left column content.

Right column content.
::tabs
Layout Container Implemented

Tabbed content sections where headings within the block define tab panels.

Attributes

AttributeValuesDefault
No attributes — tabs derived from ## or ### headings

Source

.surf
::tabs

## Linux
Install via PPA: `sudo apt install surf-browser`

## macOS
Install via Homebrew: `brew install surf-browser`

::

Rendered

Linux
macOS

Install via PPA: sudo apt install surf-browser

Degrades to

## Linux
Install via PPA: `sudo apt install surf-browser`

## macOS
Install via Homebrew: `brew install surf-browser`
::details
Layout Container Implemented

Collapsible content section with a title toggle.

Attributes

AttributeValuesDefault
titleStringNone
openBooleanfalse

Source

.surf
::details[title="Implementation details" open=false]
The sync engine uses SHA-256 content hashing.
::

Rendered

Implementation details

The sync engine uses SHA-256 content hashing.

Degrades to

<details>
<summary>Implementation details</summary>
The sync engine uses SHA-256 content hashing.
</details>
::divider
Layout Leaf Implemented

Thematic break with optional centered label.

Attributes

AttributeValuesDefault
labelStringNone

Source

.surf
::divider[label="Phase 2"]

Rendered


Phase 2

Degrades to

---

11. Landing Page Blocks

Web generation blocks for building complete websites from .surf files. These blocks are used inside ::page containers.

::site
WebContainerImplemented

Site-level configuration: domain, theme, accent color, nav, and footer text.

Attributes

AttributeValuesDefault
domainDomain nameNone

Source

.surf
::site[domain=example.com]
  name: My App
  theme: dark
  accent: #6366f1
::

Degrades to

**Site Configuration:** example.com, theme: dark
::page
WebContainerImplemented

Defines a route and its layout for web generation.

Attributes

AttributeValuesDefault
routeURL pathRequired
layouthero, cards, pricing, docs, landing, split, gallerylanding
titlePage titleFirst heading
descriptionMeta descriptionFirst paragraph
sidebarBooleanfalse

Source

.surf
::page[route=/ layout=hero]
# Welcome to My App
Build faster with less.
::cta[label="Get Started" href=/signup primary]
::

Degrades to

# Welcome to My App
Build faster with less.
[Get Started](/signup)
::cta
WebLeafImplemented

Call-to-action button with primary/secondary styling and optional icon.

Attributes

AttributeValuesDefault
labelButton textRequired
hrefURL or pathRequired
primaryBooleanfalse
iconBuilt-in icon nameNone

Source

.surf
::cta[label="Get Started" href=/signup primary icon=arrow-right]

Rendered

Degrades to

[Get Started](/signup)
::hero-image
WebLeafImplemented

Full-width hero visual for landing page headers.

Attributes

AttributeValuesDefault
srcImage path or URLRequired
altAlt textNone

Source

.surf
::hero-image[src=assets/screenshot.png alt="App screenshot"]

Degrades to

![App screenshot](assets/screenshot.png)
::testimonial
WebContainerImplemented

Customer testimonial with author, role, and company attribution.

Attributes

AttributeAliasesDefault
authornameNone
roletitleNone
companyorgNone

Source

.surf
::testimonial[author="Jane Dev" role="Engineer" company="Acme"]
Replaced 3 tools for me.
::

Rendered

“Replaced 3 tools for me.”

— Jane Dev, Engineer at Acme

Degrades to

> Replaced 3 tools for me.
> &mdash; Jane Dev, Engineer at Acme
::faq
WebContainerImplemented

Accordion FAQ where questions are defined by headings within the block.

Attributes

AttributeValuesDefault
No attributes — questions from ### headings

Source

.surf
::faq
### Is my data encrypted?
Yes &mdash; AES-256 at rest, TLS in transit.

### Can I self-host?
Yes. Docker image available.
::

Degrades to

### Is my data encrypted?
Yes &mdash; AES-256 at rest, TLS in transit.

### Can I self-host?
Yes. Docker image available.
::pricing-table
WebContainerImplemented

Pricing comparison table with tier columns.

Attributes

AttributeValuesDefault
No attributes — content is a pipe-delimited table

Source

.surf
::pricing-table
| | Free | Pro | Team |
|---|---|---|---|
| Price | $0 | $4.99/mo | $8.99/seat/mo |
| Notes | Unlimited | Unlimited | Unlimited |
::

Degrades to

| | Free | Pro | Team |
|---|---|---|---|
| Price | $0 | $4.99/mo | $8.99/seat/mo |
::logo-cloud
WebContainerSpec only

Horizontal strip of partner or customer logos with optional heading.

Attributes

AttributeValuesDefault
titleStringNone

Source

.surf
::logo-cloud[title="Trusted by"]
- assets/logos/acme.svg
- assets/logos/initech.svg
::

Degrades to

**Trusted by**: acme.svg, initech.svg
::subscribe
WebContainerSpec only

Email subscription form with custom action URL and placeholder text.

Attributes

AttributeValuesDefault
actionForm action URLNone
placeholderInput placeholderyou@email.com

Source

.surf
::subscribe[action=https://api.example.com/newsletter placeholder="you@email.com"]
Get notified when we launch.
::

Degrades to

Get notified when we launch. Subscribe: https://api.example.com/newsletter
::countdown
WebLeafSpec only

Event countdown timer with target date and label.

Attributes

AttributeValuesDefault
dateISO dateRequired
labelStringNone

Source

.surf
::countdown[date=2026-03-15 label="Launch day"]

Degrades to

**Launch day:** 2026-03-15
::style
WebContainerImplemented

Presentation overrides: accent color, fonts, spacing. No selectors, no cascade.

Attributes

AttributeValuesDefault
accentHex color#6366f1
fontFont preset namesystem
heading-fontFont preset nameInherits font
body-fontFont preset nameInherits font

Source

.surf
::style
  accent: #2563EB
  heading-font: montserrat
  body-font: inter
::

Degrades to

*Ignored entirely &mdash; content renders without styling overrides.*
::css
WebContainerSpec only

Raw CSS escape hatch for custom styling beyond ::style presets.

Attributes

AttributeValuesDefault
No attributes — body is raw CSS

Source

.surf
::css
.custom-thing { border: 2px dashed red; }
::

Degrades to

*Ignored entirely.*
::form
WebContainerImplemented

Form with input fields and a submit action.

Attributes

AttributeValuesDefault
submitForm action URLNone

Source

.surf
::form[submit=/api/contact]
Name: text
Email: email
Message: textarea
::

Degrades to

**Contact form:** /api/contact
- Name (text)
- Email (email)
- Message (textarea)

13. Inline Extensions

Inline extensions use single-colon syntax within text for evidence tags, status badges, person references, and knowledge references.

ExtensionSyntaxDegrades to
:evidence:evidence[tier=1 source="Gartner 2025"][verified — Gartner 2025]
:status:status[value=shipped][shipped]
:person:person[name="Brady Davis" role=founder]Brady Davis
:ref:ref[path=.context/docs/arch.md title="Architecture"][Architecture](arch.md)

14. Rendering Model

SurfDoc defines four rendering fidelities. The same source file produces progressively richer output.

FidelityEnvironmentOutput
1. Plain TextAny text editor (vim, nano)Raw syntax visible, fully readable
2. MarkdownGitHub, VS Code previewTables, links, headings rendered; block directives as text
3. SurfDoc RendererSurfDoc workspace, Surf BrowserInteractive: sortable tables, chat bubbles, charts, tabs
4. Exportsurf exportPublication-quality PDF, HTML, DOCX

Rendering Rules

  1. Unknown blocks are preserved. A renderer that does not understand a block type renders it as a fenced section with the block name as a label.
  2. Attributes are informational. A renderer that does not understand an attribute ignores it.
  3. Content is king. The content layer MUST always be accessible regardless of rendering fidelity.
  4. Progressive enhancement. Each fidelity level adds to the previous one.

15. Graceful Degradation

Every block type defines its degradation behavior. A SurfDoc without a renderer MUST be at least as useful as the equivalent plain markdown document.

BlockFidelity 1 (Text)Fidelity 2 (Markdown)
::callout> **Warning:** textBlockquote with bold label
::decision> **Decision:** textStyled blockquote
::summary*text*Italic paragraph
::data (table)Markdown tableMarkdown table
::metric**label:** valueBold label + value
::chartTable + labelTable + label
::turn### Name — timeHeading + paragraph
::tasks- [x] task @nameCheckbox list
::columnsSequential sectionsSequential sections
::tabsSequential headingsSequential sections
::detailsSection with heading<details> tag
::embedLink to sourceLink to source
::cta[label](href)Markdown link
::styleIgnoredIgnored

16. AI Interaction Model

SurfDoc is designed for AI agents to read, write, and modify without special tooling. The syntax is text-based, and block types are semantic.

::ai-context
AIContainerSpec only

Metadata block recording the AI context window state when content was generated.

Attributes

AttributeValuesDefault
modelModel identifierNone
tokensToken countNone
loadedBooleanfalse

Source

.surf
::ai-context[model=opus tokens=2400 loaded=true]
Context window state when this section was written.
::

Degrades to

*[AI context: opus, 2400 tokens]*
::ai-generated
AIContainerSpec only

Marks content as AI-generated with model, date, and human review status.

Attributes

AttributeValuesDefault
modelModel identifierNone
dateISO dateNone
reviewedBooleanfalse

Source

.surf
::ai-generated[model=opus date=2026-02-10 reviewed=false]
This section was generated by AI and has not been human-reviewed.
::

Degrades to

*[AI-generated, opus, 2026-02-10, not reviewed]* This section was generated by AI.

17. Document Types

The front matter type field maps to ARDS artifact types. Types are advisory — any block can appear in any document type.

TypePurposeKey Blocks
docEvergreen knowledge::data, ::callout, ::related
guideLiving how-to::callout[type=tip], ::code, ::tabs, ::details
conversationDecision record::turn, ::alternatives, ::decision, ::tasks
planTime-stamped strategy::timeline, ::metric, ::tasks, ::data
agentAgent definition::data, ::callout
preferenceUser config::data[format=json]
reportAnalysis output::chart, ::metric, ::data, ::summary
proposalRFC-style proposal::alternatives, ::decision, ::tasks, ::related
incidentIncident record::timeline, ::turn, ::callout[type=error], ::tasks
reviewStructured review::turn, ::data, ::decision

18. Relationship to ARDS

SurfDoc is the document format layer of the ARDS ecosystem. Every ARDS artifact is a SurfDoc. But SurfDoc is not limited to ARDS — it works independently as a general-purpose document format.

ARDS v1-3: File structure + discovery order + artifact types
     |
ARDS v4: Knowledge-context unification + scope model
     |
SurfDoc: Document format that makes artifacts rich, interactive, and AI-native

You do not need ARDS to use SurfDoc. You do not need SurfDoc to use ARDS. They are better together.

19. Export Targets

TargetDescription
PDFProfessional typography. Charts as vector graphics. Layout blocks produce actual columns.
HTMLFull interactivity. Sortable tables, collapsible sections, tab switching, chart rendering.
DOCXWord-compatible. Tables, headings, styled callouts. Charts as embedded images.
Slide DeckExperimental. Top-level headings become slides. ::columns become slide layouts.

20. Tooling

surf CLI

bash
surf render <file>                   # Render to terminal
surf render <file> --html             # Render to HTML
surf validate <file>                  # Validate syntax and front matter
surf convert <file>                   # Auto-annotate markdown with blocks
surf new doc "Architecture"           # Create new SurfDoc

Parser Library (surf-parse)

Reference parser in Rust. 378+ tests, 35 block types implemented. Also available as npm package, Python package, and WASM module.

rust
let doc = surf_parse::parse(content);
let html = doc.doc.to_html();            // Rendered HTML
let blocks = doc.doc.blocks();           // Structured block tree

21. Web Generation

SurfDoc files can generate complete websites. A .surf file with ::site and ::page blocks contains everything needed to produce a multi-route static site.

bash
surf build site.surf --out dist/       # Static HTML+CSS+JS
surf serve site.surf                    # Local dev server with hot reload
surf pack site.surf --out site.html    # Single portable HTML file

Layout Types

LayoutDescription
heroFull-viewport splash with centered content and CTA
cardsResponsive card grid (auto 1-2-3 columns)
pricingPricing comparison with highlighted tier
docsSidebar navigation + content area
landingVertically stacked full-width sections
splitTwo-panel side-by-side (text + image)
galleryImage/project grid with lightbox

22. Self-Contained Bundling

SurfDoc supports bundling all assets into a single .surfpack file (ZIP archive) or a single .html file with all content inlined.

document.surfpack
+-- index.surf          # The main document
+-- manifest.json       # Asset inventory with checksums
+-- assets/
    +-- images/
    +-- fonts/

surf pack --html produces one HTML file containing all content, CSS, base64-encoded assets, and the embedded runtime. The original .surf source is recoverable via surf unpack.

23. Computed Data Layer

Data blocks can reference other blocks and compute derived values using =function(#block-id, 'column') syntax.

FunctionPurpose
=sum(#id, 'col')Sum of column values
=avg(#id, 'col')Average
=count(#id)Row count
=max(#id, 'col')Maximum
=min(#id, 'col')Minimum
=last(#id, 'col')Last row value

Computed values are not Turing-complete — no loops, no conditionals. They degrade to their last-evaluated static value.

24. Security Model

SurfDoc is designed to be received from untrusted sources. The security model assumes every document is adversarial.

Core Principles

  1. Inert by default. Nothing executes on open, load, render, or view.
  2. No ambient authority. No cookies, no session tokens, no implicit credentials.
  3. Typed block tree, not arbitrary DOM. Unknown types render as plain text.
  4. Fixed visual semantics. A ::callout[type=warning] always looks like a warning.
  5. Explicit permission model. Execution, network, and filesystem require per-document consent.
  6. Deterministic rendering. Same input always produces the same visual output.

Permission Categories

PermissionDefaultGrant Mechanism
executeDeniedPer-block consent dialog
networkDenied (cross-origin)Same-origin auto; cross-origin consent
filesystemDeniedPer-file consent dialog
clipboardAllowed (read-only)Automatic for user-initiated copy
printAllowedAutomatic

25. Context-Budget Loading

SurfDoc defines a loading priority protocol for AI agents operating under token constraints. Any block can declare a priority attribute (0-4).

PriorityContentLoading
0Front matter + ::summary blocksAlways loaded first
1Core contentLoaded early
2Supporting contentOn demand
3SupplementaryIf budget permits
4Appendices, historicalOnly if specifically needed

26. Surf Browser

SurfDoc defines a browser architecture for native rendering with a dual-engine design.

Surf Browser
+-- SurfEngine (Rust + GPU)     <- .surf files
|   +-- surf-parse              <- Parser
|   +-- surf-layout             <- Block tree to positioned rectangles
|   +-- surf-render             <- GPU rendering (wgpu/skia)
|
+-- WebView (platform WebKit)   <- .html sites
|   +-- Full web compatibility
|
+-- AI Layer
    +-- Block-tree query API
    +-- Summarization
    +-- Knowledge graph

No DOM. SurfEngine uses a typed, immutable block tree. No XSS. No script injection vector. Deterministic rendering. Same .surf always produces the same visual output.

27. Executable Code

Documents contain code, and code should be runnable. The runnable attribute on ::code blocks activates execution, turning a .surf file into a Jupyter-class notebook that degrades to a readable text file.

::kernel
ExecutableContainerSpec only

Declares the execution environment (runtime, packages, sandbox level) for a language.

Attributes

AttributeValuesDefault
langLanguage identifierRequired
envEnvironment nameNone
runtimeRuntime versionSystem default
packagesPackage listNone
sandboxstrict, network, filesystem, unrestrictedstrict

Source

.surf
::kernel[lang=python env=analysis]
  runtime: python3.12
  packages: [numpy, pandas, matplotlib]
  sandbox: strict
::

Degrades to

*[Kernel: python3.12, packages: numpy, pandas, matplotlib]*
::output
ExecutableContainerSpec only

Captures the result of executing a ::code[runnable] block.

Attributes

AttributeValuesDefault
forID of source ::code blockRequired
timestampISO 8601 timestampAuto
exitExit code (0 = success)Auto
formattext, html, image, table, charttext
truncatedBooleanAuto

Source

.surf
::output[for=analysis timestamp="2026-02-10T12:00:00Z" exit=0]
Mean quarterly revenue: $12,000
Growth: 633%
::

Degrades to

```
Mean quarterly revenue: $12,000
Growth: 633%
```

28. Accessibility

SurfDoc is accessible by construction, not by remediation. If a .surf file is valid, it is accessible. Every block type defines a narration strategy, reading modes, and semantic navigation.

Block Narration Contract

Every block type MUST define a narration strategy. Adding a new block type without defining its narration is a compilation error in the reference implementation.

Reading Modes

ModeBehavior
OverviewAnnounces document structure: section count, block types, task completion
Type-FilteredRead only blocks of a given type (e.g., decisions only, metrics only)
SkimHigh-signal blocks only: summaries, callouts, metrics, decisions
ConversationNatural language queries about the document content

Semantic Navigation

KeyTarget
HNext heading
DNext ::decision
MNext ::metric
TNext ::tasks
ANext ::callout (warnings first)
CNext ::cta action
SNext ::summary