diff --git a/.github/workflows/docs-weekly.yml b/.github/workflows/docs-weekly.yml
new file mode 100644
index 0000000000..40833bf72a
--- /dev/null
+++ b/.github/workflows/docs-weekly.yml
@@ -0,0 +1,73 @@
+# Copyright 2026 The kpt Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Weekly documentation verification: spelling and external link checking.
+
+name: Docs Weekly
+on:
+ schedule:
+ - cron: '0 3 * * 1' # Every Monday at 03:00 UTC
+ workflow_dispatch: # Allow manual triggering
+
+jobs:
+ docs-verify:
+ name: docs-verify
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v6
+ with:
+ submodules: true
+ fetch-depth: 0
+
+ - name: Set up Go
+ uses: actions/setup-go@v6
+ with:
+ go-version-file: documentation/go.mod
+ cache: false
+
+ - name: Get Hugo version
+ id: hugo-version
+ run: echo "version=$(grep -m1 'HUGO_VERSION' documentation/netlify.toml | cut -d'"' -f2)" >> "$GITHUB_OUTPUT"
+
+ - name: Set up Hugo
+ uses: peaceiris/actions-hugo@v3
+ with:
+ hugo-version: ${{ steps.hugo-version.outputs.version }}
+ extended: true
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v7
+ with:
+ node-version-file: documentation/package.json
+
+ - name: Install Node dependencies
+ working-directory: documentation
+ run: npm install
+
+ - name: Verify spelling
+ working-directory: documentation
+ run: make verify
+
+ - name: Build site
+ working-directory: documentation
+ run: make production-build
+
+ - name: Check external links
+ uses: lycheeverse/lychee-action@v2
+ with:
+ args: '-vv --config lychee.toml --root-dir public --extensions html public'
+ lycheeVersion: v0.24.2
+ fail: true
+ workingDirectory: documentation
diff --git a/README.md b/README.md
index b18688df98..0f2bcc031d 100644
--- a/README.md
+++ b/README.md
@@ -24,7 +24,7 @@ scale by manipulating declarative Configuration as Data.
See [the FAQ](https://kpt.dev/faq/) for more details about how kpt is different from alternatives.
-Use our [public Dosu space](https://github.dosu.com/kptdev/kpt) to ask anything about kpt.
+Use our [public Dosu space](https://app.dosu.dev/b19fb34f-d249-48ae-a3b1-2bd8ec156e41/ask) to ask anything about kpt.
## Why kpt?
diff --git a/documentation/Makefile b/documentation/Makefile
index a767c9f1eb..35af898ad2 100644
--- a/documentation/Makefile
+++ b/documentation/Makefile
@@ -16,6 +16,11 @@ serve:
verify:
go run github.com/golangci/misspell/cmd/misspell@v0.8.0 -error content/
+.PHONY: check-links-external
+check-links-external: production-build
+ @command -v lychee >/dev/null 2>&1 || { echo "Error: lychee not found. Install it from https://github.com/lycheeverse/lychee#installation"; exit 1; }
+ lychee -vv --config lychee.toml --root-dir public --extensions html public
+
production-build:
git submodule update --init --recursive
git fetch --tags
diff --git a/documentation/README.md b/documentation/README.md
index 40c20cb484..715ad5c053 100644
--- a/documentation/README.md
+++ b/documentation/README.md
@@ -33,6 +33,34 @@ The site pulls some dependencies via Git submodules. If `npm install` succeeds b
git submodule update --init --recursive
```
+## Checking external links
+
+To validate external links in the documentation, use:
+
+```sh
+make check-links-external
+```
+
+This builds the site with Hugo and runs [lychee](https://github.com/lycheeverse/lychee) against the rendered HTML.
+
+### Prerequisites
+
+- **Hugo** — installed via `npm install` (from `devDependencies`) or [standalone](https://gohugo.io/installation/)
+- **lychee** — install via one of:
+ - macOS: `brew install lychee`
+ - Linux/macOS (Cargo): `cargo install lychee`
+ - Binary download: see [lychee releases](https://github.com/lycheeverse/lychee/releases)
+
+### Using a GitHub token
+
+To avoid GitHub rate limiting, pass a token:
+
+```sh
+GITHUB_TOKEN=$(gh auth token) make check-links-external
+```
+
+The token is only sent to github.com domains.
+
## Style guide for documentation
1. Use US English in the documentation
diff --git a/documentation/content/en/_index.md b/documentation/content/en/_index.md
index 868a56a0be..6852f130a5 100644
--- a/documentation/content/en/_index.md
+++ b/documentation/content/en/_index.md
@@ -47,7 +47,7 @@ kpt is an open source project and anyone can [contribute](https://github.com/kpt
To get familiar with kpt, the best way to start is with the first 4 chapters of the kpt [Book]({{% relref "book" %}}).
Furthermore it is useful to check the [references]({{% relref "reference" %}}) and the catalog of [selected krm functions](https://catalog.kpt.dev).
-Use our [public Dosu space](https://github.dosu.com/kptdev/kpt) to ask anything about kpt.
+Use our [public Dosu space](https://app.dosu.dev/b19fb34f-d249-48ae-a3b1-2bd8ec156e41/ask) to ask anything about kpt.
# For admins
diff --git a/documentation/content/en/book/01-getting-started/_index.md b/documentation/content/en/book/01-getting-started/_index.md
index 0f8e661270..96b6263599 100644
--- a/documentation/content/en/book/01-getting-started/_index.md
+++ b/documentation/content/en/book/01-getting-started/_index.md
@@ -30,7 +30,7 @@ configured.
#### Docker
-Follow the [instructions](https://docs.docker.com/get-docker) to install and configure Docker.
+Follow the [instructions](https://docs.docker.com/get-started/get-docker/) to install and configure Docker.
#### Podman
diff --git a/documentation/content/en/book/04-using-functions/_index.md b/documentation/content/en/book/04-using-functions/_index.md
index 8946d91480..26a320a143 100644
--- a/documentation/content/en/book/04-using-functions/_index.md
+++ b/documentation/content/en/book/04-using-functions/_index.md
@@ -739,7 +739,7 @@ kpt fn eval wordpress -i kubeconform:latest --network -- schema_location="https:
#### Mounting directories
-By default, the functions cannot access the host file system. You can use the `--mount` flag to mount the host volumes. kpt accepts the same options to `--mount`, as specified on the [Docker Volumes](https://docs.docker.com/storage/volumes/) page.
+By default, the functions cannot access the host file system. You can use the `--mount` flag to mount the host volumes. kpt accepts the same options to `--mount`, as specified on the [Docker Volumes](https://docs.docker.com/engine/storage/volumes/) page.
The `kubeconform` function can, for example, consume a JSON schema file, as follows:
diff --git a/documentation/content/en/book/05-developing-functions/_index.md b/documentation/content/en/book/05-developing-functions/_index.md
index 255f04c9b6..d07b09a088 100644
--- a/documentation/content/en/book/05-developing-functions/_index.md
+++ b/documentation/content/en/book/05-developing-functions/_index.md
@@ -127,7 +127,7 @@ for writing functions that manipulate KRM. Go provides:
- [Install kpt]({{% relref "/installation/kpt-cli" %}})
-- [Install Docker](https://docs.docker.com/get-docker/)
+- [Install Docker](https://docs.docker.com/get-started/get-docker/)
- [Golang](https://go.dev/dl/) (at least version 1.24)
diff --git a/documentation/content/en/book/07-effective-customizations/_index.md b/documentation/content/en/book/07-effective-customizations/_index.md
index b106cf3ae0..54a14208f2 100644
--- a/documentation/content/en/book/07-effective-customizations/_index.md
+++ b/documentation/content/en/book/07-effective-customizations/_index.md
@@ -326,7 +326,7 @@ The mutation pipeline fails because the Rego policy has been violated.
When using template languages I am able to provide conditional statements based
on parameter values. This allows me to ask the user for a little bit of
information and generate a lot of boilerplate configuration. Some template
-languages like [Jinja](https://palletsprojects.com/p/jinja/) are very robust and feature rich.
+languages like [Jinja](https://palletsprojects.com/projects/jinja/) are very robust and feature rich.
### Problems:
diff --git a/documentation/content/en/installation/migration.md b/documentation/content/en/installation/migration.md
index b81dbb60cb..76e28b317a 100644
--- a/documentation/content/en/installation/migration.md
+++ b/documentation/content/en/installation/migration.md
@@ -355,7 +355,7 @@ kpt `v0.39`) to `v1` version(compatible with kpt `v1.0`).
[v0.39 commands]: https://kptdev.github.io/kpt/reference/
[v1.0 commands]: /reference/cli/
-[v1 kptfile]: https://github.com/kptdev/kpt/blob/main/pkg/api/kptfile/v1/types.go
+[v1 kptfile]: https://github.com/kptdev/kpt/blob/main/api/kptfile/v1/types.go
[starlark function]: https://catalog.kpt.dev/starlark/v0.2/
[apply-setters]: https://catalog.kpt.dev/apply-setters/v0.1/
[setter inheritance]: https://kptdev.github.io/kpt/concepts/setters/#inherit-setter-values-from-parent-package
@@ -363,10 +363,10 @@ kpt `v0.39`) to `v1` version(compatible with kpt `v1.0`).
[required setters]: https://kptdev.github.io/kpt/guides/producer/setters/#required-setters
[auto-setters]: https://kptdev.github.io/kpt/concepts/setters/#auto-setters
[migrating inventory objects]: https://kptdev.github.io/kpt/reference/live/alpha/
-[live migration]: https://kptdev.github.io/kpt/reference/cli/live/alpha/
+[live migration]: https://kptdev.github.io/kpt/reference/live/alpha/
[configpath]: /book/04-using-functions/01-declarative-function-execution?id=configpath
-[example kpt package]: https://github.com/kptdev/krm-functions-catalog/tree/master/testdata/fix
-[simple example]: https://github.com/kptdev/krm-functions-catalog/tree/master/functions/go/fix#examples
+[example kpt package]: https://github.com/kptdev/krm-functions-catalog/tree/main/archived/functions/go/fix/testdata/fix
+[simple example]: https://github.com/kptdev/krm-functions-catalog/tree/main/archived/functions/go/fix#examples
[function config]: /book/04-using-functions/01-declarative-function-execution?id=configpath
[starlark runtime]: https://kptdev.github.io/kpt/guides/producer/functions/starlark/
[update guide]: /book/03-packages/05-updating-a-package
@@ -377,6 +377,6 @@ kpt `v0.39`) to `v1` version(compatible with kpt `v1.0`).
[installation instructions]: /installation/
[install]: /installation/
[kpt-functions-catalog]: https://catalog.kpt.dev/
-[v1alpha1 kptfile]: https://github.com/kptdev/kpt/blob/master/pkg/kptfile/pkgfile.go#L39
+[v1alpha1 kptfile]: https://github.com/kptdev/kpt/blob/v0/pkg/kptfile/pkgfile.go#L39
[git clone]: https://git-scm.com/docs/git-clone
[publish your package]: /book/03-packages/08-publishing-a-package
diff --git a/documentation/content/en/reference/cli/fn/eval/_index.md b/documentation/content/en/reference/cli/fn/eval/_index.md
index ee069e5613..6998b36e19 100644
--- a/documentation/content/en/reference/cli/fn/eval/_index.md
+++ b/documentation/content/en/reference/cli/fn/eval/_index.md
@@ -322,5 +322,5 @@ $ KRM_FN_RUNTIME=podman kpt fn eval DIR -i ghcr.io/example.com/my-fn
-[docker volumes]: https://docs.docker.com/storage/volumes/
+[docker volumes]: https://docs.docker.com/engine/storage/volumes/
[imperative function execution]: /book/04-using-functions/#imperative-function-execution
diff --git a/documentation/content/en/reference/schema/config-connector-status-convention/_index.md b/documentation/content/en/reference/schema/config-connector-status-convention/_index.md
index 442b9da15e..24fbeb9860 100644
--- a/documentation/content/en/reference/schema/config-connector-status-convention/_index.md
+++ b/documentation/content/en/reference/schema/config-connector-status-convention/_index.md
@@ -8,11 +8,11 @@ menu:
parent: "Schema Reference"
---
-`kpt` includes custom rules for [Config Connector](https://cloud.google.com/config-connector/docs/overview) resources to
+`kpt` includes custom rules for [Config Connector](https://docs.cloud.google.com/config-connector/docs/overview) resources to
make them easier to work with. This document describes how kpt uses fields and conditions on Config Connector
resources to compute [reconcile status]({{% relref "/book/06-deploying-packages#reconcile-status" %}}).
-[Config Connector](https://cloud.google.com/config-connector/docs/how-to/monitoring-your-resources) resources expose the
+[Config Connector](https://docs.cloud.google.com/config-connector/docs/how-to/monitoring-your-resources) resources expose the
`observedGeneration` field in the status object, and `kpt` will always report a resource as being `InProgress` if the
`observedGeneration` doesn't match the value of `metadata.generation`.
@@ -22,7 +22,7 @@ as `Current`, i.e it has been successfully reconciled.
If the `Ready` condition is `False`, `kpt` will look at the `Reason` field on the
condition object to determine whether the resource is making progress towards
reconciliation. The possible values mirrors those used by
-[Config Connector events](https://cloud.google.com/config-connector/docs/how-to/monitoring-your-resources#viewing_events).
+[Config Connector events](https://docs.cloud.google.com/config-connector/docs/how-to/monitoring-your-resources#viewing_events).
If the value is one of the following, the resource is considered to have failed
reconciliation:
- `ManagementConflict`
diff --git a/documentation/content/en/reference/schema/crd-status-convention/_index.md b/documentation/content/en/reference/schema/crd-status-convention/_index.md
index 6a76f57939..93710684ad 100644
--- a/documentation/content/en/reference/schema/crd-status-convention/_index.md
+++ b/documentation/content/en/reference/schema/crd-status-convention/_index.md
@@ -10,7 +10,7 @@ menu:
To enable kpt to calculate the [reconcile status]({{% relref "/book/06-deploying-packages#reconcile-status" %}}) for CRDs, this
document provides additional conventions for status conditions following the
-[Kubernetes API Guideline](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md).
+[Kubernetes API Guideline](https://github.com/kubernetes/community/blob/main/contributors/devel/sig-architecture/api-conventions.md).
Custom controllers should use the following conditions types to signal whether a resource has been fully reconciled, and
whether it has encountered any problems:
diff --git a/documentation/layouts/partials/footer.html b/documentation/layouts/partials/footer.html
index c37a8aae5c..a6ae508286 100644
--- a/documentation/layouts/partials/footer.html
+++ b/documentation/layouts/partials/footer.html
@@ -93,8 +93,8 @@
kpt follows The CNCF Code of Conduct |
This site was built with the Docsy Hugo
theme and deployed to Netlify.
-
- For website terms of use, trademark policy and other project policies please see lfprojects.org/policies.
+
+ For website terms of use, trademark policy and other project policies please see lfprojects.org/policies.
The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation,
please see our Trademark Usage page.
{{ if not .Site.Params.ui.footer_about_disable }}
diff --git a/documentation/lychee.toml b/documentation/lychee.toml
new file mode 100644
index 0000000000..f5dd31fd8a
--- /dev/null
+++ b/documentation/lychee.toml
@@ -0,0 +1,51 @@
+# Copyright 2026 The kpt Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# lychee configuration for external link validation.
+# See https://lychee.cli.rs for full documentation.
+#
+# Run: make check-links-external
+# With GitHub token (recommended): GITHUB_TOKEN= make check-links-external
+
+# Only check http/https links.
+scheme = ["https", "http"]
+
+# Resolve root-relative links against the Hugo output directory.
+root_dir = "public"
+
+require_https = true
+timeout = 30
+max_retries = 3
+max_concurrency = 64
+accept_timeouts = true
+user_agent = "Mozilla/5.0 (compatible; kpt-link-checker; +https://kpt.dev)"
+
+# Exclude URLs from checking (regex patterns).
+exclude = [
+ # Slack requires authentication; always returns 403 to bots.
+ "^https://kubernetes\\.slack\\.com",
+ "^https://slack\\.k8s\\.io",
+ # GitHub org project boards require a browser session.
+ "^https://github\\.com/orgs/.*/projects/",
+ # Netlify intermittently blocks CI runners.
+ "^https://www\\.netlify\\.com",
+ # Docsy theme "Edit this page" and "Create issue" links always redirect to login.
+ "^https://github\\.com/kptdev/kpt/edit/",
+ "^https://github\\.com/kptdev/kpt/issues/new",
+]
+
+# Per-host rate limiting to avoid triggering abuse detection.
+[hosts."github.com"]
+concurrency = 1
+request_interval = "3s"