Everything content-shaped follows one convention. Learn it once and you can navigate, script against, and bulk-edit any Devani site.
The layout
site-root/
├── about/ # a page: /about/
│ ├── content.html # the page body (inside <main>)
│ └── meta.json # SEO + status metadata
├── blog/
│ └── my-post/ # a post: /blog/my-post/
│ ├── content.html
│ ├── meta.json
│ └── featured-image.txt # Tonta image id
├── products/
│ └── my-product/ # a product: /products/my-product/
├── header/content.html # site-wide header region
├── footer/content.html # site-wide footer region
├── global-styles.css # the site stylesheet
└── devani/ # the application itself
└── data/ # storage, navigation, snapshots
The three files per item
content.html— the rendered body. Plain HTML using the site's canonical classes (.section,.container,.vs-btn…). No PHP allowed — writes containing<?are rejected.meta.json— status (draft/published), title, published date, author, and all SEO fields:meta_title,meta_description,meta_keywords,canonical,robots,open_graph {title, description, image},twitter {card, title, description, image},schema.featured-image.txt— just the Tonta image id. Devani derives size-appropriate URLs from it (e.g._512for cards).
Rules that keep tooling happy
- Status truth lives in
meta.json. Index tables are derived from it — the filesystem is authoritative, and sync flows re-read meta rather than invent state. - Slugs are lowercase letters, numbers, hyphens. A set of directory names is reserved (
devani,header,footer,blog,products,assets,api, …) and tooling refuses to treat them as page slugs. - Media ids, not URLs. Store the Tonta id; derive URLs. That keeps every size variant reachable and survives CDN-side changes.
- Don't hand-edit while the site is being written to. If you script bulk changes, go through the MCP tools — they snapshot before every write and keep index tables in sync.