From 7fb86e1c62dd332f7c5d0e542201ace7938cf890 Mon Sep 17 00:00:00 2001 From: JSONbored <49853598+JSONbored@users.noreply.github.com> Date: Tue, 26 May 2026 09:55:22 -0700 Subject: [PATCH] feat(docs): refresh Gittensor-aligned homepage --- CHANGELOG.md | 2 + scripts/check-docs-build.mjs | 5 + scripts/check-docs.mjs | 8 +- site/.vitepress/config.mts | 43 +- site/.vitepress/theme/custom.css | 390 ++++++++++-------- site/guide/github-app-setup.md | 88 ++-- site/guide/install.md | 62 +-- site/guide/maintainers.md | 69 ++-- site/guide/mcp.md | 34 +- site/guide/miners.md | 64 ++- site/index.md | 142 ++++--- site/public/images/gittensor-home-signal.webp | Bin 0 -> 18208 bytes 12 files changed, 472 insertions(+), 435 deletions(-) create mode 100644 site/public/images/gittensor-home-signal.webp diff --git a/CHANGELOG.md b/CHANGELOG.md index c417a18648..f279733aa7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,8 @@ - Add analytics and mcp version widget +- Refresh Gittensor-aligned homepage + ### Fixes diff --git a/scripts/check-docs-build.mjs b/scripts/check-docs-build.mjs index efee5b81dc..e3e157a70f 100644 --- a/scripts/check-docs-build.mjs +++ b/scripts/check-docs-build.mjs @@ -17,6 +17,11 @@ if (!existsSync(indexPath)) { const html = readFileSync(indexPath, "utf8"); if (!html.includes("gtn-version-pill")) failures.push("built docs are missing the MCP version pill markup."); if (!html.includes("MCP")) failures.push("built docs are missing MCP version text."); + if (!html.includes("/images/gittensor-home-signal.webp")) failures.push("built docs are missing the Gittensor context image."); +} + +if (!existsSync(join(dist, "images/gittensor-home-signal.webp"))) { + failures.push("built docs are missing the Gittensor context image asset."); } const builtFiles = existsSync(dist) ? collect(dist).filter((file) => /\.(html|js)$/.test(file)) : []; diff --git a/scripts/check-docs.mjs b/scripts/check-docs.mjs index e1c1ab841f..935e644af9 100644 --- a/scripts/check-docs.mjs +++ b/scripts/check-docs.mjs @@ -1,5 +1,5 @@ #!/usr/bin/env node -import { readdirSync, readFileSync, statSync } from "node:fs"; +import { existsSync, readdirSync, readFileSync, statSync } from "node:fs"; import { join } from "node:path"; const root = process.cwd(); @@ -43,6 +43,12 @@ const siteIndex = readFileSync(join(root, "site/index.md"), "utf8"); for (const phrase of ["Gittensor miners", "GitHub App", "MCP", "not a Gittensor frontend"]) { if (!siteIndex.includes(phrase)) failures.push(`site/index.md: missing required positioning phrase ${JSON.stringify(phrase)}`); } +if (!siteIndex.includes("/images/gittensor-home-signal.webp")) { + failures.push("site/index.md: missing Gittensor context image reference"); +} +if (!existsSync(join(root, "site/public/images/gittensor-home-signal.webp"))) { + failures.push("site/public/images/gittensor-home-signal.webp: missing Gittensor context image asset"); +} for (const required of ["SUPPORT.md", "site/security/privacy.md", "site/security/terms.md", "site/support.md"]) { try { diff --git a/site/.vitepress/config.mts b/site/.vitepress/config.mts index 98450895a8..5c5f4ab1f0 100644 --- a/site/.vitepress/config.mts +++ b/site/.vitepress/config.mts @@ -25,7 +25,7 @@ const analyticsHead: HeadConfig[] = umamiScriptUrl && umamiWebsiteId export default defineConfig({ title: "Gittensory", - description: "Backend intelligence, MCP preflight, and GitHub App review context for Gittensor contributors and maintainers.", + description: "MCP and GitHub App decision intelligence for Gittensor contributors and maintainers.", base: siteBase, cleanUrls: true, lastUpdated: true, @@ -34,9 +34,9 @@ export default defineConfig({ ["link", { rel: "icon", type: "image/svg+xml", href: "/logo.svg" }], ["link", { rel: "preconnect", href: "https://fonts.googleapis.com" }], ["link", { rel: "preconnect", href: "https://fonts.gstatic.com", crossorigin: "" }], - ["link", { rel: "stylesheet", href: "https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600;700&display=swap" }], + ["link", { rel: "stylesheet", href: "https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700;800&display=swap" }], ["meta", { property: "og:title", content: "Gittensory" }], - ["meta", { property: "og:description", content: "Private decision intelligence for healthier Gittensor repo participation." }], + ["meta", { property: "og:description", content: "Score blockers, lane fit, queue pressure, and reviewability context for Gittensor work." }], ["meta", { property: "og:url", content: siteUrl }], ["meta", { name: "theme-color", content: "#050608" }], ...analyticsHead, @@ -44,18 +44,45 @@ export default defineConfig({ themeConfig: { logo: "/logo.svg", nav: [ - { text: "Install", link: "/guide/install" }, - { text: "MCP", link: "/guide/mcp" }, - { text: "GitHub App", link: "/guide/github-app-setup" }, + { + text: "Start", + items: [ + { text: "Install", link: "/guide/install" }, + { text: "Auth", link: "/guide/auth" }, + { text: "MCP Clients", link: "/guide/mcp" }, + ], + }, + { + text: "Workflows", + items: [ + { text: "For Miners", link: "/guide/miners" }, + { text: "For Maintainers", link: "/guide/maintainers" }, + { text: "GitHub App Setup", link: "/guide/github-app-setup" }, + ], + }, { text: "API", link: "/reference/api" }, + { + text: "Safety", + items: [ + { text: "Privacy", link: "/security/privacy" }, + { text: "Terms", link: "/security/terms" }, + { text: "Support", link: "/support" }, + { text: "Troubleshooting", link: "/troubleshooting" }, + ], + }, ], sidebar: [ { - text: "Guide", + text: "Start", items: [ { text: "Install", link: "/guide/install" }, - { text: "MCP", link: "/guide/mcp" }, { text: "Auth", link: "/guide/auth" }, + { text: "MCP Clients", link: "/guide/mcp" }, + ], + }, + { + text: "Workflows", + items: [ { text: "For Miners", link: "/guide/miners" }, { text: "For Maintainers", link: "/guide/maintainers" }, { text: "GitHub App Setup", link: "/guide/github-app-setup" }, diff --git a/site/.vitepress/theme/custom.css b/site/.vitepress/theme/custom.css index 99abb928e6..a1b2d55bd1 100644 --- a/site/.vitepress/theme/custom.css +++ b/site/.vitepress/theme/custom.css @@ -44,7 +44,7 @@ --vp-button-alt-hover-text: var(--gt-green); --vp-code-color: var(--gt-green); --vp-code-bg: rgba(101, 108, 118, 0.2); - --vp-font-family-base: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + --vp-font-family-base: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; --vp-font-family-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; --vp-home-hero-name-color: var(--gt-text); --vp-home-hero-name-background: none; @@ -248,65 +248,11 @@ body { .VPHome { background: - linear-gradient(180deg, rgba(3, 28, 220, 0.14), transparent 260px), - radial-gradient(circle at 72% 20%, rgba(126, 231, 135, 0.1), transparent 330px), + linear-gradient(180deg, rgba(255, 255, 255, 0.035), transparent 240px), + linear-gradient(90deg, rgba(126, 231, 135, 0.08), transparent 28%, transparent 72%, rgba(126, 231, 135, 0.045)), var(--gt-black); } -.VPHome .main { - max-width: 1180px; -} - -.VPHomeHero { - padding-top: 92px !important; - padding-bottom: 44px !important; -} - -.VPHomeHero .container { - display: grid; - grid-template-columns: minmax(0, 1fr) minmax(320px, 430px); - gap: 48px; - max-width: 1180px; -} - -.VPHomeHero .main { - display: flex; - flex-direction: column; - align-items: flex-start; - text-align: left; -} - -.VPHomeHero .name, -.VPHomeHero .text { - max-width: 780px; - letter-spacing: 0; -} - -.VPHomeHero .name { - font-size: clamp(56px, 8vw, 112px); - line-height: 0.9; - font-weight: 800; -} - -.VPHomeHero .text { - margin-top: 20px; - color: #d7dee8; - font-size: clamp(24px, 3.4vw, 44px); - line-height: 1; - font-weight: 600; -} - -.VPHomeHero .tagline { - max-width: 660px; - color: var(--gt-muted); - font-size: 17px; - line-height: 1.7; -} - -.VPHomeHero .actions { - justify-content: flex-start; -} - .VPButton { border-radius: 4px !important; font-family: var(--vp-font-family-mono); @@ -316,79 +262,6 @@ body { text-transform: uppercase; } -.VPHomeHero .image { - display: block; -} - -.VPHomeHero .image-container { - display: flex; - align-items: center; - justify-content: center; - width: 420px; - height: 420px; - transform: none !important; -} - -.VPHomeHero .image-bg { - display: none; -} - -.VPHomeHero .image-src { - position: static !important; - width: min(100%, 420px); - max-width: 420px !important; - height: auto; - border: 1px solid var(--gt-line-strong); - border-radius: 0; - background: linear-gradient(180deg, var(--gt-panel), var(--gt-black)); - box-shadow: 0 0 0 1px rgba(126, 231, 135, 0.08), 0 24px 80px rgba(0, 0, 0, 0.38); - transform: none !important; -} - -.VPFeatures { - padding: 28px 24px 72px !important; -} - -.VPFeatures .container { - max-width: 1180px; -} - -.VPFeatures .items { - display: grid !important; - grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 1px !important; - border: 1px solid var(--gt-line); - background: var(--gt-line); -} - -.VPFeatures .item { - width: auto !important; - padding: 0 !important; -} - -.VPFeature { - height: 100%; - min-height: 168px; - border: 0 !important; - border-radius: 0 !important; - background: var(--gt-ink) !important; - padding: 22px !important; -} - -.VPFeature .title { - color: var(--gt-text); - font-family: var(--vp-font-family-mono); - font-size: 13px; - line-height: 1.35; - text-transform: uppercase; -} - -.VPFeature .details { - color: var(--gt-muted); - font-size: 14px; - line-height: 1.65; -} - .vp-doc { color: #d7dee8; } @@ -499,77 +372,230 @@ body { background: var(--gt-black); } -.gtn-home { +.gtn-hero, +.gtn-proof-strip, +.gtn-when, +.gtn-signal-panel { max-width: 1180px; - margin: 0 auto 72px; - padding: 0 24px; + margin-right: auto; + margin-left: auto; + padding-right: 24px; + padding-left: 24px; } -.gtn-strip { +.gtn-hero { display: grid; - grid-template-columns: repeat(4, minmax(0, 1fr)); - border: 1px solid var(--gt-line); - background: var(--gt-line); + grid-template-columns: minmax(0, 1fr) minmax(320px, 460px); + gap: 48px; + padding-top: 96px; + padding-bottom: 54px; + align-items: center; } -.gtn-strip__item { - min-height: 112px; - padding: 20px; - background: var(--gt-ink); +.gtn-hero__copy { + min-width: 0; } -.gtn-kicker { +.gtn-eyebrow { color: var(--gt-green); font-family: var(--vp-font-family-mono); font-size: 12px; font-weight: 700; + letter-spacing: 0.08em; text-transform: uppercase; } -.gtn-strip__item strong { - display: block; - margin-top: 12px; +.gtn-hero h1 { + margin: 18px 0 0; color: var(--gt-text); - font-size: 22px; - line-height: 1.1; + font-size: clamp(62px, 11vw, 132px); + font-weight: 800; + line-height: 0.84; + letter-spacing: 0; +} + +.gtn-hero__lead { + max-width: 760px; + margin: 28px 0 0; + color: #f8fafc; + font-size: clamp(28px, 4vw, 54px); + font-weight: 700; + line-height: 1; +} + +.gtn-hero__body { + max-width: 700px; + margin: 22px 0 0; + color: #a8b0bb; + font-size: 16px; + line-height: 1.75; } -.gtn-strip__item span { +.gtn-hero__actions { + display: flex; + flex-wrap: wrap; + gap: 12px; + margin-top: 32px; +} + +.gtn-button { + display: inline-flex; + align-items: center; + justify-content: center; + min-height: 46px; + border: 1px solid var(--gt-line-strong); + border-radius: 4px; + padding: 0 18px; + color: var(--gt-text); + font-size: 12px; + font-weight: 800; + text-decoration: none !important; + text-transform: uppercase; +} + +.gtn-button:hover { + border-color: var(--gt-green); + color: var(--gt-green); +} + +.gtn-button--primary { + border-color: var(--gt-green); + background: var(--gt-green); + color: var(--gt-black); +} + +.gtn-button--primary:hover { + background: #a4f2aa; + color: var(--gt-black); +} + +.gtn-hero__media { + position: relative; + margin: 0; + border: 1px solid rgba(126, 231, 135, 0.34); + border-radius: 8px; + padding: 10px; + background: rgba(0, 0, 0, 0.74); + box-shadow: + 0 0 0 1px rgba(255, 255, 255, 0.04), + 0 28px 72px rgba(0, 0, 0, 0.46); +} + +.gtn-hero__media img { display: block; - margin-top: 8px; + width: 100%; + height: auto; + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 4px; + background: #000; +} + +.gtn-hero__media figcaption { + position: absolute; + right: 18px; + bottom: 18px; + border: 1px solid rgba(126, 231, 135, 0.32); + border-radius: 4px; + padding: 6px 8px; + background: rgba(0, 0, 0, 0.84); + font-size: 10px; + font-weight: 700; + text-transform: uppercase; +} + +.gtn-hero__media a { + color: var(--gt-green); + text-decoration: none !important; +} + +.gtn-proof-strip { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 1px; + border: 1px solid var(--gt-line); + background: var(--gt-line); +} + +.gtn-proof-strip article { + min-height: 180px; + padding: 22px; + background: var(--gt-ink); +} + +.gtn-proof-strip span { + color: var(--gt-green); + font-size: 11px; + font-weight: 800; + text-transform: uppercase; +} + +.gtn-proof-strip h2 { + margin: 14px 0 0; + border: 0; + padding: 0; + color: var(--gt-text); + font-size: 20px; + line-height: 1.14; +} + +.gtn-proof-strip p { + margin: 12px 0 0; color: var(--gt-muted); font-size: 13px; - line-height: 1.55; + line-height: 1.58; } -.gtn-panel { +.gtn-when, +.gtn-signal-panel { display: grid; - grid-template-columns: minmax(0, 1fr) minmax(280px, 420px); + grid-template-columns: minmax(0, 0.82fr) minmax(320px, 1fr); gap: 1px; margin-top: 28px; border: 1px solid var(--gt-line); background: var(--gt-line); + padding: 0; } -.gtn-panel > section { +.gtn-when > div, +.gtn-signal-panel > div { background: var(--gt-ink); - padding: 28px; + padding: 30px; } -.gtn-panel h2 { - margin: 0; +.gtn-when h2, +.gtn-signal-panel h2 { + margin: 12px 0 0; + border: 0; + padding: 0; color: var(--gt-text); font-size: clamp(30px, 5vw, 56px); line-height: 0.98; } -.gtn-panel p { +.gtn-signal-panel p { max-width: 640px; color: var(--gt-muted); font-size: 16px; line-height: 1.72; } +.gtn-when__grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 1px; + padding: 0 !important; + background: var(--gt-line) !important; +} + +.gtn-when__grid p { + margin: 0; + padding: 22px; + background: var(--gt-panel-soft); + color: #c9d1d9; + font-size: 13px; + line-height: 1.65; +} + .gtn-terminal { font-family: var(--vp-font-family-mono); font-size: 12px; @@ -597,24 +623,22 @@ body { } @media (max-width: 960px) { - .VPHomeHero .container, - .gtn-panel { + .gtn-hero, + .gtn-when, + .gtn-signal-panel { grid-template-columns: 1fr; } - .VPHomeHero .image { - order: -1; - } - - .VPHomeHero .image-src { - width: 220px; + .gtn-hero { + gap: 28px; + padding-top: 72px; } - .gtn-strip { - grid-template-columns: repeat(2, minmax(0, 1fr)); + .gtn-hero__media { + max-width: 520px; } - .VPFeatures .items { + .gtn-proof-strip { grid-template-columns: repeat(2, minmax(0, 1fr)); } } @@ -651,27 +675,35 @@ body { overflow-wrap: anywhere; } - .VPHomeHero { - padding-top: 64px !important; + .gtn-hero, + .gtn-proof-strip, + .gtn-when, + .gtn-signal-panel { + padding-right: 18px; + padding-left: 18px; } - .VPHomeHero .name { - font-size: 54px; + .gtn-hero h1 { + font-size: 58px; } - .VPHomeHero .text { - font-size: 26px; + .gtn-hero__lead { + font-size: 29px; } - .gtn-strip { + .gtn-proof-strip, + .gtn-when__grid { grid-template-columns: 1fr; } - .VPFeatures .items { - grid-template-columns: 1fr; + .gtn-when > div, + .gtn-signal-panel > div { + padding: 22px; } - .gtn-panel > section { - padding: 22px; + .gtn-hero__media figcaption { + position: static; + margin-top: 8px; + text-align: center; } } diff --git a/site/guide/github-app-setup.md b/site/guide/github-app-setup.md index 1fea17f786..173421d29a 100644 --- a/site/guide/github-app-setup.md +++ b/site/guide/github-app-setup.md @@ -1,39 +1,27 @@ # GitHub App Setup -The GitHub App is the maintainer/install surface. GitHub OAuth is the MCP user-auth surface. +The GitHub App is the maintainer surface. GitHub OAuth is the MCP user-auth surface. -## Basic Fields - -Use these values: +## Required Settings | Field | Value | | --- | --- | | Homepage URL | `https://gittensory.aethereal.dev` | -| Webhook URL | `${GITTENSORY_API_URL}/v1/github/webhook` | -| Webhook active | enabled | -| SSL verification | enabled | -| Device Flow | enabled | - -`GITTENSORY_API_URL` is the private API origin for the deployed backend. Do not use the GitHub Pages docs domain for webhooks; Pages only serves static docs. - -Use a generated webhook secret and set the same value in Cloudflare as `GITHUB_WEBHOOK_SECRET`. - -## Required Repository Permissions +| Webhook URL | your Gittensory API origin plus `/v1/github/webhook` | +| Webhook active | Enabled | +| SSL verification | Enabled | +| Install target | Current account or selected organizations | -| Permission | Access | Why | -| --- | --- | --- | -| Metadata | Read | Required for repository identity and repository events. | -| Pull requests | Read | Required for PR metadata and webhook events. | -| Issues | Write | Required to post the sticky PR comment and apply the maintainer-configured label. | - -Optional: +## Repository Permissions | Permission | Access | Why | | --- | --- | --- | -| Checks | Write | Only needed if minimal check runs are explicitly enabled. | -| Contents | Read | Only needed if a future feature reads repository files directly through the App. | +| Metadata | Read | Required by GitHub Apps. | +| Pull requests | Read | Inspect PR author, branch, state, and linked context. | +| Issues | Write | Post sticky comments and apply the configured label. | +| Checks | Write | Optional; only needed if a maintainer explicitly enables minimal checks. | -## Required Events +## Events Subscribe to: @@ -41,51 +29,27 @@ Subscribe to: - Issues - Repository -If GitHub shows `Installation target`, select it. Some installation-related events are not always shown as normal selectable event rows; Gittensory should not block health on event names that are hidden in the app UI. - -## Default Visibility +If GitHub shows `Installation target`, select it. Some installation-related events are hidden in parts of GitHub’s UI; Gittensory health should not fail on event names that are not selectable. -Gittensory inspects PR webhooks quietly first. It publishes a public surface only when the PR author is confirmed through the official Gittensor API. +## Public Behavior -Default visible behavior: +Gittensory inspects PR webhooks quietly first. It publishes a public surface only when the author is confirmed through the official Gittensor API. - non-miner authors: no comment, no label, no check -- bot authors: no comment, no label, no check -- maintainer-associated authors: no public output unless `includeMaintainerAuthors=true` +- bot authors: no public output +- maintainer-associated authors: skipped unless `includeMaintainerAuthors=true` - confirmed miners: one sticky public-safe comment plus the configured label, defaulting to `gittensor` Check runs default to off. If enabled later, they stay minimal and do not include private reviewability, scoring, wallet, hotkey, or reward/risk context. -## Install Or Repair - -1. Update the GitHub App permissions and events. -2. Reinstall the app or approve the changed permissions. -3. Select the repos Gittensory should inspect. -4. Trigger installation-health refresh: - -```sh -curl -X POST "$GITTENSORY_API_URL/v1/internal/jobs/refresh-installation-health/run" \ - -H "Authorization: Bearer $INTERNAL_JOB_TOKEN" -``` - -5. Check health: - -```sh -curl "$GITTENSORY_API_URL/v1/readiness" \ - -H "Authorization: Bearer $GITTENSORY_API_TOKEN" -``` - -Healthy app installation state should remove the readiness warning about GitHub App installations needing attention. - -## Marketplace Readiness - -Before Marketplace submission, add: +::: warning Not an official Gittensor frontend +The app adds maintainer workflow context around Gittensor participation. It does not replace the official Gittensor site or dashboard. +::: -- public docs URL -- support contact -- privacy policy -- terms page if needed -- clear setup flow -- valid webhook and install diagnostics +## Repair Checklist -Do not submit until the privacy, support, terms, install diagnostics, and public setup flow are complete. +1. Update GitHub App permissions and event subscriptions. +2. Reinstall or approve changed permissions on the installed account. +3. Refresh installation health. +4. Confirm comments and labels are enabled only when `Issues: write` is available. +5. Confirm checks are off unless the repo explicitly opted into minimal check runs. diff --git a/site/guide/install.md b/site/guide/install.md index 194b89de28..9898f0aa81 100644 --- a/site/guide/install.md +++ b/site/guide/install.md @@ -1,54 +1,58 @@ # Install -Gittensory has two install paths: public npm for normal use, and local checkout for development. +Start here when you want Gittensory available from Codex, Claude Desktop, Cursor, or another stdio MCP client. -## Public npm - -Use this for Codex, Claude Desktop, Cursor, or any other stdio MCP client: +## 3-Step Quick Start ```sh npm install -g @jsonbored/gittensory-mcp gittensory-mcp login -gittensory-mcp status +gittensory-mcp doctor +``` + +Then run the server: + +```sh gittensory-mcp --stdio ``` -The login command uses GitHub Device Flow and stores a short-lived Gittensory session token in your local config directory. +`login` uses GitHub Device Flow and stores a short-lived Gittensory session token locally. It does not store a user PAT. -## Local checkout +::: tip No source upload by default +MCP v1 sends repository metadata, changed file paths, counts, linked issue refs, commit messages, and validation summaries. It does not upload source contents. +::: -Use this when developing Gittensory itself: +## Configure A Client + +Print a client snippet without editing local config files: ```sh -git clone https://github.com/JSONbored/gittensory.git -cd gittensory -npm install -npm link --workspace @jsonbored/gittensory-mcp -gittensory-mcp login -gittensory-mcp --stdio +gittensory-mcp init-client --print codex +gittensory-mcp init-client --print claude +gittensory-mcp init-client --print cursor ``` -## Verify The Install +If a client cannot find `gittensory-mcp`, use an absolute command path in that client’s MCP config. + +## Verify In A Repo -Run: +From any GitHub repository: ```sh -gittensory-mcp doctor -gittensory-mcp whoami gittensory-mcp analyze-branch --login YOUR_GITHUB_LOGIN --json +gittensory-mcp preflight --login YOUR_GITHUB_LOGIN --json ``` -`doctor` checks API health, auth state, source-upload defaults, local git metadata, and whether the binary is likely visible to MCP clients. +Use `doctor` when auth, PATH, API reachability, or git metadata looks wrong. -## Privacy Defaults +## Local Development -Gittensory MCP v1 sends structured metadata only: +Use this only when working on Gittensory itself: -- repository full name -- branch and base refs -- changed file paths and counts -- linked issue references -- commit messages -- validation command summaries - -It does not upload source contents. `GITTENSORY_UPLOAD_SOURCE=true` is rejected. +```sh +git clone https://github.com/JSONbored/gittensory.git +cd gittensory +npm install +npm link --workspace @jsonbored/gittensory-mcp +gittensory-mcp login +``` diff --git a/site/guide/maintainers.md b/site/guide/maintainers.md index 0c134b0ee1..7690171f74 100644 --- a/site/guide/maintainers.md +++ b/site/guide/maintainers.md @@ -1,52 +1,45 @@ # For Maintainers -Gittensory is meant to make Gittensor-driven contribution flow less noisy. +Gittensory is designed to make Gittensor-driven contribution flow less noisy. It inspects PRs quietly first and only publishes public output when the author is an officially confirmed Gittensor miner. -## GitHub App Surface +## Default Public Behavior -The GitHub App is designed to stay quiet unless a PR author is an officially confirmed Gittensor miner. +- non-miner authors: no comment, no label, no check +- bot authors: no public output +- maintainer-associated authors: no public output unless explicitly enabled +- confirmed miners: one sticky public-safe comment plus the configured label -Default visible output for confirmed miner PRs: +::: tip Public GitHub output is sanitized +Comments and labels never include private reviewability scores, wallet data, hotkeys, raw trust scores, public score estimates, or public reward estimates. +::: -- one sticky public-safe PR comment -- one maintainer-configured label, defaulting to `gittensor` -- no public output for bots, non-miners, or maintainer-associated authors unless explicitly enabled +## What Maintainers Get -Private reviewability context, queue risk, score blockers, and reward/risk reasoning stay in the API/MCP. GitHub checks default to off; if a maintainer enables them later, they remain minimal and do not carry detailed findings. +Private API/MCP surfaces can explain: -## Reviewability Actions +- contributor role context +- repo-specific outcome history +- linked issue and lane fit +- duplicate or WIP collision risk +- validation evidence +- likely review action: review now, needs author, watch, redirect, or maintainer lane -Gittensory maps PRs to maintainer-friendly actions: +The GitHub App stays low-noise. It does not close, merge, rewrite, or publicly judge contributor work. -- `review_now` -- `needs_author` -- `likely_duplicate` -- `close_or_redirect` -- `watch` -- `maintainer_lane` +## Intake Health -The point is not to shame contributors. The point is to identify the lowest-friction next step. +Repo owners can use Gittensory signals to inspect: -## Public Comments +- queue pressure +- label readiness +- config quality +- maintainer-cut readiness +- whether issue discovery is appropriate yet +- whether the installed GitHub App has the permissions needed for comments and labels -Confirmed miner comments can include: +## When To Use Gittensory -- contribution context -- PR hygiene -- duplicate or WIP risk -- maintainer review notes -- contributor next steps - -Comments must not include raw trust scores, wallet data, hotkeys, public reward estimates, or public score optimization language. - -## Repo Owner Signals - -Repo owners can use Gittensory to inspect: - -- repo lane clarity -- label configuration -- maintainer cut readiness -- queue health -- contributor intake health -- GitHub App installation health -- stale or degraded backfill state +- when confirmed Gittensor miner PRs need triage context +- when duplicate or broad PRs are increasing review load +- when you want labels/comments without public check-run noise +- before changing repo rules that affect contributor intake diff --git a/site/guide/mcp.md b/site/guide/mcp.md index d7d5d1068e..da6d7930e5 100644 --- a/site/guide/mcp.md +++ b/site/guide/mcp.md @@ -1,10 +1,20 @@ -# MCP +# MCP Clients -The MCP package is the contributor-facing surface for coding agents. It runs locally over stdio and calls the private Gittensory API with your Gittensory session token. +The MCP package is the contributor-facing surface. Your coding agent can ask Gittensory what the current branch means in Gittensor terms before you open or update a PR. -## Generate Client Config +## What Agents Can Ask -Print a config snippet: +- what repo lane applies: direct PR, issue discovery, split, inactive, or unknown +- what blocks scoreability right now +- whether local work looks stale, broad, duplicate-prone, or missing validation evidence +- what to clean up before opening more PRs +- what public-safe PR packet should be included for a maintainer + +::: warning Private score/reward-risk only +Scoreability projections and reward/risk reasoning are private MCP/API output. Public GitHub comments stay sanitized. +::: + +## Generate Config ```sh gittensory-mcp init-client --print codex @@ -12,7 +22,7 @@ gittensory-mcp init-client --print claude gittensory-mcp init-client --print cursor ``` -These commands do not edit your files. Use an absolute command path if your client does not inherit your shell `PATH`. +These commands print config only. They do not mutate your local client files. ## Codex @@ -48,11 +58,7 @@ args = ["--stdio"] } ``` -## Tools - -The local wrapper exposes repo context, contributor decision packs, local branch preflight, score blockers, PR packets, variant comparison, and registry change tools. - -Useful tools: +## Useful Tools - `gittensory_local_status` - `gittensory_get_decision_pack` @@ -65,7 +71,7 @@ Useful tools: ## Runtime Rules -- Stdio only for the local wrapper. -- No source upload in v1. -- Private score and reward/risk reasoning stay in MCP/API output. -- Public PR packets are sanitized and do not include wallet, hotkey, raw trust score, or public score estimates. +- local wrapper uses stdio +- source upload is unsupported in v1 +- auth uses a Gittensory session token minted through GitHub OAuth +- public PR packets exclude wallets, hotkeys, raw trust scores, and public score estimates diff --git a/site/guide/miners.md b/site/guide/miners.md index c3e9c575a6..a8e79a2f46 100644 --- a/site/guide/miners.md +++ b/site/guide/miners.md @@ -1,39 +1,28 @@ # For Miners -Gittensory helps miners decide what to do next with evidence instead of guesswork. +Gittensory helps miners choose work with evidence: lane fit, score blockers, queue pressure, local diff quality, and realistic scenario projections. -## What It Answers +## Branch Analysis Flow -- Is this repo a direct-PR lane, issue-discovery lane, split lane, inactive lane, or unknown lane? -- Am I in a normal contributor lane or a maintainer lane for this repo? -- Does my current branch look reviewable? -- What blocks scoreability right now? -- Should I clean up open PRs before opening more work? -- Is there duplicate or WIP collision risk? -- What public-safe PR packet should I give a maintainer? - -## Branch Analysis - -Run from a Git repo: +Run this before opening or updating a PR: ```sh gittensory-mcp analyze-branch --login YOUR_GITHUB_LOGIN --json ``` -The response includes: +The response explains: + +- repo lane and role context +- current scoreability and blocker gates +- open PR pressure and cleanup-first guidance +- duplicate or WIP collision risk +- stale-base warnings when the local diff looks inflated +- validation evidence from changed test paths and command summaries +- a public-safe PR packet for maintainers -- lane context -- role context -- preflight findings -- private score blockers -- current vs projected scoreability scenarios -- reward/risk reasoning -- base freshness warnings when the local diff may be inflated -- maintainer-fit notes -- public-safe PR packet -- ranked next actions +## Scenario Flags -When the current score is blocked by temporary account/queue state, pass the assumptions explicitly: +When approved PRs are expected to land soon, pass the assumption explicitly: ```sh gittensory-mcp analyze-branch --login YOUR_GITHUB_LOGIN \ @@ -44,7 +33,11 @@ gittensory-mcp analyze-branch --login YOUR_GITHUB_LOGIN \ --json ``` -Gittensory labels that as a user-supplied scenario. It shows the current effective score, the underlying potential score, and what changes if the open-PR and credibility gates clear. +Gittensory labels this as a user-supplied scenario. It separates the current effective score, the underlying potential score, and what changes if open-PR and credibility gates clear. + +::: tip No source upload by default +Local branch analysis sends metadata only. File contents are not uploaded. +::: ## Preflight @@ -52,18 +45,13 @@ Gittensory labels that as a user-supplied scenario. It shows the current effecti gittensory-mcp preflight --login YOUR_GITHUB_LOGIN --json ``` -Use this before opening a PR. It is especially useful when you need to know whether a branch is missing tests, missing a linked issue, colliding with active work, or likely to increase maintainer burden. - -## How This Helps +Use preflight when you need a quick answer on linked issues, tests, duplicate risk, lane fit, and maintainer review friction. -Gittensory does not promise payouts. It explains scoreability and risk: +## When To Use Gittensory -- open PR pressure -- credibility assumptions -- lane eligibility -- issue-discovery vs direct PR fit -- duplicate clusters -- stale work -- review friction +- before opening a PR +- after PR approvals but before rerunning score projections +- when deciding whether to clean up existing PRs first +- when choosing between direct PR work and issue-discovery flow -That makes recommendations actionable: land or withdraw blocked work, avoid direct PRs in issue-discovery-only repos, improve validation evidence, or pick a repo where your history and the lane actually fit. +Gittensory does not promise payouts. It explains scoreability, risk, and what actions make the work more likely to be reviewable and scoreable. diff --git a/site/index.md b/site/index.md index 26bfed92da..a39d285484 100644 --- a/site/index.md +++ b/site/index.md @@ -1,74 +1,84 @@ --- layout: home - -hero: - name: Gittensory - text: Private repo intelligence for Gittensor work. - tagline: "For Gittensor miners, maintainers, and agents: MCP preflight, scoreability projections, and GitHub App review packets. Still not a Gittensor frontend." - image: - src: /logo.svg - alt: Gittensory signal mark - actions: - - theme: brand - text: Install MCP - link: /guide/install - - theme: alt - text: GitHub App Setup - link: /guide/github-app-setup - -features: - - title: Scoreability - details: Current estimate, ungated potential, and near-term what-if scenarios. - - title: Queue Pressure - details: Open PR gates, stale branches, duplicate risk, and cleanup-first actions. - - title: Role Context - details: Contributor lane, maintainer lane, owner history, and repo-specific evidence. - - title: Reviewability - details: Private maintainer packets plus public-safe PR guidance. - - title: Registry Signals - details: Repo lanes, label multipliers, issue discovery, bounties, and config drift. - - title: MCP Native - details: Codex, Claude, Cursor, and agents get structured JSON without code upload. --- -
-
-
-
01 / Miners
- Pick work with less guesswork. - Score blockers, lane fit, stale base checks, and cleanup-first guidance. -
-
-
02 / Maintainers
- Review signal, not noise. - Role-aware context, duplicate risk, validation evidence, and next action. -
-
-
03 / Agents
- Local branch context. - Metadata-only MCP tools for Codex, Claude, Cursor, and automation. -
-
-
04 / Privacy
- Private by default. - No PAT storage, no source upload, no public score or wallet leakage. +
+
+

Gittensor contribution intelligence

+

Gittensory

+

Decision intelligence for Gittensor contributors and maintainers.

+

+ Use MCP and GitHub App signals to help Gittensor miners choose better work, understand score blockers, + reduce maintainer noise, and ship cleaner Gittensor submissions. +

+
+
+ Gittensor homepage showing live miner, reward, and repository activity. +
+ Context: Gittensor Subnet 74 +
+
+
-
-
-

Not another Gittensor frontend.

-

- Gittensory is the private signal layer behind better contributions: - official miner context, registry lanes, queue pressure, scoreability - projections, maintainer friction, and public-safe PR packets. -

-
-
-
lanedirect_pr / issue_discovery / maintainer
-
scorecurrent 0, potential visible, scenario gated
-
riskopen PR pressure, credibility, stale base
-
outputprivate MCP JSON + sanitized PR packet
-
+
+
+ 01 / Gittensor miners +

Pick work with fewer blind spots.

+

Score blockers, lane fit, queue pressure, and local branch preflight before opening another PR.

+
+
+ 02 / Maintainers +

See signal without noisy checks.

+

Confirmed-miner comments, configured labels, reviewability context, and public-safe next steps.

+
+
+ 03 / Agents +

Ask for repo-aware guidance.

+

Metadata-only MCP branch analysis for Codex, Claude, Cursor, and local automation.

+
+
+ 04 / Repo Owners +

Tune intake before it gets loud.

+

Config quality, label readiness, maintainer-lane handling, and contribution intake health.

+
+
+ +
+
+

When to use it

+

Before the work becomes review load.

+
+
+

Before opening a PR, check lane fit, linked issue expectations, validation evidence, and duplicate risk.

+

After approvals, rerun scoreability projections with realistic pending-merge assumptions.

+

When open PR pressure is high, decide whether cleanup beats opening new work.

+

When a maintainer wants confirmed-miner context, keep the public surface quiet and sanitized.

+
+
+ +
+
+

What Gittensory is

+

Not a Gittensor frontend.

+

+ Gittensory is not a Gittensor frontend. It is the private signal layer behind better Gittensor contributions: + official miner context, registry lanes, queue pressure, scoreability projections, + maintainer friction, and public-safe PR packets. +

+
+
+
lanedirect_pr / issue_discovery / maintainer
+
scoreabilitycurrent, ungated, and scenario-gated
+
riskopen PR pressure, credibility, stale base
+
outputprivate MCP JSON + sanitized PR packet
-
+ diff --git a/site/public/images/gittensor-home-signal.webp b/site/public/images/gittensor-home-signal.webp new file mode 100644 index 0000000000000000000000000000000000000000..7842fd669de740edbd5944d4c01e9cf22f97e5f3 GIT binary patch literal 18208 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