diff --git a/.gitignore b/.gitignore index e36fd9ad..5312aaf3 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,4 @@ vendor/opencode/ # OpenWork workspace-local artifacts .opencode/openwork/ .vercel +.env*.local diff --git a/.vercelignore b/.vercelignore new file mode 100644 index 00000000..b7895d05 --- /dev/null +++ b/.vercelignore @@ -0,0 +1,16 @@ +_archive +_worktrees +.git +.opencode +vendor +**/node_modules +**/.next +**/dist +**/.*.bun-build +packages/agent-lab +packages/app +packages/desktop +packages/headless +packages/opencode-router +packages/owpenbot +packages/server diff --git a/packages/app/src/app/app.tsx b/packages/app/src/app/app.tsx index 910172f9..3d83d467 100644 --- a/packages/app/src/app/app.tsx +++ b/packages/app/src/app/app.tsx @@ -143,6 +143,8 @@ import { } from "./lib/tauri"; import { parseOpenworkWorkspaceIdFromUrl, + readOpenworkConnectInviteFromSearch, + stripOpenworkConnectInviteFromUrl, createOpenworkServerClient, hydrateOpenworkServerSettingsFromEnv, normalizeOpenworkServerUrl, @@ -419,7 +421,33 @@ export default function App() { createEffect(() => { if (typeof window === "undefined") return; hydrateOpenworkServerSettingsFromEnv(); - setOpenworkServerSettings(readOpenworkServerSettings()); + + const stored = readOpenworkServerSettings(); + const invite = readOpenworkConnectInviteFromSearch(window.location.search); + + if (!invite) { + setOpenworkServerSettings(stored); + return; + } + + const merged: OpenworkServerSettings = { + ...stored, + urlOverride: invite.url, + token: invite.token ?? stored.token, + }; + + const next = writeOpenworkServerSettings(merged); + setOpenworkServerSettings(next); + + if (invite.startup === "server" && untrack(onboardingStep) === "welcome") { + setStartupPreference("server"); + setOnboardingStep("server"); + } + + const cleaned = stripOpenworkConnectInviteFromUrl(window.location.href); + if (cleaned !== window.location.href) { + window.history.replaceState(window.history.state ?? null, "", cleaned); + } }); createEffect(() => { diff --git a/packages/app/src/app/lib/openwork-server.ts b/packages/app/src/app/lib/openwork-server.ts index 0b575257..eb77ec3e 100644 --- a/packages/app/src/app/lib/openwork-server.ts +++ b/packages/app/src/app/lib/openwork-server.ts @@ -504,6 +504,89 @@ export function buildOpenworkWorkspaceBaseUrl(hostUrl: string, workspaceId?: str } } +export const DEFAULT_OPENWORK_CONNECT_APP_URL = "https://app.openwork.software"; + +const OPENWORK_INVITE_PARAM_URL = "ow_url"; +const OPENWORK_INVITE_PARAM_TOKEN = "ow_token"; +const OPENWORK_INVITE_PARAM_STARTUP = "ow_startup"; + +export type OpenworkConnectInvite = { + url: string; + token?: string; + startup?: "server"; +}; + +export function buildOpenworkConnectInviteUrl(input: { + workspaceUrl: string; + token?: string | null; + appUrl?: string | null; + startup?: "server"; +}) { + const workspaceUrl = normalizeOpenworkServerUrl(input.workspaceUrl ?? "") ?? ""; + if (!workspaceUrl) return ""; + + const base = normalizeOpenworkServerUrl(input.appUrl ?? "") ?? DEFAULT_OPENWORK_CONNECT_APP_URL; + + try { + const url = new URL(base); + const search = new URLSearchParams(url.search); + search.set(OPENWORK_INVITE_PARAM_URL, workspaceUrl); + + const token = input.token?.trim() ?? ""; + if (token) { + search.set(OPENWORK_INVITE_PARAM_TOKEN, token); + } + + const startup = input.startup ?? "server"; + search.set(OPENWORK_INVITE_PARAM_STARTUP, startup); + + url.search = search.toString(); + return url.toString(); + } catch { + const search = new URLSearchParams(); + search.set(OPENWORK_INVITE_PARAM_URL, workspaceUrl); + const token = input.token?.trim() ?? ""; + if (token) { + search.set(OPENWORK_INVITE_PARAM_TOKEN, token); + } + search.set(OPENWORK_INVITE_PARAM_STARTUP, input.startup ?? "server"); + return `${DEFAULT_OPENWORK_CONNECT_APP_URL}?${search.toString()}`; + } +} + +export function readOpenworkConnectInviteFromSearch(input: string | URLSearchParams) { + const search = + typeof input === "string" + ? new URLSearchParams(input.startsWith("?") ? input.slice(1) : input) + : input; + + const rawUrl = search.get(OPENWORK_INVITE_PARAM_URL)?.trim() ?? ""; + const url = normalizeOpenworkServerUrl(rawUrl); + if (!url) return null; + + const token = search.get(OPENWORK_INVITE_PARAM_TOKEN)?.trim() ?? ""; + const startupRaw = search.get(OPENWORK_INVITE_PARAM_STARTUP)?.trim() ?? ""; + const startup = startupRaw === "server" ? "server" : undefined; + + return { + url, + token: token || undefined, + startup, + } satisfies OpenworkConnectInvite; +} + +export function stripOpenworkConnectInviteFromUrl(input: string) { + try { + const url = new URL(input); + url.searchParams.delete(OPENWORK_INVITE_PARAM_URL); + url.searchParams.delete(OPENWORK_INVITE_PARAM_TOKEN); + url.searchParams.delete(OPENWORK_INVITE_PARAM_STARTUP); + return url.toString(); + } catch { + return input; + } +} + export function readOpenworkServerSettings(): OpenworkServerSettings { if (typeof window === "undefined") return {}; try { diff --git a/packages/app/src/app/pages/dashboard.tsx b/packages/app/src/app/pages/dashboard.tsx index a3c8732e..5cfa29ca 100644 --- a/packages/app/src/app/pages/dashboard.tsx +++ b/packages/app/src/app/pages/dashboard.tsx @@ -21,7 +21,11 @@ import { isTauriRuntime, normalizeDirectoryPath, } from "../utils"; -import { buildOpenworkWorkspaceBaseUrl, createOpenworkServerClient } from "../lib/openwork-server"; +import { + buildOpenworkConnectInviteUrl, + buildOpenworkWorkspaceBaseUrl, + createOpenworkServerClient, +} from "../lib/openwork-server"; import type { OpenworkAuditEntry, OpenworkSoulHeartbeatEntry, @@ -665,7 +669,18 @@ export default function DashboardView(props: DashboardViewProps) { : null; const url = mountedUrl || hostUrl; const token = props.openworkServerHostInfo?.clientToken?.trim() || ""; + const inviteUrl = buildOpenworkConnectInviteUrl({ + workspaceUrl: url, + token, + }); return [ + { + label: "OpenWork invite link", + value: inviteUrl, + secret: true, + placeholder: !isTauriRuntime() ? "Desktop app required" : "Starting server...", + hint: "One link that prefills worker URL and token.", + }, { label: "OpenWork worker URL", value: url, @@ -695,7 +710,17 @@ export default function DashboardView(props: DashboardViewProps) { ws.openworkToken?.trim() || props.openworkServerSettings.token?.trim() || ""; + const inviteUrl = buildOpenworkConnectInviteUrl({ + workspaceUrl: url, + token, + }); return [ + { + label: "OpenWork invite link", + value: inviteUrl, + secret: true, + hint: "One link that prefills worker URL and token.", + }, { label: "OpenWork worker URL", value: url, diff --git a/packages/app/src/app/pages/session.tsx b/packages/app/src/app/pages/session.tsx index 0d01524c..91ef23af 100644 --- a/packages/app/src/app/pages/session.tsx +++ b/packages/app/src/app/pages/session.tsx @@ -55,7 +55,11 @@ import RenameSessionModal from "../components/rename-session-modal"; import ProviderAuthModal, { type ProviderOAuthStartResult } from "../components/provider-auth-modal"; import ShareWorkspaceModal from "../components/share-workspace-modal"; import StatusBar from "../components/status-bar"; -import { buildOpenworkWorkspaceBaseUrl, createOpenworkServerClient } from "../lib/openwork-server"; +import { + buildOpenworkConnectInviteUrl, + buildOpenworkWorkspaceBaseUrl, + createOpenworkServerClient, +} from "../lib/openwork-server"; import type { OpenworkServerClient, OpenworkServerSettings, @@ -1994,7 +1998,18 @@ export default function SessionView(props: SessionViewProps) { : null; const url = mountedUrl || hostUrl; const token = props.openworkServerHostInfo?.clientToken?.trim() || ""; + const inviteUrl = buildOpenworkConnectInviteUrl({ + workspaceUrl: url, + token, + }); return [ + { + label: "OpenWork invite link", + value: inviteUrl, + secret: true, + placeholder: !isTauriRuntime() ? "Desktop app required" : "Starting server...", + hint: "One link that prefills worker URL and token.", + }, { label: "OpenWork worker URL", value: url, @@ -2024,7 +2039,17 @@ export default function SessionView(props: SessionViewProps) { ws.openworkToken?.trim() || props.openworkServerSettings.token?.trim() || ""; + const inviteUrl = buildOpenworkConnectInviteUrl({ + workspaceUrl: url, + token, + }); return [ + { + label: "OpenWork invite link", + value: inviteUrl, + secret: true, + hint: "One link that prefills worker URL and token.", + }, { label: "OpenWork worker URL", value: url, diff --git a/packages/docs/cli.mdx b/packages/docs/cli.mdx new file mode 100644 index 00000000..27dd5d01 --- /dev/null +++ b/packages/docs/cli.mdx @@ -0,0 +1,48 @@ +--- +title: "CLI" +description: "Run OpenWork with openwrk and related CLIs" +--- + +Use the CLI stack when you want automation without the desktop app. + +## Main commands + +- `openwrk`: headless orchestrator (OpenCode + OpenWork server + router) +- `openwork-server`: filesystem-backed remote API server +- `opencode-router`: Slack/Telegram bridge with directory routing + +## openwrk (recommended) + +```bash +npm install -g openwrk +openwrk start --workspace /path/to/workspace --approval auto +``` + +Useful follow-ups: + +```bash +openwrk status --openwork-url http://127.0.0.1:8787 --opencode-url http://127.0.0.1:4096 +openwrk approvals list --openwork-url http://127.0.0.1:8787 --host-token +``` + +## openwork-server + +```bash +npm install -g openwork-server +openwork-server --workspace /path/to/workspace --approval auto +``` + +Key env vars: + +- `OPENWORK_TOKEN` +- `OPENWORK_HOST_TOKEN` +- `OPENWORK_APPROVAL_MODE` + +## opencode-router + +```bash +npm install -g opencode-router +opencode-router start +``` + +Pair it with bindings for deterministic routing by peer + directory. diff --git a/packages/docs/create-openwork-instance.mdx b/packages/docs/create-openwork-instance.mdx new file mode 100644 index 00000000..0bea8fa0 --- /dev/null +++ b/packages/docs/create-openwork-instance.mdx @@ -0,0 +1,54 @@ +--- +title: "Create an OpenWork instance" +description: "Agent playbook for spinning up a shareable instance" +--- + +This playbook is optimized for agents or operators who need a repeatable setup. + +## Goal + +Produce one working OpenWork instance with: + +- at least one worker +- a stable connect URL + token +- one scheduled automation +- one teammate-ready share path + +## Path A: Desktop app + +1. Install and open OpenWork. +2. Create worker `agency-core`. +3. Open **Automations** and add one scheduled task. +4. Open worker menu -> **Share** and copy: + - `OpenWork worker URL` + - `Access token` + - `OpenWork invite link` + +## Path B: CLI (`openwrk`) + +```bash +npm install -g openwrk +openwrk start --workspace /path/to/agency-core --approval auto +``` + +Then capture pairing details printed by `openwrk`: + +- OpenWork URL +- client token +- host token (owner actions) + +## Instance acceptance checks + +- `GET /health` responds. +- Worker appears in OpenWork UI. +- You can run one prompt and see output. +- Automation fires once on schedule. +- Teammate can connect using invite link or URL + token. + +## Recommended first worker set + +- `agency-core` +- `client-a` +- `client-b` + +This structure prevents cross-client contamination and keeps prompts deterministic. diff --git a/packages/docs/development.mdx b/packages/docs/development.mdx new file mode 100644 index 00000000..2e8aa422 --- /dev/null +++ b/packages/docs/development.mdx @@ -0,0 +1,31 @@ +--- +title: "Development" +description: "Develop and publish this docs site from the OpenWork monorepo" +--- + +## Docs source + +Docs live at `packages/docs` in `different-ai/openwork`. + +## Run locally + +```bash +npm i -g mint +cd packages/docs +mint dev +``` + +## Validate docs + +```bash +mint broken-links +``` + +## Typical workflow + +1. Edit `.mdx` pages or `docs.json` in `packages/docs`. +2. Validate with local preview and `mint broken-links`. +3. Push to `different-ai/openwork`. +4. Confirm Mintlify Git settings point to: + - repo: `different-ai/openwork` + - monorepo path: `/packages/docs` diff --git a/packages/docs/docs.json b/packages/docs/docs.json new file mode 100644 index 00000000..78f4b32e --- /dev/null +++ b/packages/docs/docs.json @@ -0,0 +1,57 @@ +{ + "$schema": "https://mintlify.com/docs.json", + "theme": "mint", + "name": "OpenWork Docs", + "colors": { + "primary": "#0F766E", + "light": "#14B8A6", + "dark": "#0F766E" + }, + "navigation": { + "tabs": [ + { + "tab": "Product", + "groups": [ + { + "group": "Foundations", + "pages": [ + "index", + "openwork", + "opencode-router", + "cli" + ] + }, + { + "group": "Agent Playbooks", + "pages": [ + "quickstart", + "create-openwork-instance" + ] + }, + { + "group": "Tutorials", + "pages": [ + "tutorials/automations-repeatable-jobs", + "tutorials/worker-isolation", + "tutorials/share-worker-invite-link", + "tutorials/share-workspace-url-service" + ] + }, + { + "group": "Contributing", + "pages": [ + "development" + ] + } + ] + } + ] + }, + "navbar": { + "primary": { + "type": "button", + "label": "Download OpenWork", + "href": "https://github.com/different-ai/openwork/releases" + } + } +} diff --git a/packages/docs/index.mdx b/packages/docs/index.mdx new file mode 100644 index 00000000..860cbb22 --- /dev/null +++ b/packages/docs/index.mdx @@ -0,0 +1,34 @@ +--- +title: "Introduction" +description: "OpenWork for agents, operators, and teams" +--- + +OpenWork helps you run agentic workflows with clear control over workers, skills, automations, and messaging surfaces. + +Use this docs set to deploy OpenWork quickly, onboard teammates, and keep work predictable. + + + Agent-friendly playbook for launching an instance with desktop or CLI. + + +## Start paths + + + + Get from install to first worker in minutes. + + + Run OpenWork with `openwrk`, `openwork-server`, and `opencode-router`. + + + Route Slack and Telegram messages to the right workspace directory. + + + Avoid the shared-context chaos by separating workers by domain. + + diff --git a/packages/docs/opencode-router.mdx b/packages/docs/opencode-router.mdx new file mode 100644 index 00000000..44db8b9e --- /dev/null +++ b/packages/docs/opencode-router.mdx @@ -0,0 +1,45 @@ +--- +title: "OpenCode Router" +description: "What opencode-router is and when to use it" +--- + +`opencode-router` is a Slack + Telegram bridge and directory router for a running OpenCode/OpenWork instance. + +## What it does + +- Routes messages using `(channel, identity, peer) -> directory` bindings. +- Lets teams interact with workers from Slack or Telegram. +- Keeps chat surfaces mapped to the correct workspace. + +## Quick start + +```bash +npm install -g opencode-router +opencode-router +``` + +Or from monorepo: + +```bash +pnpm -C packages/opencode-router setup +opencode-router start +``` + +## Required config + +- `OPENCODE_URL` +- `OPENCODE_DIRECTORY` + +## Common commands + +```bash +opencode-router status +opencode-router telegram list +opencode-router slack list +opencode-router bindings list +opencode-router bindings set --channel telegram --identity default --peer --dir /path/to/workdir +``` + +## In OpenWork UI + +Open **Identities** to configure bot identities and directory bindings per worker. diff --git a/packages/docs/openwork.mdx b/packages/docs/openwork.mdx new file mode 100644 index 00000000..78fe11e6 --- /dev/null +++ b/packages/docs/openwork.mdx @@ -0,0 +1,30 @@ +--- +title: "What is OpenWork" +description: "Core concepts and system vocabulary" +--- + +OpenWork is the control surface for running agentic work with predictable sharing. + +## Core terms + +- **OpenWork app**: Desktop/mobile/web client experience layer. +- **OpenWork server**: API/control layer consumed by the app. +- **OpenWork worker**: A specific workspace runtime destination. +- **OpenCode Router**: Messaging bridge for Slack/Telegram with directory routing. + +## Why teams use it + +- Keep agent workflows portable (`.opencode/` + `opencode.json`). +- Isolate work by worker instead of mixing everything in one thread. +- Add approvals, audit visibility, and clear ownership boundaries. +- Run local-first, then move to hosted and messaging surfaces as needed. + +## Runtime modes + +- **Desktop host mode**: OpenWork app starts local OpenCode/OpenWork. +- **CLI host mode**: `openwrk` runs OpenCode + OpenWork server in terminal. +- **Remote client mode**: App connects to an existing OpenWork server URL + token. + +## Mental model + +Use one worker per outcome domain (ops, client A, client B). Then attach skills, commands, and automations to that worker. diff --git a/packages/docs/quickstart.mdx b/packages/docs/quickstart.mdx new file mode 100644 index 00000000..3eef4e9a --- /dev/null +++ b/packages/docs/quickstart.mdx @@ -0,0 +1,74 @@ +--- +title: "Quickstart" +description: "Install OpenWork and run your first worker" +--- + +## Get started in four steps + +### Step 1: Install OpenWork + + + + Download the latest release from: + `https://github.com/different-ai/openwork/releases` + + Start with macOS if you want the fastest path. + + + ```bash + npm install -g openwrk + openwrk start --workspace /path/to/workspace --approval auto + ``` + + This runs OpenCode + OpenWork server + optional router without desktop UI. + + + +### Step 2: Create your first worker + + + Use one worker per business domain. + + Suggested first worker names: + - `agency-core` + - `client-a` + - `client-b` + + This keeps context and automations isolated. + + +### Step 3: Connect and run one task + + + Start with a deterministic workflow: + - competitor research + - daily report + - weekly summary + + Keep prompts and outputs in one worker first, then scale. + + +### Step 4: Share with your team + + + Open worker actions in OpenWork and share: + - `OpenWork worker URL` + - `Access token` + - `OpenWork invite link` (prefills URL + token) + + The invite link is best for fast teammate onboarding. + + +## CLI example + +```bash +npm install -g openwrk +openwrk start --workspace /path/to/workspace --approval auto +openwrk status --openwork-url http://127.0.0.1:8787 --opencode-url http://127.0.0.1:4096 +``` + +## Next steps + +- Use `/tutorials/automations-repeatable-jobs` to add reliable recurring outputs. +- Use `/tutorials/worker-isolation` before onboarding more teammates. +- Use `/tutorials/share-worker-invite-link` to remove copy/paste friction. diff --git a/packages/docs/tutorials/automations-repeatable-jobs.mdx b/packages/docs/tutorials/automations-repeatable-jobs.mdx new file mode 100644 index 00000000..95f483aa --- /dev/null +++ b/packages/docs/tutorials/automations-repeatable-jobs.mdx @@ -0,0 +1,36 @@ +--- +title: "Automations for repeatable jobs" +description: "Schedule daily and weekly workflows in OpenWork" +--- + +Use this when you need predictable recurring outputs. + +## Why this pattern works + +- Each automation maps to one business outcome. +- Outputs stay easy to inspect and debug. +- Team expectations stay predictable. + +## Build the automation set + +1. Open **Automations** (beta). +2. Create one job for each outcome, for example: + - Daily ops summary + - Weekly wins/blockers summary + - Recurring competitor scan +3. Keep each job single-purpose. Do not merge everything into one mega prompt. +4. Name jobs by outcome, not by implementation detail. + +## Example split + +- `daily-ops-summary` +- `weekly-team-brief` +- `competitor-scan-core` + +## Debugging checklist + +- Does each job write to a clear output path? +- Can you explain job success/failure in one sentence? +- Can one job fail without blocking the others? + +If not, split further. diff --git a/packages/docs/tutorials/share-worker-invite-link.mdx b/packages/docs/tutorials/share-worker-invite-link.mdx new file mode 100644 index 00000000..4c52a00e --- /dev/null +++ b/packages/docs/tutorials/share-worker-invite-link.mdx @@ -0,0 +1,36 @@ +--- +title: "Share a worker with one invite link" +description: "Use OpenWork invite links to prefill URL and token" +--- + +OpenWork now supports a copyable invite link in the worker share modal. + +## What it does + +The invite link pre-fills: + +- worker URL +- access token +- startup mode (`server`) + +This removes copy/paste friction for teammates. + +## How to use it + +1. Open worker menu -> **Share**. +2. Copy `OpenWork invite link`. +3. Send the link to a teammate. +4. When they open it, OpenWork pre-fills remote connect fields. + +## Security note + +Invite links include a token. Treat them like credentials and rotate tokens if a link is exposed. + +## Fallback + +If links are blocked in your workflow, share: + +- `OpenWork worker URL` +- `Access token` + +manually from the same modal. diff --git a/packages/docs/tutorials/share-workspace-url-service.mdx b/packages/docs/tutorials/share-workspace-url-service.mdx new file mode 100644 index 00000000..88771081 --- /dev/null +++ b/packages/docs/tutorials/share-workspace-url-service.mdx @@ -0,0 +1,40 @@ +--- +title: "Share full workspace via URL service" +description: "Current state and target design for full workspace sharing" +--- + +This tutorial maps the desired "share full workspace as URL" flow. + +## Current state + +- You can export workspace config (`.opencode/` + `opencode.json`) as a bundle. +- You can share worker URL + token (or invite link) for runtime access. +- Full config sharing is file-based, not URL-based. + +## Target state + +Share full workspace as a URL that: + +1. Stores an encrypted workspace bundle in share service. +2. Produces a short-lived import URL. +3. Opens OpenWork and imports into a selected local folder. +4. Applies worker URL/token defaults if provided. + +## Proposed flow + +1. User clicks **Share workspace URL**. +2. OpenWork exports workspace config payload. +3. Payload uploads to share service with TTL + access scope. +4. OpenWork returns URL like `/share/workspace/?sig=...`. +5. Recipient opens link and confirms import target. + +## Operational requirements + +- Token redaction in UI logs. +- Expiring URLs and revocation. +- Audit event for share create/open/import. +- Size limits and checksum validation. + +## Recommendation + +Ship this as a dedicated share-service feature after invite-link adoption is stable. diff --git a/packages/docs/tutorials/worker-isolation.mdx b/packages/docs/tutorials/worker-isolation.mdx new file mode 100644 index 00000000..77ab4960 --- /dev/null +++ b/packages/docs/tutorials/worker-isolation.mdx @@ -0,0 +1,33 @@ +--- +title: "Worker isolation by domain" +description: "Avoid free-for-all behavior with worker boundaries" +--- + +When teams share one hot context, behavior becomes unpredictable. Use worker isolation instead. + +## Rule + +Enforce isolation by worker, not by thread. + +## Setup + +Create separate workers per domain: + +- `agency-core` +- `client-a` +- `client-b` + +Assign skills, commands, and automations to the correct worker. + +## Team operating model + +1. Work starts by selecting the target worker. +2. Only that worker's skills and automations are used. +3. Cross-domain tasks are copied intentionally, not merged by default. + +## Benefits + +- Better prompt determinism +- Clearer audit history +- Safer data boundaries +- Easier onboarding for non-technical teammates diff --git a/packages/landing/next.config.js b/packages/landing/next.config.js index 6d32668b..55138894 100644 --- a/packages/landing/next.config.js +++ b/packages/landing/next.config.js @@ -1,6 +1,56 @@ /** @type {import('next').NextConfig} */ +const mintlifyOrigin = "https://differentai.mintlify.app"; + const nextConfig = { - reactStrictMode: true + reactStrictMode: true, + async rewrites() { + return [ + { + source: "/_mintlify/:path*", + destination: `${mintlifyOrigin}/_mintlify/:path*`, + }, + { + source: "/api/request", + destination: `${mintlifyOrigin}/_mintlify/api/request`, + }, + { + source: "/docs", + destination: `${mintlifyOrigin}/`, + }, + { + source: "/docs/get-started", + destination: `${mintlifyOrigin}/quickstart`, + }, + { + source: "/docs/llms.txt", + destination: `${mintlifyOrigin}/llms.txt`, + }, + { + source: "/docs/llms-full.txt", + destination: `${mintlifyOrigin}/llms-full.txt`, + }, + { + source: "/docs/sitemap.xml", + destination: `${mintlifyOrigin}/sitemap.xml`, + }, + { + source: "/docs/robots.txt", + destination: `${mintlifyOrigin}/robots.txt`, + }, + { + source: "/docs/mcp", + destination: `${mintlifyOrigin}/mcp`, + }, + { + source: "/docs/:path*", + destination: `${mintlifyOrigin}/:path*`, + }, + { + source: "/mintlify-assets/:path+", + destination: `${mintlifyOrigin}/mintlify-assets/:path+`, + }, + ]; + }, }; module.exports = nextConfig;