From 9d17dee5c3a4bfc7fa5192a2765b48133eac765a Mon Sep 17 00:00:00 2001 From: "Claude Code (winnie)" <91998347+gwenwindflower@users.noreply.github.com> Date: Wed, 26 Aug 2026 21:15:32 -0500 Subject: [PATCH 1/3] docs: add agent start walkthrough at /start Hidden page fetched as /start.md by coding agents; seo.indexing all keeps hidden pages in llms.txt and the markdown export. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Q7j1Lnzqm9WnSwg1zYbrKY --- docs.json | 3 ++ start.mdx | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 start.mdx diff --git a/docs.json b/docs.json index 8ad8c61f..89c20ac0 100644 --- a/docs.json +++ b/docs.json @@ -11,6 +11,9 @@ "library": "tabler" }, "favicon": "/favicon.png", + "seo": { + "indexing": "all" + }, "navigation": { "tabs": [ { diff --git a/start.mdx b/start.mdx new file mode 100644 index 00000000..c7d112a7 --- /dev/null +++ b/start.mdx @@ -0,0 +1,112 @@ +--- +title: "Start" +description: "A guided walkthrough for coding agents helping a user set up Lightdash from scratch" +hidden: true +--- + +You are a coding agent helping a user set up [Lightdash](https://www.lightdash.com), a code-based BI and agentic analytics platform built on a semantic layer. Your job: get their tools installed, help them choose a path, and get them to their first explorable data in Lightdash Cloud. Work conversationally — ask the questions below one at a time, run commands only with the user's permission, and share the linked docs pages so they can read along. + +Any page on `docs.lightdash.com` can be fetched as plain markdown by appending `.md` to its URL. Do that whenever you need more detail than this walkthrough carries. + +## Step 1: Install the CLI and agent skills + +Install the Lightdash CLI. On macOS, prefer Homebrew (no Node.js required): + +```bash +brew tap lightdash/lightdash +brew install lightdash +``` + +Anywhere with Node.js available, npm works too: + +```bash +npm install -g @lightdash/cli +``` + +Verify with `lightdash --version`. For Windows (WSL or PowerShell) and direct binary downloads, follow https://docs.lightdash.com/workflow/cli/install. + +Then install the Lightdash agent skills so you can work with semantic layer YAML fluently. Run the variant matching your own harness, from the project directory the user will work in: + +```bash +lightdash install-skills # Claude Code (also read by GitHub Copilot) +lightdash install-skills --agent cursor # Cursor +lightdash install-skills --agent codex # Codex +``` + +Add `--global` if the user wants the skills available across all their projects. Details: https://docs.lightdash.com/workflow/install-agent-skills. + +## Step 2: Real project or sandbox? + +Ask the user which they want: + +- **A real project** — they have data in a warehouse (or a dbt project) and want Lightdash on top of it. Continue to Step 3. +- **A sandbox** — they want to try Lightdash on sample data first. Skip to Step 4. + +If they want a real project but have no data warehouse yet, treat that as the sandbox path — it gets them a working warehouse too. + +Lightdash connects to BigQuery, Postgres, Supabase, Redshift, Snowflake, Databricks, Trino, ClickHouse, DuckDB (MotherDuck or DuckLake), and Athena. Full connection reference: https://docs.lightdash.com/get-started/quickstart/connect-project. + +## Step 3: Real project + +Ask whether the user works with dbt. + +### With dbt + +Lightdash generates its semantic layer from dbt models (dbt v1.4 or later, available on the path as `dbt`). + +1. Navigate to their dbt project. If they want a brand-new one, scaffold it with `dbt init` and dbt's own guide (https://docs.getdbt.com/tutorial/setting-up) before continuing. dbt Cloud users need the repo cloned locally. +2. Create the Lightdash account — see Step 5 — then authenticate the CLI: `lightdash login ` opens a browser OAuth flow. +3. Generate Lightdash Tables from their dbt models and deploy: + + ```bash + lightdash dbt run + lightdash deploy --create + ``` + +Follow https://docs.lightdash.com/get-started/quickstart/prepare-your-dbt-project as the canonical script for this path, and https://docs.lightdash.com/get-started/quickstart/connect-project for the warehouse connection settings the deploy will ask for. + +### Without dbt + +Define the semantic layer directly in Lightdash YAML — no dbt project needed: + +1. Create `lightdash.config.yml` at the project root declaring the warehouse type, and model files under `lightdash/models/*.yml` (`type: model`, `name`, `sql_from`, plus `metrics` and `dimensions`). With the skills from Step 1 installed, use the `developing-in-lightdash` skill to profile the user's warehouse and generate sensible starter models. +2. Validate with `lightdash lint`. +3. Create the Lightdash account — see Step 5 — then `lightdash login ` and deploy without credentials: + + ```bash + lightdash deploy --create --no-warehouse-credentials + ``` + +4. Have the user add warehouse credentials in the app (Settings → Current project → Connection settings). + +Canonical reference for this whole path: https://docs.lightdash.com/semantic-layer/yaml. + +## Step 4: Sandbox project + +The fastest sandbox today is Supabase — free tier, no dbt required: + +1. Clone https://github.com/lightdash/lightdash-supabase-quickstart. It includes setup scripts (macOS/Linux and Windows), a preconfigured Supabase MCP so you can generate Lightdash models from the schema, and a `set-warehouse` script that wires up credentials via the API. +2. Have the user create a free project at https://supabase.com if they don't have one. +3. Follow the repo's README — it goes from zero to charts in about 15 minutes, including the account creation from Step 5. + +Alternatively, MotherDuck (managed DuckDB, free trial at https://motherduck.com) works well with the Lightdash YAML path from Step 3: connect to one of MotherDuck's built-in sample databases, generate models with the `developing-in-lightdash` skill, and deploy. The MotherDuck connection settings are documented at https://docs.lightdash.com/get-started/quickstart/connect-project. + +{/* Placeholder: a dedicated sandbox template repo (warehouse trial + preloaded models) is planned; link it here when it ships. */} + +## Step 5: Create the Lightdash account + +Every path lands here. Send the user to sign up — this is their step, in the browser: + +https://www.lightdash.com/start + +Once they have an instance (Lightdash Cloud is `app.lightdash.cloud`, or `eu1.lightdash.cloud` in the EU), return to wherever you left off: `lightdash login `, deploy, and confirm the project appears in the app. + +## After setup + +Point the user at their next steps: + +- Explore their first Tables: https://docs.lightdash.com/get-started/explore-your-data +- Grow the semantic layer with metrics and dimensions: https://docs.lightdash.com/get-started/build-your-semantic-layer +- Connect you (the agent) to their Lightdash instance over MCP: https://docs.lightdash.com/agents/lightdash-mcp +- Preview changes safely before deploying: https://docs.lightdash.com/workflow/preview-projects +- Invite their team: https://docs.lightdash.com/get-started/quickstart/invite-new-users From e12ad3015601434c558144fd9a8e5261f4e12962 Mon Sep 17 00:00:00 2001 From: "Claude Code (winnie)" <91998347+gwenwindflower@users.noreply.github.com> Date: Wed, 26 Aug 2026 21:15:37 -0500 Subject: [PATCH 2/3] feat: add copy-prompt button to the homepage Copies an agent start prompt pointing at /start.md; four agent brand icons with hover motion, and a char-scramble preview line that cycles between the prompt and the copied confirmation. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Q7j1Lnzqm9WnSwg1zYbrKY --- introduction.mdx | 4 + snippets/copy-prompt-button.jsx | 163 ++++++++++++++++++++++++++++++++ styles.css | 144 ++++++++++++++++++++++++++++ 3 files changed, 311 insertions(+) create mode 100644 snippets/copy-prompt-button.jsx diff --git a/introduction.mdx b/introduction.mdx index 153a7b4a..9dc4106a 100644 --- a/introduction.mdx +++ b/introduction.mdx @@ -4,12 +4,16 @@ description: "Enterprise-ready agentic analytics that turns questions into insig mode: "wide" --- +import { CopyPromptButton } from "/snippets/copy-prompt-button.jsx"; + At its core, Lightdash builds a shared understanding of your data and your business — a single source of truth for what everything means. The more your team uses Lightdash, the richer and smarter that foundation becomes. Lightdash then allows your team to use conversational analytics, build dashboards, and custom data apps all with an AI-powered experience that means they don't need to write any SQL. Everything is built from a single source of truth, so you have lineage for every data asset and can trace any query to its official definition. Everything you create in Lightdash can be shared instantly with your team with control over roles, permissions, and row-level security to make sure people see all the data they need and nothing more. + + **Talk to the docs with your agent** over MCP, no authentication required. Get [step-by-step instructions here](/agents/lightdash-mcp#lightdash-docs-mcp). diff --git a/snippets/copy-prompt-button.jsx b/snippets/copy-prompt-button.jsx new file mode 100644 index 00000000..d31ec416 --- /dev/null +++ b/snippets/copy-prompt-button.jsx @@ -0,0 +1,163 @@ +{/* Mintlify evaluates each snippet export in isolation inside the page's MDX + scope, so everything the component references must live inside this one + export — module-level constants would be undefined at runtime. */} + +export const CopyPromptButton = () => { + const START_PROMPT = + "Read https://docs.lightdash.com/start.md then help me setup a Lightdash project..."; + const PROMPT_DISPLAY = "“" + START_PROMPT + "”"; + const COPIED_DISPLAY = + "✓ Copied — now paste that into your coding agent for a guided walkthrough!"; + const CYCLE_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_./:;[]<>"; + const AGENT_ICONS = [ + { + name: "Claude Code", + path: "M20.998 10.949H24v3.102h-3v3.028h-1.487V20H18v-2.921h-1.487V20H15v-2.921H9V20H7.488v-2.921H6V20H4.487v-2.921H3V14.05H0V10.95h3V5h17.998v5.949zM6 10.949h1.488V8.102H6v2.847zm10.51 0H18V8.102h-1.49v2.847z", + }, + { + name: "Codex", + path: "M8.086.457a6.105 6.105 0 013.046-.415c1.333.153 2.521.72 3.564 1.7a.117.117 0 00.107.029c1.408-.346 2.762-.224 4.061.366l.063.03.154.076c1.357.703 2.33 1.77 2.918 3.198.278.679.418 1.388.421 2.126a5.655 5.655 0 01-.18 1.631.167.167 0 00.04.155 5.982 5.982 0 011.578 2.891c.385 1.901-.01 3.615-1.183 5.14l-.182.22a6.063 6.063 0 01-2.934 1.851.162.162 0 00-.108.102c-.255.736-.511 1.364-.987 1.992-1.199 1.582-2.962 2.462-4.948 2.451-1.583-.008-2.986-.587-4.21-1.736a.145.145 0 00-.14-.032c-.518.167-1.04.191-1.604.185a5.924 5.924 0 01-2.595-.622 6.058 6.058 0 01-2.146-1.781c-.203-.269-.404-.522-.551-.821a7.74 7.74 0 01-.495-1.283 6.11 6.11 0 01-.017-3.064.166.166 0 00.008-.074.115.115 0 00-.037-.064 5.958 5.958 0 01-1.38-2.202 5.196 5.196 0 01-.333-1.589 6.915 6.915 0 01.188-2.132c.45-1.484 1.309-2.648 2.577-3.493.282-.188.55-.334.802-.438.286-.12.573-.22.861-.304a.129.129 0 00.087-.087A6.016 6.016 0 015.635 2.31C6.315 1.464 7.132.846 8.086.457zm-.804 7.85a.848.848 0 00-1.473.842l1.694 2.965-1.688 2.848a.849.849 0 001.46.864l1.94-3.272a.849.849 0 00.007-.854l-1.94-3.393zm5.446 6.24a.849.849 0 000 1.695h4.848a.849.849 0 000-1.696h-4.848z", + }, + { + name: "opencode", + path: "M16 6H8v12h8V6zm4 16H4V2h16v20z", + }, + { + name: "Cursor", + path: "M22.106 5.68L12.5.135a.998.998 0 00-.998 0L1.893 5.68a.84.84 0 00-.419.726v11.186c0 .3.16.577.42.727l9.607 5.547a.999.999 0 00.998 0l9.608-5.547a.84.84 0 00.42-.727V6.407a.84.84 0 00-.42-.726zm-.603 1.176L12.228 22.92c-.063.108-.228.064-.228-.061V12.34a.59.59 0 00-.295-.51l-9.11-5.26c-.107-.062-.063-.228.062-.228h18.55c.264 0 .428.286.296.514z", + }, + ]; + + const [target, setTarget] = useState(PROMPT_DISPLAY); + const [cycle, setCycle] = useState(0); + const [copied, setCopied] = useState(false); + const [text, setText] = useState(PROMPT_DISPLAY); + const rafRef = useRef(0); + const resetRef = useRef(0); + const wrapRef = useRef(null); + + useEffect(() => { + setText(target); + }, [target]); + + /* Scramble-and-settle on the preview line: each character cycles through + random glyphs then settles to the target, staggered left-to-right. + Re-runs on every `cycle` bump; the full sweep lands in about a second. + Skipped entirely under prefers-reduced-motion. */ + useEffect(() => { + if (!cycle) return; + if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) { + setText(target); + return; + } + + const totalFrames = 6; + const staggerPerChar = 0.2; + const interval = 900 / 30; + const chars = target.split(""); + const total = chars.length * staggerPerChar + totalFrames; + let frame = 0; + let last = 0; + + cancelAnimationFrame(rafRef.current); + const tick = (t) => { + if (t - last < interval) { + rafRef.current = requestAnimationFrame(tick); + return; + } + last = t; + + setText( + chars + .map((c, i) => { + const settleStart = i * staggerPerChar; + if (frame >= settleStart + totalFrames) return c; + if (c === " ") return c; + if (frame < settleStart && Math.random() >= 0.35) return c; + return CYCLE_CHARS[Math.floor(Math.random() * CYCLE_CHARS.length)]; + }) + .join(""), + ); + + if (frame > total) { + setText(target); + rafRef.current = 0; + return; + } + frame++; + rafRef.current = requestAnimationFrame(tick); + }; + + rafRef.current = requestAnimationFrame(tick); + return () => cancelAnimationFrame(rafRef.current); + }, [cycle, target]); + + useEffect( + () => () => { + cancelAnimationFrame(rafRef.current); + clearTimeout(resetRef.current); + }, + [], + ); + + const handleClick = () => { + if (navigator.clipboard) { + navigator.clipboard.writeText(START_PROMPT).catch(() => { }); + } + setCopied(true); + setTarget(COPIED_DISPLAY); + setCycle((c) => c + 1); + clearTimeout(resetRef.current); + resetRef.current = setTimeout(() => { + /* If the reader is still on the button (or reached it by keyboard) the + preview stays visible, so scramble back to the prompt; otherwise the + is-copied class drop fades it out and the text can swap silently. */ + const wrap = wrapRef.current; + const stillWatching = + wrap && + (wrap.matches(":hover") || + wrap.querySelector(".copy-prompt-btn:focus-visible")); + setCopied(false); + setTarget(PROMPT_DISPLAY); + if (stillWatching) setCycle((c) => c + 1); + }, 2200); + }; + + return ( +
+ + + {copied ? "Prompt copied to clipboard" : ""} + + +
+ ); +}; diff --git a/styles.css b/styles.css index 2d39723d..5e14de8c 100644 --- a/styles.css +++ b/styles.css @@ -97,3 +97,147 @@ svg.matrix-no { html.dark svg.matrix-no { background-color: #2e2947; } + +/* + * Copy-prompt button (snippets/copy-prompt-button.jsx): copies an agent start + * prompt pointing at start.md. Pill shape and sizing follow the mint theme's + * primary CTA; the background is the accent purple from docs.json, identical + * in both themes, so hover/focus colours are hardcoded to match. + * + * Two interactions live here: the four agent icons lean toward the cursor on + * hover (JS drives only the label scramble), and the prompt preview fades in + * under the button so readers see exactly what a click puts on the clipboard. + */ + +.copy-prompt { + margin: 1.5rem 0; +} + +.copy-prompt-btn { + display: inline-flex; + align-items: center; + gap: 0.75rem; + padding: 0.75rem 1.375rem; + border: none; + border-radius: 9999px; + background-color: #8072ff; + color: #ffffff; + font-size: 0.875rem; + font-weight: 500; + line-height: 1.25rem; + cursor: pointer; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08); + transition: background-color 150ms ease; +} + +.copy-prompt-btn:hover { + background-color: #6c5df2; +} + +.copy-prompt-btn:focus-visible { + outline: 2px solid #8072ff; + outline-offset: 2px; +} + +.copy-prompt-label { + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; +} + +.copy-prompt-icons { + display: inline-flex; + align-items: center; + gap: 0.3125rem; +} + +.copy-prompt-icons svg { + width: 1.25rem; + height: 1.25rem; + flex: none; + transition: transform 300ms ease-out; +} + +.copy-prompt-icons svg:nth-child(1) { + transform: rotate(-6deg); +} + +.copy-prompt-icons svg:nth-child(4) { + transform: rotate(6deg); +} + +.copy-prompt-btn:hover .copy-prompt-icons svg:nth-child(1) { + transform: translateX(-4px) rotate(-12deg); +} + +.copy-prompt-btn:hover .copy-prompt-icons svg:nth-child(2) { + transform: translate(-1px, -1px) rotate(6deg) scale(1.1); +} + +.copy-prompt-btn:hover .copy-prompt-icons svg:nth-child(3) { + transform: translate(1px, 2px) rotate(-6deg) scale(1.1); +} + +.copy-prompt-btn:hover .copy-prompt-icons svg:nth-child(4) { + transform: translateX(4px) rotate(12deg); +} + +/* Preview stays in flow (opacity only) so revealing it never shifts layout. */ +.copy-prompt-preview { + margin: 0.625rem 0 0 0.25rem; + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; + font-size: 0.8125rem; + color: #9ca3af; + opacity: 0; + transform: translateY(4px); + transition: + opacity 200ms ease, + transform 200ms ease; +} + +html.dark .copy-prompt-preview { + color: #6b7280; +} + +/* Success state: the preview shifts into the accent family — a darker shade + on light ground, a purple-tinted near-white on dark — so the copied + confirmation reads as a state change, not just new words. */ +.copy-prompt-preview.is-copied { + color: #5747cf; +} + +html.dark .copy-prompt-preview.is-copied { + color: #cfc9ff; +} + +/* Visible while hovered, while the button holds keyboard focus, or while the + copied confirmation is up. Plain mouse focus is deliberately excluded + (:focus-visible, not :focus-within) so the confirmation can fade back out + after its cooloff even though a click leaves focus on the button. */ +.copy-prompt:hover .copy-prompt-preview, +.copy-prompt:has(.copy-prompt-btn:focus-visible) .copy-prompt-preview, +.copy-prompt-preview.is-copied { + opacity: 1; + transform: none; +} + +.copy-prompt-sr-status { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +@media (prefers-reduced-motion: reduce) { + .copy-prompt-icons svg, + .copy-prompt-preview { + transition: none; + } + + .copy-prompt-preview { + transform: none; + } +} From b3d1888b7c345b7ca37140a14497e11480e9daf8 Mon Sep 17 00:00:00 2001 From: "Claude Code (winnie)" <91998347+gwenwindflower@users.noreply.github.com> Date: Wed, 26 Aug 2026 21:15:40 -0500 Subject: [PATCH 3/3] docs(agents): document local preview and hidden-page conventions Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Q7j1Lnzqm9WnSwg1zYbrKY --- .mintlify/AGENTS.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.mintlify/AGENTS.md b/.mintlify/AGENTS.md index cb27aca5..88b1613c 100644 --- a/.mintlify/AGENTS.md +++ b/.mintlify/AGENTS.md @@ -51,9 +51,13 @@ Ship the redirect in the same change (principle 7): 2. Re-point any existing redirect whose destination you moved — redirects must never chain. 3. Rewrite inbound internal links to the final URL (`rg` the old slug); internal links never route through a redirect. +## Local preview + +Start `mint dev --port 3333` **once** in the background and reuse it for the whole session — it hot-reloads `.mdx`, `snippets/`, `styles.css`, and `docs.json`, so never restart it to pick up an edit. If the port is taken, mint silently binds the next port up instead of failing, so relaunching stacks zombie servers. To stop it, kill the background task's PID (the process cmdline is `node .../mint/index.js dev`, so `pkill -f "mint dev"` matches nothing); check for strays with `procs mint`. Launching needs to run outside the sandbox (`mint` writes preview locks under `~/.mintlify`), as does spawning Chrome for screenshots. + ## Before done -Frontmatter is complete, the page is reachable from nav, and `mint broken-links` passes. +Frontmatter is complete, the page is reachable from nav, and `mint broken-links` passes. Pages meant to be fetched by URL rather than browsed declare `hidden: true` in frontmatter instead of a nav entry — the validator exempts them from nav reachability, and `seo.indexing: "all"` in `docs.json` keeps them in `llms.txt` and the `.md` export. `start.mdx` (the agent endpoint behind the homepage copy-prompt button) is the one such page; don't add it to nav. ## Reference docs