Writing pages
The file layout, front matter and the Markdown you can use, with examples of each.
Where a page lives#
documentation/
en/
20-getting-started/
_section.md
10-install-with-docker.md
20-first-login.md
am/
20-getting-started/
_section.md
10-install-with-docker.md
- The first folder is the language:
enoram. - The second is the section. Its file
_section.mdgives the section's title and summary. - Each other
.mdfile is a page. - The Amharic version of a page has the same path under
am/.
A leading number such as 20- or 10- orders things and is not part of the address. The page above is at /docs/en/getting-started/install-with-docker.
Addresses (slugs)#
The address comes from the file or folder name, after any number. Use lower-case letters, digits and single hyphens: install-with-docker. These names are reserved and cannot be used: search, sitemap, robots, static. A file that breaks the rule is skipped and reported in the server log; it never stops the module from updating.
Front matter#
A page may start with a small block between two lines of ---:
---
title: Install with Docker
summary: A self-contained stack on port 8291.
sequence: 10
published: true
---
| Key | Meaning | If missing |
|---|---|---|
title | The page title. | The first # Heading in the file, else the file name. |
summary | One line shown under the title, in the section index and in search results. | none |
sequence | Sort order. | The number in the file name, else alphabetical. |
published | false keeps the page as a draft. | true |
This is not full YAML: only simple key: value lines. Put quotes around a value if it contains a colon.
A first-line # Title is used as the title and removed from the text, because the site prints the title itself. Start your headings at ##.
Markdown you can use#
## A section heading
### A sub-section
Plain paragraphs, with **bold**, *italic*, ~~strikethrough~~ and `inline code`.
- A bullet list
- with a nested item
1. A numbered list
2. Second step
[An external link](https://n8n.io) and [a page in these docs](doc:administration/troubleshooting)
| Column | Other column |
|---|---|
| a cell | another cell |
> A quotation
---
Everything above is rendered by the site. Headings get an address you can link to, and appear in On this page.
Fixed heading addresses#
A heading's address normally comes from its words, so rewording it changes the address, and a translated heading gets a different one. Put an explicit address at the end of the heading to keep it stable:
## Guardrails {#guardrails}
The {#guardrails} part is not shown. Use it on any heading that other pages link to, and give the same address in the English and Amharic versions, so a link like doc:ai-workforce/autonomy-levels#guardrails works in both.
Links between pages#
Use the doc: form, which follows the reader's language and the site's address:
| You write | It links to |
|---|---|
[Troubleshooting](doc:administration/troubleshooting) | that page |
[Administration](doc:administration) | that section |
[A heading](doc:administration/troubleshooting#installing) | a heading on that page |
Ordinary https:// links open in a new tab.
Code blocks#
Put three backticks and, optionally, a language:
```bash
cd deploy && ./start.sh
```
Nothing inside is interpreted. Readers get a Copy button.
Tables#
Pipe tables, with optional alignment through colons in the separator row:
| Left | Right |
|:--|--:|
| a | 1 |
A literal | inside a cell is written \|.
Callouts#
Start a quotation with a marker in square brackets:
> [!NOTE]
> Something worth knowing.
> [!WARNING] Back up first
> A custom title goes after the marker.
| Marker | Use for |
|---|---|
[!NOTE] | Extra information. |
[!TIP] | A better way to do it. |
[!IMPORTANT] | Something the reader must not miss. |
[!WARNING] | Something that can go wrong. |
[!CAUTION] | Something that can cause damage or data loss. |
The default title is the English word. In an Amharic page, give a title in Amharic after the marker.
A caution callout looks like this:

Images#
Show a screenshot by its asset id, on a line of its own:

The site picks the image for the reader's language and, when there is one, a dark version. The alt text and the caption come from the image's record, in both languages. To make screenshots, see Screenshots.
An ordinary image still works, for example one hosted elsewhere:

Only http, https and relative or root-relative addresses are allowed. Prefer asset ids: they carry alt text in both languages and the tests check them.
What is not supported#
To keep the site safe and simple:
- Raw HTML is shown as text, not run.
- No footnotes, task lists, definition lists or setext (underlined) headings.
- No
javascript:ordata:links. They are replaced by#.
Preview#
On your own computer, without Odoo#
You need only Python 3. From the folder that contains smarterp_docs:
python3 smarterp_docs/tools/preview.py --open
Your browser opens the site at http://127.0.0.1:8300/docs. Edit a .md file, save, and reload the browser: no restart is needed. Add --editor to see pages marked published: false, labelled as drafts. Use --port if 8300 is taken, and --docs to preview another documentation folder.
The preview uses the same page templates, styles, fonts, search and Markdown renderer as the real site, so pages look and search the same. It does not have Odoo's back office, logins or database; use it to write and check content.
Inside Odoo#
- Edit in Odoo: Documentation → Pages, open the page and press View on Site. Unpublished pages show to you, labelled as drafts.
- Edit files: update the module (or Documentation → Sync from Files) and reload the page.
A good habit: read the page in both languages, and use the site's search to check that a reader would find it.