feat(sources): admin page to add and remove git sources (TODO.md L4)
This commit is contained in:
@@ -65,16 +65,21 @@ uv run python -m scripts.import_docs # import the configured sources (below)
|
||||
|
||||
Two source modes:
|
||||
|
||||
- **Git sources (recommended)** — set `BOR_GIT_SOURCES` in `.env` to a
|
||||
comma-separated list of git repo URLs. `import_docs` clones each repo
|
||||
- **Git sources (recommended)** — the list is managed on the **admin
|
||||
Git sources page** (`/git-sources.html`) and stored in Postgres (see
|
||||
[Git-based sources](#git-based-sources)). `import_docs` clones each repo
|
||||
(first run) or pulls it (subsequent runs) into
|
||||
`BOR_SOURCES_DIR/<repo-name>/` (default `~/bor-sources`) and indexes the
|
||||
checkouts — see [Git-based sources](#git-based-sources).
|
||||
checkouts. While the stored list is empty, the `BOR_GIT_SOURCES` variable
|
||||
in `.env` is the fallback — the moment the page stores a source, the
|
||||
variable is ignored.
|
||||
- **Manual directories** — `--source <path>` (repeatable) imports local
|
||||
directories directly and *always wins* over `BOR_GIT_SOURCES`.
|
||||
- If neither is set, the import falls back to the **previous** default,
|
||||
directories directly and *always wins* over the git sources (stored list
|
||||
or env).
|
||||
- If neither is set (stored list, `--source`, and `BOR_GIT_SOURCES` all
|
||||
empty), the import falls back to the **previous** default,
|
||||
`~/Homelab` + `~/Deployments` — kept only for backwards compatibility,
|
||||
now replaced by `BOR_GIT_SOURCES`.
|
||||
now replaced by the git sources list.
|
||||
|
||||
### 6. Run the app
|
||||
```bash
|
||||
@@ -102,6 +107,12 @@ uv run uvicorn app.main:app --reload
|
||||
new tab). **Admin-only** — anonymous visitors see a sign-in gate instead
|
||||
(the catalog is what the login locks; the document viewer itself stays
|
||||
open to everyone).
|
||||
- **Git sources** (`/git-sources.html`) — the list of git repositories the
|
||||
**Sync sources** button clones and indexes; **admin-only** (the same
|
||||
sign-in gate as Sources). Add or remove repositories here — no `.env`
|
||||
editing, no restart. Adding/removing does not clone or prune on its
|
||||
own: the Sync button performs that, and a removed repository's documents
|
||||
leave the index on the next sync.
|
||||
|
||||
## Thinking
|
||||
|
||||
@@ -262,26 +273,38 @@ embedded.
|
||||
|
||||
Rather than pointing the import at local folders, point it at **git
|
||||
repositories** — the notes live in the repos and `import_docs` keeps local
|
||||
checkouts of them up to date for you:
|
||||
checkouts of them up to date for you.
|
||||
|
||||
**Where the list lives (phase 35):** the primary management surface is
|
||||
the **admin Git sources page** (`/git-sources.html`) — add or remove
|
||||
repositories there and the list is stored in Postgres (the `git_sources`
|
||||
table). `BOR_GIT_SOURCES` in `.env` is the **empty-table fallback**: it
|
||||
only applies while the stored list is empty, and is ignored once the page
|
||||
has any row (the page becomes the source of truth — no `.env` editing, no
|
||||
restart needed afterwards).
|
||||
|
||||
```env
|
||||
# .env
|
||||
# .env — the fallback list (fresh setups, or until the admin page
|
||||
# stores a source; phase 35 demotes this variable, it does not remove it)
|
||||
BOR_GIT_SOURCES=https://git.reeseapps.com/reese/homelab.git,git@github.com:reese/deployments.git
|
||||
BOR_SOURCES_DIR=~/bor-sources # default; each repo lands in <dir>/<repo-name>/
|
||||
```
|
||||
|
||||
- `BOR_GIT_SOURCES` is a **comma-separated list** of URLs. Auth is whatever
|
||||
the machine supplies — `https://…` via the OS credential helper, or
|
||||
`git@host:repo.git` via your SSH key; no credentials are stored in the
|
||||
app or `.env`.
|
||||
- The effective list (stored rows, else `BOR_GIT_SOURCES` while the stored
|
||||
list is empty) is a set of git repo URLs. Auth is whatever the machine
|
||||
supplies — `https://…` via the OS credential helper, or `git@host:repo.git`
|
||||
via your SSH key; no credentials are stored in the app or `.env`.
|
||||
Stored URLs are shape-validated on the page (`https://`, `ssh://`,
|
||||
`git@…` — scp-style `host:repo` is rejected).
|
||||
- Every run **clones** each repo (first time, shallow `--depth 1`) or
|
||||
**pulls** it (`git pull --ff-only` — fast-forward only, so a diverged or
|
||||
broken checkout fails loudly instead of merging) into
|
||||
`BOR_SOURCES_DIR/<repo-name>/`, then indexes the checkouts exactly like
|
||||
any local directory (A9 format filter, hidden-dir skip, sha256 delta).
|
||||
`documents.source` is the repo directory name (e.g. `homelab`).
|
||||
- **`--source <path>` overrides**: when the flag is given,
|
||||
`BOR_GIT_SOURCES` is ignored and the manual directory(ies) are imported.
|
||||
- **`--source <path>` overrides**: when the flag is given, the git
|
||||
sources (stored list *and* `BOR_GIT_SOURCES`) are ignored and the
|
||||
manual directory(ies) are imported.
|
||||
- **A failed sync aborts the run**: if any repo cannot be cloned/pulled,
|
||||
`import_docs` exits non-zero naming the failing repo and imports
|
||||
**nothing** (no partial junk). Fix the URL/connectivity and re-run — the
|
||||
@@ -293,9 +316,10 @@ The **Sync sources** button on the **Sources** page — visible to the
|
||||
**admin only** (anonymous visitors never see it) — runs the whole
|
||||
git-source refresh in one click, in-process:
|
||||
|
||||
1. **clone/pull** every `BOR_GIT_SOURCES` repo (the same
|
||||
`clone_or_pull` the CLI uses — shallow clone on first run,
|
||||
`git pull --ff-only` afterwards);
|
||||
1. **clone/pull** every configured git source — the admin-managed list
|
||||
(the `git_sources` table; `BOR_GIT_SOURCES` only while that list is
|
||||
empty), through the same `clone_or_pull` the CLI uses (shallow clone
|
||||
on first run, `git pull --ff-only` afterwards);
|
||||
2. **re-import with prune** — the `--prune` equivalent, so files deleted
|
||||
upstream leave the index (the button is the canonical "mirror the
|
||||
repos" action); the sha256 delta still skips unchanged files, so an
|
||||
@@ -304,10 +328,12 @@ git-source refresh in one click, in-process:
|
||||
chat turn injects) — but only when the import actually changed the
|
||||
knowledge base.
|
||||
|
||||
- **Prerequisites:** `BOR_GIT_SOURCES` must be set — an unset/empty list
|
||||
fails the sync loudly ("no git sources configured"), because the button
|
||||
targets the git repos only (manual `--source` directories have no repo
|
||||
to clone) — and `git` must be on the app's `PATH`.
|
||||
- **Prerequisites:** at least one git source must be configured — a row
|
||||
on the admin Git sources page, or `BOR_GIT_SOURCES` in `.env` while the
|
||||
stored list is empty; **both** empty fails the sync loudly ("no git
|
||||
sources configured"), because the button targets the git repos only
|
||||
(manual `--source` directories have no repo to clone) — and `git` must
|
||||
be on the app's `PATH`.
|
||||
- **States:** clicking starts the run (`202`) and the button goes
|
||||
disabled with **Syncing…** (spinning icon) while the page polls
|
||||
`GET /api/sync/status` every 2 s. There is deliberately **no
|
||||
@@ -534,8 +560,8 @@ served locally (no CDN), `BOR_ENVIRONMENT=production`.
|
||||
| `BOR_HYBRID_LEXICAL_CANDIDATES` | `30` | FTS list width for the RRF fusion |
|
||||
| `BOR_RRF_K` | `60` | RRF damping constant (`1/(k + rank)`) |
|
||||
| `BOR_IMPORT_EXTENSIONS` | `md,markdown,txt,yaml,yml,json,py` | csv of importable formats (may only narrow the A9 set) |
|
||||
| `BOR_GIT_SOURCES` | — (empty) | csv of git repo URLs; `import_docs` clones/pulls them into `BOR_SOURCES_DIR` and indexes the checkouts (see *Git-based sources*) |
|
||||
| `BOR_SOURCES_DIR` | `~/bor-sources` | where the `BOR_GIT_SOURCES` repos are cloned/pulled (one subdirectory per repo) |
|
||||
| `BOR_GIT_SOURCES` | — (empty) | csv of git repo URLs — **fallback while the admin Git sources page's list (Postgres `git_sources`) is empty**; the page is the primary management surface (see *Git-based sources*) |
|
||||
| `BOR_SOURCES_DIR` | `~/bor-sources` | where the git source repos are cloned/pulled (one subdirectory per repo) |
|
||||
| `BOR_STEERING_MAX_CHARS` | `8000` | char budget for the `<tuning>` (steering notes) prompt section |
|
||||
| `BOR_SUMMARY_MAX_CHARS` | `12000` | cap on document content sent to the `lite` summary model at import (see *Document summaries*) |
|
||||
| `BOR_KB_OVERVIEW_MAX_CHARS` | `4000` | char budget for the `<knowledge_base>` (KB overview) prompt section |
|
||||
|
||||
Reference in New Issue
Block a user