This workflow governs how documentation moves from code-aware drafting into the published Wiki.js documentation site.
The documentation system uses three connected components:
boroughforge-wikidocs repositoryThe GitHub boroughforge-wikidocs repository is the canonical source for published documentation.
Wiki.js renders documentation from the GitHub repository. The Wiki.js browser editor should not be used for normal editing of published pages.
This repository has three independent writers, and every rule in this document exists to keep them from colliding:
drafts/gitlab-generated/ and nothing else.The ownership partition is path-level: CI writes only to its draft directory, humans write everywhere else, and Wiki.js is (ideally) a reader. Each writer must assume the others may have pushed since it last looked, which is why the rebase-before-push discipline described below applies to all three, not just humans.
The GitLab repository is used for code-aware drafting. LLM tools working inside the source repository may generate documentation skeletons using knowledge of the actual codebase.
GitLab CI mirrors generated draft documentation into the GitHub documentation repository.
GitLab CI owns only the generated draft area:
drafts/gitlab-generated/
The GitHub boroughforge-wikidocs repository is the canonical human-edited documentation repository.
Humans edit documentation by cloning this repository locally, editing in an IDE or text editor, committing, and pushing.
Published documentation lives in folders such as:
dev/
sysadmin/
users/
properties/
permitting/
inspections/
cecases/
assets/
Wiki.js is the rendered documentation site.
Wiki.js imports changes from the GitHub documentation repository through Git sync.
The Wiki.js browser editor is reserved for emergency edits only. Any emergency browser edit must be reconciled into the Git history immediately — see the Emergency Edits section for the exact sequence, because doing it out of order arms a conflict trap.
Git history is a graph of immutable commits, each pointing at its parent. Two operations reconcile divergent lines of history:
Before, where you committed A and B locally while the remote gained C and D:
A — B <- your local commits
/
X — Y — C — D <- origin/main moved while you worked
After git rebase origin/main:
X — Y — C — D — A' — B' <- linear; A' and B' are new commits with the same content
git pull --rebase doesPlain git pull is fetch + merge: if you and the remote have both moved, it produces a merge commit ("Merge branch 'main' of github.com...") that records nothing except that two people edited concurrently. git pull --rebase is fetch + rebase: your local unpushed commits are replayed on top of the updated remote tip. History stays a straight line.
The iron law of rebase: never rewrite commits that anyone else has built upon. Replacing published SHAs forces everyone downstream to reconcile against history that changed under them, and it is the operation that creates the need for force-pushing.
git pull --rebase satisfies this law by construction: the only commits it rewrites are your local unpushed ones, which nobody has seen. This is why rebase-pull is safe as a daily habit even for people who would never rebase a shared branch.
This repository is single-branch, multiple-writer, direct-push: no feature branches, no merge requests, everyone commits to main. In that topology, merge-pulls generate a content-free merge commit every time two writers overlap, and Wiki.js surfaces this Git history as the page-history view readers see. Rebase-pull keeps main linear, so the published history reads as a clean sequence of documentation edits.
Note the contrast with the codeNforce source repository, where milestone feature branches are merged with --no-ff precisely to preserve merge structure: there, branches are deliverable units worth seeing in the graph. Here, there are no units to preserve — just interleaved small edits — so linearity wins. Same principles, opposite conclusions, because the repository topologies differ.
--rebase in other contextsDo not carry this habit into situations where its safety condition fails:
--force. A rejected push means the remote moved; the answer is git pull --rebase (or a merge), never overwriting the remote. If you ever believe a force-push is necessary, stop and reconstruct how you got there first.git rebase --continue after each. If you get lost mid-rebase, git rebase --abort returns you cleanly to your pre-rebase state — nothing is lost.--rebase pulls here.A code-aware LLM drafts a skeleton page in the GitLab source repository.
The file is placed under:
drafts/gitlab-generated/
GitLab CI mirrors the generated draft into the GitHub documentation repository.
A human editor reviews the generated draft in a local clone of the GitHub documentation repository.
The human editor promotes useful content into the appropriate published documentation folder. Promotion includes the human revision pass and the AI-assistance disclosure required before publication.
The human editor commits and pushes changes to the GitHub documentation repository.
Wiki.js imports the changes during its periodic Git sync.
Files under drafts/gitlab-generated/ may be overwritten by GitLab CI at any time.
Do not treat generated draft files as durable human-edited documentation. Anything worth keeping gets promoted out of the draft path by a human commit.
Published documentation is edited in the GitHub documentation repository.
Do not edit published pages in the Wiki.js browser UI during normal work.
git add <changed-files> and Never git add .Human commits must stage files by name:
git add users/permits-overview.md dev/patch-conventions.md
Never git add . in this repository. The generated-draft path is tracked in Git and owned by CI; a blanket add from a working tree that contains mirrored drafts sweeps CI-owned files into a human commit, blurring the ownership boundary this entire document exists to define. The explicit add is not a stylistic preference — it is the human side of the same path-ownership rule imposed on the CI job below. Run git status first, read the list, stage what you actually edited.
Emergency Wiki.js browser edits are allowed only when a published page must change faster than the Git flow allows.
The reconciliation sequence matters, because Wiki.js pushes on a timer, not immediately:
git pull --rebase origin main
Configuration recommendation: if emergency edits are genuinely rare, configure the Wiki.js Git storage module for one-way sync (pull only, push disabled). An emergency edit then lives only in the Wiki.js database until a human transcribes it into the repository — deliberately inconvenient, which is the incentive to use the real flow, and it removes the third writer's push path entirely. If bidirectional sync is kept, the race described in step 2 exists permanently and this section is the mitigation.
GitLab CI must not mirror or overwrite the entire GitHub documentation repository.
GitLab CI may only write to its explicitly owned generated-draft path:
drafts/gitlab-generated/
The CI mirror job must not use broad commands such as:
git add .
rsync --delete ./ wiki-target/
The CI job stages and commits only known generated paths.
The CI job needs the same rebase-before-push discipline as humans. A human push can land between the CI job's clone and its push; without a pull, the job's push is intermittently rejected — and the tempting one-character "fix" of adding --force would overwrite human commits. The mirror script must include, immediately before its push:
git pull --rebase origin main
This is safe for the same structural reason it is safe for humans: the only commits being replayed are the job's own unpushed draft-mirror commits, confined to the CI-owned path, so the rebase cannot conflict with human edits elsewhere in the tree.
# One-time setup (a fresh clone is already current;
# no pull needed immediately after cloning)
git clone git@github.com:TechnologyRediscovery/boroughforge-wikidocs.git
cd boroughforge-wikidocs
# Each editing session begins by syncing:
git pull --rebase origin main
# edit documentation
# Review what changed, then stage by name -- never `git add .`
git status
git add <changed-files>
git commit -m "Update documentation"
# Close the race between your last sync and your push:
# if another writer pushed while you edited, this replays
# your commit on top of their work; then push.
git pull --rebase origin main
git push origin main
The second pull --rebase is not ritual: a push is rejected whenever the remote has moved since your last fetch, and in a three-writer repository the remote moves. Rebase-pull immediately before pushing closes that window.
GitLab is the code-aware drafting system.
GitHub is the canonical documentation editing repository.
Wiki.js is the rendered documentation site.
Three writers share one branch; path ownership keeps their edits disjoint, and rebase-pull before every push keeps the shared history linear. Published documentation has one active source of truth: the GitHub documentation repository.