Skip to content
Jonathan D.A. Jewell edited this page Sep 15, 2026 · 4 revisions

Getting Started

Install

You need Rust 1.89 or newer. Nothing else — no Node, no database, no container runtime.

git clone https://github.com/metadatastician/berrywiki.git
cd berrywiki
cargo build --release

The binary lands at target/release/berrywiki.

Point it at a wiki

A GitHub wiki is an ordinary git repository. Clone yours:

git clone https://github.com/OWNER/REPO.wiki.git my-wiki
berrywiki serve my-wiki

Open http://127.0.0.1:23779. You get three panes: the page tree, the page itself, and an outline with backlinks.

That port is the default and is deliberate: 23779 sits in an IANA-unassigned block, well away from the 8080/3000-class ports that collide with everything else you have running. BerryWiki listens on TCP only, loopback by default. --addr host:port moves it.

To try it without touching a real wiki, the repository ships a fixture notebook:

cargo run -p berrywiki-cli -- serve fixtures/test-wiki

The other commands

berrywiki check my-wiki              # tree + diagnostics; exit 1 on any error
berrywiki sidebar my-wiki --write    # regenerate _Sidebar.md
berrywiki serve --github OWNER/REPO  # mirror a GitHub wiki (read-only)
berrywiki backup my-wiki ./backups   # recoverable copy: bundle + drafts + journal
berrywiki restore ./backups my-wiki  # rebuild a wiki from that copy
berrywiki import notes.ctd my-wiki   # CherryTree notebook; reports, writes nothing

check is the one to run in anger. It reports broken links, missing parents, cycles and duplicate ids, and exits non-zero if any of them are errors — so it works as a pre-commit hook or a CI step on your wiki repo.

For a private wiki, supply a token through the environment, never as an argument:

BERRYWIKI_GITHUB_TOKEN=ghp_… berrywiki serve --github OWNER/REPO

Passing it as a flag would leave it in your shell history and in the process list, so BerryWiki does not accept one.

Backing up, and getting it back

berrywiki backup my-wiki ./backups-2026-09-09
berrywiki restore ./backups-2026-09-09 my-new-wiki

A backup is a directory holding three things: a git bundle of all committed history, your drafts, and the operation journal. Two refusals are deliberate and worth knowing before you script this:

  • backup refuses a dirty working tree. A bundle carries committed history only, so backing up over uncommitted edits would silently omit them. Commit first, or accept that the backup is of the last commit.
  • restore refuses a folder that already has contents. It rebuilds into a new folder, sets the remote from the recorded origin, and puts the drafts back under the new folder's own app state — remember drafts are keyed by the wiki's path, so this step is what stops a restore losing them.

The search index is not archived. It is derived data and is rebuilt on demand.

Importing a CherryTree notebook

berrywiki import notes.ctd my-wiki           # report only
berrywiki import notes.ctd my-wiki --json    # the same report, machine-readable
berrywiki import notes.ctd my-wiki --apply   # actually write it

Without --apply nothing is written at all — the command tells you what the notebook would become and stops. With --apply it still refuses rather than overwrite: two siblings sharing a title, a page that already exists and did not come from this same node, or a target folder that is not a git working tree each stop the run before the first write, not partway through. An applied import is one commit.

Re-running an import that already succeeded writes nothing, because every imported page records the node it came from.

Only the plain .ctd format is read. .ctb, .ctz and .ctx are refused by name rather than half-parsed — see Decisions for why that line is drawn where it is.

Publishing your changes

A local folder that is a git working tree is served with commit-on-save: every save is one commit, the regenerated sidebar included. That is the default, so you do not need to commit by hand on top of it — and should not, or you will be committing over commits BerryWiki has already made.

Pushing stays separate and explicit. The /changes page offers fetch, fast-forward and push — never a merge, never a force. A history that has diverged is reported rather than reconciled behind your back.

berrywiki serve my-wiki --author "Ada Lovelace <ada@example.org>"
berrywiki serve my-wiki --no-commit

--author sets the commit identity; without it BerryWiki uses the git config of the clone. --no-commit serves the folder without touching git at all, if you would rather commit by hand — and a folder that is not a git working tree falls back to that automatically, with a warning.

What is still missing is the resolving of a conflict once one exists: it is detected and shown, on one /conflicts page for the whole wiki, but you finish the job in git. See Roadmap.

Clone this wiki locally