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/:
- a fully custom landing page — put
config/web/index.html(raw HTML, served as-is; see §13.4). The recommended path for a custom design; - a markdown site — create
config/web/index.mdwith a non-emptycards(§13.2) andconfig/web/pages/*.mdpages.
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 () and prev/next (Getting started
Configuration
Tools
Hooks
Automation
Operations
Extending the platform
Internals and reliability
), 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
GET /sitemap.xml— the index plus everycard.href,extra_pages.href, and raw.htmlpage (exceptindex.html).GET /robots.txt—Allow: /and theSitemap:pointer.<link rel="canonical">,og:*, andtwitter:cardon every page, usingcanonical_base(or fromHost+X-Forwarded-Proto).GET /favicon.icoandGET /site/favicon.svg— inline SVG favicon.
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.