From 97f048ac2529f3d02e759f1b19d21e4e2049398e Mon Sep 17 00:00:00 2001
From: Kiss
Date: Wed, 13 May 2026 13:02:48 +0200
Subject: [PATCH 1/7] Add markdown button and make llms.txt available
---
docs/conf.py | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
diff --git a/docs/conf.py b/docs/conf.py
index 85997cc8..e06ff152 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -5,6 +5,8 @@
author = "Shrey Ajmera, Akhila Yeruva"
import os
+from pathlib import Path
+import shutil
html_baseurl = os.environ.get("READTHEDOCS_CANONICAL_URL", "instinct.docs.amd.com")
html_context = {}
if os.environ.get("READTHEDOCS", "") == "True":
@@ -20,6 +22,7 @@
html_theme_options = {
"flavor": "instinct",
"link_main_doc": True,
+ "use_download_button": True,
# Add any additional theme options here
}
extensions = [
@@ -41,3 +44,54 @@
tags_intro_text = ""
tags_page_title = "Tag page"
tags_page_header = "Pages with this tag"
+
+EXCLUDED_DIRS = {
+ "_build",
+ "_templates",
+ "_static",
+ ".git",
+ ".venv",
+}
+
+def should_skip(path: Path) -> bool:
+ return any(part in EXCLUDED_DIRS for part in path.parts)
+
+
+def generate_combined_markdown(app, exception):
+ if exception:
+ return
+
+ docs_root = Path(app.srcdir)
+ output_file = Path(app.outdir) / "llms.txt"
+
+ print(output_file)
+
+ all_files = sorted(docs_root.rglob("*.md"))
+
+ combined = []
+ combined.append("# Combined Documentation\n")
+
+ for doc_file in all_files:
+ if should_skip(doc_file):
+ continue
+
+ relative = doc_file.relative_to(docs_root)
+
+ combined.append(f"\n---\n")
+ combined.append(f"\n# {relative}\n")
+
+ try:
+ content = doc_file.read_text(encoding="utf-8")
+ combined.append(content)
+ combined.append("\n")
+
+ except Exception as e:
+ combined.append(f"\n[ERROR reading file: {e}]\n")
+
+ output_file.write_text(
+ "\n".join(combined),
+ encoding="utf-8",
+ )
+
+def setup(app):
+ app.connect("build-finished", generate_combined_markdown)
From 2b1fa59f7a476e23f7a6259c82cae94340023589 Mon Sep 17 00:00:00 2001
From: Kiss
Date: Tue, 19 May 2026 09:47:52 +0200
Subject: [PATCH 2/7] Add base llms.txt, treshold and exclude MyST directives
---
docs/conf.py | 92 +++++++++++++++++++++++++++++++++++++++++++--------
docs/llms.txt | 53 +++++++++++++++++++++++++++++
2 files changed, 132 insertions(+), 13 deletions(-)
create mode 100644 docs/llms.txt
diff --git a/docs/conf.py b/docs/conf.py
index e06ff152..e3f30eee 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -45,6 +45,8 @@
tags_page_title = "Tag page"
tags_page_header = "Pages with this tag"
+import re
+
EXCLUDED_DIRS = {
"_build",
"_templates",
@@ -53,43 +55,107 @@
".venv",
}
+MARKUP_PREFIXES = (
+ ":::",
+ "```{",
+ "```",
+ ":img-top:",
+ ":class",
+ ":link:",
+ ":link-type:",
+ ":shadow:",
+ ":columns:",
+ ":padding:",
+ ":gutter:",
+ ":open:",
+ ":name:",
+ ":header-rows:",
+ ":alt:",
+ "+++",
+ "<",
+ "-->",
+ "{bdg-",
+)
+
+# Matches lines like "align: center", "alt:", "name: foo" (directive options
+# not starting with a colon, common in MyST figure/table fences)
+_BARE_DIRECTIVE_RE = re.compile(r"^[a-z][a-z_-]*:\s*\S*$")
+
+# Matches MyST/RST anchor labels like "(some-label)="
+_ANCHOR_LABEL_RE = re.compile(r"^\(\w[\w-]*\)=$")
+
+MIN_PROSE_LINES = 10
+
+
def should_skip(path: Path) -> bool:
return any(part in EXCLUDED_DIRS for part in path.parts)
+def is_prose_line(line: str) -> bool:
+ stripped = line.strip()
+ if not stripped:
+ return False
+ if stripped.startswith(MARKUP_PREFIXES):
+ return False
+ # Drop bare directive-option lines (e.g. "align: center", "alt:")
+ if _BARE_DIRECTIVE_RE.match(stripped):
+ return False
+ # Drop MyST/RST anchor labels (e.g. "(some-label)=")
+ if _ANCHOR_LABEL_RE.match(stripped):
+ return False
+ # Drop lines that contain an HTML tag anywhere (e.g. ".
")
+ if re.search(r"?[a-zA-Z]", stripped):
+ return False
+ return True
+
+
def generate_combined_markdown(app, exception):
if exception:
return
docs_root = Path(app.srcdir)
output_file = Path(app.outdir) / "llms.txt"
+ base_file = docs_root / "llms.txt"
- print(output_file)
+ combined = []
- all_files = sorted(docs_root.rglob("*.md"))
+ if base_file.exists():
+ base_text = base_file.read_text(encoding="utf-8").rstrip().rstrip("-").rstrip()
+ combined.append(base_text)
+ else:
+ combined.append("# AMD Network Operator")
- combined = []
- combined.append("# Combined Documentation\n")
+ all_files = sorted(docs_root.rglob("*.md"))
for doc_file in all_files:
if should_skip(doc_file):
continue
- relative = doc_file.relative_to(docs_root)
-
- combined.append(f"\n---\n")
- combined.append(f"\n# {relative}\n")
+ if doc_file == base_file:
+ continue
try:
content = doc_file.read_text(encoding="utf-8")
- combined.append(content)
- combined.append("\n")
+ except Exception:
+ continue
+
+ lines = content.splitlines()
+ prose_lines = [line for line in lines if is_prose_line(line)]
+
+ if len(prose_lines) < MIN_PROSE_LINES:
+ continue
+
+ relative = doc_file.relative_to(docs_root)
+ cleaned = "\n".join(
+ line for line in lines
+ if line.strip() == "" or is_prose_line(line)
+ )
- except Exception as e:
- combined.append(f"\n[ERROR reading file: {e}]\n")
+ combined.append(f"\n\n---\n\n# {relative}\n")
+ combined.append(cleaned.strip())
output_file.write_text(
- "\n".join(combined),
+ "\n".join(combined) + "\n",
encoding="utf-8",
)
diff --git a/docs/llms.txt b/docs/llms.txt
new file mode 100644
index 00000000..939ae5c3
--- /dev/null
+++ b/docs/llms.txt
@@ -0,0 +1,53 @@
+# AMD Network Operator
+
+> Deploy and manage AMD AINICs in Kubernetes environments. The AMD Network Operator manages all networking components required to enable RDMA workloads within a Kubernetes cluster, including NIC driver management, device plugin configuration, secondary network CNI plugins, and metrics collection.
+
+## Overview
+
+- [Network Operator overview](https://instinct.docs.amd.com/projects/network-operator/en/main/overview.html): Components of the AMD Network Operator and their roles in managing AMD NICs in Kubernetes clusters.
+- [Release notes](https://instinct.docs.amd.com/projects/network-operator/en/main/releasenotes.html): Release history and changelog for the AMD Network Operator.
+
+## Installation
+
+- [Install with Helm](https://instinct.docs.amd.com/projects/network-operator/en/main/installation/kubernetes-helm.html): Install the AMD Network Operator on a Kubernetes cluster using Helm.
+- [Install with GPU Operator and Network Operator together](https://instinct.docs.amd.com/projects/network-operator/en/main/installation/kubernetes-helm-operators.html): Install AMD GPU Operator and AMD Network Operator together in the same Kubernetes cluster.
+- [Custom Resource guide](https://instinct.docs.amd.com/projects/network-operator/en/main/installation/networkconfig.html): Configure the NetworkConfig Custom Resource, including driver management, device plugin, and secondary network settings.
+- [NetworkConfig full reference](https://instinct.docs.amd.com/projects/network-operator/en/main/installation/networkconfig-full.html): Comprehensive list of NetworkConfig CR configuration options.
+- [Deploy a workload with a network device](https://instinct.docs.amd.com/projects/network-operator/en/main/installation/workload.html): Create a NetworkAttachmentDefinition and deploy a workload with an assigned network device.
+
+## Driver management
+
+- [Driver management](https://instinct.docs.amd.com/projects/network-operator/en/main/drivers/drivers.html): Manage AMD AI NIC drivers using the AMD Network Operator on Kubernetes clusters.
+- [Driver upgrades](https://instinct.docs.amd.com/projects/network-operator/en/main/drivers/upgrading.html): Upgrade AMD Network drivers on worker nodes.
+
+## Device plugin
+
+- [Device Plugin and Node Labeller](https://instinct.docs.amd.com/projects/network-operator/en/main/device_plugin/deviceplugin.html): Configure the Device Plugin and Node Labeller via the NetworkConfig Custom Resource.
+- [Resource health monitoring](https://instinct.docs.amd.com/projects/network-operator/en/main/device_plugin/resource-health.html): Real-time monitoring and reporting of network device health status integrated with Kubernetes pod scheduling.
+
+## Secondary networks
+
+- [Kubernetes integration flow](https://instinct.docs.amd.com/projects/network-operator/en/main/secondary_network/integration-flow.html): How pod network attachment annotations trigger CNI plugins through the Kubernetes networking stack.
+- [AMD Host Device CNI plugin](https://instinct.docs.amd.com/projects/network-operator/en/main/secondary_network/amd-host-device-cni.html): Move PF or VF network interfaces from host into pod network namespaces with IP address preservation.
+- [Alternative CNI plugins](https://instinct.docs.amd.com/projects/network-operator/en/main/secondary_network/other-cnis.html): Alternative CNI plugins tested with AMD Network Operator via NetworkAttachmentDefinition.
+
+## Metrics
+
+- [Metrics Exporter](https://instinct.docs.amd.com/projects/network-operator/en/main/metrics/exporter.html): Configure the Metrics Exporter via the NetworkConfig Custom Resource.
+- [Prometheus integration](https://instinct.docs.amd.com/projects/network-operator/en/main/metrics/prometheus.html): Integrate the AMD Network Operator with Prometheus using ServiceMonitor for automatic metrics scraping.
+- [Grafana dashboard](https://instinct.docs.amd.com/projects/network-operator/en/main/metrics/grafana_dashboard.html): AINIC System Grafana dashboard for visualizing network metrics.
+- [Health checks](https://instinct.docs.amd.com/projects/network-operator/en/main/metrics/health.html): Health monitoring via the metrics exporter gRPC socket for Kubernetes device availability decisions.
+- [Kube-RBAC-Proxy](https://instinct.docs.amd.com/projects/network-operator/en/main/metrics/kube-rbac-proxy.html): Secure the metrics endpoint with RBAC or static authorization using the kube-rbac-proxy sidecar.
+
+## Upgrades
+
+- [Upgrade](https://instinct.docs.amd.com/projects/network-operator/en/main/upgrades/upgrade.html): Verify cluster readiness and upgrade the AMD Network Operator.
+- [Component upgrades](https://instinct.docs.amd.com/projects/network-operator/en/main/upgrades/componentupgrades.html): Upgrade Device Plugin, Node Labeller, Metrics Exporter, and CNI Plugin daemonsets.
+
+## Operations
+
+- [Troubleshooting](https://instinct.docs.amd.com/projects/network-operator/en/main/troubleshooting.html): Diagnose and resolve common issues with the AMD Network Operator.
+- [Uninstall](https://instinct.docs.amd.com/projects/network-operator/en/main/uninstallation/uninstallation.html): Remove the operator and related resources in the correct sequence.
+- [Cluster Validation and Job Scheduling Framework](https://instinct.docs.amd.com/projects/network-operator/en/main/cluster_validation_framework/README.html): Periodically verify worker node health and readiness before scheduling distributed AI and HPC workloads.
+
+---
From 5d46fa04005a9214c20000cac43904c8618c1a6f Mon Sep 17 00:00:00 2001
From: Kiss
Date: Thu, 21 May 2026 12:29:30 +0200
Subject: [PATCH 3/7] Add llms-full.txt and keep the llms.txt as base
---
docs/conf.py | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/docs/conf.py b/docs/conf.py
index e3f30eee..9464e28e 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -84,6 +84,9 @@
# Matches MyST/RST anchor labels like "(some-label)="
_ANCHOR_LABEL_RE = re.compile(r"^\(\w[\w-]*\)=$")
+# Matches RST section underlines (e.g. "====", "----", "~~~~")
+_RST_UNDERLINE_RE = re.compile(r"^[=\-~^\"\'#*+]{3,}$")
+
MIN_PROSE_LINES = 10
@@ -106,6 +109,15 @@ def is_prose_line(line: str) -> bool:
# Drop lines that contain an HTML tag anywhere (e.g. ".")
if re.search(r"?[a-zA-Z]", stripped):
return False
+ # Drop RST directives, comments, hyperlink targets, and substitution definitions
+ if stripped.startswith(".."):
+ return False
+ # Drop RST field list items (e.g. ":type: int") and MyST directive options not in MARKUP_PREFIXES
+ if re.match(r"^:[A-Za-z]", stripped):
+ return False
+ # Drop RST section underlines (e.g. "====", "----", "~~~~")
+ if _RST_UNDERLINE_RE.match(stripped):
+ return False
return True
@@ -125,7 +137,9 @@ def generate_combined_markdown(app, exception):
else:
combined.append("# AMD Network Operator")
- all_files = sorted(docs_root.rglob("*.md"))
+ all_files = sorted(
+ list(docs_root.rglob("*.md")) + list(docs_root.rglob("*.rst"))
+ )
for doc_file in all_files:
if should_skip(doc_file):
From cd0ae679320414044cd9da3cca53e608347feec0 Mon Sep 17 00:00:00 2001
From: Kiss
Date: Fri, 29 May 2026 12:00:01 +0200
Subject: [PATCH 4/7] Update the filter function of llms-full.txt generation
---
docs/conf.py | 42 +++++++++++++++++++++++++++++++++---------
1 file changed, 33 insertions(+), 9 deletions(-)
diff --git a/docs/conf.py b/docs/conf.py
index 9464e28e..0c5d70d1 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -87,6 +87,9 @@
# Matches RST section underlines (e.g. "====", "----", "~~~~")
_RST_UNDERLINE_RE = re.compile(r"^[=\-~^\"\'#*+]{3,}$")
+# Matches RST code block directives (e.g. ".. code-block:: cpp", ".. code:: sh")
+_RST_CODE_BLOCK_RE = re.compile(r"^\.\.\s+(code-block|code|sourcecode)::")
+
MIN_PROSE_LINES = 10
@@ -106,14 +109,13 @@ def is_prose_line(line: str) -> bool:
# Drop MyST/RST anchor labels (e.g. "(some-label)=")
if _ANCHOR_LABEL_RE.match(stripped):
return False
- # Drop lines that contain an HTML tag anywhere (e.g. ".")
- if re.search(r"?[a-zA-Z]", stripped):
- return False
# Drop RST directives, comments, hyperlink targets, and substitution definitions
if stripped.startswith(".."):
return False
- # Drop RST field list items (e.g. ":type: int") and MyST directive options not in MARKUP_PREFIXES
- if re.match(r"^:[A-Za-z]", stripped):
+ # Drop RST field list items (e.g. ":type: int") and MyST directive options without
+ # a leading colon (e.g. "align: center"). Excludes inline roles at line start
+ # (e.g. ":cpp:func:`hipMalloc` returns..." or ":ref:`foo ` describes...").
+ if re.match(r"^:[A-Za-z][A-Za-z0-9_-]*:(\s|$)", stripped):
return False
# Drop RST section underlines (e.g. "====", "----", "~~~~")
if _RST_UNDERLINE_RE.match(stripped):
@@ -160,10 +162,32 @@ def generate_combined_markdown(app, exception):
continue
relative = doc_file.relative_to(docs_root)
- cleaned = "\n".join(
- line for line in lines
- if line.strip() == "" or is_prose_line(line)
- )
+ in_backtick_fence = False
+ in_rst_code_block = False
+ kept = []
+ for line in lines:
+ stripped = line.strip()
+ # Backtick fences (MyST/Markdown)
+ if stripped.startswith("```"):
+ in_backtick_fence = not in_backtick_fence
+ kept.append(line)
+ continue
+ if in_backtick_fence:
+ kept.append(line)
+ continue
+ # RST code block: exit when a non-blank, non-indented line appears
+ if in_rst_code_block:
+ if not stripped or line[0] in (" ", "\t"):
+ kept.append(line)
+ continue
+ in_rst_code_block = False
+ # RST code block: enter on directive line (directive itself is dropped)
+ if _RST_CODE_BLOCK_RE.match(stripped):
+ in_rst_code_block = True
+ continue
+ if not stripped or is_prose_line(line):
+ kept.append(line)
+ cleaned = "\n".join(kept)
combined.append(f"\n\n---\n\n# {relative}\n")
combined.append(cleaned.strip())
From 3621c25a9fe3dd260894dafdf9e0250b443924b9 Mon Sep 17 00:00:00 2001
From: Kiss
Date: Fri, 29 May 2026 13:07:09 +0200
Subject: [PATCH 5/7] sync llms filter fixes from rocm-docs-core
---
docs/conf.py | 41 ++++++++++++++++++++++++++++++++++++-----
1 file changed, 36 insertions(+), 5 deletions(-)
diff --git a/docs/conf.py b/docs/conf.py
index 0c5d70d1..f7450bd4 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -72,7 +72,6 @@
":header-rows:",
":alt:",
"+++",
- "<",
"-->",
"{bdg-",
)
@@ -90,6 +89,17 @@
# Matches RST code block directives (e.g. ".. code-block:: cpp", ".. code:: sh")
_RST_CODE_BLOCK_RE = re.compile(r"^\.\.\s+(code-block|code|sourcecode)::")
+# Matches markdown table separator rows (e.g. "|---|---|", "| :--- | ---: |").
+_MD_TABLE_SEP_RE = re.compile(r"^\|[\s|:\-]+\|$")
+
+# Matches RST directives whose indented body should be discarded (e.g. raw HTML).
+_RST_SKIP_BLOCK_RE = re.compile(r"^\.\.\s+raw::")
+
+# Matches HTML tags (e.g. "", "", ")
- Add in_html_open_tag state to discard multi-line HTML opening tag continuations
---
docs/conf.py | 31 ++++++++++++++++++++++++++++++-
1 file changed, 30 insertions(+), 1 deletion(-)
diff --git a/docs/conf.py b/docs/conf.py
index f7450bd4..afed319f 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -100,6 +100,10 @@
# URL schemes so that multi-line RST inline hyperlinks are preserved.
_HTML_TAG_RE = re.compile(r"^<(?!https?://|ftp://|mailto:)[a-zA-Z/!]")
+# Matches trailing HTML close tags at the end of a prose line
+# (e.g. "Browse blogs.", "See the guide.").
+_TRAILING_HTML_CLOSE_RE = re.compile(r"([a-zA-Z]+>)+\s*$")
+
MIN_PROSE_LINES = 10
@@ -186,6 +190,8 @@ def generate_combined_markdown(app, exception):
in_backtick_fence = False
in_rst_code_block = False
in_rst_skip_block = False
+ in_html_comment = False # inside block
+ in_html_open_tag = False # inside a multi-line HTML opening tag
kept = []
for line in lines:
stripped = line.strip()
@@ -197,6 +203,11 @@ def generate_combined_markdown(app, exception):
if in_backtick_fence:
kept.append(line)
continue
+ # HTML comment block (): discard all content until -->
+ if in_html_comment:
+ if "-->" in stripped:
+ in_html_comment = False
+ continue
# RST skip block (e.g. .. raw::): discard all indented content
if in_rst_skip_block:
if not stripped or line[0] in (" ", "\t"):
@@ -216,8 +227,26 @@ def generate_combined_markdown(app, exception):
if _RST_CODE_BLOCK_RE.match(stripped):
in_rst_code_block = True
continue
- if not stripped or is_prose_line(line):
+ # HTML comment open (): discard opener and enter state
+ if stripped.startswith("" not in stripped:
+ in_html_comment = True
+ continue
+ # Multi-line HTML opening tag: skip continuation lines until >
+ if in_html_open_tag:
+ if ">" in stripped:
+ in_html_open_tag = False
+ continue
+ # Detect HTML opening tags that wrap across lines (no > on this line)
+ if _HTML_TAG_RE.match(stripped) and ">" not in stripped:
+ in_html_open_tag = True
+ continue
+ if not stripped:
kept.append(line)
+ elif is_prose_line(line):
+ # Strip trailing HTML close tags (e.g. "See the guide.")
+ cleaned = _TRAILING_HTML_CLOSE_RE.sub("", line).rstrip()
+ kept.append(cleaned if cleaned.strip() else line)
cleaned = "\n".join(kept)
combined.append(f"\n\n---\n\n# {relative}\n")
From f994cef411d2ac7534b35d36db4badf2cdded438 Mon Sep 17 00:00:00 2001
From: Kiss
Date: Fri, 29 May 2026 14:20:04 +0200
Subject: [PATCH 7/7] llms: drop punctuation-only lines after stripping
trailing HTML close tags
Lines like "." from sphinx-design grid cards pass _is_prose_line
because they start with ".". After stripping "", the remaining
content is a bare "." with no word characters and should be discarded.
Co-Authored-By: Claude Sonnet 4.6
---
docs/conf.py | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/docs/conf.py b/docs/conf.py
index afed319f..7f0888e2 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -246,7 +246,15 @@ def generate_combined_markdown(app, exception):
elif is_prose_line(line):
# Strip trailing HTML close tags (e.g. "See the guide.")
cleaned = _TRAILING_HTML_CLOSE_RE.sub("", line).rstrip()
- kept.append(cleaned if cleaned.strip() else line)
+ cleaned_stripped = cleaned.strip()
+ if not cleaned_stripped:
+ # Entire line was HTML close tags — keep original (shouldn't
+ # normally reach here since _is_prose_line filters HTML).
+ kept.append(line)
+ elif re.search(r"\w", cleaned_stripped):
+ # Line has real word content after stripping close tags.
+ kept.append(cleaned)
+ # else: only punctuation remains (e.g. bare ".") — discard.
cleaned = "\n".join(kept)
combined.append(f"\n\n---\n\n# {relative}\n")