Web content

🔵 Agent OS includes a small content filesystem: the public site is rendered from Markdown + YAML that lives entirely in the config tree (config/web/), plus you can drop in raw HTML pages (for example, a fully custom landing page) that are served as-is. There is no database and no admin CMS — to change a page, you edit a file; with live reload, the change goes out without a restart or rebuild.


13.0 Built-in site and replacing it

A default site is baked into the binary (crates/modules/surfaces/agent_os_site/web/, code — crates/modules/surfaces/agent_os_site/src/lib.rs). It is compiled into the binary at build time and is served as long as config/web/ does not exist.

To replace it with your own site, create config/web/:

As soon as config/web/ exists and loads successfully (Site::load), it overrides the built-in site. If config/web/ does not exist, the built-in one is served. If it exists but fails to parse, the server falls back to the built-in one at startup, and on live reload it keeps the last working version (with a warning in the log).

config/web/ is hot-reloaded: edits, as well as added/removed pages, are picked up without a restart (§13.8).


13.1 What is configurable

File (in config/web/) Purpose Required
index.md YAML front matter (title, nav, cards, demos, extra pages) + markdown body of the landing page only for a markdown site
style.css stylesheet included on every page no
index.tpl.html landing page template (placeholders {...}) no (built-in default)
page.tpl.html detail page template no (built-in default)
pages/*.md content of detail pages per page
*.html (e.g. index.html, landing.html) full HTML document, served as-is no

Site::load is called at startup and again on live reload. The site is served under / and /site/.


13.2 index.md — front matter

Front matter is YAML between the lines ---. All fields are optional unless stated otherwise; defaults are shown.

---
title: My Site
tagline: One-line description
description: SEO / OG meta description (падает на tagline)
canonical_base: https://example.com   # абсолютная база; иначе из запроса
footer: © 2026 My Site

cases_title: Case Studies            # по умолчанию "Кейсы внедрения"
demos_title: Live Demos              # по умолчанию "Живые демо"
dev_title: For Developers            # по умолчанию "Для разработчиков"
dev_href: developers.html            # по умолчанию "developers.html"
dev_label: Tools and API             # по умолчанию "Инструменты и API платформы"
dev_icon: 🔧

nav:
  - { label: Home, href: index.html }
  - { label: Docs, href: documentation.html }

cards:
  - tag: Platform
    title: Overview
    href: overview.html
    desc: One-liner shown on the card
    src: pages/overview.md           # опц.; по умолчанию pages/<href minus .html>.md

demos:
  - { icon: "🚗", title: "Cars demo", href: "/demo/overlay?model=drom-agent", desc: "…" }

extra_pages:
  - { title: "Download", href: download.html, src: pages/download.md }
---

Field reference

Field Type Default Meaning
title string empty site title (<h1> and <title>)
tagline string empty subtitle; falls back as description
description string tagline <meta name="description"> + OG/Twitter
canonical_base string from the request absolute base for canonical/OG and sitemap.xml
footer string empty footer text (HTML-escaped)
cases_title string "Кейсы внедрения" heading of the cards section
demos_title string "Живые демо" heading of the demos section
dev_title / dev_href / dev_label / dev_icon string see above "for developers" section
nav list [] top navigation (label, href)
cards list required, non-empty case cards; href sets the name of the output .html
demos list [] live demo cards (open in a new tab)
extra_pages list [] extra pages that are not cards (title, href, src, optional section, hidden)

src cards by default pages/<href minus .html>.md; set it explicitly to pull a page from somewhere else (for example, a doc file outside config/web/). A card without a resolvable markdown source is skipped with a warning.

cards must not be empty — otherwise the site fails to load with an error (except when a raw index.html overrides the landing page; see §13.4).

Pages whose href starts with doc- are treated as documentation pages: they get a sidebar (

Getting started
Configuration
Tools
Hooks
Automation
Integrations
Operations
Extending the platform
Internals and reliability
) and prev/next (), grouped by section. The hidden: true flag keeps the page accessible via a direct link but removes it from the sidebar, pager, and sitemap.xml — for internal plans and notes.


13.3 Detail pages (pages/*.md)

Each page is a single Markdown file, rendered with the CommonMark dialect (comrak). The following extensions are enabled:

Extension Effect
tables GFM tables
strikethrough ~~текст~~
autolink bare URLs become links
tasklist - [ ] / - [x]
tagfilter escapes dangerous raw HTML

Internal links between markdown ([x](foo.md)) are rewritten to foo.html automatically.

Mermaid diagrams

Pages can embed ```mermaid blocks. The built-in template loads mermaid.js from a CDN and renders them client-side into SVG:

```mermaid
graph TD; A-->B;
```

The site's Content-Security-Policy allows https://cdn.jsdelivr.net.


13.4 Raw HTML pages (arbitrary landing page)

Any .html file directly in config/web/ (except *.tpl.html) is served as-is — bypassing markdown rendering and templates, with full control over <head>, scripts, styles, and fonts.

File Served at
index.html /, /index.html, /site/, /site/index.html — replaces the markdown landing page
any name.html /name.html and /site/name.html

A raw HTML page with the same name takes priority over a markdown page. Raw pages are included in sitemap.xml (except index.html, which maps to /).

This is the recommended way to make a custom landing page: put a full HTML document in config/web/index.html and embed the widget (a standalone /widget.js) anywhere. Raw pages are served without the markdown site's strict CSP, so external scripts, fonts, and iframes work as written.

index.md is optional when raw HTML pages are present: without it, the markdown site just doesn't render. For a markdown landing page and SEO meta, a valid index.md with a non-empty cards is still needed.


13.5 Templates

index.tpl.html and page.tpl.html are optional. If present in config/web/, they replace the built-in defaults. Placeholders are filled by {key}:

index.tpl.html page.tpl.html
{title} {head} {tagline} {nav_links} {content} {cases_title} {cards} {demos_title} {demos} {dev_title} {dev_href} {dev_label} {dev_icon} © 2026 Vector Solutions {title} {head} {site_title} {nav_links} {content} © 2026 Vector Solutions

{head} — the generated SEO/OG meta block; {content} — the body render. The built-in defaults are in crates/modules/surfaces/agent_os_site/src/lib.rs (INDEX_TPL_DEFAULT / PAGE_TPL_DEFAULT / DOC_TPL_DEFAULT); the built-in content is in crates/modules/surfaces/agent_os_site/web/.


13.6 SEO and crawler surfaces

Pages are served with a weak ETag (content hash) and Cache-Control: no-cache, so unchanged pages return 304 on live reload.


13.7 Routing

URL Serves
/, /index.html landing page
/site 301 redirect to /site/
/site/, /site/index.html landing page
/site/<page>.html detail page (from pages, src card, or raw .html)
/site/style.css style from config/web/style.css
/site/favicon.svg, /favicon.ico favicon
/robots.txt, /sitemap.xml crawler files
/:page, /site/:page any page from config/web/ (markdown or raw HTML); the handler reads the shared slot on every request, so added/removed pages work without a restart

Unknown pages — a styled 404.


13.8 Live reload

With kernel.live_reload: true (the default), the watcher re-renders the site from config/web/ on any file change — without a restart or rebuild. Added and removed pages are picked up the same way: the /… and /site/… routes are resolved from the shared slot on every request rather than being fixed at startup. It works the same way when the config comes from a git repository (AGENT_OS_CONFIG_REPO / --config-repo); see §3.1.


13.9 Embedding external content — /proxy

For pages that don't live in your config tree, there are two endpoints:

Endpoint Behavior
GET /proxy?url=... smart proxy: checks X-Frame-Options / CSP frame-ancestors; redirects to the direct URL if the site allows iframes, otherwise downloads and serves through the proxy
GET /proxy/content?url=... internal <body> only with scripts stripped, for embedding in div

Both are SSRF-safe: private, loopback, link-local, and reserved ranges (including 169.254.169.254) are blocked at every hop. proxy.allow_hosts in server.yaml additionally restricts hosts; empty = any public host.


13.10 Web content for agents

The above is a site for humans. For agents reading web content, the tools are described in §5:

Tool Use
http_fetch (built-in) fetch a URL into the agent's context
site_tool a configured page scraper
archive_tool full-text search over an offline site archive
rss_tool reading/searching RSS feeds
pdf_tool extracting text from PDF

The site is usually crawled (agent-os scrape) into an archive, which is then searched by archive_tool.