# git-forge wikis (Gitea · GitLab · GitHub) — deep dive (findings) **Date:** 2026-06-14 · **Source:** SHARD-WP-0003 T5 · **Subject:** the Markdown wikis hosted by the three major git forges — **Gitea**, **GitLab**, **GitHub** — treated as one family because they share one architecture: *a wiki is a separate git repo of Markdown.* ## Why this dive INTENT names **Gitea wikis** as a shard participant, and the whole project is "a **Git-based Markdown** wiki orchestrator." The forge wikis are therefore the **least exotic, highest- fit** backend in the entire study: the page store is *literally a git repository of Markdown files*. After fourteen dives into DBs, CRDTs, graphs and SaaS, this one confirms the **home case** — and sharpens it by contrasting *git-IS-the-store* (forge wikis) against *git-is-a-mirror* (Wiki.js, UC-68). ## 1. The shared architecture — a wiki is a `.wiki.git` repo All three forges implement a project/repo wiki as a **second, dedicated git repository** alongside the code repo, addressable as `.wiki.git`: - `git@host:owner/project.wiki.git` (GitLab), `…/owner/repo.wiki.git` (Gitea/GitHub). - **Pages are Markdown files** (`Home.md`, `Some-Page.md`), one file per page; the **page title ↔ filename** (spaces ↔ hyphens by convention). Other markups are accepted (AsciiDoc, Textile, reStructuredText, Org) — GitHub/Gitea via **Gollum** (the Ruby git-backed wiki library), GitLab via its own renderer. - **History is git history** — every page edit (web or pushed) is a git commit with author/timestamp/message. *The wiki's revision history is a real git log.* - **Special pages** by convention: `_Sidebar`, `_Footer`, `_Header` (GitHub/Gitea), `_sidebar` (GitLab) — engine-rendered chrome stored as ordinary files. - **Subdirectories / nested pages**: GitLab and Gitea support directory structure; GitHub wikis are historically flat (Gollum supports paths but the GitHub UI is shallow). The decisive property: **you can `git clone` the wiki repo, edit files, commit, and push**, and the forge UI reflects it — *and vice versa*. Git is **a** (often **the**) first-class write path. This is exactly shard-wiki's native medium with no impedance. ## 2. Where they differ — the API matrix | | git clone/push of `.wiki.git` | wiki content **API** | nested dirs | markups | |--|--|--|--|--| | **Gitea** | ✅ yes | ✅ **REST wiki endpoints** (list/get/create/edit/delete pages) | ✅ | Markdown (+Gollum-style) | | **GitLab** | ✅ yes | ✅ **REST Wikis API** (project & group wikis) | ✅ | Markdown/AsciiDoc/RDoc/Org | | **GitHub** | ✅ yes | ❌ **no wiki REST API** — wiki is **git-only** (Gollum) | ⚠️ flat UI | Markdown + Gollum markups | The key asymmetry: **GitHub exposes wiki content *only* through git** (the REST/GraphQL API covers issues/PRs/code but **not** wiki pages); **GitLab and Gitea offer both** a wiki API *and* git access. So the **git-clone path is the universal one** (works for all three); the API path is an *optional, capability-varying* alternative. ## 3. git-IS-the-store vs git-is-a-mirror (the UC-68 contrast) Wiki.js (UC-68) keeps a **DB as canonical** and *maintains a git mirror* — so writing by commit risks **racing the engine's DB↔git sync** (catalog open-Q22). Forge wikis are the opposite: **the git repo IS the canonical store**; there is *no* separate DB of record for wiki content. Therefore: - **The source-of-truth question (Q22) is resolved for this case:** the `.wiki.git` repo is authoritative. shard-wiki can **write by commit/push directly** with no engine to race — the forge merely *renders* what git holds. - The forge **API** (GitLab/Gitea), where present, is a *convenience over the same git repo*, not a competing store — so API-write and git-write converge on one history. This makes forge wikis the **cleanest possible write-through file-store shard**: clone = projection/mirror, commit = overlay-applied/write, git log = the coordination journal *as is*. ## 4. Capability profile | Dimension (synthesis spectrum) | Gitea / GitLab / GitHub wiki | |--------------------------------|------------------------------| | Attachment mode | **file-store (native: git clone)** + optional **external-API** (GitLab/Gitea wiki REST) | | Addressing granularity | **page = file**; sub-page = path (GitLab/Gitea) | | Content identity | path/filename within the wiki repo (title-derived) | | Identity vs placement | placement-bound (path = identity), like a plain git repo | | Structure | flat or directory tree of Markdown files; `_Sidebar`/`_Footer` chrome | | History | **native git history** (real commits, authors, messages) | | Merge model | **git** (3-way merge, branches) — though wiki repos are usually single-branch | | Native query | none (it's files); forge full-text search over the wiki | | Translation | **Markdown-native** (+ AsciiDoc/Org via renderer) — minimal/no translation needed | | Attachment/write granularity | **file (page)** per commit | | Operational envelope | ordinary git + forge; clone is cheap; API rate limits apply to API path | | Access grant | **forge repo permissions** (delegated auth; per-repo/role ACL) | | Content opacity | transparent Markdown in git | | Provenance | git author/committer/timestamp per commit — native | ## 5. INTENT mapping ### Reinforcements (this is the home case) - **Git-based Markdown orchestrator** (INTENT core): forge wikis *are* git repos of Markdown. The **wiki page model** (Markdown-first, path-addressed, git-versioned) maps 1:1 — minimal adapter, maximal fit. - **Coordination journal = git** (INTENT): the wiki repo's **git log is already the coordination journal** — no synthesis needed; adopt it directly. - **Overlay before mutation**: overlays are **branches/commits** on the cloned wiki repo; applying = push (or open an MR/PR where the forge supports wiki MRs — GitLab does not for wikis, so push-to-branch + manual is the path). - **Graceful degradation**: even GitHub (no wiki API) is fully usable via git-clone — the *universal* path means a limited forge is still a first-class read/write shard. - **No silent remote mutation**: writes are explicit git pushes (or explicit API calls) under the user's forge credentials and repo permissions. ### Divergences (boundaries / notes — minor) - **Capability varies by forge**: GitHub = git-only (no content API); GitLab/Gitea = git + API. The adapter must **model the API as an optional capability**, defaulting to the universal git path (T11/T14). Not a bug — exactly the capability-awareness INTENT mandates. - **Wiki repos rarely use branches/MRs for review**: forge wikis usually edit a single branch directly; the rich PR-review flow is on the *code* repo, not the wiki. So "overlay → review → merge" needs shard-wiki to provide the review layer, not the forge. - **Identity = path** (like any git repo) — cross-shard identity (T16) is layered above, as for plain git/`wiki/` subdir shards. ### What to keep 1. **git-clone as the universal, canonical file-store attach** for forge wikis — Markdown + git history directly as page model + coordination journal (UC-76). The reference easy-case backend. 2. **Forge wiki API as an optional capability** (GitLab/Gitea), with **git-only fallback** (GitHub) — capability-aware binding (UC-77). 3. **git-IS-store ⇒ write-by-commit is safe** (no engine race) — record this as the resolution of the Wiki.js mirror dilemma (Q22) for forge wikis. ## 6. UC seeds | # | Seed | Disposition | |---|------|-------------| | UC-76 | Attach a **git-forge wiki** by **cloning its dedicated `.wiki.git`** — git is the native store; Markdown files = pages, git log = coordination journal; commit/push = write (no engine to race) | **new** | | UC-77 | Attach/write a forge wiki via the **forge's wiki API** (GitLab/Gitea REST) where git-clone is unavailable or API-write is preferred; **git-only fallback** for GitHub — capability varies by forge | **new** | | — | git-native file-store as the *canonical store* (not mirror) | enrich **UC-40** | | — | dual-path attach (git clone vs forge API) | enrich **UC-02** | | — | git-IS-store vs engine-maintained mirror (resolves Q22) | enrich **UC-68** | | — | forge as an API host for the wiki resource | enrich **UC-38** | ## 7. Architecture notes for SHARD-WP-0002 - **T14 (adapter binding / attach path):** forge wikis are the canonical **file-store attach** — bind to the `.wiki.git` clone as the universal path; model the **wiki API as an optional, forge-specific capability** (present: GitLab, Gitea; absent: GitHub). One shard, two possible bindings converging on the same git history. - **T11 (capability model):** "has-content-API" is a **per-forge capability flag**; git clone/push is the baseline every forge satisfies. Minimal adapter profile — near the Oddmuse-simple end but Markdown-native and git-versioned. - **Coordination journal:** adopt the wiki repo's **git log directly** — the one backend where INTENT's git-backed journal needs *zero* synthesis. - **Resolves Q22 (UC-68):** because git **is** the store (not a mirror), **write-by-commit is safe** — no engine DB↔git sync to race. Record the distinction *engine-mirror* (Wiki.js: DB canonical, careful) vs *git-canonical* (forge wikis: commit freely). ## 8. Open questions 1. For overlay → **review** → apply, does shard-wiki supply the review layer over a forge wiki (which lacks wiki-MRs), e.g. via a branch + its own diff/approve, or push directly? 2. When a forge offers **both** git and a wiki API (GitLab/Gitea), which does the adapter prefer by default — git (universal, full history) with API as a fallback for hosts where clone is disabled? (cf. UC-43 backend-swap under stable binding.) 3. Should the **code-repo `wiki/` subdir** shard and the **forge wiki repo** shard share one adapter (both git+Markdown) with a "which repo / which path" parameter, or stay distinct? ## 9. Sources - GitLab Docs — *Wiki* (separate git repo; web/git/API; `.wiki.git`) — docs.gitlab.com - Gitea — wiki via git clone + repository **wiki API**; forum/issue threads on `.wiki.git` clone (go-gitea/gitea #1426, #15420) — gitea.com / github.com/go-gitea - GitHub — wiki = Gollum git repo (`.wiki.git`), no wiki REST API — docs.github.com - Gollum (git-based wiki library) — github.com/gollum/gollum - prior: `research/260614-wikijs-deep-dive/` (engine-maintained mirror contrast, UC-68) ## 10. Traceability New UCs **UC-76–UC-77** carry the marker **⎇** in the wikiengines column of `spec/UseCaseCatalog.md`. Enriched: UC-40, UC-02, UC-68, UC-38. Architecture cross-refs: SHARD-WP-0002 T14, T11; coordination-journal-from-git; resolves catalog open-Q22.