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
4 changes: 2 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -509,12 +509,12 @@ REDIS_URL=redis://redis:6379 # REQUIRED for the self-host review
# GRAFANA_REPORTING_EXPORT_INTERVAL_SECONDS=30 # refresh cadence for the redacted reporting SQLite export
# LOOPOVER_REPORTING_SOURCE_DB=/appdb/loopover.sqlite # if DATABASE_PATH=/data/custom.sqlite, set /appdb/custom.sqlite
#
# AMS (gittensory-miner) ledger dashboards — only useful when a miner ALSO runs on this same host (see
# AMS (loopover-miner) ledger dashboards — only useful when a miner ALSO runs on this same host (see
# packages/gittensory-miner/docs/observability.md). Requires --profile ams-observability, separate from the
# general observability profile above: an engine-only deployment has nothing for this exporter to read.
# Grafana never mounts the live ledgers directly — this exporter reads them read-only and writes a redacted
# snapshot (free-form attempt_log_events.reason/.payload_json dropped) into the same reporting volume.
# LOOPOVER_MINER_CONFIG_DIR=~/.config/gittensory-miner # host dir the exporter mounts read-only at /ams-ledgers
# LOOPOVER_MINER_CONFIG_DIR=~/.config/loopover-miner # host dir the exporter mounts read-only at /ams-ledgers
# LOOPOVER_AMS_REPORTING_EXPORT_INTERVAL_SECONDS=30 # refresh cadence for the redacted AMS ledger exports
#
# Claude usage telemetry → OTEL collector → Prometheus → the Claude usage dashboard. OFF by default.
Expand Down
8 changes: 4 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ alertmanager/*_url
alertmanager/*_url_file
# Private self-host operator config. Root AGENTS.md/CLAUDE.md are public project docs;
# repo-scoped review instructions live under this ignored mount.
gittensory-config/
gittensory-config.backup-*/
loopover-config/
loopover-config.backup-*/
# Operator deploy-backup snapshots -- contains raw .env/.yml backups and config tarballs, same
# exposure class as gittensory-config/ above (secrets + private review rules), just under a
# exposure class as loopover-config/ above (secrets + private review rules), just under a
# different directory name that the pattern above does not match.
.deploy-backups/
# Codex/CLI auth state must only live in runtime volumes or operator home dirs.
Expand All @@ -55,7 +55,7 @@ apps/gittensory-ui/public/downloads/loopover-extension.zip
.worker-configuration.gen-check.d.ts
# Ad-hoc operator backup files (e.g. `cp file.yml file.yml.bak-notes-20260707`) -- general
# catch-alls so a stray manual snapshot never dirties `git status` on a Git-backed self-host
# checkout. Trailing on purpose: the narrower gittensory-config.backup-*/ and .deploy-backups/
# checkout. Trailing on purpose: the narrower loopover-config.backup-*/ and .deploy-backups/
# rules above already cover their specific directories, and nothing tracked in the repo matches
# either pattern (verified via `git ls-files | grep -E '\.bak-|\.backup-'`) (#1660).
*.bak-*
Expand Down
8 changes: 4 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Self-host image for gittensory-api (#980). Runs the SAME Worker handlers on Node via src/server.ts —
# Self-host image for loopover-api (#980). Runs the SAME Worker handlers on Node via src/server.ts —
# the Cloudflare bindings become self-host adapters (D1 -> node:sqlite, Queue -> in-process). The hosted
# Cloudflare Worker (wrangler) deploy is unaffected. SECRETS ARE NEVER BAKED: supply them at run time via
# the .env file or mounted *_FILE secrets (see docker-compose.yml + .env.example).
Expand All @@ -13,7 +13,7 @@ WORKDIR /app
# (workspaces: apps/*, packages/*), and `npm ci` only symlinks node_modules/<pkg> to a workspace whose
# directory already exists on disk. Copying just the root package*.json first (the usual dependency-layer
# caching trick) left every workspace package.json missing at `npm ci` time, so npm silently skipped every
# internal symlink -- @loopover/engine (a workspace dependency of gittensory-miner's checked-in
# internal symlink -- @loopover/engine (a workspace dependency of loopover-miner's checked-in
# lib/*.js artifacts, #2281) then couldn't be resolved by esbuild no matter how/when its own dist/ was built.
COPY . .
# --ignore-scripts: no native builds are needed (SQLite is the built-in node:sqlite; @hono/node-server is
Expand All @@ -32,7 +32,7 @@ ARG LOOPOVER_VERSION=
ENV NODE_ENV=production \
PLATFORM=self-hosted \
PORT=8787 \
DATABASE_PATH=/data/gittensory.sqlite \
DATABASE_PATH=/data/loopover.sqlite \
MIGRATIONS_DIR=/app/migrations \
NPM_CONFIG_PREFIX=/home/node/.npm-global \
LOOPOVER_VERSION=${LOOPOVER_VERSION}
Expand Down Expand Up @@ -96,7 +96,7 @@ FROM runtime-base AS runtime-prebuilt
COPY --chown=node:node dist/server.mjs ./dist/server.mjs
COPY --chown=node:node migrations ./migrations
# Generic, safe self-host private-config templates (config/examples/, #layered-private-config) — reference only.
# GITTENSORY_REPO_CONFIG_DIR still points at the operator-mounted /config, so shipping these activates nothing.
# LOOPOVER_REPO_CONFIG_DIR still points at the operator-mounted /config, so shipping these activates nothing.
COPY --chown=node:node config/examples ./config/examples

# Default local/operator builds still build the bundle inside Docker, but only the JS bundle reaches runtime.
Expand Down
4 changes: 2 additions & 2 deletions apps/gittensory-miner-ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ fleet/bare-host operator who wants the dashboard durably available, `npm run bui
`vite-*-api.ts` plugins register for both `configureServer` and `configurePreviewServer`, so nothing
extra is needed beyond the build step) on port `4174` by default.

[`systemd/gittensory-miner-ui.service.example`](../../systemd/gittensory-miner-ui.service.example) at
[`systemd/loopover-miner-ui.service.example`](../../systemd/loopover-miner-ui.service.example) at
the repo root is a ready-to-adapt persistent unit for this — a companion to
`gittensory-miner.service.example` (the loop daemon), not a replacement for it. Its header comment
`loopover-miner.service.example` (the loop daemon), not a replacement for it. Its header comment
carries the full install steps. Like the loop daemon, this is a `Type=simple` service, not a `.timer`
job — the dashboard is a long-running HTTP server, not a periodic batch task.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,9 +223,9 @@ function MaintainerSelfHosting() {
<code>Checks: write</code> included — re-approve on existing Apps after permission bumps).
</li>
<li>
Mount <code>./gittensory-config</code> and copy{" "}
Mount <code>./loopover-config</code> and copy{" "}
<code>config/examples/global.loopover.yml</code> →{" "}
<code>gittensory-config/.loopover.yml</code> for a centralized private default (per-repo
<code>loopover-config/.loopover.yml</code> for a centralized private default (per-repo
files deep-merge on top).
</li>
<li>
Expand All @@ -245,12 +245,12 @@ function MaintainerSelfHosting() {
{
title: "Single-command repo onboarding",
description:
"Today: edit .env allowlist, copy YAML templates, sign into the panel, click activate. Proposed: one CLI/API command that adds owner/repo to LOOPOVER_REVIEW_REPOS, seeds gittensory-config/owner__repo/.loopover.yml from global.loopover.yml, and POSTs activation — idempotent, dry-run aware.",
"Today: edit .env allowlist, copy YAML templates, sign into the panel, click activate. Proposed: one CLI/API command that adds owner/repo to LOOPOVER_REVIEW_REPOS, seeds loopover-config/owner__repo/.loopover.yml from global.loopover.yml, and POSTs activation — idempotent, dry-run aware.",
},
{
title: "Centralized private default only",
description:
"Most fleets need one gittensory-config/.loopover.yml with optional per-repo overrides — docs now treat that as the default story instead of implying every repo needs its own file.",
"Most fleets need one loopover-config/.loopover.yml with optional per-repo overrides — docs now treat that as the default story instead of implying every repo needs its own file.",
},
{
title: "Advisory-by-default on first install",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,16 +135,16 @@ function SelfHostingConfiguration() {
cp config/examples/loopover.minimal.yml .loopover.yml

# Self-host private mount (operator-only policy)
mkdir -p gittensory-config
cp config/examples/global.loopover.yml gittensory-config/.loopover.yml`}
mkdir -p loopover-config
cp config/examples/global.loopover.yml loopover-config/.loopover.yml`}
/>
<Callout variant="note">
Keep anti-abuse thresholds, maintainer allowlists, and autonomy dials in the{" "}
<strong>private</strong> mount — not in a public <code>.loopover.yml</code> contributors can
read. <code>config/examples/TEMPLATES.md</code> documents the public-vs-private split and
how to apply the templates to <code>gittensory</code>, <code>awesome-claude</code>, and{" "}
<code>metagraphed</code> without committing private policy. Lint before deploy:{" "}
<code>npx tsx scripts/gittensory-config-lint.ts path/to/.loopover.yml</code>.
<code>npx tsx scripts/loopover-config-lint.ts path/to/.loopover.yml</code>.
</Callout>
<p>Authoritative copies in git:</p>
<ul>
Expand Down Expand Up @@ -459,7 +459,7 @@ LOOPOVER_REVIEW_REPUTATION=false`}
</p>
<CodeBlock
filename="config directory"
code={`gittensory-config/
code={`loopover-config/
owner__repo/.loopover.yml
repo-name/.loopover.yml
owner__repo.yml
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ function SelfHostingDocsAudit() {
deterministic review are verified; each has explicit enablement switches.
</li>
<li>
<strong>Operator-owned paths:</strong> <code>gittensory-config/</code>,{" "}
<strong>Operator-owned paths:</strong> <code>loopover-config/</code>,{" "}
<code>loopover-data</code>, and secrets via <code>.env</code> or <code>*_FILE</code>{" "}
mounts — never baked into images.
</li>
Expand Down
20 changes: 10 additions & 10 deletions apps/gittensory-ui/src/routes/docs.self-hosting-operations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -937,8 +937,8 @@ SENTRY_ORG_SLUG=<your-sentry-org-slug>
<code>LOOPOVER_VERSION</code> (source path).
</li>
<li>
<code>./gittensory-config/</code> bind mount — private per-repo{" "}
<code>.loopover.yml</code> policy.
<code>./loopover-config/</code> bind mount — private per-repo <code>.loopover.yml</code>{" "}
policy.
</li>
<li>
Named data volumes — especially <code>loopover-data</code> (SQLite DB, Codex/Claude auth
Expand Down Expand Up @@ -984,7 +984,7 @@ SENTRY_ORG_SLUG=<your-sentry-org-slug>
<code>cp docker-compose.yml docker-compose.yml.bak-notes-20260707</code> does not count
against this — the trailing <code>*.bak-*</code>/<code>*.backup-*</code> patterns in{" "}
<code>.gitignore</code> keep stray manual backups out of <code>git status</code> entirely,
on top of the narrower <code>gittensory-config.backup-*/</code> and{" "}
on top of the narrower <code>loopover-config.backup-*/</code> and{" "}
<code>.deploy-backups/</code> patterns that already covered those specific directories.
<code>scripts/selfhost-update.sh</code> (below) checks this for you and refuses to
continue on a dirty tree.
Expand Down Expand Up @@ -1048,10 +1048,10 @@ GITTENSORY_IMAGE=ghcr.io/jsonbored/loopover-selfhost@sha256:... ./scripts/deploy
</p>
<p>
None of this touches operator-owned state: <code>.env</code>, the{" "}
<code>gittensory-config/</code> mount, <code>.deploy-backups/</code>, any{" "}
<code>*.local</code> or <code>docker-compose.local-*.yml</code> compose override, or
Alertmanager file, and every named data volume are already gitignored or outside the source
tree entirely, so a fetch-and-rebuild never touches them. See the{" "}
<code>loopover-config/</code> mount, <code>.deploy-backups/</code>, any <code>*.local</code>{" "}
or <code>docker-compose.local-*.yml</code> compose override, or Alertmanager file, and every
named data volume are already gitignored or outside the source tree entirely, so a
fetch-and-rebuild never touches them. See the{" "}
<Link to="/docs/self-hosting-quickstart">Quickstart</Link> for the initial clone; this
script assumes that checkout already exists and already tracks <code>origin/main</code>.
</p>
Expand Down Expand Up @@ -1191,8 +1191,8 @@ docker inspect --format '{{.Config.Image}}' "$(docker compose ps -q loopover)"`}
<code>docker compose down</code> (without <code>-v</code>) leaves every named volume (
<code>loopover-data</code>, <code>loopover-pg</code>, <code>qdrant-data</code>,{" "}
<code>loopover-backups</code>, <code>grafana-data</code>, and the rest declared in{" "}
<code>docker-compose.yml</code>) on disk, along with the <code>./gittensory-config</code>{" "}
host directory (a bind mount, not a named volume, so it is never affected by <code>-v</code>{" "}
<code>docker-compose.yml</code>) on disk, along with the <code>./loopover-config</code> host
directory (a bind mount, not a named volume, so it is never affected by <code>-v</code>{" "}
either way). Pick one:
</p>
<FeatureRow
Expand All @@ -1210,7 +1210,7 @@ docker inspect --format '{{.Config.Image}}' "$(docker compose ps -q loopover)"`}
{
title: "Delete everything",
description:
"docker compose down -v removes every named volume permanently — the review database, vector index, Grafana dashboards state, and any local backup archives in loopover-backups go with it. This does not touch ./gittensory-config (delete that host directory yourself if it should go too).",
"docker compose down -v removes every named volume permanently — the review database, vector index, Grafana dashboards state, and any local backup archives in loopover-backups go with it. This does not touch ./loopover-config (delete that host directory yourself if it should go too).",
},
]}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,11 +226,11 @@ SELFHOST_DEPLOYMENT_MODE=dry-run # keep shadowing until you trust output`}
</p>
<CodeBlock
lang="bash"
code={`mkdir -p gittensory-config
cp config/examples/global.loopover.yml gittensory-config/.loopover.yml
code={`mkdir -p loopover-config
cp config/examples/global.loopover.yml loopover-config/.loopover.yml
# optional per-repo override:
mkdir -p gittensory-config/owner__my-repo
cp config/examples/global.loopover.yml gittensory-config/owner__my-repo/.loopover.yml`}
mkdir -p loopover-config/owner__my-repo
cp config/examples/global.loopover.yml loopover-config/owner__my-repo/.loopover.yml`}
/>
<p>
Sign in to the control panel (<code>ADMIN_GITHUB_LOGINS</code> must include your GitHub
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ git push origin orb-v0.1.0`}
</td>
<td className="py-2 align-top text-muted-foreground">
Only the <code>gittensory</code> service restarts (<code>--no-deps</code>);{" "}
<code>.env</code>, data volumes, and <code>gittensory-config/</code> are untouched;{" "}
<code>.env</code>, data volumes, and <code>loopover-config/</code> are untouched;{" "}
<code>/ready</code> returns 200 after the health-check wait.
</td>
</tr>
Expand Down Expand Up @@ -538,7 +538,7 @@ docker rm -f gt-qdrant && docker network rm gt-rag-smoke`}
{
title: "Private repo config — NOT included",
description:
"gittensory-config and **/gittensory-config are excluded via .dockerignore; only the generic config/examples/ reference templates are copied, and LOOPOVER_REPO_CONFIG_DIR is resolved against an operator-mounted /config at runtime.",
"loopover-config and **/loopover-config are excluded via .dockerignore; only the generic config/examples/ reference templates are copied, and LOOPOVER_REPO_CONFIG_DIR is resolved against an operator-mounted /config at runtime.",
},
{
title: "Data volumes — NOT included",
Expand Down Expand Up @@ -675,7 +675,7 @@ The \`latest\` tag now points here.

## Operator-owned

- \`.env\`, \`gittensory-config/\`, and all data volumes (database, Redis, Qdrant, Grafana) — never
- \`.env\`, \`loopover-config/\`, and all data volumes (database, Redis, Qdrant, Grafana) — never
overwritten by an update and never baked into the image.
- GitHub App credentials or \`ORB_ENROLLMENT_SECRET\`, AI-provider credentials, and any \`SENTRY_DSN\`.
- Resource limits and profile selection — see [Resource profiles](https://gittensory.aethereal.dev/docs/self-hosting-operations)
Expand Down
16 changes: 8 additions & 8 deletions config/examples/TEMPLATES.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ for precedence and deep-merge rules.

**Never commit real private policy** (maintainer logins, thresholds, autonomy dials you do not want
contributors to read) into a public repository. Copy `global.loopover.yml` into your gitignored
`gittensory-config/` mount and edit there.
`loopover-config/` mount and edit there.

## Quick start

Expand All @@ -53,16 +53,16 @@ cp config/examples/loopover.minimal.yml .loopover.yml
### Self-host private mount (operator-only policy)

```bash
mkdir -p gittensory-config
cp config/examples/global.loopover.yml gittensory-config/.loopover.yml
mkdir -p loopover-config
cp config/examples/global.loopover.yml loopover-config/.loopover.yml
# edit your-admin-login placeholders before going live
# optional per-repo overlay:
mkdir -p gittensory-config/myorg__myrepo
cp config/examples/repo-override.loopover.yml gittensory-config/myorg__myrepo/.loopover.yml
mkdir -p loopover-config/myorg__myrepo
cp config/examples/repo-override.loopover.yml loopover-config/myorg__myrepo/.loopover.yml
```

Point `GITTENSORY_REPO_CONFIG_DIR` at that directory (default `/config` in `docker-compose.yml` maps
`./gittensory-config`).
`./loopover-config`).

## Fleet examples (without committing private policy)

Expand All @@ -73,7 +73,7 @@ into public git** — use the private mount for anything marked *private* below.

- **Public** `.loopover.yml` in the repo: work-area guardrails, test expectations, gate dimensions
contributors should understand.
- **Private** `gittensory-config/` (gitignored locally, operator mount in production): fleet
- **Private** `loopover-config/` (gitignored locally, operator mount in production): fleet
autonomy, anti-abuse caps, maintainer exemption lists — the same split described in
[`global.loopover.yml`](./global.loopover.yml).
- Start from `loopover.minimal.yml` in the public repo until gate semantics are tuned, then promote
Expand Down Expand Up @@ -101,5 +101,5 @@ Every template in this directory is parsed in CI (`test/unit/config-templates.te
`.loopover.yml.example` from `# WHERE IT LIVES` onward. Lint a local file before deploy:

```bash
npx tsx scripts/gittensory-config-lint.ts path/to/.loopover.yml
npx tsx scripts/loopover-config-lint.ts path/to/.loopover.yml
```
2 changes: 1 addition & 1 deletion config/examples/global.loopover.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# ============================================================================
#
# Copy this file to the ROOT of your own GITTENSORY_REPO_CONFIG_DIR mount (e.g.
# `./gittensory-config/.loopover.yml` for the default docker-compose.yml mount) and edit your
# `./loopover-config/.loopover.yml` for the default docker-compose.yml mount) and edit your
# copy — never this one. It applies to every repo that has no per-repo file of its own, and is
# deep-merged UNDER any per-repo file that does exist (see ../README.md for the precedence chain
# and merge semantics; see ../../.loopover.yml.example at the repo root for every supported
Expand Down
Loading
Loading