Skip to content

Commit 1677d57

Browse files
authored
Merge pull request #110 from jsilvanus/claude/whatnext-planning-n0bndq
Design + schedule: multi-tenant auth, public-repo sharing, locked model sets
2 parents 4d87c08 + 0c375eb commit 1677d57

5 files changed

Lines changed: 1133 additions & 13 deletions

File tree

docs/PLAN.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4691,6 +4691,67 @@ that deprecated it, and its removal status.
46914691

46924692
---
46934693

4694+
## Multi-Tenant Auth Track (Phases 122–125)
4695+
4696+
> **Full design:** [`docs/multi-tenant-auth-plan.md`](multi-tenant-auth-plan.md)
4697+
> is the single design reference for this track (current-state assessment,
4698+
> the identity/membership/grant axis model, personal groups, and Phases
4699+
> A–D). Phase A has no dependents blocking it; Phase B hard-depends on
4700+
> Phase A; Phase C depends only on Phase A; Phase D can slip independently
4701+
> of all three. Phase entries below use the next free top-level phase
4702+
> numbers after 121.
4703+
4704+
| Phase | Spec section | Title | Deliverable |
4705+
|---|---|---|---|
4706+
| **122** | §5 Phase A | Identity & credentials core | New `users`/`sessions`/`api_keys` tables; `POST /api/v1/auth/login`/`logout`/`tokens` routes; `authMiddleware` extended to try user-credential resolution first, falling back to today's legacy `GITSEMA_SERVE_KEY`/`repo_tokens` path; CLI `gitsema auth login/logout/token */whoami`. No authorization changes yet — identity only. |
4707+
| **123** | §5 Phase B | Orgs, personal groups, repo/branch grants, self-service | New `orgs` (`kind: personal\|team`)/`org_members`/`repo_grants` tables; nullable `repos.org_id`; `auth.personalGroups`/`GITSEMA_PERSONAL_GROUPS` config gate (default `true`) auto-provisioning a one-member personal org per new user; `gitsema repos move-to-org`; branch-pattern grants requiring `branch: string``string \| string[]` across ~16 routes; CLI `gitsema orgs */repos grant/grants list/revoke/move-to-org`, `gitsema users create/list`; `docs/deprecations.md` row for `repo_tokens`. |
4708+
| **124** | §5 Phase C | SSO/OIDC linking | New `sso_identities` table; `gitsema auth login <server-url> --sso <provider>` device-code-style flow; provider allowlist config; first new third-party dependency (an OIDC client library) — flagged against CLAUDE.md's minimal-deps preference. |
4709+
| **125** | §5 Phase D | Audit log | New `audit_log` table (actor, action, target, timestamp); `gitsema audit log [--org][--repo]` CLI; records `org.repo.moved` and other Phase B/C actions. Lowest priority of the track, no hard dependents. |
4710+
4711+
**Status:** not started — draft design, scheduled here per `/phase-plan`.
4712+
4713+
---
4714+
4715+
## Public Repo Sharing Track (Phases 126–127)
4716+
4717+
> **Full design:** [`docs/public-repo-sharing-plan.md`](public-repo-sharing-plan.md)
4718+
> is the single design reference for this track (visibility flag,
4719+
> attach-as-reader auto-grants, first-index gate, refresh throttle). Both
4720+
> phases hard-depend on the Multi-Tenant Auth Track's Phase A (122) and
4721+
> Phase B (123) landing first — there is no `users`/`repo_grants` model to
4722+
> attach a reader grant to otherwise.
4723+
4724+
| Phase | Spec section | Title | Deliverable |
4725+
|---|---|---|---|
4726+
| **126** | §5 Phase 1 | Visibility flag + attach-as-reader | `repos.visibility` (`'private'\|'public'`, default `'private'`) + `ownerUserId` columns; `gitsema repos visibility <repoId> public\|private` CLI (owner/superadmin only); registration-flow change in `src/server/routes/remote.ts` auto-issuing a `repo_grants` reader row when a second user attaches to an existing public repo's shared index. |
4727+
| **127** | §5 Phase 2 | First-index gate + refresh throttle | `auth.allowPublicAutoIndex`/`GITSEMA_PUBLIC_AUTO_INDEX` config gate (default `false`) restricting who may register a brand-new public-flagged repo; `auth.minReindexIntervalSeconds` per-`(user, repoId)` refresh throttle returning `429`/`Retry-After`. No hard dependency on Phase 126 beyond the `visibility` column existing. |
4728+
4729+
**Status:** not started — draft design, scheduled here per `/phase-plan`.
4730+
Explicitly out of scope (per the design doc §6): cross-repo blob-level dedup
4731+
for forks with different URLs ("shape 2") remains undesigned and unscheduled.
4732+
4733+
---
4734+
4735+
## Superadmin-Locked Model Set Track (Phases 128–130)
4736+
4737+
> **Full design:** [`docs/locked-model-set-plan.md`](locked-model-set-plan.md)
4738+
> is the single design reference for this track (multi-profile embedding
4739+
> serving, admin-gated enabled sets, never-persisted per-request BYOK).
4740+
> Phase 128 has no hard dependency on the role model and could ship before
4741+
> the Multi-Tenant Auth Track lands; Phase 129 hard-depends on that track's
4742+
> Phase A (122) and Phase B (123); Phase 130 has no hard dependency on
4743+
> Phase 128 but benefits from Phase 129's allow-list existing.
4744+
4745+
| Phase | Spec section | Title | Deliverable |
4746+
|---|---|---|---|
4747+
| **128** | §5 Phase 1 | Multi-profile embedding serving | Server config shape for N named embedding profiles; `gitsema tools serve` builds a `Map<profileName, {textProvider, codeProvider}>` instead of one global pair; `repos.profileName` column pinned at first index and immutable after; CLI `gitsema index start --profile <name>`, `gitsema repos info` surfacing the pinned profile. |
4748+
| **129** | §5 Phase 2 | Admin-gated enabled sets | Superadmin admin CLI/route enabling/disabling defined profiles and narrator/guide configs server-wide; org-level narrowing (never widening) reusing the Multi-Tenant Auth Track's org/role model; picker UX (pre-selected/disabled when exactly one profile is allowed, real picker otherwise). |
4749+
| **130** | §5 Phase 3 | BYOK for narrator/guide | Request-scoped credential field on `narrate`/`explain`/`guide` CLI/HTTP/MCP entry points; one-off provider construction via `createNarratorProviderFor()` with no persistence path; "lock to none" support (empty allow-list as a valid, tested state). |
4750+
4751+
**Status:** not started — draft design, scheduled here per `/phase-plan`.
4752+
4753+
---
4754+
46944755
## Deployment scenarios & usage envisioning
46954756

46964757
The architecture of gitsema supports three distinct deployment scenarios, each with different operational models and target users. This section clarifies the intended usage patterns and the infrastructure requirements for each.

docs/feature-ideas.md

Lines changed: 168 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
This document tracks upcoming feature ideas that are **not yet in active development** (not in `PLAN.md`) and haven't been **fully designed** (no design file). It's a staging area for "what now?" questions and medium-term product direction.
44

5-
**Last updated:** 2026-06-22
5+
**Last updated:** 2026-06-22 (refined public-repo sharing's access-control half into `docs/public-repo-sharing-plan.md` and the superadmin-locked model set idea into `docs/locked-model-set-plan.md`; kept cross-repo blob dedup as an open idea)
66
**Audience:** Developers considering next phases; product planning
77

88
> **Note:** As of this update, the LSP/MCP remote-delegation foundation this
@@ -156,25 +156,30 @@ A **managed platform** built on top of the self-hosted remote MCP foundation:
156156

157157
### Design Gaps
158158

159-
- [ ] `gitsema auth login`/`logout`/`token` commands (currently no `auth` command group — tokens are managed via `gitsema config set`/repo tokens today)
160-
- [ ] How are user credentials stored locally? (keychain integration?)
161-
- [ ] Token expiration & refresh flow?
162-
- [ ] What's the max index size per user tier?
163-
- [ ] Rate limits (queries/sec, indexing jobs/month)?
164-
- [ ] Team sharing (shared indexes, collaborative access)?
165-
- [ ] Audit logging (who indexed what, when)?
166-
- [ ] SLA and uptime guarantees?
167-
- [ ] Data residency (GDPR compliance)?
159+
> **Refined into:** the gitsema-side identity/auth/access-control work
160+
> (user accounts, `gitsema auth login/logout/token`, per-user per-repo
161+
> per-branch grants, org-scoped self-service, SSO linking) has been promoted
162+
> to its own design document: **[`docs/multi-tenant-auth-plan.md`](multi-tenant-auth-plan.md)**.
163+
> The gaps below are kept for history; see that doc for resolved answers and
164+
> the remaining genuinely-open questions.
165+
166+
- [x] `gitsema auth login`/`logout`/`token` commands — see `multi-tenant-auth-plan.md` §4.3, §5 Phase A.
167+
- [x] How are user credentials stored locally? — see `multi-tenant-auth-plan.md` §4.1 (follows the existing `config.json` plaintext-secret precedent, `~/.config/gitsema/credentials.json`, 0o600).
168+
- [x] Token expiration & refresh flow? — see `multi-tenant-auth-plan.md` §4.1 (sessions expire, API keys don't by default, `--expires` opt-in).
169+
- [x] Team sharing (shared indexes, collaborative access)? — see `multi-tenant-auth-plan.md` §4.2 (orgs, per-repo/per-branch `repo_grants`, org-scoped self-service).
170+
- [ ] What's the max index size per user tier? — still open; Semahub Layer-2 (billing/quota) territory, not gitsema-side.
171+
- [ ] Rate limits (queries/sec, indexing jobs/month)? — still open; per-user/org quotas explicitly out of scope for `multi-tenant-auth-plan.md` Phases A–D (see its §6), deferred to Semahub Layer 2.
172+
- [ ] Audit logging (who indexed what, when)? — partially addressed: `multi-tenant-auth-plan.md` §5 Phase D scopes a gitsema-side `audit_log` table, but it's the lowest-priority phase and may slip.
173+
- [ ] SLA and uptime guarantees? — still open; Semahub Layer-2.
174+
- [ ] Data residency (GDPR compliance)? — still open; Semahub Layer-2.
168175

169176
### MVP Scope
170177

171178
Start small:
172179
1. **Phase A (Semahub):** User signup, index storage, job queue
173-
2. **Phase B (gitsema, small):** `gitsema auth login/logout/token` convenience commands wrapping existing config/token plumbing
180+
2. **Phase B (gitsema):** see `docs/multi-tenant-auth-plan.md` for the now-fully-designed phased plan (Phases A–D there, ~1850–2550 LOC total) — supersedes the placeholder estimate that used to be here.
174181
3. **Phase C (Semahub):** Web dashboard, billing
175182

176-
**Total effort:** Semahub: 6-10 weeks (gitsema-side work is now minimal — a thin `auth` command group, ~200-300 LOC)
177-
178183
### Competitive Advantages
179184

180185
- **Integrated IDE experience:** CLI, LSP, MCP all work seamlessly
@@ -244,6 +249,156 @@ a language-specific structural extractor, or an org-specific compliance scan.
244249

245250
---
246251

252+
## Shared/Deduplicated Indexing for Public Repos
253+
254+
> **Refined into:** the access-control half of this idea (a `visibility`
255+
> flag, auto-granted read access when a user attaches to an existing public
256+
> repo, and abuse-resistant gating of first-index vs. refresh) has been
257+
> promoted to its own design document:
258+
> **[`docs/public-repo-sharing-plan.md`](public-repo-sharing-plan.md)**.
259+
> That doc's research also found that the storage/clone-duplication concern
260+
> this idea originally worried about is **already solved** today —
261+
> `src/core/indexing/repoRegistry.ts` already dedupes registrations by
262+
> normalized URL onto one clone/index DB, and re-indexing an unchanged repo
263+
> is already cheap (incremental + blob-hash dedup). See that doc's §2 for
264+
> the full citations.
265+
266+
The second, looser shape below — cross-repo blob-level dedup for forks with
267+
*different* URLs — was explicitly kept **out of scope** for that design (it's
268+
architecturally a much bigger lift) and remains here as a genuinely
269+
undesigned idea:
270+
271+
### Remaining open idea: partial index reuse / blob-level sharing across forks
272+
Even for different URLs (e.g. a fork), recognize when blobs are
273+
byte-identical (same blob hash — already how gitsema dedupes *within* one
274+
repo) and skip re-embedding those blobs server-wide, only embedding the
275+
genuinely new/changed blobs introduced by the fork.
276+
277+
- [ ] Requires re-scoping `blobs`/`embeddings` storage to be content-
278+
addressed *globally* rather than per-repo-DB file, cutting across the
279+
storage-backend abstraction (`src/core/storage/types.ts`) and every
280+
backend (sqlite/postgres/qdrant).
281+
- [ ] Needs a cross-repo identity for a blob beyond what one index DB knows
282+
— either a shared blob registry + per-repo lookup tables, or a
283+
sync/copy mechanism between DBs.
284+
- [ ] Interacts with whatever visibility/grant model
285+
`public-repo-sharing-plan.md` ships — sharing blobs across two
286+
*different* repos' indexes raises the same "who's allowed to read
287+
what" questions as that doc, just one level deeper (blob-level instead
288+
of repo-level).
289+
290+
### Effort Estimate
291+
- Substantial — comparable in size to the storage-backends work itself
292+
(multi-phase). Not estimated further until shape-1's access-control layer
293+
(`public-repo-sharing-plan.md`) ships and proves out the simpler case.
294+
295+
### Prerequisites
296+
- `docs/public-repo-sharing-plan.md` landing first (the visibility/grant
297+
model this would need to extend), and likely `multi-tenant-auth-plan.md`
298+
before that.
299+
300+
---
301+
302+
## Superadmin-Locked Model Set (Server-Side Model Allowlist)
303+
304+
> **Refined into:** **[`docs/locked-model-set-plan.md`](locked-model-set-plan.md)**.
305+
> That doc's research found that the embedding half of this idea needed a
306+
> genuinely new capability — a multi-tenant server has only ever had a
307+
> single, process-wide embedding model with no per-request override, so
308+
> "locking" it was previously a no-op; the design adds multi-profile serving
309+
> first, then admin/org-level enabled-set control on top. The narrator/guide
310+
> half was already multi-model today and just needed admin-gating + a
311+
> never-persisted BYOK path, both designed in that doc. The gaps below are
312+
> kept for history; see that doc for resolved answers and remaining open
313+
> questions.
314+
315+
### Problem
316+
- On a shared/multi-tenant server (`gitsema tools serve`), nothing today
317+
stops a user from indexing or querying with whatever
318+
`GITSEMA_MODEL`/`GITSEMA_TEXT_MODEL`/`GITSEMA_CODE_MODEL` they pass —
319+
there's no concept of an operator-controlled allowed set.
320+
- This matters most for **embedding models**: vectors from two different
321+
embedding models aren't comparable, so if a shared index's vectors mix
322+
models, search silently degrades or breaks. A server operator needs to be
323+
able to pin the server to one (or a small vetted few) embedding model(s)
324+
so every repo's index stays internally consistent.
325+
- It also applies to narrator/guide chat models (used by `narrate`/`explain`/
326+
`guide`), though the motivation there is different (cost/quality/abuse
327+
control of LLM calls) rather than vector compatibility.
328+
- There's currently no "superadmin" role concept at all in gitsema — today's
329+
server auth is a single global `GITSEMA_SERVE_KEY` plus per-repo
330+
`repo_tokens` (see `docs/multi-tenant-auth-plan.md` for the in-progress
331+
identity/role model this idea would need to sit on top of).
332+
333+
### Intended Behavior
334+
A server superadmin configures an **allowed model set** — separately for
335+
embedding models and for narrator/guide models — via a new admin CLI/API
336+
(not just a config file edit, per the answered design question, since this
337+
needs to be a controlled, auditable admin action once roles exist). Regular
338+
users:
339+
- When the allowed set has exactly one model, see it as a **pre-selected,
340+
disabled** choice (not an editable picker) wherever a model would
341+
otherwise be selectable (`index start --model`, `gitsema config set
342+
model`, etc.) — they always see *which* model is active, they just can't
343+
change it.
344+
- When the allowed set has more than one model, get a real picker limited to
345+
that set.
346+
- Can still **bring their own API key (BYOK)** to use a model of their own
347+
choosing for narrator/guide chat, even when the server's own default
348+
narrator/guide model is locked or disabled entirely ("lock to none" is an
349+
explicit valid server posture for chat — i.e. no server-provided chat
350+
model at all, BYOK-only). BYOK does not apply to embedding models, since
351+
BYOK embeddings would reintroduce the vector-incompatibility problem this
352+
idea exists to prevent.
353+
- Per the answered design question, the allowed set is **global by default**
354+
(set by the superadmin for the whole server) but an **org_admin may
355+
further narrow** (never widen) the set for their own org — layering on top
356+
of `docs/multi-tenant-auth-plan.md`'s org/role model rather than
357+
introducing a second, separate permission system.
358+
359+
### Design Gaps
360+
- [ ] The "superadmin" role doesn't exist yet — does it ride on top of
361+
`multi-tenant-auth-plan.md`'s eventual `org_admin`/user roles as a new
362+
server-wide role, or is it a separate concept (e.g. tied to whoever
363+
holds `GITSEMA_SERVE_KEY` today)? This idea is blocked on that role
364+
existing in some form.
365+
- [ ] Exact shape of the new admin CLI/API: `gitsema admin models allow
366+
<model> [--kind embedding|narrator]` / `gitsema admin models deny
367+
<model>`? An HTTP route under `/api/v1/admin/...`? Both?
368+
- [ ] What happens to a repo's *existing* index if the superadmin later
369+
removes its embedding model from the allowed set — does search just
370+
stop working for that repo (data still there, queries rejected), or
371+
does it force a re-index banner/block?
372+
- [ ] How does org-level narrowing interact with personal groups
373+
(`multi-tenant-auth-plan.md` §4.2a) — does a personal group count as
374+
an "org" for this purpose, or do personal-group users always inherit
375+
the server-wide set unmodified?
376+
- [ ] Where does the "pre-selected, disabled" single-model UX surface
377+
outside the CLI — does the (currently nonexistent) Semahub web
378+
dashboard need this too, or is this purely a CLI/HTTP-API-level
379+
concern for now?
380+
- [ ] BYOK credential storage/handling for narrator/guide: does the user's
381+
own API key get stored server-side (raising the same plaintext-secret
382+
precedent question as `multi-tenant-auth-plan.md` §4.1), or is it
383+
supplied per-request only and never persisted?
384+
385+
### Effort Estimate
386+
- Depends heavily on the role-model prerequisite landing first. Once a
387+
role/permission system exists (per `multi-tenant-auth-plan.md`), this is a
388+
moderate addition: a new allowlist concept (global + org-level override),
389+
admin CLI/routes to manage it, and enforcement points at every model-
390+
selection site (`index start`, `config set model/textModel/codeModel`,
391+
narrator/guide model activation). Rough order: 500-800 LOC, mostly
392+
enforcement-point plumbing rather than novel architecture.
393+
394+
### Prerequisites
395+
- Needs a superadmin/role concept to exist — directly depends on
396+
`docs/multi-tenant-auth-plan.md` landing (at least Phase A's user/session
397+
model, likely Phase B's org/role model for the org-level narrowing
398+
behavior). Not actionable before that.
399+
400+
---
401+
247402
## Related Issues & Documents
248403

249404
- **Parity tracking:** See `docs/parity.md` for tool availability across interfaces

0 commit comments

Comments
 (0)