diff --git a/.claude/skills/docs-review/SKILL.md b/.claude/skills/docs-review/SKILL.md
index 61a37a5c..12060b5a 100644
--- a/.claude/skills/docs-review/SKILL.md
+++ b/.claude/skills/docs-review/SKILL.md
@@ -51,6 +51,7 @@ Perform critical editorial reviews as a tech writer / copyeditor, focusing on cl
- **Heading count**: 20+ headings signals over-segmentation; consolidate
- **Information flow**: Conceptual content (trade-offs, when to use) should come before implementation details, not after
- **Admonition weight**: Tips, notes, and warnings should be supplementary. If an admonition contains primary feature documentation (full YAML examples, the only explanation of a field or concept), it should be promoted to a proper section or its own page. A good test: if this admonition is the only place a feature is documented, it's not a tip - it's a section that needs a heading and ToC visibility.
+- **Enterprise construct usage**: Three constructs exist for enterprise content - check they're used correctly. `:::enterprise` admonitions are for callout blocks (2-4 sentences, max 1-2 per page). `` is for inline feature labels next to headings or list items. `className: 'enterprise-only'` in the sidebar is for enterprise-only pages. Flag misuse: enterprise admonitions used for single-feature labels (use `` instead), badge used on entire page descriptions (use the admonition instead), or excessive enterprise admonitions on a single page.
- **Diataxis alignment**: Don't mix tutorials, how-tos, reference, and concepts in one doc without clear separation
### LLM-Generated Content Patterns
diff --git a/AGENTS.md b/AGENTS.md
index 3c3bca8a..adc647e8 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -263,7 +263,43 @@ This website is built using Docusaurus, which has some specific requirements and
- Titles are added using the `title="..."` attribute in the opening code fence.
- Line highlights are added using comma-separated `{number}` or `{start-end}` ranges in the opening code fence, or `highlight-next-line`, `highlight-start`, and `highlight-end` comments within the code block.
- Use admonitions for notes, tips, warnings, and other annotations. This provides a consistent look and feel across the site.
- - Use the `:::type` syntax to define the admonition type: `note`, `tip`, `info`, `warning`, or `danger`. Use square brackets to add a custom title, e.g. `:::info[Title]`. Add empty lines around the start and end directives.
+ - Use the `:::type` syntax to define the admonition type: `note`, `tip`, `info`, `warning`, `danger`, or `enterprise`. Use square brackets to add a custom title, e.g. `:::info[Title]`. Add empty lines around the start and end directives.
+ - The `:::enterprise` admonition is for Stacklok Enterprise content only - see "Enterprise content constructs" below.
- Place images in `static/img` using WebP, PNG, or SVG format.
- Use the `ThemedImage` component to provide both light and dark mode screenshots for apps/UIs that support both. Typically used with the `useBaseUrl` hook to construct the image paths. Both require import statements.
- Use the `Tabs` and `TabItem` components to create tabbed content sections. These are in the global scope and do not require imports.
+- Use the `EnterpriseBadge` component to label individual features or capabilities as enterprise-only. This is in the global scope and does not require imports. See "Enterprise content constructs" below.
+
+### Enterprise content constructs
+
+Three constructs are available for presenting Stacklok Enterprise content inline with OSS documentation. Use the right one for the context:
+
+**`:::enterprise` admonition** - for callout content within OSS pages, typically 2-4 sentences describing an Enterprise capability with a link to the Enterprise landing page. Use when Enterprise adds a meaningful capability to the topic being documented. Don't overuse - one per page is typical, two is the practical maximum.
+
+```mdx
+:::enterprise
+
+Stacklok Enterprise includes turnkey integrations for common identity providers. Instead of manually configuring OIDC, use the built-in Okta or Entra ID integration to map IdP groups directly to ToolHive roles and policy sets.
+
+[Learn more about Stacklok Enterprise](/toolhive/enterprise).
+
+:::
+```
+
+**``** - inline label for tagging individual features, capabilities, or configuration options as enterprise-only. Works next to headings, in lists, or inline with text. Use when a specific feature within a broader page is enterprise-only.
+
+```mdx
+### Session pinning
+
+- **Automatic failover** - connections are automatically rerouted when a node becomes unavailable.
+```
+
+**`className: 'enterprise-only'` sidebar badge** - for marking enterprise-only pages in the sidebar navigation. Applied in `sidebars.ts`, not in the page itself. Renders a small "ENT" pill badge with a tooltip on hover.
+
+```ts title="sidebars.ts"
+{
+ type: 'doc',
+ id: 'toolhive/guides-enterprise/config-server',
+ className: 'enterprise-only',
+}
+```
diff --git a/docs/theme-preview.mdx b/docs/theme-preview.mdx
index bac15d71..bc7a03dd 100644
--- a/docs/theme-preview.mdx
+++ b/docs/theme-preview.mdx
@@ -174,6 +174,48 @@ This is getting silly
:::::
+## Enterprise constructs
+
+Components for presenting Stacklok Enterprise content inline with OSS docs.
+
+### Enterprise admonition
+
+Custom `:::enterprise` admonition for callout content within OSS pages. Uses the
+Stacklok symbol as the icon and a teal color palette distinct from the other
+admonition types. Supports custom titles via `:::enterprise[My title]`.
+
+:::enterprise
+
+Stacklok Enterprise includes turnkey integrations for common identity providers.
+Instead of manually configuring OIDC, use the built-in Okta or Entra ID
+integration to map IdP groups directly to ToolHive roles and policy sets.
+
+[Learn more about Stacklok Enterprise](/toolhive/enterprise).
+
+:::
+
+### Enterprise badge
+
+Inline `` component for labeling individual features or
+capabilities within a page. Works next to headings, in lists, or inline with
+text.
+
+#### Session pinning
+
+Sessions can be pinned to a specific node for the duration of a connection.
+
+- **Automatic failover** - connections are automatically
+ rerouted when a node becomes unavailable.
+- **Manual failover** - connections can be manually rerouted by an
+ administrator.
+
+### Sidebar badge
+
+Enterprise-only pages can be marked with an `ENT` badge in the sidebar by adding
+`className: 'enterprise-only'` to the sidebar item in `sidebars.ts`. The badge
+includes a tooltip on hover. See "Stacklok Enterprise" in the sidebar for an
+example.
+
## Tables
A standard Markdown table:
diff --git a/docusaurus.config.ts b/docusaurus.config.ts
index 6ac68b95..0e47e307 100644
--- a/docusaurus.config.ts
+++ b/docusaurus.config.ts
@@ -171,6 +171,10 @@ const config: Config = {
// Populate lastUpdatedAt metadata for JSON-LD structured data.
// The rendered timestamp is hidden via CSS (.theme-last-updated).
showLastUpdateTime: true,
+ admonitions: {
+ keywords: ['enterprise'],
+ extendDefaults: true,
+ },
},
blog: {
blogTitle: 'ToolHive Updates and Announcements',
diff --git a/eslint.config.mjs b/eslint.config.mjs
index a7e1a248..8697d0a0 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -45,6 +45,7 @@ export default [
Tabs: 'readonly',
TabItem: 'readonly',
MCPMetadata: 'readonly',
+ EnterpriseBadge: 'readonly',
},
},
},
diff --git a/src/components/EnterpriseBadge/index.tsx b/src/components/EnterpriseBadge/index.tsx
new file mode 100644
index 00000000..013c217b
--- /dev/null
+++ b/src/components/EnterpriseBadge/index.tsx
@@ -0,0 +1,10 @@
+import React from 'react';
+import styles from './styles.module.css';
+
+export default function EnterpriseBadge(): React.ReactNode {
+ return (
+
+ Enterprise
+
+ );
+}
diff --git a/src/components/EnterpriseBadge/styles.module.css b/src/components/EnterpriseBadge/styles.module.css
new file mode 100644
index 00000000..ef302f83
--- /dev/null
+++ b/src/components/EnterpriseBadge/styles.module.css
@@ -0,0 +1,20 @@
+.badge {
+ display: inline-flex;
+ align-items: center;
+ font-size: 0.7rem;
+ font-weight: 600;
+ letter-spacing: 0.02em;
+ line-height: 1;
+ padding: 0.2em 0.6em;
+ border: 1.5px solid #2a9d8f;
+ border-radius: 6px;
+ color: #1a5c54;
+ vertical-align: middle;
+ margin-left: 0.4em;
+ white-space: nowrap;
+}
+
+:global([data-theme='dark']) .badge {
+ color: #c8ece7;
+ border-color: #2a9d8f;
+}
diff --git a/src/css/custom.css b/src/css/custom.css
index 328673b2..151fab84 100644
--- a/src/css/custom.css
+++ b/src/css/custom.css
@@ -382,6 +382,71 @@ details summary:hover {
--ifm-alert-foreground-color: var(--stacklok-green-light);
}
+/* Enterprise admonitions - teal */
+.alert--enterprise {
+ --ifm-alert-background-color: #d5f0ec;
+ --ifm-alert-border-color: #1a8a7d;
+ --ifm-alert-foreground-color: #0f4f48;
+}
+
+[data-theme='dark'] .alert--enterprise {
+ --ifm-alert-background-color: #1a3330;
+ --ifm-alert-border-color: #2a9d8f;
+ --ifm-alert-foreground-color: #c8ece7;
+}
+
+/* Sidebar badge for enterprise-only pages */
+.enterprise-only > .menu__link {
+ position: relative;
+}
+
+.enterprise-only > .menu__link::after {
+ content: 'ENT';
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 0.55rem;
+ font-weight: 700;
+ letter-spacing: 0.03em;
+ line-height: 1;
+ padding: 0.15em 0.4em;
+ margin-left: 0.75em;
+ border: 1.5px solid #2a9d8f;
+ border-radius: 999px;
+ color: #1a5c54;
+ flex-shrink: 0;
+}
+
+.enterprise-only > .menu__link:hover::before,
+.enterprise-only > .menu__link:focus-visible::before {
+ content: 'Stacklok Enterprise feature';
+ position: absolute;
+ left: 50%;
+ bottom: calc(100% + 6px);
+ transform: translateX(-50%);
+ padding: 0.3em 0.6em;
+ font-size: 0.7rem;
+ font-weight: 500;
+ line-height: 1.3;
+ white-space: nowrap;
+ color: #fff;
+ background: #1a5c54;
+ border-radius: 4px;
+ pointer-events: none;
+ z-index: 10;
+}
+
+[data-theme='dark'] .enterprise-only > .menu__link::after {
+ color: #c8ece7;
+ border-color: #2a9d8f;
+}
+
+[data-theme='dark'] .enterprise-only > .menu__link:hover::before,
+[data-theme='dark'] .enterprise-only > .menu__link:focus-visible::before {
+ background: #1a5c54;
+ color: #c8ece7;
+}
+
/* Screenshot styling with subtle border */
.screenshot {
border: 1px solid var(--ifm-table-border-color);
diff --git a/src/theme/Admonition/Types.tsx b/src/theme/Admonition/Types.tsx
new file mode 100644
index 00000000..3b701ba9
--- /dev/null
+++ b/src/theme/Admonition/Types.tsx
@@ -0,0 +1,46 @@
+import React, { type ReactNode } from 'react';
+import DefaultAdmonitionTypes from '@theme-original/Admonition/Types';
+import AdmonitionLayout from '@theme/Admonition/Layout';
+
+const StacklokIcon = () => (
+
+);
+
+interface EnterpriseAdmonitionProps {
+ children: ReactNode;
+ title?: string;
+ className?: string;
+}
+
+function EnterpriseAdmonition(props: EnterpriseAdmonitionProps): ReactNode {
+ return (
+ }
+ title={props.title ?? 'Stacklok Enterprise'}
+ className={`alert alert--enterprise ${props.className ?? ''}`}
+ >
+ {props.children}
+
+ );
+}
+
+const AdmonitionTypes = {
+ ...DefaultAdmonitionTypes,
+ enterprise: EnterpriseAdmonition,
+};
+
+export default AdmonitionTypes;
diff --git a/src/theme/MDXComponents.tsx b/src/theme/MDXComponents.tsx
index aef9f3e0..1db71f66 100644
--- a/src/theme/MDXComponents.tsx
+++ b/src/theme/MDXComponents.tsx
@@ -10,6 +10,7 @@ import MDXComponents from '@theme-original/MDXComponents';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import MCPMetadata from '@site/src/components/MCPMetadata';
+import EnterpriseBadge from '@site/src/components/EnterpriseBadge';
export default {
// Reusing the default mapping
@@ -18,4 +19,5 @@ export default {
Tabs,
TabItem,
MCPMetadata,
+ EnterpriseBadge,
};