From 7bc4c63d73387eca532d5c5131ab397732530f19 Mon Sep 17 00:00:00 2001 From: oktofeesh1 <287075021+oktofeesh1@users.noreply.github.com> Date: Thu, 16 Jul 2026 08:48:35 +0200 Subject: [PATCH] docs(ams): port docs/fleet-run-manifest.md to a website docs page (docs.ams-fleet-manifest.tsx) Add content/docs/ams-fleet-manifest.mdx covering the top-level fleet-operator config for running the miner across many repos -- the repos list, per-repo and total worktree/concurrency budgets, and how it contrasts with the per-repo .loopover-miner.yml goal spec -- rendered via the existing DocsPage/Callout/CodeBlock/FeatureRow primitives. Add the page to docs-nav.tsx's "AMS: deployment" subgroup and to docs.index.tsx's Maintainers audience card. packages/loopover-miner/docs/fleet-run-manifest.md stays as the canonical source (ships inside the published @loopover/miner package) with a short pointer added to the new website page. --- .../content/docs/ams-fleet-manifest.mdx | 64 +++++++++++++++++++ .../src/components/site/docs-nav.tsx | 1 + apps/loopover-ui/src/routeTree.gen.ts | 21 ++++++ .../src/routes/docs.ams-fleet-manifest.tsx | 49 ++++++++++++++ apps/loopover-ui/src/routes/docs.index.tsx | 1 + .../loopover-miner/docs/fleet-run-manifest.md | 4 ++ 6 files changed, 140 insertions(+) create mode 100644 apps/loopover-ui/content/docs/ams-fleet-manifest.mdx create mode 100644 apps/loopover-ui/src/routes/docs.ams-fleet-manifest.tsx diff --git a/apps/loopover-ui/content/docs/ams-fleet-manifest.mdx b/apps/loopover-ui/content/docs/ams-fleet-manifest.mdx new file mode 100644 index 0000000000..26993590ac --- /dev/null +++ b/apps/loopover-ui/content/docs/ams-fleet-manifest.mdx @@ -0,0 +1,64 @@ +--- +title: Fleet run-manifest +description: The top-level config a fleet operator authors to run the miner across many repos at once -- which repos are in scope and how the worktree/concurrency budget is split. +--- + +The **fleet run-manifest** is the top-level config a *fleet operator* authors to run the miner +across many repos at once: it declares which repos are in scope for a fleet run and how a finite +worktree/concurrency budget is split between them. It is parsed by +`parseFleetRunManifestContent` / `parseFleetRunManifest` in `@loopover/engine` +(`packages/loopover-engine/src/fleet-run-manifest.ts`). + +It is **not** the same file as `.loopover-miner.yml` (see the [MinerGoalSpec field +reference](/docs/ams-goal-spec)) — the naming is easy to conflate. Same tolerant-parser +convention (every field optional, unknown keys ignored, a malformed field degrades to a +documented default with a warning rather than throwing), but the opposite author and the +opposite direction of intent: + + + +## Schema + + + Every field is optional; unknown keys are ignored; a malformed field falls back to a documented + default with a warning rather than hard-failing the run. + + +- **`repos`** — a list of target repos. Each entry is either a bare `"owner/repo"` string (uses + the default per-repo budget) or a `{ repoFullName, maxConcurrentWorktrees }` mapping. Invalid or + duplicate entries are skipped with a warning. `repoFullName` is a canonical `owner/repo`, + compatible with `opportunity-fanout.js`'s target list. Default: `[]`. +- **`repos[].maxConcurrentWorktrees`** — max concurrent worktrees (in-flight attempts) for that + repo. A positive integer (floored; sub-1 falls back to the default). Default: `1`. +- **`totalConcurrentWorktrees`** — total concurrent worktrees across the whole fleet, regardless + of per-repo budgets. A positive integer. Default: `1`. + +## Wiring + +This module produces only the parsed, typed manifest. Driving the fleet concurrency allocator +from it is the allocator's own concern, and the cross-repo `portfolio-queue.js` backlog reads the +same repo list — both *consume* this manifest; neither wiring lives here. + +## Example (`fleet-run.yml`) + + diff --git a/apps/loopover-ui/src/components/site/docs-nav.tsx b/apps/loopover-ui/src/components/site/docs-nav.tsx index 5138d1994a..ef54ae1f2f 100644 --- a/apps/loopover-ui/src/components/site/docs-nav.tsx +++ b/apps/loopover-ui/src/components/site/docs-nav.tsx @@ -84,6 +84,7 @@ export const docsNav: DocsGroup[] = [ { to: "/docs/ams-env-reference", label: "Env var reference" }, { to: "/docs/ams-discovery-plane", label: "Discovery plane (opt-in)" }, { to: "/docs/ams-goal-spec", label: "Miner goal spec" }, + { to: "/docs/ams-fleet-manifest", label: "Fleet run-manifest" }, ], }, ], diff --git a/apps/loopover-ui/src/routeTree.gen.ts b/apps/loopover-ui/src/routeTree.gen.ts index 8c54eaf2e4..fabcff69f6 100644 --- a/apps/loopover-ui/src/routeTree.gen.ts +++ b/apps/loopover-ui/src/routeTree.gen.ts @@ -62,6 +62,7 @@ import { Route as DocsAmsSizingRouteImport } from './routes/docs.ams-sizing' import { Route as DocsAmsOperationsRunbookRouteImport } from './routes/docs.ams-operations-runbook' import { Route as DocsAmsObservabilityRouteImport } from './routes/docs.ams-observability' import { Route as DocsAmsGoalSpecRouteImport } from './routes/docs.ams-goal-spec' +import { Route as DocsAmsFleetManifestRouteImport } from './routes/docs.ams-fleet-manifest' import { Route as DocsAmsEnvReferenceRouteImport } from './routes/docs.ams-env-reference' import { Route as DocsAmsDiscoveryPlaneRouteImport } from './routes/docs.ams-discovery-plane' import { Route as DocsAmsDeploymentRouteImport } from './routes/docs.ams-deployment' @@ -364,6 +365,11 @@ const DocsAmsGoalSpecRoute = DocsAmsGoalSpecRouteImport.update({ path: '/ams-goal-spec', getParentRoute: () => DocsRoute, } as any) +const DocsAmsFleetManifestRoute = DocsAmsFleetManifestRouteImport.update({ + id: '/ams-fleet-manifest', + path: '/ams-fleet-manifest', + getParentRoute: () => DocsRoute, +} as any) const DocsAmsEnvReferenceRoute = DocsAmsEnvReferenceRouteImport.update({ id: '/ams-env-reference', path: '/ams-env-reference', @@ -495,6 +501,7 @@ export interface FileRoutesByFullPath { '/docs/ams-deployment': typeof DocsAmsDeploymentRoute '/docs/ams-discovery-plane': typeof DocsAmsDiscoveryPlaneRoute '/docs/ams-env-reference': typeof DocsAmsEnvReferenceRoute + '/docs/ams-fleet-manifest': typeof DocsAmsFleetManifestRoute '/docs/ams-goal-spec': typeof DocsAmsGoalSpecRoute '/docs/ams-observability': typeof DocsAmsObservabilityRoute '/docs/ams-operations-runbook': typeof DocsAmsOperationsRunbookRoute @@ -567,6 +574,7 @@ export interface FileRoutesByTo { '/docs/ams-deployment': typeof DocsAmsDeploymentRoute '/docs/ams-discovery-plane': typeof DocsAmsDiscoveryPlaneRoute '/docs/ams-env-reference': typeof DocsAmsEnvReferenceRoute + '/docs/ams-fleet-manifest': typeof DocsAmsFleetManifestRoute '/docs/ams-goal-spec': typeof DocsAmsGoalSpecRoute '/docs/ams-observability': typeof DocsAmsObservabilityRoute '/docs/ams-operations-runbook': typeof DocsAmsOperationsRunbookRoute @@ -643,6 +651,7 @@ export interface FileRoutesById { '/docs/ams-deployment': typeof DocsAmsDeploymentRoute '/docs/ams-discovery-plane': typeof DocsAmsDiscoveryPlaneRoute '/docs/ams-env-reference': typeof DocsAmsEnvReferenceRoute + '/docs/ams-fleet-manifest': typeof DocsAmsFleetManifestRoute '/docs/ams-goal-spec': typeof DocsAmsGoalSpecRoute '/docs/ams-observability': typeof DocsAmsObservabilityRoute '/docs/ams-operations-runbook': typeof DocsAmsOperationsRunbookRoute @@ -720,6 +729,7 @@ export interface FileRouteTypes { | '/docs/ams-deployment' | '/docs/ams-discovery-plane' | '/docs/ams-env-reference' + | '/docs/ams-fleet-manifest' | '/docs/ams-goal-spec' | '/docs/ams-observability' | '/docs/ams-operations-runbook' @@ -792,6 +802,7 @@ export interface FileRouteTypes { | '/docs/ams-deployment' | '/docs/ams-discovery-plane' | '/docs/ams-env-reference' + | '/docs/ams-fleet-manifest' | '/docs/ams-goal-spec' | '/docs/ams-observability' | '/docs/ams-operations-runbook' @@ -867,6 +878,7 @@ export interface FileRouteTypes { | '/docs/ams-deployment' | '/docs/ams-discovery-plane' | '/docs/ams-env-reference' + | '/docs/ams-fleet-manifest' | '/docs/ams-goal-spec' | '/docs/ams-observability' | '/docs/ams-operations-runbook' @@ -1300,6 +1312,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof DocsAmsGoalSpecRouteImport parentRoute: typeof DocsRoute } + '/docs/ams-fleet-manifest': { + id: '/docs/ams-fleet-manifest' + path: '/ams-fleet-manifest' + fullPath: '/docs/ams-fleet-manifest' + preLoaderRoute: typeof DocsAmsFleetManifestRouteImport + parentRoute: typeof DocsRoute + } '/docs/ams-env-reference': { id: '/docs/ams-env-reference' path: '/ams-env-reference' @@ -1497,6 +1516,7 @@ interface DocsRouteChildren { DocsAmsDeploymentRoute: typeof DocsAmsDeploymentRoute DocsAmsDiscoveryPlaneRoute: typeof DocsAmsDiscoveryPlaneRoute DocsAmsEnvReferenceRoute: typeof DocsAmsEnvReferenceRoute + DocsAmsFleetManifestRoute: typeof DocsAmsFleetManifestRoute DocsAmsGoalSpecRoute: typeof DocsAmsGoalSpecRoute DocsAmsObservabilityRoute: typeof DocsAmsObservabilityRoute DocsAmsOperationsRunbookRoute: typeof DocsAmsOperationsRunbookRoute @@ -1546,6 +1566,7 @@ const DocsRouteChildren: DocsRouteChildren = { DocsAmsDeploymentRoute: DocsAmsDeploymentRoute, DocsAmsDiscoveryPlaneRoute: DocsAmsDiscoveryPlaneRoute, DocsAmsEnvReferenceRoute: DocsAmsEnvReferenceRoute, + DocsAmsFleetManifestRoute: DocsAmsFleetManifestRoute, DocsAmsGoalSpecRoute: DocsAmsGoalSpecRoute, DocsAmsObservabilityRoute: DocsAmsObservabilityRoute, DocsAmsOperationsRunbookRoute: DocsAmsOperationsRunbookRoute, diff --git a/apps/loopover-ui/src/routes/docs.ams-fleet-manifest.tsx b/apps/loopover-ui/src/routes/docs.ams-fleet-manifest.tsx new file mode 100644 index 0000000000..6663f5bb12 --- /dev/null +++ b/apps/loopover-ui/src/routes/docs.ams-fleet-manifest.tsx @@ -0,0 +1,49 @@ +import { createFileRoute, notFound } from "@tanstack/react-router"; +import { Suspense } from "react"; + +import { DocsPage } from "@/components/site/docs-page"; +import { docsClientLoader } from "@/lib/docs-client-loader"; + +// Rendered from content/docs/ams-fleet-manifest.mdx via fumadocs-mdx's browser entry +// (docsClientLoader), through the existing DocsPage/Callout/CodeBlock/FeatureRow +// primitives -- not fumadocs-ui's bundled components. See docs-source.ts's comment +// for why the loader below resolves only a plain, serializable path string. +export const Route = createFileRoute("/docs/ams-fleet-manifest")({ + loader: async () => { + const { docsSource } = await import("@/lib/docs-source"); + const page = docsSource.getPage(["ams-fleet-manifest"]); + if (!page) throw notFound(); + return { path: page.path, title: page.data.title, description: page.data.description }; + }, + head: () => ({ + meta: [ + { title: "Fleet run-manifest — LoopOver docs" }, + { + name: "description", + content: + "The top-level config a fleet operator authors to run the miner across many repos at once -- which repos are in scope and how the worktree/concurrency budget is split.", + }, + { property: "og:title", content: "Fleet run-manifest — LoopOver docs" }, + { + property: "og:description", + content: + "The top-level config a fleet operator authors to run the miner across many repos at once -- which repos are in scope and how the worktree/concurrency budget is split.", + }, + { property: "og:url", content: "/docs/ams-fleet-manifest" }, + ], + links: [{ rel: "canonical", href: "/docs/ams-fleet-manifest" }], + }), + component: AmsFleetManifest, +}); + +function AmsFleetManifest() { + const { path, title, description } = Route.useLoaderData(); + const Content = docsClientLoader.getComponent(path); + return ( + + Loading…

}> + +
+
+ ); +} diff --git a/apps/loopover-ui/src/routes/docs.index.tsx b/apps/loopover-ui/src/routes/docs.index.tsx index f99497e665..432818363c 100644 --- a/apps/loopover-ui/src/routes/docs.index.tsx +++ b/apps/loopover-ui/src/routes/docs.index.tsx @@ -82,6 +82,7 @@ const AUDIENCES: Audience[] = [ { to: "/docs/ams-env-reference", label: "Env var reference" }, { to: "/docs/ams-discovery-plane", label: "Discovery plane (opt-in)" }, { to: "/docs/ams-goal-spec", label: "Miner goal spec" }, + { to: "/docs/ams-fleet-manifest", label: "Fleet run-manifest" }, { to: "/docs/self-hosting-docs-audit", label: "Self-host docs audit" }, { to: "/docs/maintainer-install-trust", label: "Install & trust guide" }, { to: "/docs/github-app", label: "GitHub App configuration" }, diff --git a/packages/loopover-miner/docs/fleet-run-manifest.md b/packages/loopover-miner/docs/fleet-run-manifest.md index ae0ec15715..6aa420fa83 100644 --- a/packages/loopover-miner/docs/fleet-run-manifest.md +++ b/packages/loopover-miner/docs/fleet-run-manifest.md @@ -1,5 +1,9 @@ # Fleet run-manifest +> Also published on the docs website: [Fleet run-manifest](https://loopover.ai/docs/ams-fleet-manifest) +> (same content, rendered with search and the rest of the maintainer docs nav). This file remains +> the canonical source and ships inside the published `@loopover/miner` package. + The **fleet run-manifest** is the top-level config a *fleet operator* authors to run the miner across many repos at once: it declares which repos are in scope for a fleet run and how a finite worktree/concurrency budget is split between them. It is parsed by `parseFleetRunManifestContent` / `parseFleetRunManifest` in