diff --git a/docs/desktop/connect-to-cloud.md b/docs/desktop/connect-to-cloud.md
index b89e1df..eb64c89 100644
--- a/docs/desktop/connect-to-cloud.md
+++ b/docs/desktop/connect-to-cloud.md
@@ -1,3 +1,9 @@
+---
+description: >-
+ Pair OpenAdapt Desktop or the CLI with an OpenAdapt Cloud workspace, approve
+ local artifacts, and publish an attested workflow for governed operation.
+---
+
# Connect the desktop app to a cloud workspace
The local loop (record, compile, replay, teach) works offline and needs no
@@ -16,8 +22,9 @@ a recording → see it in the dashboard.
!!! info "Hosted subscription"
OpenAdapt Hosted is a public $500/month subscription for approved browser
- workflows. Start at [openadapt.ai](https://openadapt.ai/#pricing), then use
- the same workspace and ingest-token mechanism below.
+ workflows. Start at the
+ [Cloud plan](https://openadapt.ai/pricing#cloud-preview), then use the same
+ workspace and ingest-token mechanism below.
## 1. Create or sign in to your workspace
@@ -92,32 +99,36 @@ openadapt flow login --token oai_ingest_… # validates + remembers the hos
environment variable, then `~/.openadapt/config.toml`. See the
[CLI reference](../reference/cli.md#login).
-## 4. Push your first recording
+## 4. Register the recording, then publish the governed bundle
Record a workflow (see [Record your own app](../guides/record-your-app.md)), then
-push it. From the desktop app, use **Push to cloud** on the recording (where your
-build includes it). Or from the CLI:
+create, review, approve, and register its sanitized derivative. From the desktop
+app, use **Push to cloud** on the approved recording. Or use the CLI:
```bash
openadapt flow push ./my-recording --name "Triage"
-# → zips the recording, POSTs it to /api/ingest,
-# compiles it in the cloud, and prints a workflow id + dashboard URL
+# → prepares the local derivative and opens review when approval is needed
```
-The recording directory is zipped before upload (the server ingests a `.zip`; the
-engine emits a directory). You can also push an already-compiled bundle with
-`--kind bundle`. See [`push`](../reference/cli.md#push).
+Recording registration preserves the exact approved source and returns its next
+validation step; it does not turn a recording into a runnable workflow. Compile
+the approved derivative locally, run strict lint, certification, and a governed
+replay, then sanitize and approve the bundle, run `validate-hosted`, and push the
+exact attested bundle. The complete copy-and-paste sequence is in
+[OpenAdapt Hosted](../guides/hosted.md#exact-local-to-hosted-sequence) and the
+[`push` reference](../reference/cli.md#push).
!!! warning "Push scrubs, but the cloud lane is for non-PHI/PII work"
A pre-push scrub runs fail-closed and the server re-scans on ingest, but the
cloud lane is **not** the PHI/PII lane. Keep regulated recordings local and use
[on-prem](../guides/deploy-on-prem.md).
-## 5. See it in the dashboard
+## 5. See the governed workflow in the dashboard
-Open the dashboard URL that `push` printed (or go to
-`app.openadapt.ai/dashboard/workflows`). The workflow appears there, compiled and
-runnable; any run that halts surfaces under **Needs attention** for triage.
+After the attested bundle is accepted, open the dashboard URL that `push`
+printed (or go to `app.openadapt.ai/dashboard/workflows`). The governed workflow
+and its active bundle appear together; any run that halts surfaces under
+**Needs attention** for triage.
## Reporting a halt back to the workspace
diff --git a/docs/desktop/install.md b/docs/desktop/install.md
index 4519cc3..d2e3196 100644
--- a/docs/desktop/install.md
+++ b/docs/desktop/install.md
@@ -1,3 +1,9 @@
+---
+description: >-
+ Install the OpenAdapt Desktop cockpit on Windows, macOS, or Linux, grant the
+ required permissions, and verify your first local recording.
+---
+
# Desktop app: install and first run
The OpenAdapt desktop app is the local cockpit for the record →
@@ -112,7 +118,7 @@ first-week failures.
## During a governed run
-Desktop 0.13.1 can show a separate always-on-top status surface without adding
+Desktop 0.14.0 can show a separate always-on-top status surface without adding
anything to the target application. While OpenAdapt is observing or executing,
the surface is non-focusable, ignores pointer input, exposes no controls, and is
excluded from capture before it becomes visible. Controls become interactive
diff --git a/docs/ecosystem/index.md b/docs/ecosystem/index.md
index 4190c24..32cd0a5 100644
--- a/docs/ecosystem/index.md
+++ b/docs/ecosystem/index.md
@@ -21,7 +21,8 @@ for the tested package ranges.
These labels describe the public role of a repository, not the quality of every
module inside it:
-- **Supported**: a product or optional component you can build on.
+- **Beta**: an active product or component on the supported product path.
+- **Experimental**: an active integration whose contract is still being proven.
- **Research**: evidence or model work, not required by deterministic replay.
- **Deprecated**: retained for history or migration; no new integrations.
@@ -29,14 +30,14 @@ module inside it:
| Repository | Lifecycle | Public role |
|---|---|---|
-| [OpenAdapt](https://github.com/OpenAdaptAI/OpenAdapt) | **Supported** | Installer/meta-package and unified `openadapt flow` dispatcher. |
-| [openadapt-flow](https://github.com/OpenAdaptAI/openadapt-flow) | **Supported** | Canonical compiler and governed runtime. Drives web, native Windows, native macOS, native Linux, RDP, and Citrix/VDI as first-class substrates behind one backend protocol. |
-| [OpenAdapt Cloud](https://app.openadapt.ai/) | **Supported** | Proprietary live control plane for the managed subscription: organizations, exact-hash admission, runner orchestration, reports, billing, and usage. |
-| [openadapt-desktop](https://github.com/OpenAdaptAI/openadapt-desktop) | **Supported** | Public Beta `desktop-v0.14.0` provides Windows MSI/NSIS, macOS arm64/x64 DMG, and Linux AppImage/DEB installers. Every installer path is installed, launched, and uninstalled in the native release workflow; the release includes exact checksums, a CycloneDX SBOM, platform metadata, and build-provenance attestations. |
-| [openadapt-agent](https://github.com/OpenAdaptAI/openadapt-agent) | **Supported** | Active v2 bridge that exposes governed Flow bundles to MCP clients and Agent Skills. The pre-v2 model-driven execution wrapper is the deprecated line; the repository itself is active. |
-| [openadapt-capture](https://github.com/OpenAdaptAI/openadapt-capture) | **Supported** | Canonical native screen, mouse, keyboard, timing, and window-scoped recorder behind Flow's Windows, macOS, Linux, RDP, and Citrix recording paths. Capture 1.1 retains Windows UIA evidence at action time; remote sessions remain externally black-box. Browser recording remains inside Flow's Playwright listener. |
-| [openadapt-privacy](https://github.com/OpenAdaptAI/openadapt-privacy) | **Supported** | Optional PII/PHI scrubbing used on configured persist, log, and upload paths. |
-| [openadapt-types](https://github.com/OpenAdaptAI/openadapt-types) | **Supported** | Shared interoperability schemas; contributor-facing, not an end-user product. |
+| [OpenAdapt](https://github.com/OpenAdaptAI/OpenAdapt) | **Beta** | Installer/meta-package and unified `openadapt flow` dispatcher. |
+| [openadapt-flow](https://github.com/OpenAdaptAI/openadapt-flow) | **Beta** | Canonical compiler and governed runtime. Drives web, native Windows, native macOS, native Linux, RDP, and Citrix/VDI as first-class substrates behind one backend protocol. |
+| [OpenAdapt Cloud](https://app.openadapt.ai/) | **Beta** | Proprietary live control plane for the managed subscription: organizations, exact-hash admission, runner orchestration, reports, billing, and usage. |
+| [openadapt-desktop](https://github.com/OpenAdaptAI/openadapt-desktop) | **Beta** | Public `desktop-v0.14.0` provides Windows MSI/NSIS, macOS arm64/x64 DMG, and Linux AppImage/DEB installers. Every installer path is installed, launched, and uninstalled in the native release workflow; the release includes exact checksums, a CycloneDX SBOM, platform metadata, and build-provenance attestations. |
+| [openadapt-agent](https://github.com/OpenAdaptAI/openadapt-agent) | **Experimental** | Active v2 bridge that exposes governed Flow bundles to MCP clients and Agent Skills. The pre-v2 model-driven execution wrapper is the deprecated line; the repository itself is active. |
+| [openadapt-capture](https://github.com/OpenAdaptAI/openadapt-capture) | **Beta** | Canonical native screen, mouse, keyboard, timing, and window-scoped recorder behind Flow's Windows, macOS, Linux, RDP, and Citrix recording paths. Capture 1.1 retains Windows UIA evidence at action time; remote sessions remain externally black-box. Browser recording remains inside Flow's Playwright listener. |
+| [openadapt-privacy](https://github.com/OpenAdaptAI/openadapt-privacy) | **Experimental** | Optional PII/PHI scrubbing used on configured persist, log, and upload paths. |
+| [openadapt-types](https://github.com/OpenAdaptAI/openadapt-types) | **Experimental** | Shared interoperability schemas; contributor-facing, not an end-user product. |
## Research components
diff --git a/docs/get-started/index.md b/docs/get-started/index.md
index 1df7aa9..55431fa 100644
--- a/docs/get-started/index.md
+++ b/docs/get-started/index.md
@@ -1,3 +1,9 @@
+---
+description: >-
+ Install OpenAdapt and complete the five-minute record, compile, certify,
+ replay, repair, seal, and deploy journey from the unified CLI.
+---
+
# Get started
OpenAdapt turns a single demonstration into a deterministic, locally-run
diff --git a/docs/get-started/what-works-today.md b/docs/get-started/what-works-today.md
index a5c90c0..ca2e56a 100644
--- a/docs/get-started/what-works-today.md
+++ b/docs/get-started/what-works-today.md
@@ -1,3 +1,9 @@
+---
+description: >-
+ Inspect OpenAdapt qualification evidence by exact workflow, application,
+ environment, run count, effect oracle, refusal case, and execution surface.
+---
+
# Qualification evidence
OpenAdapt compiles demonstrated GUI workflows into deterministic, locally
diff --git a/docs/guides/hosted.md b/docs/guides/hosted.md
index a04d737..199a59a 100644
--- a/docs/guides/hosted.md
+++ b/docs/guides/hosted.md
@@ -1,3 +1,9 @@
+---
+description: >-
+ Connect locally authored, sanitized, qualified workflows to OpenAdapt Cloud
+ for managed browser execution, run history, evidence, usage, and billing.
+---
+
# OpenAdapt Hosted
OpenAdapt Hosted is the managed control plane for governed workflows. The
@@ -12,7 +18,7 @@ available for explicitly initiated public, non-regulated browser sessions; use
local recording and a reviewed sanitized derivative when source observations
cannot enter the OpenAdapt-hosted boundary.
-[Start with OpenAdapt](https://openadapt.ai/#pricing){ .md-button .md-button--primary }
+[Start with OpenAdapt](https://openadapt.ai/pricing#cloud-preview){ .md-button .md-button--primary }
[Review the data boundary](security-review.md){ .md-button }
Payment runs through Stripe, and the price shown on the website is the exact
diff --git a/docs/guides/qualify-a-workflow.md b/docs/guides/qualify-a-workflow.md
index 1bccb31..af78f96 100644
--- a/docs/guides/qualify-a-workflow.md
+++ b/docs/guides/qualify-a-workflow.md
@@ -1,3 +1,9 @@
+---
+description: >-
+ Review a compiled workflow, assign risk, bind identity and effect checks, run
+ qualification cases, certify it, and export a sealed governed artifact.
+---
+
# Qualify a workflow
Qualification turns a compiled demonstration into a governed artifact tied to
diff --git a/docs/guides/security-and-data-handling.md b/docs/guides/security-and-data-handling.md
index a2ca556..6f3c569 100644
--- a/docs/guides/security-and-data-handling.md
+++ b/docs/guides/security-and-data-handling.md
@@ -220,13 +220,13 @@ configured retention component separately from this destructive-operation gate.
## Release integrity
-The public Desktop `desktop-v0.13.1` release includes Windows, macOS, and Linux
+The public Desktop `desktop-v0.14.0` release includes Windows, macOS, and Linux
installers, `SHA256SUMS`, a CycloneDX SBOM, per-platform metadata, and GitHub
build-provenance attestations. These prove source and build provenance, not
publisher identity. Windows and Linux installers remain unsigned and macOS
installers are ad-hoc signed; Apple Developer ID/notarization and Windows
Authenticode require the corresponding external identities. Verify the
-[release assets](https://github.com/OpenAdaptAI/openadapt-desktop/releases/tag/desktop-v0.13.1)
+[release assets](https://github.com/OpenAdaptAI/openadapt-desktop/releases/tag/desktop-v0.14.0)
before overriding an operating-system publisher warning.
## Deployment options
diff --git a/docs/guides/security-review.md b/docs/guides/security-review.md
index 91970c6..a4d0461 100644
--- a/docs/guides/security-review.md
+++ b/docs/guides/security-review.md
@@ -1,3 +1,9 @@
+---
+description: >-
+ Review OpenAdapt's architecture, execution boundaries, sensitive-data flow,
+ identity and effect gates, release integrity, and deployment checklist.
+---
+
# Security and deployment review
This page answers the questions an enterprise security reviewer should ask
@@ -172,7 +178,7 @@ execution](hosted.md) and [Qualification evidence](../get-started/what-works-tod
## Release and secure-development evidence
Python releases publish immutable wheel and sdist artifacts with PyPI
-provenance attestations. Desktop `desktop-v0.13.1` publishes its complete
+provenance attestations. Desktop `desktop-v0.14.0` publishes its complete
Windows, macOS, and Linux installer set with checksums, a CycloneDX SBOM,
per-platform metadata, and GitHub build-provenance attestations. The native
installers are still unsigned on Windows/Linux and ad-hoc signed on macOS;
diff --git a/docs/index.md b/docs/index.md
index 121ba8e..5f7b0d7 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,5 +1,8 @@
---
title: OpenAdapt, the demonstration compiler
+description: >-
+ Learn how OpenAdapt compiles demonstrated browser, desktop, RDP, and Citrix
+ workflows into deterministic replay with identity, effect, and refusal gates.
hide:
- toc
---
@@ -18,7 +21,7 @@ fails.
[Try it locally](get-started/index.md){ .md-button .md-button--primary }
[Read the concepts](concepts/demonstration-compiler.md){ .md-button }
-[Evaluate a workflow](https://openadapt.ai/#book){ .md-button }
+[Evaluate a workflow](https://openadapt.ai/qualify){ .md-button }
---
@@ -53,9 +56,10 @@ success oracle before production use.
---
A compiled workflow replays with **zero model calls** on the healthy path.
- Local template match, OCR, and geometry resolve each step. Self-hosted
- healthy replay has no model-API charge; hosted infrastructure and service
- pricing are separate.
+ Structural selectors or accessibility evidence lead where the surface
+ provides them; visual anchors, OCR, and geometry cover opaque interfaces.
+ Self-hosted healthy replay has no model-API charge; hosted infrastructure
+ and service pricing are separate.
[The demonstration compiler →](concepts/demonstration-compiler.md)
diff --git a/docs/packages/openadapt-agent.md b/docs/packages/openadapt-agent.md
new file mode 100644
index 0000000..c1e61c9
--- /dev/null
+++ b/docs/packages/openadapt-agent.md
@@ -0,0 +1,16 @@
+---
+title: openadapt-agent documentation moved
+description: OpenAdapt package documentation now lives in the canonical product and component guide.
+canonical: https://docs.openadapt.ai/ecosystem/
+redirect_to: /ecosystem/
+hide:
+ - navigation
+ - toc
+---
+
+# openadapt-agent documentation moved
+
+The current product and component guide lives at
+[Package and repository lifecycle](/ecosystem/).
+
+[Continue to the current guide →](/ecosystem/){ .md-button .md-button--primary }
diff --git a/docs/packages/openadapt-capture.md b/docs/packages/openadapt-capture.md
new file mode 100644
index 0000000..59ed028
--- /dev/null
+++ b/docs/packages/openadapt-capture.md
@@ -0,0 +1,16 @@
+---
+title: openadapt-capture documentation moved
+description: OpenAdapt package documentation now lives in the canonical product and component guide.
+canonical: https://docs.openadapt.ai/ecosystem/
+redirect_to: /ecosystem/
+hide:
+ - navigation
+ - toc
+---
+
+# openadapt-capture documentation moved
+
+The current product and component guide lives at
+[Package and repository lifecycle](/ecosystem/).
+
+[Continue to the current guide →](/ecosystem/){ .md-button .md-button--primary }
diff --git a/docs/packages/openadapt-desktop.md b/docs/packages/openadapt-desktop.md
new file mode 100644
index 0000000..4830acf
--- /dev/null
+++ b/docs/packages/openadapt-desktop.md
@@ -0,0 +1,16 @@
+---
+title: openadapt-desktop documentation moved
+description: OpenAdapt package documentation now lives in the canonical product and component guide.
+canonical: https://docs.openadapt.ai/ecosystem/
+redirect_to: /ecosystem/
+hide:
+ - navigation
+ - toc
+---
+
+# openadapt-desktop documentation moved
+
+The current product and component guide lives at
+[Package and repository lifecycle](/ecosystem/).
+
+[Continue to the current guide →](/ecosystem/){ .md-button .md-button--primary }
diff --git a/docs/packages/openadapt-flow.md b/docs/packages/openadapt-flow.md
new file mode 100644
index 0000000..1526ece
--- /dev/null
+++ b/docs/packages/openadapt-flow.md
@@ -0,0 +1,16 @@
+---
+title: openadapt-flow documentation moved
+description: OpenAdapt package documentation now lives in the canonical product and component guide.
+canonical: https://docs.openadapt.ai/ecosystem/
+redirect_to: /ecosystem/
+hide:
+ - navigation
+ - toc
+---
+
+# openadapt-flow documentation moved
+
+The current product and component guide lives at
+[Package and repository lifecycle](/ecosystem/).
+
+[Continue to the current guide →](/ecosystem/){ .md-button .md-button--primary }
diff --git a/docs/packages/openadapt-privacy.md b/docs/packages/openadapt-privacy.md
new file mode 100644
index 0000000..413ee6a
--- /dev/null
+++ b/docs/packages/openadapt-privacy.md
@@ -0,0 +1,16 @@
+---
+title: openadapt-privacy documentation moved
+description: OpenAdapt package documentation now lives in the canonical product and component guide.
+canonical: https://docs.openadapt.ai/ecosystem/
+redirect_to: /ecosystem/
+hide:
+ - navigation
+ - toc
+---
+
+# openadapt-privacy documentation moved
+
+The current product and component guide lives at
+[Package and repository lifecycle](/ecosystem/).
+
+[Continue to the current guide →](/ecosystem/){ .md-button .md-button--primary }
diff --git a/docs/packages/openadapt-types.md b/docs/packages/openadapt-types.md
new file mode 100644
index 0000000..96402b6
--- /dev/null
+++ b/docs/packages/openadapt-types.md
@@ -0,0 +1,16 @@
+---
+title: openadapt-types documentation moved
+description: OpenAdapt package documentation now lives in the canonical product and component guide.
+canonical: https://docs.openadapt.ai/ecosystem/
+redirect_to: /ecosystem/
+hide:
+ - navigation
+ - toc
+---
+
+# openadapt-types documentation moved
+
+The current product and component guide lives at
+[Package and repository lifecycle](/ecosystem/).
+
+[Continue to the current guide →](/ecosystem/){ .md-button .md-button--primary }
diff --git a/docs/packages/openadapt.md b/docs/packages/openadapt.md
index 3b955dc..2f17c70 100644
--- a/docs/packages/openadapt.md
+++ b/docs/packages/openadapt.md
@@ -1,13 +1,13 @@
---
title: OpenAdapt package documentation moved
+description: OpenAdapt package documentation now lives in the canonical product and component guide.
+canonical: https://docs.openadapt.ai/ecosystem/
+redirect_to: /ecosystem/
hide:
- navigation
- toc
---
-
-
-
# OpenAdapt package documentation moved
The product and package guide now lives at
diff --git a/docs/reference/cli.md b/docs/reference/cli.md
index 214eef9..08c180a 100644
--- a/docs/reference/cli.md
+++ b/docs/reference/cli.md
@@ -25,6 +25,7 @@ is a subcommand of `openadapt flow`.
| [`teach`](#teach) | Resolve a halted run from a fix demonstration, governed | 0 if promoted, 1 if refused, 2 on bad inputs |
| [`lint`](#lint) | Report a bundle's coverage gaps | nonzero by severity |
| [`certify`](#certify) | Enforce a safety policy, refuse the bundle if it fails | 2 on failure |
+| [`seal`](#seal) | Copy, encrypt, integrity-check, and atomically publish a deployment candidate | 0 on success, 2 on refusal |
| [`qualify`](#qualify) | Review, test, explain, and certify a versioned qualification project | nonzero on refusal |
| [`disambiguate`](#disambiguate) | Surface and resolve compile-time ambiguities | 2 if a consequential ambiguity is unresolved |
| [`connect`](#connect) | Pair this computer to a Cloud workspace (launcher command, needs OpenAdapt 1.7+) | 0/1 |
@@ -390,6 +391,29 @@ openadapt flow certify bundle --config deployment.yaml
Provide `--policy` or a `--config` that sets `policy.policy`; certify errors if
neither supplies a policy. Exits 2 when the bundle fails certification.
+## seal
+
+Copy a reviewed bundle into a new encrypted deployment candidate without
+modifying the source. The key comes only from `OPENADAPT_BUNDLE_KEY`, so it does
+not leak through process arguments. `seal` refuses symlinks, an invalid source,
+or an existing destination; verifies the encrypted result before atomic
+publication; and invalidates any certification inherited from the source so the
+exact sealed bytes must pass certification before deployment.
+
+```bash
+export OPENADAPT_BUNDLE_KEY=''
+openadapt flow seal bundle-v2 --out bundle-prod
+openadapt flow certify bundle-prod --config deployment.yaml
+```
+
+| Argument / flag | Description |
+|---|---|
+| `source` (positional) | Existing workflow bundle directory. It is validated and never modified. |
+| `--out`, `-o` (required) | New destination directory. It must not already exist. |
+
+Exits `0` after verified publication and `2` on refusal. Key custody and
+rotation remain deployment responsibilities.
+
## qualify
Create and operate a versioned qualification project for one compiled workflow,
diff --git a/docs/stylesheets/brand.css b/docs/stylesheets/brand.css
index 5ab3b2c..68aaea5 100644
--- a/docs/stylesheets/brand.css
+++ b/docs/stylesheets/brand.css
@@ -361,6 +361,27 @@ a:focus-visible {
line-height: 1.5;
}
+/* Material's default slate footer mutes copyright links below AA contrast at
+ the small footer size. Keep the dark footer quiet, but make every action
+ readable against the actual #111317 meta background. */
+[data-md-color-scheme="slate"] .md-footer__link,
+[data-md-color-scheme="slate"] .md-footer__title,
+[data-md-color-scheme="slate"] .md-footer-meta__inner,
+[data-md-color-scheme="slate"] .md-copyright,
+[data-md-color-scheme="slate"] .md-copyright__highlight,
+[data-md-color-scheme="slate"] .md-social__link {
+ color: #c9cdc2;
+}
+[data-md-color-scheme="slate"] .md-footer-meta.md-typeset a {
+ color: #86d9a8;
+}
+[data-md-color-scheme="slate"] .md-footer__link:hover,
+[data-md-color-scheme="slate"] .md-footer-meta.md-typeset a:focus,
+[data-md-color-scheme="slate"] .md-footer-meta.md-typeset a:hover,
+[data-md-color-scheme="slate"] .md-social__link:hover {
+ color: #a8e8bf;
+}
+
@media screen and (max-width: 76.25em) {
.md-grid {
padding-left: 0.8rem;
diff --git a/mkdocs.yml b/mkdocs.yml
index 118b6a3..196a3fd 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -152,12 +152,12 @@ nav:
- Connect to a cloud workspace: desktop/connect-to-cloud.md
- Troubleshooting: guides/troubleshooting.md
- Security:
+ - Security and deployment review: guides/security-review.md
- Account security and privileged access: guides/account-security.md
- Qualification evidence: get-started/what-works-today.md
- Fail-closed regulated execution: concepts/regulated-execution.md
- Settings and policy governance: concepts/settings-governance.md
- Security and data handling: guides/security-and-data-handling.md
- - Security and deployment review: guides/security-review.md
- Commercial:
- commercial/index.md
- Qualification Sprint: commercial/qualification-sprint.md
diff --git a/overrides/main.html b/overrides/main.html
index 18af438..b4c6e25 100644
--- a/overrides/main.html
+++ b/overrides/main.html
@@ -1,5 +1,49 @@
{% extends "base.html" %}
+{# Allow retired static routes to declare their destination once. Material's
+ default canonical URL is the current page, which would otherwise create a
+ duplicate canonical beside a hand-authored redirect tag. #}
+{% block site_meta %}
+
+
+ {% if page.meta and page.meta.description %}
+
+ {% elif config.site_description %}
+
+ {% endif %}
+ {% if page.meta and page.meta.author %}
+
+ {% elif config.site_author %}
+
+ {% endif %}
+ {% if page.meta and page.meta.canonical %}
+
+ {% elif page.canonical_url %}
+
+ {% endif %}
+ {% if page.meta and page.meta.redirect_to %}
+
+
+ {% endif %}
+ {% if page.previous_page %}
+
+ {% endif %}
+ {% if page.next_page %}
+
+ {% endif %}
+ {% if config.extra.alternate is iterable %}
+ {% for alt in config.extra.alternate %}
+
+ {% endfor %}
+ {% endif %}
+ {% if "rss" in config.plugins %}
+
+
+ {% endif %}
+
+
+{% endblock %}
+
{#
Privacy-safe analytics for docs.openadapt.ai.
diff --git a/scripts/validate_docs.py b/scripts/validate_docs.py
index 535931e..d42a5ae 100644
--- a/scripts/validate_docs.py
+++ b/scripts/validate_docs.py
@@ -44,7 +44,7 @@
"Production deployments should pin the exact versions",
),
"packages/openadapt.md": (
- 'content="0; url=/ecosystem/"',
+ "redirect_to: /ecosystem/",
"pip install openadapt",
),
}
diff --git a/tests/test_validate_docs.py b/tests/test_validate_docs.py
index 2dba553..91bebfc 100644
--- a/tests/test_validate_docs.py
+++ b/tests/test_validate_docs.py
@@ -90,8 +90,8 @@ def _write_contract_docs(root):
"Production deployments should pin the exact versions."
),
"packages/openadapt.md": (
+ "---\nredirect_to: /ecosystem/\n---\n\n"
"# OpenAdapt package documentation moved\n\n"
- '\n\n'
"`pip install openadapt`"
),
}