Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 24 additions & 13 deletions docs/getting-started/try-it-out/on-k3d-locally.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,39 +10,46 @@ import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
import { versions, defaultCredentials } from "../../_constants.mdx";
import AgentSetupBuilder from "@site/src/components/AgentSetupBuilder";
import AgentCallout from "@site/src/components/AgentCallout";
import {
SetupSwitch,
SetupAgent,
SetupManual,
} from "@site/src/components/SetupSwitch";

# Run OpenChoreo on K3d Locally

This guide walks you through setting up OpenChoreo on your machine with k3d. You will install each plane one at a time, and after each one you will do something real with it: log in, deploy a service, or trigger a build.
This guide runs all four OpenChoreo planes on your machine, in a single k3d cluster.

OpenChoreo has four planes:

- **Control Plane** runs the API, console, identity provider, and controllers.
- **Data Plane** runs your workloads and routes traffic to them.
- **Workflow Plane** builds container images from source using Argo Workflows.
- **Observability Plane** collects logs and metrics from all other planes.
- **Observability Plane** collects logs and metrics from the other planes.

By the end you will have all four running in a single k3d cluster.
By the end you'll have a working installation on localhost: a web app you can open in your browser, a source-to-image build pipeline, and log collection.

**What you will get:**
Pick how you want to install it:

- A working OpenChoreo installation on localhost
- A deployed web app you can open in your browser
- A source-to-image build pipeline
- Log collection and querying
<SetupSwitch>

<AgentCallout>
<SetupAgent>

Install the skill, pick your planes, and paste the prompt into your agent (Claude Code, Codex, Cursor, or any coding agent).
Install the `openchoreo-setup` skill.

```bash
npx skills add openchoreo/skills --skill openchoreo-setup
npx skills add openchoreo/skills --skill openchoreo-setup -g
```

Then pick your planes and copy the prompt into your agent.

<AgentSetupBuilder fixedEnv="k3d" currentVersion={versions.helmChart} />

</AgentCallout>
</SetupAgent>

<SetupManual>

Install OpenChoreo by hand, one plane at a time. Start with the prerequisites, then work through each step in order.

## Prerequisites

Expand Down Expand Up @@ -1002,3 +1009,7 @@ k3d cluster delete openchoreo
- Explore the <Link to={`https://github.com/openchoreo/openchoreo/tree/${versions.githubRef}/samples`}>sample applications</Link>
- Read the [Deployment Topology](../../platform-engineer-guide/deployment-topology.mdx) guide for production setups
- Learn about [Multi-Cluster Connectivity](../../platform-engineer-guide/multi-cluster-connectivity.mdx) for separating planes across clusters

</SetupManual>

</SetupSwitch>
41 changes: 26 additions & 15 deletions docs/getting-started/try-it-out/on-your-environment.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,48 @@ import CodeBlock from "@theme/CodeBlock";
import Link from "@docusaurus/Link";
import { versions, defaultCredentials } from "../../_constants.mdx";
import AgentSetupBuilder from "@site/src/components/AgentSetupBuilder";
import AgentCallout from "@site/src/components/AgentCallout";
import {
SetupSwitch,
SetupAgent,
SetupManual,
} from "@site/src/components/SetupSwitch";

# Run OpenChoreo in Your Environment

This guide walks you through setting up OpenChoreo on any Kubernetes cluster (k3s, GKE, EKS, DOKS, AKS, or self-managed). You will install each plane one at a time, and after each one you will do something real with it: log in, deploy a service, or trigger a build.
This guide runs OpenChoreo on any Kubernetes cluster (k3s, GKE, EKS, DOKS, AKS, or self-managed), using a **single-cluster topology** with all planes in one cluster. For split-cluster setups, follow [Multi-Cluster Connectivity](../../platform-engineer-guide/multi-cluster-connectivity.mdx).

It uses a **single-cluster topology** (all planes in one cluster). For split-cluster setups, follow [Multi-Cluster Connectivity](../../platform-engineer-guide/multi-cluster-connectivity.mdx).

All gateways are configured with HTTPS using self-signed certificates by default. You can replace them with certificates from a real CA later.
Gateways use HTTPS with self-signed certificates by default; you can swap in certificates from a real CA later.

OpenChoreo has four planes:

- **Control Plane** runs the API, console, identity provider, and controllers.
- **Data Plane** runs your workloads and routes traffic to them.
- **Workflow Plane** builds container images from source using Argo Workflows.
- **Observability Plane** collects logs and metrics from all other planes.
- **Observability Plane** collects logs and metrics from the other planes.

By the end you'll have OpenChoreo running on your cluster over HTTPS, reachable at a console URL through your LoadBalancer, with a web app deployed and, optionally, a source-to-image build pipeline and log collection.

**What you will get:**
Pick how you want to install it:

- OpenChoreo running on your Kubernetes cluster with HTTPS
- A reachable console URL over your cluster LoadBalancer
- A deployed web app you can open in your browser
- Optional source-to-image build pipeline and log collection
<SetupSwitch>

<AgentCallout>
<SetupAgent>

Install the skill, pick your environment and planes, and paste the prompt into your agent (Claude Code, Codex, Cursor, or any coding agent).
Install the `openchoreo-setup` skill.

```bash
npx skills add openchoreo/skills --skill openchoreo-setup
npx skills add openchoreo/skills --skill openchoreo-setup -g
```

Then pick your environment and planes, and copy the prompt into your agent.

<AgentSetupBuilder currentVersion={versions.helmChart} />

</AgentCallout>
</SetupAgent>

<SetupManual>

Install OpenChoreo by hand, one plane at a time. Start with the prerequisites, then work through each step in order.

## Prerequisites

Expand Down Expand Up @@ -1253,3 +1260,7 @@ kubectl delete namespace \
- Follow [Deploy and Explore](../deploy-and-explore.mdx) to understand the resources OpenChoreo creates
- Explore the <Link to={`https://github.com/openchoreo/openchoreo/tree/${versions.githubRef}/samples`}>sample applications</Link>
- Move to multi-cluster isolation using [Multi-Cluster Connectivity](../../platform-engineer-guide/multi-cluster-connectivity.mdx)

</SetupManual>

</SetupSwitch>
17 changes: 17 additions & 0 deletions plugins/docusaurus-plugin-markdown-export/mdxProcessor.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ async function processMarkdownFile(content, constants, sourceDir, linkContext) {
const { frontmatter, body } = extractFrontmatter(result);
result = body;

// Step 2.5: Unwrap the interactive setup-switch. Drop the agent panel
// (interactive prompt builder — not meaningful as markdown) and strip the
// switch/manual container tags so the manual guide stays as clean markdown.
result = processSetupSwitch(result);

// Step 3: Process CodeBlock components
result = processCodeBlocks(result, constants);

Expand Down Expand Up @@ -118,6 +123,18 @@ function extractFrontmatter(content) {
return { frontmatter, body };
}

function processSetupSwitch(content) {
let result = content;
// Remove the entire agent panel (prompt builder, npx, etc.).
result = result.replace(/<SetupAgent>[\s\S]*?<\/SetupAgent>/g, '');
// Unwrap the switch + manual containers, keeping their markdown children.
result = result.replace(/<\/?SetupSwitch>/g, '');
result = result.replace(/<\/?SetupManual>/g, '');
// Drop any stray self-closing component tags (e.g. the plane builder).
result = result.replace(/<AgentSetupBuilder\b[^>]*\/>/g, '');
return result;
}

function removeImports(content) {
// Remove all import statements (single and multi-line)
return content.replace(/^import\s+[\s\S]*?from\s+['"][^'"]+['"];?\s*$/gm, '');
Expand Down
10 changes: 10 additions & 0 deletions src/components/AgentCallout/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,13 @@
.content {
margin-top: 0.75rem;
}

.content :global([class*="codeBlockContainer"]) {
background: var(--ifm-background-surface-color);
border: 1px solid var(--ifm-color-emphasis-300);
box-shadow: none;
}

.content :global(.prism-code) {
background: var(--ifm-background-surface-color);
}
6 changes: 4 additions & 2 deletions src/components/AgentSetupBuilder/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,11 @@ export default function AgentSetupBuilder({ currentVersion, fixedEnv }: Props) {
</svg>
)}
</span>
<span className={styles.planeName}>{p.label}</span>
<span className={styles.planeName}>
{p.label}
{p.required && <span className={styles.planeReqInline}> (required)</span>}
</span>
<span className={styles.planeDesc}>{p.desc}</span>
{p.required && <span className={styles.planeReqBadge}>required</span>}
</button>
);
})}
Expand Down
22 changes: 10 additions & 12 deletions src/components/AgentSetupBuilder/styles.module.css
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.builder {
display: flex;
flex-direction: column;
gap: 0.75rem;
gap: 1rem;
margin-top: 0.75rem;
}

Expand Down Expand Up @@ -64,7 +64,7 @@
.planesGrid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0.4rem;
gap: 0.55rem;
}

@media (max-width: 480px) {
Expand All @@ -75,26 +75,25 @@
position: relative;
display: flex;
flex-direction: column;
gap: 0.1rem;
padding: 0.5rem 0.5rem 0.5rem 2rem;
gap: 0.2rem;
padding: 0.7rem 0.75rem 0.7rem 2.1rem;
border-radius: 8px;
border: 1px solid var(--ifm-color-emphasis-200);
background: var(--ifm-color-emphasis-100);
border: 1px solid var(--ifm-color-emphasis-300);
background: var(--ifm-background-surface-color);
cursor: pointer;
text-align: left;
transition: border-color 0.12s, background 0.12s, opacity 0.12s;
}

.planeCardRequired {
cursor: default;
opacity: 0.55;
}

.planeCard:not(.planeCardRequired):hover {
border-color: var(--ifm-color-primary);
}

.planeCardOn:not(.planeCardRequired) {
.planeCardOn {
border-color: var(--ifm-color-primary);
background: rgba(43, 140, 247, 0.08);
}
Expand Down Expand Up @@ -133,10 +132,9 @@
color: var(--ifm-color-emphasis-600);
}

.planeReqBadge {
font-size: 0.65rem;
color: var(--ifm-color-emphasis-500);
font-style: italic;
.planeReqInline {
font-weight: 400;
color: var(--ifm-color-emphasis-600);
}

.builder :global(.prism-code) {
Expand Down
93 changes: 93 additions & 0 deletions src/components/SetupSwitch/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import React, { createContext, useContext, useEffect, useRef, useState } from "react";
import styles from "./styles.module.css";

// Split switch for the install pages. Both panels stay in the DOM and toggle
// via `hidden` (not unmounted) so the manual guide stays crawlable.

type Choice = "agent" | "manual";

const SwitchCtx = createContext<{ sel: Choice; setSel: (s: Choice) => void }>({
sel: "agent",
setSel: () => {},
});

export function SetupSwitch({ children }: { children: React.ReactNode }) {
const [sel, setSel] = useState<Choice>("agent");

// Expose the active pane on <html> so the page TOC (rendered outside this
// component) can hide the manual headings while the agent panel is showing.
useEffect(() => {
const root = document.documentElement;
root.setAttribute("data-setup-pane", sel);
return () => root.removeAttribute("data-setup-pane");
}, [sel]);

return (
<SwitchCtx.Provider value={{ sel, setSel }}>
<div className={styles.band} role="tablist">
<button
type="button"
className={styles.half}
role="tab"
aria-selected={sel === "agent"}
onClick={() => setSel("agent")}
>
<span className={styles.title}>Set this up with your agent</span>
<span className={styles.desc}>Install the skill and paste one prompt into Claude Code, Codex, Cursor, or any coding agent.</span>
</button>
<button
type="button"
className={styles.half}
role="tab"
aria-selected={sel === "manual"}
onClick={() => setSel("manual")}
>
<span className={styles.title}>Set this up manually</span>
<span className={styles.desc}>Install each plane yourself, step by step, and learn what every piece does and how it fits together.</span>
</button>
</div>
Comment on lines +27 to +48

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant file and nearby components.
git ls-files src/components/SetupSwitch/index.tsx src/components/SetupSwitch

echo '--- outline ---'
ast-grep outline src/components/SetupSwitch/index.tsx --view expanded || true

echo '--- file with line numbers (first 220 lines) ---'
cat -n src/components/SetupSwitch/index.tsx | sed -n '1,220p'

echo '--- search for related ARIA/tab patterns in repo ---'
rg -n --hidden --glob '!**/node_modules/**' 'role="tablist"|role="tab"|role="tabpanel"|aria-controls|aria-labelledby' src || true

Repository: openchoreo/openchoreo.github.io

Length of output: 5213


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the existing tab implementation used elsewhere for comparison.
cat -n src/pages/ecosystem/item.tsx | sed -n '770,850p'

Repository: openchoreo/openchoreo.github.io

Length of output: 4447


Finish the tab semantics or use plain buttons. The controls are marked as tabs, but the panels aren’t wired with aria-controls/id, role="tabpanel", or roving tabIndex, so this reads as an incomplete tabs pattern to assistive tech. Either implement the full contract or drop the tab roles and keep it as a simple toggle.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/SetupSwitch/index.tsx` around lines 27 - 48, The SetupSwitch
controls are using tab semantics incompletely, so either finish the full tabs
pattern or simplify them to plain buttons. In SetupSwitch, if you keep
role="tab", add the matching aria-controls/id wiring, role="tabpanel" on the
content areas, and proper roving tabIndex/keyboard behavior; otherwise remove
the tablist/tab roles and leave the buttons as a simple toggle between agent and
manual.

{children}
</SwitchCtx.Provider>
);
}

export function SetupAgent({ children }: { children: React.ReactNode }) {
const { sel } = useContext(SwitchCtx);
return <div hidden={sel !== "agent"}>{children}</div>;
}

export function SetupManual({ children }: { children: React.ReactNode }) {
const { sel, setSel } = useContext(SwitchCtx);
const ref = useRef<HTMLDivElement>(null);
const pendingId = useRef<string | null>(null);

// A deep link or TOC click to a manual heading should reveal this panel.
useEffect(() => {
const reveal = () => {
const id = decodeURIComponent(window.location.hash.slice(1));
if (!id || !ref.current) return;
const target = document.getElementById(id);
if (target && ref.current.hidden && ref.current.contains(target)) {
pendingId.current = id;
setSel("manual");
}
};
reveal();
window.addEventListener("hashchange", reveal);
return () => window.removeEventListener("hashchange", reveal);
}, [setSel]);

useEffect(() => {
if (sel === "manual" && pendingId.current) {
const target = document.getElementById(pendingId.current);
pendingId.current = null;
if (target) target.scrollIntoView();
}
}, [sel]);

return (
<div ref={ref} hidden={sel !== "manual"}>
{children}
</div>
);
}
Loading