Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ Public GitHub surfaces:
app/infra state) resolves to a neutral, non-blocking gate. Adding a blocker must keep it
confirmed-contributor-gated through `evaluateGateCheck`.

Config as code (`.gittensory.yml`) — every repository setting is controllable from the config file:
Config as code (`.loopover.yml`; the legacy `.gittensory.yml` filename is dual-read indefinitely, #4773) — every repository setting is controllable from the config file:

- **`settings:`** is a partial of the repository settings: any behaviour a maintainer can toggle in the
dashboard can be set here as code — `commentMode`, `publicAudienceMode`, `publicSurface`, `checkRunMode`,
Expand All @@ -296,14 +296,15 @@ Config as code (`.gittensory.yml`) — every repository setting is controllable
`validationEvidence`, `openPrQueue`, `contributorContext`, `gateResult`). Maintainer text that fails the
public-safe filter (reward/score/wallet/hotkey/etc.) is dropped, never published.
- **`repoDocGeneration:`** opts a repo into the AGENTS.md/CLAUDE.md generation roadmap (#2993) — a
`.gittensory.yml`-only surface with no dashboard/DB counterpart. `enabled` (default `false`) turns it on;
`.loopover.yml`-only surface with no dashboard/DB counterpart. `enabled` (default `false`) turns it on;
`scope` (default `["agents"]`) picks which generated file types are in play (`"agents"` for
AGENTS.md/CLAUDE.md, plus `"skills"` once skill-file generation lands); `allowOverwriteExisting` (default
`false`) is a separate opt-in required before the engine proposes an overwrite for a repo that already has
a hand-maintained AGENTS.md/CLAUDE.md — absent it, an existing hand-written file is left alone and
generation is skipped.
- Precedence: `.gittensory.yml` `gate:` > `.gittensory.yml` `settings:` > dashboard repository settings >
safe defaults; unset fields fall back to the next layer. The committed root `.gittensory.yml` is the
- Precedence: `.loopover.yml` `gate:` > `.loopover.yml` `settings:` > dashboard repository settings >
safe defaults; unset fields fall back to the next layer (the legacy `.gittensory.yml` filename works
identically wherever `.loopover.yml` does, #4773). The committed root `.gittensory.yml` is the
worked example. Resolved once in `resolveRepositorySettings`, so the whole app honours the file.
- The config chooses **what** LoopOver does (gate on/off, blockers, comments, labels, surface, panel
content); it never changes **who** can be blocked — only confirmed Gittensor contributors are ever
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,16 @@ LoopOver CI and LoopOver review score, gate, and comment on pull requests. The r
- **CI + full-file grounding** — grounds the AI reviewer with the PR's finished CI status and the full post-change content of the changed files, so claims are verified against reality instead of predicted.
- **Codebase RAG** — retrieval-augmented context that queries the codebase vector index for related callers, modules, and conventions and appends them to the reviewer prompt (additive only; inert until an index exists).
- **Submitter-reputation gating** — an internal-only spend control that downgrades new / burst / low-reputation submitters to a deterministic-only review, never surfaced on any public comment, label, or check.
- **Unified review comment** — renders the public PR feedback as one in-place comment instead of multiple panels. With `.gittensory.yml`'s `review.changed_files_summary` also on (off by default), it gains a deterministic, no-AI "Changed files" collapsible: one row per file category (source/test/docs/config/generated), with file counts and +/- totals.
- **Unified review comment** — renders the public PR feedback as one in-place comment instead of multiple panels. With `.loopover.yml`'s `review.changed_files_summary` also on (off by default; legacy `.gittensory.yml` name also still works, indefinitely), it gains a deterministic, no-AI "Changed files" collapsible: one row per file category (source/test/docs/config/generated), with file counts and +/- totals.
- **Per-repo activation** — capabilities roll forward (and back) one flag and one repo at a time via the `GITTENSORY_REVIEW_REPOS` allowlist.

**Check-run and comment surfaces, disambiguated** (a common point of confusion — these are three independent, separately-configured things, not layers of the same feature):

- **`LoopOver Orb Review Agent`** (`gate.*` / `settings.reviewCheckMode`, off by default) — the authoritative GitHub Check Run carrying the gate's pass/fail verdict. This is the one worth making a required status check.
- **`LoopOver Context`** (`settings.checkRunMode` / `settings.checkRunDetailLevel`, off by default) — a separate, purely advisory Check Run. At its default `checkRunDetailLevel: minimal` it publishes no findings at all; even at `standard`/`deep` it only re-renders content already shown elsewhere. Never make this one required.
- **Inline review comments** (`GITTENSORY_REVIEW_INLINE_COMMENTS` + `.gittensory.yml`'s `review.inline_comments`, off by both by default) — real, reply-able line-anchored PR review comment threads (CodeRabbit-style). This is the ONLY one of the three that posts an interactive per-line thread; the two check runs above never do. With `.gittensory.yml`'s `review.suggestions` also on, a precise line-anchored fix is additionally rendered as a one-click, committable GitHub suggested-change block. With `review.finding_categories` also on (off by default), each finding is additionally tagged with a category — security/correctness/performance/maintainability/tests/style — in both the inline comment label and the unified comment's "Finding categories" collapsible; a deterministic path/keyword fallback covers whatever the model omits.
- **Inline review comments** (`GITTENSORY_REVIEW_INLINE_COMMENTS` + `.loopover.yml`'s `review.inline_comments`, off by both by default) — real, reply-able line-anchored PR review comment threads (CodeRabbit-style). This is the ONLY one of the three that posts an interactive per-line thread; the two check runs above never do. With `.loopover.yml`'s `review.suggestions` also on, a precise line-anchored fix is additionally rendered as a one-click, committable GitHub suggested-change block. With `review.finding_categories` also on (off by default), each finding is additionally tagged with a category — security/correctness/performance/maintainability/tests/style — in both the inline comment label and the unified comment's "Finding categories" collapsible; a deterministic path/keyword fallback covers whatever the model omits.

See [Tuning your reviews](https://gittensory.aethereal.dev/docs/tuning) for the full flag, setting, and `.gittensory.yml` reference.
See [Tuning your reviews](https://gittensory.aethereal.dev/docs/tuning) for the full flag, setting, and `.loopover.yml` reference (the legacy `.gittensory.yml` filename is dual-read indefinitely — #4773 — so an existing repo's committed file keeps working unchanged).

## Start Here

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ export function AiProviderModeFieldGroup({
<Callout variant="safety" title="API keys stay out of this form">
Provider API keys are configured via environment variables, encrypted key storage, or the
maintainer BYOK dashboard — never in generated{" "}
<code className="font-mono">.gittensory.yml</code> files. This field group only records
mode and model <em>names</em>.
<code className="font-mono">.loopover.yml</code> files. This field group only records mode
and model <em>names</em>.
</Callout>
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ describe("ConfigGeneratorYamlPreview", () => {

expect(screen.getByText("Preview")).toBeTruthy();
// The filename appears both in the descriptive copy and the CodeBlock's own filename label.
expect(screen.getAllByText(".gittensory.yml").length).toBeGreaterThanOrEqual(2);
expect(screen.getAllByText(".loopover.yml").length).toBeGreaterThanOrEqual(2);
// The legacy filename is still mentioned as also-supported (#4773), not silently dropped.
expect(screen.getAllByText(".gittensory.yml").length).toBeGreaterThanOrEqual(1);
expect(screen.getByText(/combine: consensus/)).toBeTruthy();
expect(screen.getByText(/provider: anthropic/)).toBeTruthy();
expect(screen.getByRole("button", { name: "Copy code" })).toBeTruthy();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,23 @@ import { CodeBlock } from "@/components/site/primitives";
import { formStateToYaml, type GeneratorFormState } from "@/lib/config-generator-yaml";

/**
* Read-only `.gittensory.yml` preview for the config generator (#2210, part of #1683): renders the
* Read-only `.loopover.yml` preview for the config generator (#2210, part of #1683): renders the
* current GeneratorFormState as text via CodeBlock (built-in copy-to-clipboard) so the output is
* explicit and reviewable before a self-hoster saves or copies it. Purely presentational — field-group
* panels own collecting the form state.
* panels own collecting the form state. The legacy `.gittensory.yml` filename works identically if a
* self-hoster already has one committed (#4773) — this preview just names the new canonical filename.
*/
export function ConfigGeneratorYamlPreview({ formState }: { formState: GeneratorFormState }) {
return (
<section className="rounded-token border-hairline bg-card p-5">
<h2 className="font-display text-token-lg font-semibold">Preview</h2>
<p className="mt-1 text-token-xs text-muted-foreground">
The exact <code className="font-mono">.gittensory.yml</code> this configuration would
produce. Nothing is saved until you copy it into your repo.
The exact <code className="font-mono">.loopover.yml</code> this configuration would produce
(the legacy <code className="font-mono">.gittensory.yml</code> name also still works).
Nothing is saved until you copy it into your repo.
</p>
<div className="mt-4">
<CodeBlock code={formStateToYaml(formState)} filename=".gittensory.yml" />
<CodeBlock code={formStateToYaml(formState)} filename=".loopover.yml" />
</div>
</section>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ const GATE_FIELDS: FieldDef[] = [
label: "Review agent check",
kind: "select",
// "visible" (publishes but never required in branch protection) is deliberately not offered here --
// this toggle keeps its historical off/enabled shape; set .gittensory.yml gate.checkMode: visible directly
// this toggle keeps its historical off/enabled shape; set .loopover.yml gate.checkMode: visible directly
// for that finer-grained mode.
options: [
["disabled", "off"],
Expand Down Expand Up @@ -718,7 +718,8 @@ type FocusManifestResponse = { manifest: unknown };

/**
* Edit the repo's focus manifest as JSON. The manifest is repo-public config-as-code (it mirrors
* `.gittensory.yml`); this surface lets a maintainer edit the API-record copy without committing a file.
* `.loopover.yml`, or the legacy `.gittensory.yml`, #4773); this surface lets a maintainer edit the
* API-record copy without committing a file.
*/
function FocusManifestEditor({ base }: { base: string | null }) {
const [text, setText] = useState("");
Expand Down Expand Up @@ -776,8 +777,7 @@ function FocusManifestEditor({ base }: { base: string | null }) {
</h3>
<p className="mt-1 text-token-2xs text-muted-foreground">
The repo&apos;s maintainer focus policy as JSON — wanted paths, linked-issue policy, test
expectations, and gate overrides. Mirrors <code className="font-mono">.gittensory.yml</code>
.
expectations, and gate overrides. Mirrors <code className="font-mono">.loopover.yml</code>.
</p>
<textarea
value={loading ? "Loading…" : text}
Expand Down
2 changes: 1 addition & 1 deletion apps/gittensory-ui/src/lib/config-generator-yaml.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest";

import { formStateToYaml, type GeneratorFormState } from "@/lib/config-generator-yaml";

const HEADER = "# .gittensory.yml — generated by the config generator";
const HEADER = "# .loopover.yml — generated by the config generator";

describe("formStateToYaml", () => {
it("serializes a full gate.aiReview config with every field set", () => {
Expand Down
8 changes: 5 additions & 3 deletions apps/gittensory-ui/src/lib/config-generator-yaml.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// Config-generator YAML preview serializer (#2210, part of #1683). Pure form-state -> `.gittensory.yml`
// Config-generator YAML preview serializer (#2210, part of #1683). Pure form-state -> `.loopover.yml`
// text builder — the reviewable-output half of the config generator; field-group panels (#2208 and
// siblings) own collecting GeneratorFormState, this module only turns it into text. Key names and
// nesting match the real manifest schema (packages/gittensory-engine/src/focus-manifest.ts's
// gateConfigToJson `gate.aiReview` shape, the same shape documented in this repo's own root
// .gittensory.yml under the commented-out `aiReview:` example) — no parallel schema. Every field is
// optional so a fresh/partial form never produces invalid output; unset keys are omitted entirely.
// The generated header names the new-brand `.loopover.yml` filename; the legacy `.gittensory.yml`
// name still works identically if that's what a self-hoster already has committed (#4773).

export type AiCombineStrategy = "single" | "consensus" | "synthesis";
export type AiProvider = "anthropic" | "openai";
Expand All @@ -21,7 +23,7 @@ export type GeneratorFormState = {
};
};

const YAML_HEADER = "# .gittensory.yml — generated by the config generator";
const YAML_HEADER = "# .loopover.yml — generated by the config generator";

/** Plain-scalar YAML value needs quoting when it would otherwise be ambiguous (a YAML special
* character, leading/trailing whitespace, or the empty string). Model names are free text, so this
Expand All @@ -35,7 +37,7 @@ function yamlLine(indent: number, key: string, value: string): string {
return `${" ".repeat(indent)}${key}: ${yamlScalar(value)}`;
}

/** Serializes the `gate.aiReview` slice of GeneratorFormState into `.gittensory.yml` text, omitting
/** Serializes the `gate.aiReview` slice of GeneratorFormState into `.loopover.yml` text, omitting
* every unset field/block so the preview is always valid YAML (including the empty-state case). */
export function formStateToYaml(state: GeneratorFormState): string {
const aiReview = state.gate?.aiReview;
Expand Down
2 changes: 1 addition & 1 deletion apps/gittensory-ui/src/routes/app.config-generator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function ConfigGeneratorRoute() {
<PageHeader
eyebrow="Maintainer"
title="Config generator"
description="Build a typed .gittensory.yml from field groups. Secrets never enter generated config — only public-safe keys and model names."
description="Build a typed .loopover.yml from field groups. Secrets never enter generated config — only public-safe keys and model names."
/>
<ConfigGeneratorPanel />
</div>
Expand Down
2 changes: 1 addition & 1 deletion apps/gittensory-ui/src/routes/docs.beta-onboarding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ gittensory-mcp preflight --login your-login --json`}

<h2>Repo owner journey</h2>
<p>
Repo owners care about registration readiness and sensible <code>.gittensory.yml</code>{" "}
Repo owners care about registration readiness and sensible <code>.loopover.yml</code>{" "}
configuration before promoting labels or maintainer-cut policy.
</p>
<ol>
Expand Down
9 changes: 5 additions & 4 deletions apps/gittensory-ui/src/routes/docs.github-app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -223,12 +223,13 @@ GET /v1/installations/:id/repair`}
</p>

<h2>
Configure as code (<code>.gittensory.yml</code>)
Configure as code (<code>.loopover.yml</code>)
</h2>
<p>
Every setting can be committed to <code>.gittensory.yml</code> at the repo root instead of,
or layered over, the dashboard. Precedence is <code>.gittensory.yml</code> &gt; repository
settings &gt; safe defaults; an unset field falls back to the next layer. It only chooses{" "}
Every setting can be committed to <code>.loopover.yml</code> at the repo root instead of, or
layered over, the dashboard (the legacy <code>.gittensory.yml</code> name also still works,
indefinitely — #4773). Precedence is <code>.loopover.yml</code> &gt; repository settings
&gt; safe defaults; an unset field falls back to the next layer. It only chooses{" "}
<em>what</em> LoopOver does — a configured blocker gates every author identically,
regardless of config.
</p>
Expand Down
7 changes: 4 additions & 3 deletions apps/gittensory-ui/src/routes/docs.gittensory-commands.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ function GittensoryCommandsReference() {
<DocsPage
eyebrow="Commands"
title="@gittensory command reference"
description="The full PR and issue-comment control surface: Q&A verbs, maintainer digests, and PR action commands. Roles reflect the shipped default policy; maintainers can override per command in .gittensory.yml."
description="The full PR and issue-comment control surface: Q&A verbs, maintainer digests, and PR action commands. Roles reflect the shipped default policy; maintainers can override per command in .loopover.yml (or legacy .gittensory.yml)."
>
<Callout variant="safety" title="Gate vs auto-review">
Commands never flip the gate to advisory and never bypass the one-shot disposition.{" "}
Expand All @@ -126,8 +126,9 @@ function GittensoryCommandsReference() {
<h2>Per-command authorization overrides</h2>
<p>
Default allowed roles ship in the worker configuration. A maintainer can tighten or widen a
single verb via <code>commandAuthorization</code> in <code>.gittensory.yml</code> (resolved
in the same order as other per-repo settings: manifest → database → defaults).
single verb via <code>commandAuthorization</code> in <code>.loopover.yml</code> (or legacy{" "}
<code>.gittensory.yml</code>, #4773; resolved in the same order as other per-repo settings:
manifest → database → defaults).
</p>
<CodeBlock
lang="yaml"
Expand Down
9 changes: 5 additions & 4 deletions apps/gittensory-ui/src/routes/docs.how-reviews-work.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,10 @@ function HowReviewsWork() {
defaults.
</p>
<Callout variant="safety">
Defaults are quiet. With no settings and no <code>.gittensory.yml</code>, the gate is{" "}
<code>off</code>, AI review is <code>off</code>, and the comment is posted only to detected
contributors. Every capability is an explicit opt-in.
Defaults are quiet. With no settings and no <code>.loopover.yml</code> (or legacy{" "}
<code>.gittensory.yml</code>, #4773), the gate is <code>off</code>, AI review is{" "}
<code>off</code>, and the comment is posted only to detected contributors. Every capability
is an explicit opt-in.
</Callout>

<h2>1. The gate: advisory vs. block</h2>
Expand Down Expand Up @@ -169,7 +170,7 @@ function HowReviewsWork() {
author on any repo, with no confirmed-contributor tracking at all).
</p>
<CodeBlock
filename=".gittensory.yml"
filename=".loopover.yml"
code={`gate:
enabled: true
pack: gittensor
Expand Down
Loading
Loading