From 52fb578717a01a97059fb9d1eb58001c8fcab328 Mon Sep 17 00:00:00 2001 From: jakearmstrong59 Date: Sun, 12 Jul 2026 18:56:50 +0000 Subject: [PATCH 1/2] docs(miner): add coding-agent driver page --- .../src/components/site/command-palette.tsx | 1 + .../src/components/site/docs-nav.tsx | 5 +- apps/gittensory-ui/src/routeTree.gen.ts | 19 ++ apps/gittensory-ui/src/routes/docs.index.tsx | 1 + .../routes/docs.miner-coding-agent.test.tsx | 92 ++++++++ .../src/routes/docs.miner-coding-agent.tsx | 206 ++++++++++++++++++ .../src/routes/docs.miner-quickstart.tsx | 6 + .../src/routes/docs.miner-workflow.tsx | 5 + test/unit/docs-miner-quickstart.test.ts | 9 +- test/unit/docs-miner-workflow.test.ts | 17 ++ 10 files changed, 359 insertions(+), 2 deletions(-) create mode 100644 apps/gittensory-ui/src/routes/docs.miner-coding-agent.test.tsx create mode 100644 apps/gittensory-ui/src/routes/docs.miner-coding-agent.tsx create mode 100644 test/unit/docs-miner-workflow.test.ts diff --git a/apps/gittensory-ui/src/components/site/command-palette.tsx b/apps/gittensory-ui/src/components/site/command-palette.tsx index 9242c5e7ab..1dc7dcaabc 100644 --- a/apps/gittensory-ui/src/components/site/command-palette.tsx +++ b/apps/gittensory-ui/src/components/site/command-palette.tsx @@ -32,6 +32,7 @@ const DEFAULT_ITEMS: PaletteItem[] = [ { label: "Beta onboarding", to: "/docs/beta-onboarding", group: "Docs" }, { label: "Quickstart", to: "/docs/quickstart", group: "Docs" }, { label: "MCP clients", to: "/docs/mcp-clients", group: "Docs" }, + { label: "Coding-agent driver", to: "/docs/miner-coding-agent", group: "Docs" }, { label: "Miner workflow", to: "/docs/miner-workflow", group: "Docs" }, { label: "Maintainer workflow", to: "/docs/maintainer-workflow", group: "Docs" }, { label: "Self-host reviews", to: "/docs/maintainer-self-hosting", group: "Docs" }, diff --git a/apps/gittensory-ui/src/components/site/docs-nav.tsx b/apps/gittensory-ui/src/components/site/docs-nav.tsx index 62a9ff1e03..1f9d0ce7f2 100644 --- a/apps/gittensory-ui/src/components/site/docs-nav.tsx +++ b/apps/gittensory-ui/src/components/site/docs-nav.tsx @@ -22,7 +22,10 @@ export const docsNav: DocsGroup[] = [ }, { title: "Workflows", - items: [{ to: "/docs/miner-workflow", label: "Miner workflow" }], + items: [ + { to: "/docs/miner-coding-agent", label: "Coding-agent driver" }, + { to: "/docs/miner-workflow", label: "Miner workflow" }, + ], }, { title: "Maintainers", diff --git a/apps/gittensory-ui/src/routeTree.gen.ts b/apps/gittensory-ui/src/routeTree.gen.ts index 089a069454..1cfcf9f5a7 100644 --- a/apps/gittensory-ui/src/routeTree.gen.ts +++ b/apps/gittensory-ui/src/routeTree.gen.ts @@ -43,6 +43,7 @@ import { Route as DocsScoreabilityRouteImport } from './routes/docs.scoreability import { Route as DocsQuickstartRouteImport } from './routes/docs.quickstart' import { Route as DocsPrivacySecurityRouteImport } from './routes/docs.privacy-security' import { Route as DocsOwnerChecklistRouteImport } from './routes/docs.owner-checklist' +import { Route as DocsMinerCodingAgentRouteImport } from './routes/docs.miner-coding-agent' import { Route as DocsMinerWorkflowRouteImport } from './routes/docs.miner-workflow' import { Route as DocsMinerQuickstartRouteImport } from './routes/docs.miner-quickstart' import { Route as DocsMcpClientsRouteImport } from './routes/docs.mcp-clients' @@ -251,6 +252,11 @@ const DocsOwnerChecklistRoute = DocsOwnerChecklistRouteImport.update({ path: '/owner-checklist', getParentRoute: () => DocsRoute, } as any) +const DocsMinerCodingAgentRoute = DocsMinerCodingAgentRouteImport.update({ + id: '/miner-coding-agent', + path: '/miner-coding-agent', + getParentRoute: () => DocsRoute, +} as any) const DocsMinerWorkflowRoute = DocsMinerWorkflowRouteImport.update({ id: '/miner-workflow', path: '/miner-workflow', @@ -424,6 +430,7 @@ export interface FileRoutesByFullPath { '/docs/maintainer-self-hosting': typeof DocsMaintainerSelfHostingRoute '/docs/maintainer-workflow': typeof DocsMaintainerWorkflowRoute '/docs/mcp-clients': typeof DocsMcpClientsRoute + '/docs/miner-coding-agent': typeof DocsMinerCodingAgentRoute '/docs/miner-quickstart': typeof DocsMinerQuickstartRoute '/docs/miner-workflow': typeof DocsMinerWorkflowRoute '/docs/owner-checklist': typeof DocsOwnerChecklistRoute @@ -484,6 +491,7 @@ export interface FileRoutesByTo { '/docs/maintainer-self-hosting': typeof DocsMaintainerSelfHostingRoute '/docs/maintainer-workflow': typeof DocsMaintainerWorkflowRoute '/docs/mcp-clients': typeof DocsMcpClientsRoute + '/docs/miner-coding-agent': typeof DocsMinerCodingAgentRoute '/docs/miner-quickstart': typeof DocsMinerQuickstartRoute '/docs/miner-workflow': typeof DocsMinerWorkflowRoute '/docs/owner-checklist': typeof DocsOwnerChecklistRoute @@ -613,6 +621,7 @@ export interface FileRouteTypes { | '/docs/maintainer-self-hosting' | '/docs/maintainer-workflow' | '/docs/mcp-clients' + | '/docs/miner-coding-agent' | '/docs/miner-quickstart' | '/docs/miner-workflow' | '/docs/owner-checklist' @@ -673,6 +682,7 @@ export interface FileRouteTypes { | '/docs/maintainer-self-hosting' | '/docs/maintainer-workflow' | '/docs/mcp-clients' + | '/docs/miner-coding-agent' | '/docs/miner-quickstart' | '/docs/miner-workflow' | '/docs/owner-checklist' @@ -1026,6 +1036,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof DocsMinerWorkflowRouteImport parentRoute: typeof DocsRoute } + '/docs/miner-coding-agent': { + id: '/docs/miner-coding-agent' + path: '/miner-coding-agent' + fullPath: '/docs/miner-coding-agent' + preLoaderRoute: typeof DocsMinerCodingAgentRouteImport + parentRoute: typeof DocsRoute + } '/docs/miner-quickstart': { id: '/docs/miner-quickstart' path: '/miner-quickstart' @@ -1270,6 +1287,7 @@ interface DocsRouteChildren { DocsMaintainerSelfHostingRoute: typeof DocsMaintainerSelfHostingRoute DocsMaintainerWorkflowRoute: typeof DocsMaintainerWorkflowRoute DocsMcpClientsRoute: typeof DocsMcpClientsRoute + DocsMinerCodingAgentRoute: typeof DocsMinerCodingAgentRoute DocsMinerQuickstartRoute: typeof DocsMinerQuickstartRoute DocsMinerWorkflowRoute: typeof DocsMinerWorkflowRoute DocsOwnerChecklistRoute: typeof DocsOwnerChecklistRoute @@ -1307,6 +1325,7 @@ const DocsRouteChildren: DocsRouteChildren = { DocsMaintainerSelfHostingRoute: DocsMaintainerSelfHostingRoute, DocsMaintainerWorkflowRoute: DocsMaintainerWorkflowRoute, DocsMcpClientsRoute: DocsMcpClientsRoute, + DocsMinerCodingAgentRoute: DocsMinerCodingAgentRoute, DocsMinerQuickstartRoute: DocsMinerQuickstartRoute, DocsMinerWorkflowRoute: DocsMinerWorkflowRoute, DocsOwnerChecklistRoute: DocsOwnerChecklistRoute, diff --git a/apps/gittensory-ui/src/routes/docs.index.tsx b/apps/gittensory-ui/src/routes/docs.index.tsx index b00e20cf17..03f4cdbd79 100644 --- a/apps/gittensory-ui/src/routes/docs.index.tsx +++ b/apps/gittensory-ui/src/routes/docs.index.tsx @@ -59,6 +59,7 @@ const AUDIENCES: Audience[] = [ links: [ { to: "/docs/quickstart", label: "Quickstart" }, { to: "/docs/miner-quickstart", label: "Quickstart by lane" }, + { to: "/docs/miner-coding-agent", label: "Coding-agent driver" }, { to: "/docs/miner-workflow", label: "Miner workflow" }, { to: "/docs/branch-analysis", label: "Branch analysis" }, { to: "/docs/scoreability", label: "Scoreability" }, diff --git a/apps/gittensory-ui/src/routes/docs.miner-coding-agent.test.tsx b/apps/gittensory-ui/src/routes/docs.miner-coding-agent.test.tsx new file mode 100644 index 0000000000..6904bbb447 --- /dev/null +++ b/apps/gittensory-ui/src/routes/docs.miner-coding-agent.test.tsx @@ -0,0 +1,92 @@ +import { render, screen } from "@testing-library/react"; +import { type ReactNode } from "react"; +import { describe, expect, it, vi } from "vitest"; + +import { CODING_AGENT_DRIVER_NAMES } from "../../../../packages/gittensory-engine/src/miner/driver-factory"; +import { + MINER_CODING_AGENT_ENV_ROWS, + MINER_CODING_AGENT_PROVIDER_ITEMS, + MinerCodingAgentDriverDocs, +} from "./docs.miner-coding-agent"; + +vi.mock("@tanstack/react-router", async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + Link: ({ to, children }: { to: string; children: ReactNode }) => {children}, + }; +}); + +vi.mock("@/components/site/docs-page", () => ({ + DocsPage: ({ + children, + title, + eyebrow, + description, + }: { + children: ReactNode; + title: string; + eyebrow?: string; + description?: string; + }) => ( +
+ {eyebrow ?
{eyebrow}
: null} +

{title}

+ {description ?

{description}

: null} + {children} +
+ ), +})); + +vi.mock("@/components/site/primitives", () => ({ + Callout: ({ children, title }: { children: ReactNode; title?: string }) => ( +
+ {title ? {title} : null} +
{children}
+
+ ), + CodeBlock: ({ code }: { code: string }) =>
{code}
, + FeatureRow: ({ items }: { items: Array<{ title: string; description: string }> }) => ( +
+ {items.map((item) => ( +
+
{item.title}
+
{item.description}
+
+ ))} +
+ ), +})); + +describe("miner coding-agent docs page", () => { + it("mounts the docs route and renders the expected sections", async () => { + render(); + + expect(await screen.findByRole("heading", { name: "Miner coding-agent driver" })).toBeTruthy(); + expect(screen.getByRole("heading", { name: "Provider selection" })).toBeTruthy(); + expect(screen.getByRole("heading", { name: "Model and timeout overrides" })).toBeTruthy(); + expect( + screen.getByRole("heading", { name: "Recognizing a stale or missing credential" }), + ).toBeTruthy(); + expect(screen.getByRole("heading", { name: "Related docs" })).toBeTruthy(); + }); + + it("keeps the provider list aligned with the engine's accepted provider names", () => { + expect(MINER_CODING_AGENT_PROVIDER_ITEMS.map((item) => item.title)).toEqual([ + ...CODING_AGENT_DRIVER_NAMES, + ]); + }); + + it("documents every driver env var the page claims to cover", () => { + expect(MINER_CODING_AGENT_ENV_ROWS.map((row) => row.name)).toEqual([ + "MINER_CODING_AGENT_PROVIDER", + "MINER_CODING_AGENT_CLAUDE_MODEL", + "MINER_CODING_AGENT_CODEX_MODEL", + "MINER_CODING_AGENT_TIMEOUT_MS", + ]); + }); + + it("exports the route component used by the route definition", () => { + expect(typeof MinerCodingAgentDriverDocs).toBe("function"); + }); +}); diff --git a/apps/gittensory-ui/src/routes/docs.miner-coding-agent.tsx b/apps/gittensory-ui/src/routes/docs.miner-coding-agent.tsx new file mode 100644 index 0000000000..67458e507d --- /dev/null +++ b/apps/gittensory-ui/src/routes/docs.miner-coding-agent.tsx @@ -0,0 +1,206 @@ +import { createFileRoute, Link } from "@tanstack/react-router"; + +import { DocsPage } from "@/components/site/docs-page"; +import { Callout, CodeBlock, FeatureRow } from "@/components/site/primitives"; + +export const MINER_CODING_AGENT_PROVIDER_ITEMS: Array<{ title: string; description: string }> = [ + { + title: "noop", + description: + "Fail-closed stub. Useful when you want the miner to stay off or you are running tests.", + }, + { + title: "claude-cli", + description: + "Spawns the local `claude` CLI subprocess. Uses `MINER_CODING_AGENT_CLAUDE_MODEL` when set.", + }, + { + title: "codex-cli", + description: + "Spawns the local `codex` CLI subprocess. Uses `MINER_CODING_AGENT_CODEX_MODEL` when set.", + }, + { + title: "agent-sdk", + description: + "Runs the in-process Agent SDK path. It ignores the model and timeout overrides on this seam.", + }, +]; + +export const MINER_CODING_AGENT_ENV_ROWS: Array<{ + name: string; + appliesTo: string; + defaultValue: string; + notes: string; +}> = [ + { + name: "MINER_CODING_AGENT_PROVIDER", + appliesTo: "All production provider selection", + defaultValue: "unset / empty", + notes: + "Comma-separated preference list. The first configured name wins; unknown names are skipped.", + }, + { + name: "MINER_CODING_AGENT_CLAUDE_MODEL", + appliesTo: "claude-cli", + defaultValue: "CLI default", + notes: + "Optional override for the Claude Code subprocess. Ignored by noop, codex-cli, and agent-sdk.", + }, + { + name: "MINER_CODING_AGENT_CODEX_MODEL", + appliesTo: "codex-cli", + defaultValue: "CLI default", + notes: + "Optional override for the Codex subprocess. Ignored by noop, claude-cli, and agent-sdk.", + }, + { + name: "MINER_CODING_AGENT_TIMEOUT_MS", + appliesTo: "claude-cli / codex-cli", + defaultValue: "120000 ms", + notes: + "Positive integer wall-clock ceiling. Unset or invalid falls back to the CLI driver's default timeout.", + }, +]; + +export const MINER_CODING_AGENT_TRUST_ROWS: Array<{ title: string; description: string }> = [ + { + title: "claude_code_no_oauth_token", + description: + "Claude Code cannot find a runtime token. Re-run `claude setup-token` and keep the credential operator-owned.", + }, + { + title: "claude_code_error_401", + description: + "Claude rejected the token. Generate a fresh one with `claude setup-token` and replace the old secret.", + }, + { + title: "codex_no_auth", + description: + "Codex cannot find `auth.json`. Re-run `codex auth` on the mounted CLI home or volume.", + }, + { + title: "codex_credential_isolation_required", + description: + "The Codex home or auth path is not isolated from operator-owned storage. Remove the unsafe override.", + }, +]; + +export const Route = createFileRoute("/docs/miner-coding-agent")({ + head: () => ({ + meta: [ + { title: "Miner coding-agent driver — LoopOver docs" }, + { + name: "description", + content: + "Enable Claude Code or Codex as the miner's coding-agent driver, and document the provider, model, timeout, and credential troubleshooting paths.", + }, + { property: "og:title", content: "Miner coding-agent driver — LoopOver docs" }, + { + property: "og:description", + content: + "Enable Claude Code or Codex as the miner's coding-agent driver, and document the provider, model, timeout, and credential troubleshooting paths.", + }, + { property: "og:url", content: "/docs/miner-coding-agent" }, + ], + links: [{ rel: "canonical", href: "/docs/miner-coding-agent" }], + }), + component: MinerCodingAgentDriverDocs, +}); + +export function MinerCodingAgentDriverDocs() { + return ( + +

+ The miner resolves MINER_CODING_AGENT_PROVIDER as a comma-separated preference + list. The first configured name wins, unknown names are skipped, and an empty or unset list + leaves production construction fail-closed instead of guessing a default backend. +

+ + + This seam is explicit on purpose: if you do not configure a provider, the miner does not + silently pick one for you. + + +

Provider selection

+ + +MINER_CODING_AGENT_TIMEOUT_MS=120000 + +# Prefer Codex, fall back to Claude. +MINER_CODING_AGENT_PROVIDER=codex-cli,claude-cli +MINER_CODING_AGENT_CODEX_MODEL=`} + /> + + `noop` and agent-sdk ignore the model and timeout knobs. Only the CLI + subprocess providers consume them. + + +

Model and timeout overrides

+

+ The only driver-specific knobs today are the provider-specific model overrides and the + shared wall-clock timeout. Anything else is task-level orchestration, not provider config. +

+
+ + + + + + + + + + + {MINER_CODING_AGENT_ENV_ROWS.map((row) => ( + + + + + + + ))} + +
Env varApplies toDefaultNotes
{row.name}{row.appliesTo}{row.defaultValue}{row.notes}
+
+ +

Recognizing a stale or missing credential

+

+ The shared troubleshooting table for Claude Code and Codex lives on{" "} + + Self-host AI providers + + . This page keeps the miner-specific reminder: the credential lives on the operator's + machine or mounted volume, not in repo config. +

+ + + If the CLI cannot see its credential, the miner cannot spawn a healthy provider. Fix the + operator-owned credential path first, then come back to the miner env vars. + + +

Related docs

+
    +
  • + Miner quickstart by lane — install and verify the + miner before you wire a coding agent. +
  • +
  • + Miner workflow — the rest of the contributor loop + after the driver is configured. +
  • +
  • + Self-host AI providers — the broader + credential and provider reference that shares the troubleshooting table above. +
  • +
+
+ ); +} diff --git a/apps/gittensory-ui/src/routes/docs.miner-quickstart.tsx b/apps/gittensory-ui/src/routes/docs.miner-quickstart.tsx index 5e7cb37aed..66940f7205 100644 --- a/apps/gittensory-ui/src/routes/docs.miner-quickstart.tsx +++ b/apps/gittensory-ui/src/routes/docs.miner-quickstart.tsx @@ -2,6 +2,7 @@ import { createFileRoute } from "@tanstack/react-router"; import { DocsPage } from "@/components/site/docs-page"; import { CodeBlock, Callout } from "@/components/site/primitives"; +import { Link } from "@tanstack/react-router"; export const Route = createFileRoute("/docs/miner-quickstart")({ head: () => ({ @@ -40,6 +41,11 @@ function MinerQuickstart() { only branch metadata (changed file paths, commit messages) is sent to authenticated LoopOver MCP/API responses.

+

+ If you are setting up Claude Code or Codex as the miner's coding-agent driver, read{" "} + Miner coding-agent driver first so the env vars + match the provider you actually plan to run. +

0. Install and sign in (every lane)

diff --git a/apps/gittensory-ui/src/routes/docs.miner-workflow.tsx b/apps/gittensory-ui/src/routes/docs.miner-workflow.tsx index 75e35f5dbc..a85c1b2fd7 100644 --- a/apps/gittensory-ui/src/routes/docs.miner-workflow.tsx +++ b/apps/gittensory-ui/src/routes/docs.miner-workflow.tsx @@ -1,4 +1,5 @@ import { createFileRoute } from "@tanstack/react-router"; +import { Link } from "@tanstack/react-router"; import { DocsPage } from "@/components/site/docs-page"; import { CodeBlock, Callout } from "@/components/site/primitives"; @@ -114,6 +115,10 @@ function MinerWorkflow() { title="Miner workflow" description="A deterministic four-step loop. Each step is pure metadata; each output is structured JSON your agent can consume." > +

+ If the workflow will spawn Claude Code or Codex, configure that driver first in{" "} + Miner coding-agent driver. +

The mirrored loop

Each step on the left is what the contributor runs; the matching step on the right is what diff --git a/test/unit/docs-miner-quickstart.test.ts b/test/unit/docs-miner-quickstart.test.ts index 4670d938de..038fcdad37 100644 --- a/test/unit/docs-miner-quickstart.test.ts +++ b/test/unit/docs-miner-quickstart.test.ts @@ -43,6 +43,11 @@ describe("docs miner quickstart page", () => { expect(source).toMatch(/Choose your lane/); }); + it("cross-links to the miner coding-agent driver page for Claude Code / Codex setup", () => { + expect(source).toMatch(/Miner coding-agent driver/); + expect(source).toMatch(/\/docs\/miner-coding-agent/); + }); + it("maps lanes to the repo's configured participation lane from code", () => { // These must match ParticipationLane in src/signals/engine.ts so the doc reflects real config. expect(source).toMatch(/direct_pr/); @@ -62,7 +67,9 @@ describe("docs miner quickstart page", () => { expect(source).toMatch(/GITTENSORY_UPLOAD_SOURCE=false/); expect(source).toMatch(/local absolute paths are redacted/i); expect(source).toMatch(/public-safe/i); - expect(normalizedSource).toMatch(/scrubbed of economic and identity signals/i); + expect(normalizedSource).toMatch( + /scrubbed of economic and identity signals/i, + ); }); it("documents validation expectations with the real --validation flag", () => { diff --git a/test/unit/docs-miner-workflow.test.ts b/test/unit/docs-miner-workflow.test.ts new file mode 100644 index 0000000000..c4c265af96 --- /dev/null +++ b/test/unit/docs-miner-workflow.test.ts @@ -0,0 +1,17 @@ +import { readFileSync } from "node:fs"; +import { resolve } from "node:path"; +import { describe, expect, it } from "vitest"; + +const MINER_WORKFLOW_PATH = resolve( + import.meta.dirname, + "../../apps/gittensory-ui/src/routes/docs.miner-workflow.tsx", +); + +describe("docs miner workflow page", () => { + const source = readFileSync(MINER_WORKFLOW_PATH, "utf8"); + + it("cross-links to the miner coding-agent driver page before the loop steps", () => { + expect(source).toMatch(/Miner coding-agent driver/); + expect(source).toMatch(/\/docs\/miner-coding-agent/); + }); +}); From 7861d4fec3641fb51343c3c3ce76db039280fc5b Mon Sep 17 00:00:00 2001 From: jakearmstrong59 Date: Sun, 12 Jul 2026 19:15:42 +0000 Subject: [PATCH 2/2] docs(miner): remove stale deployment claims --- packages/gittensory-miner/DEPLOYMENT.md | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/packages/gittensory-miner/DEPLOYMENT.md b/packages/gittensory-miner/DEPLOYMENT.md index 744f2e164d..2fc2aa9881 100644 --- a/packages/gittensory-miner/DEPLOYMENT.md +++ b/packages/gittensory-miner/DEPLOYMENT.md @@ -12,16 +12,9 @@ Two form factors for running `@jsonbored/gittensory-miner`: **laptop mode** (sin ## Coding-agent provider configuration -For provider selection and model/timeout knobs, see the README section on -[coding-agent driver configuration](README.md#coding-agent-driver-configuration) and the -interface-level contract in [`docs/coding-agent-driver.md`](docs/coding-agent-driver.md). -The short version is: - -- `MINER_CODING_AGENT_PROVIDER` is a comma-separated preference list; the first configured name wins. -- Valid provider names are `noop`, `claude-cli`, `codex-cli`, and `agent-sdk`. -- `MINER_CODING_AGENT_CLAUDE_MODEL` and `MINER_CODING_AGENT_CODEX_MODEL` only affect their matching CLI providers. -- `MINER_CODING_AGENT_TIMEOUT_MS` only affects the CLI providers and falls back to `120000` ms when unset or invalid. -- `noop` and `agent-sdk` ignore the model and timeout knobs. +For provider selection and the CLI-specific model/timeout overrides, see +[`README.md`](README.md) and the interface-level contract in +[`docs/coding-agent-driver.md`](docs/coding-agent-driver.md). ## Laptop mode walkthrough