diff --git a/apps/gittensory-ui/src/routeTree.gen.ts b/apps/gittensory-ui/src/routeTree.gen.ts index c5e3cff079..4e750aa681 100644 --- a/apps/gittensory-ui/src/routeTree.gen.ts +++ b/apps/gittensory-ui/src/routeTree.gen.ts @@ -28,6 +28,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 DocsMinerWorkflowRouteImport } from './routes/docs.miner-workflow' +import { Route as DocsMinerQuickstartRouteImport } from './routes/docs.miner-quickstart' import { Route as DocsMcpClientsRouteImport } from './routes/docs.mcp-clients' import { Route as DocsMaintainerWorkflowRouteImport } from './routes/docs.maintainer-workflow' import { Route as DocsMaintainerInstallTrustRouteImport } from './routes/docs.maintainer-install-trust' @@ -144,6 +145,11 @@ const DocsMinerWorkflowRoute = DocsMinerWorkflowRouteImport.update({ path: '/miner-workflow', getParentRoute: () => DocsRoute, } as any) +const DocsMinerQuickstartRoute = DocsMinerQuickstartRouteImport.update({ + id: '/miner-quickstart', + path: '/miner-quickstart', + getParentRoute: () => DocsRoute, +} as any) const DocsMcpClientsRoute = DocsMcpClientsRouteImport.update({ id: '/mcp-clients', path: '/mcp-clients', @@ -277,6 +283,7 @@ export interface FileRoutesByFullPath { '/docs/maintainer-install-trust': typeof DocsMaintainerInstallTrustRoute '/docs/maintainer-workflow': typeof DocsMaintainerWorkflowRoute '/docs/mcp-clients': typeof DocsMcpClientsRoute + '/docs/miner-quickstart': typeof DocsMinerQuickstartRoute '/docs/miner-workflow': typeof DocsMinerWorkflowRoute '/docs/privacy-security': typeof DocsPrivacySecurityRoute '/docs/quickstart': typeof DocsQuickstartRoute @@ -315,6 +322,7 @@ export interface FileRoutesByTo { '/docs/maintainer-install-trust': typeof DocsMaintainerInstallTrustRoute '/docs/maintainer-workflow': typeof DocsMaintainerWorkflowRoute '/docs/mcp-clients': typeof DocsMcpClientsRoute + '/docs/miner-quickstart': typeof DocsMinerQuickstartRoute '/docs/miner-workflow': typeof DocsMinerWorkflowRoute '/docs/privacy-security': typeof DocsPrivacySecurityRoute '/docs/quickstart': typeof DocsQuickstartRoute @@ -357,6 +365,7 @@ export interface FileRoutesById { '/docs/maintainer-install-trust': typeof DocsMaintainerInstallTrustRoute '/docs/maintainer-workflow': typeof DocsMaintainerWorkflowRoute '/docs/mcp-clients': typeof DocsMcpClientsRoute + '/docs/miner-quickstart': typeof DocsMinerQuickstartRoute '/docs/miner-workflow': typeof DocsMinerWorkflowRoute '/docs/privacy-security': typeof DocsPrivacySecurityRoute '/docs/quickstart': typeof DocsQuickstartRoute @@ -400,6 +409,7 @@ export interface FileRouteTypes { | '/docs/maintainer-install-trust' | '/docs/maintainer-workflow' | '/docs/mcp-clients' + | '/docs/miner-quickstart' | '/docs/miner-workflow' | '/docs/privacy-security' | '/docs/quickstart' @@ -438,6 +448,7 @@ export interface FileRouteTypes { | '/docs/maintainer-install-trust' | '/docs/maintainer-workflow' | '/docs/mcp-clients' + | '/docs/miner-quickstart' | '/docs/miner-workflow' | '/docs/privacy-security' | '/docs/quickstart' @@ -479,6 +490,7 @@ export interface FileRouteTypes { | '/docs/maintainer-install-trust' | '/docs/maintainer-workflow' | '/docs/mcp-clients' + | '/docs/miner-quickstart' | '/docs/miner-workflow' | '/docs/privacy-security' | '/docs/quickstart' @@ -638,6 +650,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof DocsMinerWorkflowRouteImport parentRoute: typeof DocsRoute } + '/docs/miner-quickstart': { + id: '/docs/miner-quickstart' + path: '/miner-quickstart' + fullPath: '/docs/miner-quickstart' + preLoaderRoute: typeof DocsMinerQuickstartRouteImport + parentRoute: typeof DocsRoute + } '/docs/mcp-clients': { id: '/docs/mcp-clients' path: '/mcp-clients' @@ -835,6 +854,7 @@ interface DocsRouteChildren { DocsMaintainerInstallTrustRoute: typeof DocsMaintainerInstallTrustRoute DocsMaintainerWorkflowRoute: typeof DocsMaintainerWorkflowRoute DocsMcpClientsRoute: typeof DocsMcpClientsRoute + DocsMinerQuickstartRoute: typeof DocsMinerQuickstartRoute DocsMinerWorkflowRoute: typeof DocsMinerWorkflowRoute DocsPrivacySecurityRoute: typeof DocsPrivacySecurityRoute DocsQuickstartRoute: typeof DocsQuickstartRoute @@ -852,6 +872,7 @@ const DocsRouteChildren: DocsRouteChildren = { DocsMaintainerInstallTrustRoute: DocsMaintainerInstallTrustRoute, DocsMaintainerWorkflowRoute: DocsMaintainerWorkflowRoute, DocsMcpClientsRoute: DocsMcpClientsRoute, + DocsMinerQuickstartRoute: DocsMinerQuickstartRoute, DocsMinerWorkflowRoute: DocsMinerWorkflowRoute, DocsPrivacySecurityRoute: DocsPrivacySecurityRoute, DocsQuickstartRoute: DocsQuickstartRoute, diff --git a/apps/gittensory-ui/src/routes/docs.index.tsx b/apps/gittensory-ui/src/routes/docs.index.tsx index 56f031edc5..479843c813 100644 --- a/apps/gittensory-ui/src/routes/docs.index.tsx +++ b/apps/gittensory-ui/src/routes/docs.index.tsx @@ -58,6 +58,7 @@ const AUDIENCES: Audience[] = [ primary: { to: "/docs/beta-onboarding", label: "Beta onboarding" }, links: [ { to: "/docs/quickstart", label: "Quickstart" }, + { to: "/docs/miner-quickstart", label: "Quickstart by lane" }, { 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-quickstart.tsx b/apps/gittensory-ui/src/routes/docs.miner-quickstart.tsx new file mode 100644 index 0000000000..092a86a200 --- /dev/null +++ b/apps/gittensory-ui/src/routes/docs.miner-quickstart.tsx @@ -0,0 +1,191 @@ +import { createFileRoute } from "@tanstack/react-router"; + +import { DocsPage } from "@/components/site/docs-page"; +import { CodeBlock, Callout } from "@/components/site/primitives"; + +export const Route = createFileRoute("/docs/miner-quickstart")({ + head: () => ({ + meta: [ + { title: "Miner quickstart by lane — Gittensory docs" }, + { + name: "description", + content: + "Pick a contribution lane, install @jsonbored/gittensory-mcp, sign in, and run plan → preflight → packet. Lane-by-lane commands with JSON output and redaction notes.", + }, + { property: "og:title", content: "Miner quickstart by lane — Gittensory docs" }, + { + property: "og:description", + content: + "Pick a contribution lane, install @jsonbored/gittensory-mcp, sign in, and run plan → preflight → packet. Lane-by-lane commands with JSON output and redaction notes.", + }, + { property: "og:url", content: "/docs/miner-quickstart" }, + ], + links: [{ rel: "canonical", href: "/docs/miner-quickstart" }], + }), + component: MinerQuickstart, +}); + +function MinerQuickstart() { + return ( + +

+ Gittensory is copilot-only. It ranks and explains your options and drafts public-safe PR + packets. It does not edit code, open PRs, or post comments for you, it makes no earnings + promises, and it never predicts a public number. Every command below also accepts{" "} + --json for machine-readable output, and your source never leaves your machine — + only branch metadata (changed file paths, commit messages) is sent to authenticated + Gittensory MCP/API responses. +

+ +

0. Install and sign in (every lane)

+

+ The MCP is published as @jsonbored/gittensory-mcp. Run it with npx{" "} + or install it globally, then authenticate with GitHub Device Flow — Gittensory never asks + for a Personal Access Token. +

+ + + Session tokens are Gittensory tokens backed by GitHub identity, not your + GitHub PATs. Source upload stays disabled (GITTENSORY_UPLOAD_SOURCE=false) and + local absolute paths are redacted from anything that leaves your machine. Log out anytime + with gittensory-mcp logout. + + +

1. Choose your lane

+

+ Lanes describe how you contribute. Pick the one that matches the work in front of + you, then read what the target repo actually supports: agent plan and{" "} + repo-decision report the repo's configured lane so you can align before + you start. +

+ +

+ The repo's configured lane comes back as one of these (it is set by the repo's + registry config, not by you): +

+
    +
  • + direct_pr — implementation PRs only. Prefer focused PRs with clear evidence, + linked context, and low review churn. +
  • +
  • + issue_discovery — discovery work only. Focus on high-proof issue reports and + avoid self-resolved issue loops. +
  • +
  • + split — both paths are active. Pick one intentionally: issue discovery for + reports, direct PR for implementation. +
  • +
  • + inactive — registered but with no current allocation. Treat it as normal + upstream contribution work unless the registry changes. +
  • +
  • + unknown — not registered (or no config yet). Do not assume the repo is ready + for Gittensor-specific contribution guidance. +
  • +
+ +

2. Direct PR lane

+

+ You are implementing a change and opening a PR directly. Use this in a{" "} + direct_pr or split repo. Plan, preflight your branch metadata, + then generate the public-safe packet to paste into the PR body. +

+ + +

3. Issue-solving PR lane

+

+ You are fixing a specific open issue. Same loop as a direct PR, but link the issue in your + branch so preflight can credit the linked context. Confirm the linked-issue signal in the + preflight output before opening the PR. +

+ + +

4. Issue discovery lane

+

+ You are reporting a high-proof issue rather than opening a PR. Use this in an{" "} + issue_discovery or split repo. Start from the plan to see which + discovery work is worth it, and keep reports specific and reproducible — avoid self-resolved + loops. +

+ + +

5. Docs and context work

+

+ Documentation and context contributions still ship as PRs, so they follow the direct PR + loop. Run preflight on the branch metadata and generate a packet — the packet is the same + public-safe artifact regardless of whether the change is code or docs. +

+ + +

6. Repo-specific lanes

+

+ Some repos run their own lane policy. Always let the repo tell you:{" "} + repo-decision returns the configured lane plus contributor guidance, and{" "} + analyze-branch lets you model a scenario (pending merges, expected open PRs) + before you commit to a path. +

+ + +

Validation expectations (every lane)

+

+ Before you open anything, the loop should be clean: doctor green, your branch + metadata preflighted, and a validation note attached. Pass what you actually ran via{" "} + --validation "status|command|summary" (for example{" "} + "passed|npm test|all green") so the preflight verdict reflects real + validation, not a guess. +

+ + + The PR packet from agent packet is public-safe: it is scrubbed + of economic and identity signals (wallet/hotkey, payout, trust-score, ranking, and + public-prediction language) before it can be pasted into a public GitHub surface. Pair this + page with the miner workflow for the full loop and{" "} + privacy & security for the boundary details. + +
+ ); +} diff --git a/test/unit/docs-miner-quickstart.test.ts b/test/unit/docs-miner-quickstart.test.ts new file mode 100644 index 0000000000..4670d938de --- /dev/null +++ b/test/unit/docs-miner-quickstart.test.ts @@ -0,0 +1,82 @@ +import { readFileSync } from "node:fs"; +import { resolve } from "node:path"; +import { describe, expect, it } from "vitest"; + +const MINER_QUICKSTART_PATH = resolve( + import.meta.dirname, + "../../apps/gittensory-ui/src/routes/docs.miner-quickstart.tsx", +); + +describe("docs miner quickstart page", () => { + const source = readFileSync(MINER_QUICKSTART_PATH, "utf8"); + const normalizedSource = source.replace(/\s+/g, " "); + + it("documents the full miner loop: install, auth, doctor, plan, preflight, packet", () => { + expect(source).toMatch(/@jsonbored\/gittensory-mcp/); + expect(source).toMatch(/gittensory-mcp login/); + expect(source).toMatch(/gittensory-mcp whoami/); + expect(source).toMatch(/gittensory-mcp status/); + expect(source).toMatch(/gittensory-mcp doctor/); + expect(source).toMatch(/agent plan --login/); + expect(source).toMatch(/gittensory-mcp preflight --login/); + expect(source).toMatch(/agent packet --login/); + }); + + it("uses CLI commands that match the current MCP package syntax", () => { + // Real flags from `gittensory-mcp --help` — guards against drift in documented syntax. + expect(source).toMatch(/--repo owner\/repo/); + expect(source).toMatch(/--base origin\/main/); + expect(source).toMatch(/--branch-eligibility eligible/); + expect(source).toMatch(/--pending-merged-prs/); + expect(source).toMatch(/--expected-open-prs/); + expect(source).toMatch(/repo-decision --login/); + expect(source).toMatch(/decision-pack --login/); + expect(source).toMatch(/analyze-branch --login/); + }); + + it("organizes the quickstart by contribution lane", () => { + expect(source).toMatch(/Direct PR lane/); + expect(source).toMatch(/Issue-solving PR lane/); + expect(source).toMatch(/Issue discovery lane/); + expect(source).toMatch(/Docs and context work/); + expect(source).toMatch(/Repo-specific lanes/); + expect(source).toMatch(/Choose your lane/); + }); + + 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/); + expect(source).toMatch(/issue_discovery/); + expect(source).toMatch(/split/); + expect(source).toMatch(/inactive/); + expect(source).toMatch(/unknown/); + }); + + it("includes JSON-output notes for automation on every command", () => { + expect(source).toMatch(/--json/); + expect(normalizedSource).toMatch(/machine-readable output/i); + }); + + it("documents the local privacy boundary and packet redaction", () => { + expect(normalizedSource).toMatch(/source never leaves your machine/i); + 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); + }); + + it("documents validation expectations with the real --validation flag", () => { + expect(source).toMatch(/Validation expectations/); + expect(source).toMatch(/--validation/); + }); + + it("avoids reward guarantees and public score-prediction language", () => { + expect(source).toMatch(/makes no earnings\s+promises/i); + expect(source).toMatch(/never predicts a public number/i); + expect(source).not.toMatch(/you will (earn|receive|get)/i); + expect(source).not.toMatch(/guaranteed (reward|payout|score)/i); + expect(source).not.toMatch(/predict(s|ed)?\s+your\s+score/i); + // Identity secrets must never appear in onboarding copy or examples. + expect(source).not.toMatch(/seed phrase|mnemonic|private key/i); + }); +});