From bc054320902d7a93b761bf5c0c97f1c8ab423585 Mon Sep 17 00:00:00 2001 From: Yuriy Andamasov Date: Thu, 7 May 2026 10:26:22 +0300 Subject: chore(claude-md): document repo conventions on sagitta MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backport of [#1902](https://github.com/vyos/vyos-documentation/pull/1902) (current). Adds the CLAUDE.md describing the post-flip MyST-as-primary state, build/test/lint commands, RST override mechanism, and source conventions. Content is identical to [#1902](https://github.com/vyos/vyos-documentation/pull/1902) — every file referenced (`tests/test_swap_sources.py`, `scripts/swap_sources.py`, `docs/_rst_overrides.txt`, `docs/_ext/vyos.py`, `docs/_ext/autosectionlabel.py`) exists on sagitta too, and the branches table covers all 3 release lines. \xf0\x9f\xa4\x96 Generated by [robots](https://vyos.io) --- CLAUDE.md | 186 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..5b5f6225 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,186 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project + +VyOS user documentation, built with Sphinx and hosted on Read the Docs at https://docs.vyos.io. Sources are MyST Markdown (`.md`) for migrated pages and RST (`.rst`) for the rest. Both formats are first-class to Sphinx; MD is the canonical source for any page that has been migrated, and RST is the canonical source for pages that haven't. + +A small swap mechanism exists for the rare case where a maintainer needs to render the legacy RST version of a page that already has an MD primary — see `RST override mechanism` below. The override list is empty by default. + +## Build + +```bash +# Docker (recommended — bundles Sphinx and the MyST/RTD plugin set) +docker build -t vyos/vyos-documentation docker +docker run --rm -it -v "$(pwd)":/vyos -w /vyos/docs \ + -e GOSU_UID=$(id -u) -e GOSU_GID=$(id -g) \ + vyos/vyos-documentation make html + +# Live-reload server on port 8000 +docker run --rm -it -p 8000:8000 -v "$(pwd)":/vyos -w /vyos/docs \ + -e GOSU_UID=$(id -u) -e GOSU_GID=$(id -g) \ + vyos/vyos-documentation make livehtml + +# Local (Python 3, see requirements.txt for pinned versions) +pip install -r requirements.txt +cd docs && make html +``` + +Output: `docs/_build/html/`. + +## Tests + +`tests/test_swap_sources.py` imports `swap_sources` from `scripts/`, which is +not on `PYTHONPATH` by default. Run from the `tests/` directory: + +```bash +cd tests +PYTHONPATH=../scripts python -m pytest # all tests +PYTHONPATH=../scripts python -m pytest test_swap_sources.py # single file +``` + +## Lint + +The repo doesn't ship a local lint config or pin a linter binary. CI runs +`vyoslinter` (`doc-linter.py` from the `vyos/.github` repo, via the +`lint-doc.yml` workflow) on changed files only — see the CI section +below. For local checks, manually grep for the rules in +[Source conventions](#source-conventions) (line length, address space, +suppression markers). + +## Branches and versions + +One long-lived branch per VyOS release line. Branch names are constellations sorted by area: + +| Branch | VyOS version | +|--------|--------------| +| `current` | rolling / 1.5+ (default branch — all new docs target this) | +| `circinus` | 1.5.x | +| `sagitta` | 1.4.x | +| `equuleus` | 1.3.x (legacy) | +| `crux` | 1.2.x (legacy) | + +PRs target `current`. After merge, request backports via Mergify comments on the PR: + +``` +@Mergifyio backport circinus +@Mergifyio backport sagitta +``` + +Mergify is configured at the org level (no `.mergify.yml` in the repo). The PR template has a `## Backport` section to declare intent. + +## Architecture + +### Sphinx config (`docs/conf.py`) + +- `source_suffix = ['.rst', '.md']` — both formats build into the same site. +- MyST extensions: `colon_fence`, `deflist`, `fieldlist`, `substitution`. +- `myst_fence_as_directive = ["cfgcmd", "opcmd", "cmdincludemd"]` — MyST fences with these names get parsed as if they were RST directives. This is how command pages stay format-portable. +- Custom modules live in `docs/_ext/` (only files listed in `extensions = [...]` in `conf.py` are actual Sphinx extensions; the others are support scripts loaded ad hoc): + - `vyos.py` (Sphinx extension, registered as `vyos`) — defines the `cfgcmd`, `opcmd`, `cmdinclude`, `cmdincludemd`, `cfgcmdlist`, `opcmdlist` directives and `cfgcmd`/`opcmd` roles that drive command coverage tracking. + - `autosectionlabel.py` (Sphinx extension, registered as `autosectionlabel`) — connects to `doctree-read` to register sections as labels. + - `testcoverage.py` — standalone helper that reads VyOS XML command definitions and exposes coverage stats; not a Sphinx extension. + - `releasenotes.py` — standalone release-notes/changelog generator script; not a Sphinx extension. + +### RST override mechanism + +For pages that have been migrated from RST to MyST: + +- `docs/.md` — canonical MD source (primary). +- `docs/rst-.rst` — preserved RST sibling kept around as an override option, prefixed `rst-` so it doesn't collide with the MD. Excluded from the build by `exclude_patterns` in `conf.py`. +- `docs/_rst_overrides.txt` — list of page stems that should render from `rst-.rst` instead of `.md`. Empty by default; pages listed here have their RST temporarily activated for the build. +- `scripts/swap_sources.py` — CLI for `--swap` (apply overrides), `--restore`, `--dry-run`, `--status`. Build-time state lands in `docs/_build/_rst_override_state.json` and `docs/_build/_md_exclude.txt` (gitignored). + +For pages that have NOT been migrated: + +- `docs/.rst` — original RST, no `rst-` prefix, no MD sibling. + +**Editing rules:** +- Migrated page (has `.md`): edit the `.md`. Don't touch `rst-.rst` unless you're maintaining a parallel RST version that someone has flagged in `_rst_overrides.txt`. +- Non-migrated page (RST-only): edit the `.rst`. +- New page: write it as `.md` from the start. The `md-` prefix that earlier MyST migration commits used is gone — never add it. + +Running `make html` runs the swap automatically (it's a no-op when the override list is empty, which is the default state). + +### Command directives + +`.. cfgcmd::`, `.. opcmd::`, and `.. cmdinclude::` are the VyOS-specific Sphinx directives in RST. They are tracked for command coverage — do **not** convert them to plain `.. code-block::`. In MyST the same directives are written as fenced blocks: ` ```{cfgcmd} set system ... ` (enabled by `myst_fence_as_directive`). The MyST include directive is named `cmdincludemd` (not `cmdinclude`) so that template parsing follows MyST rules in MD pages and RST rules in RST pages — pick `cmdinclude` in `.rst`, `cmdincludemd` in `.md`. + +## Source conventions + +### RST heading hierarchy + +``` +##### Title (overline+underline, one per file) +***** Chapters +===== Sections +----- Subsections +^^^^^ Subsubsections +""""" Paragraphs +``` + +The first heading in every RST file uses `#` overline+underline. Field lists (e.g., `:lastproofread:`) or labels may precede it. + +### Formatting + +- 80-character line limit (exception: inside `.. code-block::` / fenced code blocks — `
` preserves source verbatim).
+- American English.
+- Indent with 2 spaces.
+- Blank lines around headings.
+- Inline code: `` ``command`` ``.
+
+### IP addresses (linter-enforced)
+
+Allowed without suppression:
+- RFC 5737 IPv4 docs: `192.0.2.0/24`, `198.51.100.0/24`, `203.0.113.0/24`
+- RFC 3849 IPv6 docs: `2001:db8::/32`
+- RFC 1918 private ranges: `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`
+- Loopback (`127.0.0.0/8`), link-local (`169.254.0.0/16`), `0.0.0.0/0`
+
+Allowed ASN: `64496-64511` (16-bit), `65536-65551` (32-bit).
+Allowed MAC ranges: `00-53-00`–`00-53-FF` (unicast), `90-10-00`–`90-10-FF` (multicast).
+
+**Requires `stop/start_vyoslinter` suppression:**
+- Real public IPs (e.g., `8.8.8.8` for DNS examples).
+- NAT64 well-known prefix `64:ff9b::/96`.
+- Lines over 80 chars (URLs, certificate fingerprints).
+
+### Linter suppression markers
+
+```rst
+.. stop_vyoslinter
+
+.. code-block:: none
+
+   content with real IPs or long lines here
+
+.. start_vyoslinter
+```
+
+In MyST `.md` files use the comment form `% stop_vyoslinter` / `% start_vyoslinter` for top-level Markdown content. Inside `{eval-rst}` blocks (where the embedded content is parsed as RST) keep the RST form `.. stop_vyoslinter` / `.. start_vyoslinter` — the linter scans the source line literally and only the form that matches the surrounding parser is recognized. Likewise, `.txt` template files (included via `{include}` or `cmdincludemd`) keep the RST form.
+
+Markers must always come in pairs. Indentation may match the surrounding directive (indented inside a block) or sit at column 0 (top-level) — both are valid.
+
+### Configuration page structure
+
+1. **Theory** — what it is, when to use it, relevant RFCs.
+2. **Configuration** — all CLI options as `.. cfgcmd::` (RST) or ` ```{cfgcmd} ` (MD).
+3. **Examples** — practical configurations with topology diagrams.
+4. **Known issues** — problems and workarounds.
+5. **Debugging** — log collection, `show` commands, state indicators.
+
+### `.. TODO::` markers
+
+Two valid uses:
+1. **Tracking** marker on pages that still need `cfgcmd`/`opcmd` conversion — intentional.
+2. **Stale** marker on pages that already have full content — should be removed.
+
+A PR that both adds and removes TODOs is not contradictory; intent matters.
+
+## CI
+
+- **vyoslinter** (`doc-linter.py` from the `vyos/.github` repo, run via `lint-doc.yml`) — line length and IP rules, on changed files only.
+- **Sphinx build** — runs on Read the Docs for every PR; preview URL appears as a check.
+- **CLA check** — contributors must sign the VyOS CLA before merge.
+- **Conflict check** — fails the PR if it doesn't merge cleanly into base.
-- 
cgit v1.2.3


From 6c4529401aca13d65cc91fc6dc93cbe81fe1f25c Mon Sep 17 00:00:00 2001
From: Yuriy Andamasov 
Date: Thu, 7 May 2026 10:30:30 +0300
Subject: docs(claude-md): document PR review bot workflow
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Add a "PR review workflow" section after CI describing how Copilot
and CodeRabbit are used on this repo:

- Copilot is opt-in (`@copilot review`) and works on drafts.
- CodeRabbit auto-runs when a PR flips to ready-for-review and does
  not review drafts.
- Convention: draft → iterate with Copilot → flip ready → iterate
  CodeRabbit → human review.
- Every review thread needs an explicit reply before resolving.

This matches the cross-repo workflow in `vyos-github` org rules and
makes the convention discoverable for new contributors landing on the
repo without prior context.

\xf0\x9f\xa4\x96 Generated by [robots](https://vyos.io)
---
 CLAUDE.md | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/CLAUDE.md b/CLAUDE.md
index 5b5f6225..4225b39b 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -184,3 +184,20 @@ A PR that both adds and removes TODOs is not contradictory; intent matters.
 - **Sphinx build** — runs on Read the Docs for every PR; preview URL appears as a check.
 - **CLA check** — contributors must sign the VyOS CLA before merge.
 - **Conflict check** — fails the PR if it doesn't merge cleanly into base.
+
+## PR review workflow
+
+Two automated reviewers run on PRs in this repo:
+
+- **Copilot** (`@copilot`) — opt-in, works on draft PRs. Trigger by commenting `@copilot review` on the PR.
+- **CodeRabbit** (`@coderabbitai`) — auto-runs when a PR flips to ready-for-review. Does **not** review drafts. Re-trigger with `@coderabbitai review` after each round of fixes.
+
+Convention:
+
+1. Open the PR as a **draft** (`gh pr create --draft`).
+2. Iterate while draft: comment `@copilot review` per round of commits until Copilot is silent.
+3. Flip to ready (`gh pr ready `). CodeRabbit picks it up automatically.
+4. Address CodeRabbit threads, push commits, re-comment `@coderabbitai review` if you want another pass.
+5. When both bots are silent, the PR is ready for human review.
+
+Every review thread (Copilot or CodeRabbit) needs an **explicit reply** before resolving — fix in code with the commit SHA, or push back with technical reasoning. Never silently resolve.
-- 
cgit v1.2.3


From 2a779dc9e199c5e3770d36f31fca79ad31a9284a Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 7 May 2026 07:32:28 +0000
Subject: fix(claude-md): correct swap-is-automatic claim — swap is manual
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Agent-Logs-Url: https://github.com/vyos/vyos-documentation/sessions/e8823899-f182-4932-9652-e05abb57ef45

Co-authored-by: andamasov <12631358+andamasov@users.noreply.github.com>
---
 CLAUDE.md | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/CLAUDE.md b/CLAUDE.md
index 4225b39b..048fd0c3 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -101,7 +101,17 @@ For pages that have NOT been migrated:
 - Non-migrated page (RST-only): edit the `.rst`.
 - New page: write it as `.md` from the start. The `md-` prefix that earlier MyST migration commits used is gone — never add it.
 
-Running `make html` runs the swap automatically (it's a no-op when the override list is empty, which is the default state).
+The swap is **not** automatic. When `_rst_overrides.txt` is non-empty, run the
+swap script around the build manually:
+
+```bash
+python scripts/swap_sources.py --swap    # activate RST overrides
+cd docs && make html
+python scripts/swap_sources.py --restore # restore MD primaries
+```
+
+With the default empty override list no manual step is needed — `make html`
+builds entirely from MD sources as-is.
 
 ### Command directives
 
-- 
cgit v1.2.3


From dce4104c9142d9bd868e8974b6ec4f34e936b1b0 Mon Sep 17 00:00:00 2001
From: Yuriy Andamasov 
Date: Thu, 7 May 2026 10:32:32 +0300
Subject: Revert "docs(claude-md): document PR review bot workflow"

The bot review workflow is a cross-repo convention that lives in
the org-level rule file (`vyos-github`-style global instructions),
not in per-repo CLAUDE.md. Documenting it here would duplicate the
canonical source and risk drift if the workflow changes.

This reverts the section added in the previous commit on this branch.

\xf0\x9f\xa4\x96 Generated by [robots](https://vyos.io)
---
 CLAUDE.md | 17 -----------------
 1 file changed, 17 deletions(-)

diff --git a/CLAUDE.md b/CLAUDE.md
index 048fd0c3..afb0a068 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -194,20 +194,3 @@ A PR that both adds and removes TODOs is not contradictory; intent matters.
 - **Sphinx build** — runs on Read the Docs for every PR; preview URL appears as a check.
 - **CLA check** — contributors must sign the VyOS CLA before merge.
 - **Conflict check** — fails the PR if it doesn't merge cleanly into base.
-
-## PR review workflow
-
-Two automated reviewers run on PRs in this repo:
-
-- **Copilot** (`@copilot`) — opt-in, works on draft PRs. Trigger by commenting `@copilot review` on the PR.
-- **CodeRabbit** (`@coderabbitai`) — auto-runs when a PR flips to ready-for-review. Does **not** review drafts. Re-trigger with `@coderabbitai review` after each round of fixes.
-
-Convention:
-
-1. Open the PR as a **draft** (`gh pr create --draft`).
-2. Iterate while draft: comment `@copilot review` per round of commits until Copilot is silent.
-3. Flip to ready (`gh pr ready `). CodeRabbit picks it up automatically.
-4. Address CodeRabbit threads, push commits, re-comment `@coderabbitai review` if you want another pass.
-5. When both bots are silent, the PR is ready for human review.
-
-Every review thread (Copilot or CodeRabbit) needs an **explicit reply** before resolving — fix in code with the commit SHA, or push back with technical reasoning. Never silently resolve.
-- 
cgit v1.2.3


From 9408153eb889da403ea626277a418a63c98d11c7 Mon Sep 17 00:00:00 2001
From: Yuriy Andamasov 
Date: Thu, 7 May 2026 11:25:46 +0300
Subject: Revert "fix(claude-md): correct swap-is-automatic claim — swap is
 manual"
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

[#1908](https://github.com/vyos/vyos-documentation/pull/1908) merged 2026-05-07 and brought sagitta's `docs/Makefile` to
parity with current/circinus, including the auto-swap integration
(`html: swap` prereq with `--restore` trap on exit). The
"swap is manual" wording added by Copilot SWE agent on this PR
(commit 2a779dc9) was accurate against pre-#1908 sagitta but is
now wrong.

Restore the original wording from #1902/#1906 so all three branches
say the same thing again — "Running `make html` runs the swap
automatically" — matching reality across the trio.

This brings CLAUDE.md md5 back to identical with #1902 and #1906.

\xf0\x9f\xa4\x96 Generated by [robots](https://vyos.io)
---
 CLAUDE.md | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/CLAUDE.md b/CLAUDE.md
index afb0a068..5b5f6225 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -101,17 +101,7 @@ For pages that have NOT been migrated:
 - Non-migrated page (RST-only): edit the `.rst`.
 - New page: write it as `.md` from the start. The `md-` prefix that earlier MyST migration commits used is gone — never add it.
 
-The swap is **not** automatic. When `_rst_overrides.txt` is non-empty, run the
-swap script around the build manually:
-
-```bash
-python scripts/swap_sources.py --swap    # activate RST overrides
-cd docs && make html
-python scripts/swap_sources.py --restore # restore MD primaries
-```
-
-With the default empty override list no manual step is needed — `make html`
-builds entirely from MD sources as-is.
+Running `make html` runs the swap automatically (it's a no-op when the override list is empty, which is the default state).
 
 ### Command directives
 
-- 
cgit v1.2.3


From c00cf7b7d72a27312f1574e5237f6ab0d0133c7c Mon Sep 17 00:00:00 2001
From: Yuriy Andamasov 
Date: Thu, 7 May 2026 11:28:49 +0300
Subject: docs(claude-md): fix Markdown rendering + clarify rst- prefix wording
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Three rendering/clarity fixes flagged by Copilot review across the
post-flip CLAUDE.md trio (#1902/#1906/#1907):

1. **Triple-backtick examples in single-backtick code spans broke
   Markdown rendering.** The MyST fence example
   ```{cfgcmd} set system ...``` was wrapped in a single-backtick
   span, where the inner triple backticks confuse the parser. Switch
   to a four-backtick code span so the literal fence renders cleanly.
   Same fix applied to the "Configuration page structure" bullet.

2. **RST inline-literal example used confusing nested backticks.** The
   line "Inline code: \`\`\`\`command\`\`\`\`" parsed but
   was hard to read. Replace with a plain explanation:
   "Inline code: use double backticks (\`\`command\`\`)".

3. **Clarify that the `rst-` override prefix attaches to the basename,
   not the path stem.** The previous wording `docs/rst-.rst`
   could be misread as a top-level prefix. The actual behavior in
   `scripts/swap_sources.py` is: for a page at
   `docs/automation/cloud-init.md`, the override file lives at
   `docs/automation/rst-cloud-init.rst` (basename-prefixed sibling).
   Spell that out with a concrete example.

Same fixes applied symmetrically across [#1902](https://github.com/vyos/vyos-documentation/pull/1902) (current),
[#1906](https://github.com/vyos/vyos-documentation/pull/1906) (circinus), and [#1907](https://github.com/vyos/vyos-documentation/pull/1907) (sagitta) — all three worktrees
back to byte-identical (md5 `d1ceaddc...`).

\xf0\x9f\xa4\x96 Generated by [robots](https://vyos.io)
---
 CLAUDE.md | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/CLAUDE.md b/CLAUDE.md
index 5b5f6225..0d897d51 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -88,7 +88,7 @@ Mergify is configured at the org level (no `.mergify.yml` in the repo). The PR t
 For pages that have been migrated from RST to MyST:
 
 - `docs/.md` — canonical MD source (primary).
-- `docs/rst-.rst` — preserved RST sibling kept around as an override option, prefixed `rst-` so it doesn't collide with the MD. Excluded from the build by `exclude_patterns` in `conf.py`.
+- `rst-.rst` — preserved RST sibling living next to `.md` (e.g. for `docs/automation/cloud-init.md`, the override sits at `docs/automation/rst-cloud-init.rst`). The `rst-` prefix attaches to the basename in the same directory, not to the path stem. Excluded from the build by `exclude_patterns` in `conf.py`.
 - `docs/_rst_overrides.txt` — list of page stems that should render from `rst-.rst` instead of `.md`. Empty by default; pages listed here have their RST temporarily activated for the build.
 - `scripts/swap_sources.py` — CLI for `--swap` (apply overrides), `--restore`, `--dry-run`, `--status`. Build-time state lands in `docs/_build/_rst_override_state.json` and `docs/_build/_md_exclude.txt` (gitignored).
 
@@ -97,7 +97,7 @@ For pages that have NOT been migrated:
 - `docs/.rst` — original RST, no `rst-` prefix, no MD sibling.
 
 **Editing rules:**
-- Migrated page (has `.md`): edit the `.md`. Don't touch `rst-.rst` unless you're maintaining a parallel RST version that someone has flagged in `_rst_overrides.txt`.
+- Migrated page (has `.md`): edit the `.md`. Don't touch the `rst-`-prefixed sibling unless you're maintaining a parallel RST version that someone has flagged in `_rst_overrides.txt`.
 - Non-migrated page (RST-only): edit the `.rst`.
 - New page: write it as `.md` from the start. The `md-` prefix that earlier MyST migration commits used is gone — never add it.
 
@@ -105,7 +105,7 @@ Running `make html` runs the swap automatically (it's a no-op when the override
 
 ### Command directives
 
-`.. cfgcmd::`, `.. opcmd::`, and `.. cmdinclude::` are the VyOS-specific Sphinx directives in RST. They are tracked for command coverage — do **not** convert them to plain `.. code-block::`. In MyST the same directives are written as fenced blocks: ` ```{cfgcmd} set system ... ` (enabled by `myst_fence_as_directive`). The MyST include directive is named `cmdincludemd` (not `cmdinclude`) so that template parsing follows MyST rules in MD pages and RST rules in RST pages — pick `cmdinclude` in `.rst`, `cmdincludemd` in `.md`.
+`.. cfgcmd::`, `.. opcmd::`, and `.. cmdinclude::` are the VyOS-specific Sphinx directives in RST. They are tracked for command coverage — do **not** convert them to plain `.. code-block::`. In MyST the same directives are written as fenced blocks: ```` ```{cfgcmd} set system ... ```` (enabled by `myst_fence_as_directive`). The MyST include directive is named `cmdincludemd` (not `cmdinclude`) so that template parsing follows MyST rules in MD pages and RST rules in RST pages — pick `cmdinclude` in `.rst`, `cmdincludemd` in `.md`.
 
 ## Source conventions
 
@@ -128,7 +128,7 @@ The first heading in every RST file uses `#` overline+underline. Field lists (e.
 - American English.
 - Indent with 2 spaces.
 - Blank lines around headings.
-- Inline code: `` ``command`` ``.
+- Inline code: use double backticks (`\`\`command\`\``).
 
 ### IP addresses (linter-enforced)
 
@@ -165,7 +165,7 @@ Markers must always come in pairs. Indentation may match the surrounding directi
 ### Configuration page structure
 
 1. **Theory** — what it is, when to use it, relevant RFCs.
-2. **Configuration** — all CLI options as `.. cfgcmd::` (RST) or ` ```{cfgcmd} ` (MD).
+2. **Configuration** — all CLI options as `.. cfgcmd::` (RST) or ```` ```{cfgcmd} ```` (MD).
 3. **Examples** — practical configurations with topology diagrams.
 4. **Known issues** — problems and workarounds.
 5. **Debugging** — log collection, `show` commands, state indicators.
-- 
cgit v1.2.3


From 89dd4c6d8c4f5be7e25300224ad5a28a3ec5da0b Mon Sep 17 00:00:00 2001
From: Yuriy Andamasov 
Date: Thu, 7 May 2026 11:30:13 +0300
Subject: docs(claude-md): align rst- prefix wording with the canonical
 detailed version

Yuriy/Copilot SWE pushed a more detailed rst-prefix block to [#1906](https://github.com/vyos/vyos-documentation/pull/1906)
that gives an explicit subdirectory example and a counter-example
(`configuration/firewall/zone` maps to
`docs/configuration/firewall/rst-zone.rst`, NOT
`docs/rst-configuration/firewall/zone.rst`). Adopt that exact wording
on the other two PRs in the trio so all three CLAUDE.md files match
again (md5 `acd58911...`).

\xf0\x9f\xa4\x96 Generated by [robots](https://vyos.io)
---
 CLAUDE.md | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/CLAUDE.md b/CLAUDE.md
index 0d897d51..c921033c 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -87,10 +87,19 @@ Mergify is configured at the org level (no `.mergify.yml` in the repo). The PR t
 
 For pages that have been migrated from RST to MyST:
 
-- `docs/.md` — canonical MD source (primary).
-- `rst-.rst` — preserved RST sibling living next to `.md` (e.g. for `docs/automation/cloud-init.md`, the override sits at `docs/automation/rst-cloud-init.rst`). The `rst-` prefix attaches to the basename in the same directory, not to the path stem. Excluded from the build by `exclude_patterns` in `conf.py`.
-- `docs/_rst_overrides.txt` — list of page stems that should render from `rst-.rst` instead of `.md`. Empty by default; pages listed here have their RST temporarily activated for the build.
-- `scripts/swap_sources.py` — CLI for `--swap` (apply overrides), `--restore`, `--dry-run`, `--status`. Build-time state lands in `docs/_build/_rst_override_state.json` and `docs/_build/_md_exclude.txt` (gitignored).
+- `docs//.md` — canonical MD source (primary).
+- `docs//rst-.rst` — preserved RST sibling kept around as an override
+  option. The `rst-` prefix applies only to the **filename**, not the directory, so
+  `configuration/firewall/zone` maps to `docs/configuration/firewall/rst-zone.rst`
+  (not `docs/rst-configuration/firewall/zone.rst`). Excluded from the build by
+  `exclude_patterns` in `conf.py`.
+- `docs/_rst_overrides.txt` — one stem per line, relative to `docs/` (e.g.
+  `configuration/firewall/zone`). Pages listed here render from
+  `rst-.rst` instead of `.md`. Empty by default.
+- `scripts/swap_sources.py` — CLI for `--swap` (apply overrides), `--restore`,
+  `--dry-run`, `--status`. Build-time state lands in
+  `docs/_build/_rst_override_state.json` and `docs/_build/_md_exclude.txt`
+  (gitignored).
 
 For pages that have NOT been migrated:
 
-- 
cgit v1.2.3


From 52ee2fc03571a47ca4e350922b24f793d8764ee4 Mon Sep 17 00:00:00 2001
From: Yuriy Andamasov 
Date: Thu, 7 May 2026 11:44:46 +0300
Subject: docs(claude-md): drop literal ``command`` example, link RST quickref
 instead
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The previous wording `Inline code: use double backticks (\`\`command\`\`)`
included literal backslashes intended to escape the inner backticks.
Markdown doesn't interpret backslashes inside code spans, so the
backslashes rendered verbatim — the rendered output read as
\`\`command\`\` instead of the intended ``command``.

Replace with a prose-only line that links the RST docutils quickref
(Inline markup section). No literal RST snippet to escape; rendering
is straightforward.

Same fix applied symmetrically across [#1902](https://github.com/vyos/vyos-documentation/pull/1902)/[#1906](https://github.com/vyos/vyos-documentation/pull/1906)/[#1907](https://github.com/vyos/vyos-documentation/pull/1907) — the
trio is byte-identical (md5 `bdea8e5c...`).

\xf0\x9f\xa4\x96 Generated by [robots](https://vyos.io)
---
 CLAUDE.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CLAUDE.md b/CLAUDE.md
index c921033c..99320758 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -137,7 +137,7 @@ The first heading in every RST file uses `#` overline+underline. Field lists (e.
 - American English.
 - Indent with 2 spaces.
 - Blank lines around headings.
-- Inline code: use double backticks (`\`\`command\`\``).
+- Inline code: use double backticks per RST convention (the [Inline markup](https://docutils.sourceforge.io/docs/user/rst/quickref.html#inline-markup) section of the docutils quick reference).
 
 ### IP addresses (linter-enforced)
 
-- 
cgit v1.2.3


From 220163505c2bd31f783dd3e6b194948581c65b06 Mon Sep 17 00:00:00 2001
From: Yuriy Andamasov 
Date: Thu, 7 May 2026 11:52:31 +0300
Subject: chore(github): backport PULL_REQUEST_TEMPLATE.md to sagitta

Sagitta is missing `.github/PULL_REQUEST_TEMPLATE.md` while current
and circinus have it (byte-identical between the two). Backport the
template verbatim so contributors landing on sagitta get the same
`## Change Summary`/`## Related Task(s)`/`## Related PR(s)`/
`## Backport`/`## Checklist:` form they see on the other branches.

Bundled here because [#1907](https://github.com/vyos/vyos-documentation/pull/1907)'s CLAUDE.md references the template's
`## Backport` section as the place to declare backport intent, and
the previous Copilot review pointed out (correctly) that the
referenced template didn't exist on sagitta. Backporting the file
makes the CLAUDE.md claim accurate.

\xf0\x9f\xa4\x96 Generated by [robots](https://vyos.io)
---
 .github/PULL_REQUEST_TEMPLATE.md | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)
 create mode 100644 .github/PULL_REQUEST_TEMPLATE.md

diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 00000000..c1eaa038
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,22 @@
+
+
+
+## Change Summary
+
+
+## Related Task(s)
+
+* https://vyos.dev/Txxxx
+
+## Related PR(s)
+
+
+## Backport
+
+
+
+
+## Checklist:
+
+
+- [ ] I have read the [**CONTRIBUTING**](https://github.com/vyos/vyos-documentation/blob/current/CONTRIBUTING.md) document
\ No newline at end of file
-- 
cgit v1.2.3