Incompatible Mycorrhiza fork made for inner Mojosa needs https://mycorrhiza.wiki
  • Go 85.8%
  • HTML 7.4%
  • CSS 3.5%
  • JavaScript 2.1%
  • Shell 0.5%
  • Other 0.7%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
surdeus 00cdb67e4b docs: the push help page describes the schedule it now has
The page ended with "It does not run on a schedule, and it does not run
after every edit — you press the button." That stopped being true when the
timer landed, so it is now a section on what the schedule does and does
not do: nothing is sent when the history has not changed, a failure is
retried on the next interval, and the setting takes effect without a
restart.

The "what a push does not do" section keeps the two things that remain
true and matter: there is no fetch, so a rejected push keeps failing until
it is resolved by hand; and a push is a replica, not a snapshot, so a
deleted page is deleted on the remote too.
2026-10-30 02:00:06 +05:00
internal docs: the push help page describes the schedule it now has 2026-10-30 02:00:06 +05:00
.dockerignore build: make the container say what it is and weigh a third as much 2026-10-27 21:49:20 +05:00
.gitignore feat!: rename the product to Mojowiki 2026-10-26 20:26:55 +05:00
.mailmap chore: map both of the maintainer's addresses to the current one 2026-10-26 23:17:39 +05:00
build.sh build: two shell scripts instead of a Makefile 2026-10-29 18:12:21 +05:00
cli.go feat: mojowiki version prints the release, and -l the build 2026-10-29 00:02:16 +05:00
cli_test.go feat: mojowiki version prints the release, and -l the build 2026-10-29 00:02:16 +05:00
config.md feat: push the history to the remote every so often 2026-10-30 01:49:08 +05:00
csrf_test.go refactor: delete the configuration globals 2026-10-28 21:37:01 +05:00
Dockerfile build: two shell scripts instead of a Makefile 2026-10-29 18:12:21 +05:00
go.mod feat: take the HTTP plumbing from goss, and add trusted proxies 2026-10-28 19:14:13 +05:00
go.sum feat: take the HTTP plumbing from goss, and add trusted proxies 2026-10-28 19:14:13 +05:00
httpd.go feat: take the HTTP plumbing from goss, and add trusted proxies 2026-10-28 19:14:13 +05:00
httpd_test.go feat: stop on a signal the way a server should 2026-10-27 04:53:07 +05:00
image.sh fix: tell a missing tag apart from a missing repository 2026-10-29 18:29:41 +05:00
license.txt chore: name the readme and licence as goss does 2026-10-24 14:51:41 +05:00
logging.go feat!: rename the product to Mojowiki 2026-10-26 20:26:55 +05:00
logging_test.go feat!: rename the product to Mojowiki 2026-10-26 20:26:55 +05:00
main.go feat: push the history to the remote every so often 2026-10-30 01:49:08 +05:00
readme.md build: a tests.sh that is the gate, since there is no CI 2026-10-29 18:23:23 +05:00
reload_test.go refactor: one layout for a wiki's paths, in its own package 2026-10-28 22:50:59 +05:00
repo_helper_test.go refactor: cut the markup-to-views edge, and make mimetype a leaf again 2026-10-28 23:18:22 +05:00
routes_test.go refactor: one layout for a wiki's paths, in its own package 2026-10-28 22:50:59 +05:00
saving_test.go refactor: one layout for a wiki's paths, in its own package 2026-10-28 22:50:59 +05:00
scripts_test.go fix: tell a missing tag apart from a missing repository 2026-10-29 18:29:41 +05:00
tests.sh build: a tests.sh that is the gate, since there is no CI 2026-10-29 18:23:23 +05:00

🔗 Mojowiki

Mojowiki is a lightweight wiki engine. Pages are plain files, history is a Git repository, and there is nothing to install but the binary and git. It is a fork of Mycorrhiza Wiki by Timur Ismagilov.

Features

  • No database to run. Everything is a plain file in a directory, so installing is copying a binary and a git executable, backing up is copying a directory, and you can edit pages with any text editor.
  • Everything is a page. A page is a unit of content: a picture, a video or a text article. Pages can transclude and link each other, forming a tight network of hypertext.
  • Pages are authored in Mojomarkup, a markup language that's designed to be unambiguous yet easy to use.
  • Categories let you organize pages without any hierarchy restrictions, with all the benefits of a category system.
  • Nesting of pages is also supported if you like hierarchies.
  • History of changes. Every edit is a Git commit, so nothing is lost and the wiki can be cloned like any repository. Recent changes are published as a JSON Feed.
  • Keyboard-driven navigation. Press ? to see the list of shortcuts.
  • Support for authorization. Username-password accounts, with rights managed from the admin panel.
  • Link previews. Pages carry the title and description that chat apps and search engines show when someone shares them.
  • Interwiki support.

Installing

Build it from a checkout. Clone the repository and build the binary yourself:

$ git clone https://codeberg.org/mojosa/mojowiki
$ cd mojowiki
$ go build -o mojowiki .

That leaves the binary in the directory you built it in. Put it anywhere on your PATH:

$ install -Dm755 mojowiki ~/.local/bin/mojowiki

go build uses cgo, so the result links against libc and libresolv. For a binary you can copy to a machine with no libc, disable cgo:

$ CGO_ENABLED=0 go build -o mojowiki .

Requires Go 1.26.3 or newer, which is what go.mod asks for.

A plain go build reports the version the Go toolchain derived from the checkout: the tag when the tree is on one, and the commit alongside it. mojowiki version prints the release, as 0.45.1; mojowiki version -l prints the release, the commit and whether the tree had uncommitted changes, as 0.45.1+e34c32c-dirty.

build.sh is that build with paths trimmed out of the binary, so a stack trace from it does not name the machine it was built on. image.sh builds the container image. The image cannot derive a version — its build context has no .git — so image.sh passes it the same git describe string the binary would have derived. At a tag both report 0.45.1.

$ ./build.sh
$ ./image.sh

Both are ordinary shell scripts and run from anywhere; they work in the directory they live in. image.sh stops with a message rather than building an image that cannot say which build it is: outside a git checkout there is no version to stamp, and docker build would otherwise be handed an empty one.

Between tags they differ in what they can say, because they know different things: the toolchain will not call a commit that is not a release by a release number, so a binary built past the tag reports (devel)+40bf83e, while the image reports the distance, 0.45.1-3-g40bf83e. Neither claims to be a release it is not.

go install codeberg.org/mojosa/mojowiki@latest is not the way to get this yet: the module proxy still resolves @latest to an old deleted tag, so it builds code from before most of the wiki. Clone and build from main, or check out a release tag first:

$ git tag --sort=-v:refname | head -1
$ git checkout <that tag>

Mojowiki shells out to git for every edit, so the git program has to be on the PATH of the account the wiki runs as. It is the only runtime dependency: the wiki does not link a git library, and a build without git installed will start and then fail with Could not find the Git executable.

The manual page is not installed by a build; copy it yourself if you want it:

$ install -Dm644 internal/help/mojowiki.1 /usr/local/share/man/man1/mojowiki.1

Then run it against a directory:

mojowiki serve /srv/wiki

Run mojowiki on its own to see the commands, and mojowiki serve -h for the options of one of them. mojowiki version prints the release, as 0.45.1; mojowiki version -l prints the full build string, as 0.45.1+e34c32c, with -dirty when the tree it was built from had uncommitted changes.

The directory is created if it does not exist, and a config.json with the defaults is written into it. Every setting is documented in config.md.

The wiki logs to stderr:

time=2026-10-24T22:51:01.565+05:00 level=INFO msg="Listening over HTTP" addr=0.0.0.0:1737

Set MOJOWIKI_LOG_FORMAT=json to get one JSON object per line instead, which is what a log collector expects. MOJOWIKI_LOG_LEVEL sets the threshold: debug, info (the default), warn or error.

Checking that it is up

The wiki answers GET /health with 200 and {"status":"ok"} while it is serving. The answer is Cache-Control: no-store and it is logged at debug rather than info, so a prober that asks every few seconds does not fill the log. Put it in front of a reverse proxy or a restart policy:

$ curl -fsS http://127.0.0.1:1737/health
{"status":"ok"}

It reports that the process is running, not that the wiki is healthy in some deeper sense: a page that failed to render still answers ok. It is a liveness probe.

Only one process may serve a wiki directory. A second one exits at once with another mojowiki is already serving this wiki and the pid holding it, because two servers on one directory run git against the same index and lose edits at random. The lock is .mojowiki.lock in the wiki directory, held by the kernel, so a killed process does not leave the wiki unstartable.

Docker

docker build --build-arg VERSION="$(git describe --tags --dirty)" -t mojowiki .
docker run -p 1737:1737 -v /srv/wiki:/wiki mojowiki

./image.sh runs the same command with the same value and tags the image with it, so docker images and mojowiki version agree.

The wiki listens on 0.0.0.0:1737 by default. Set URL in config.json so that feeds and Open Graph tags point at the address the wiki is actually reached on.

The version has to be passed, or the image cannot tell you which build it is. The build context leaves .git out, so the Go toolchain has nothing to derive one from. An image built without the argument is refused rather than stamped (devel) and left looking like a broken build. With it, docker run --entrypoint mojowiki mojowiki version prints the tag — 0.45.1, or 0.45.1-3-g40bf83e three commits past it — and -l prints the same string, because git describe already said everything there is to say about that build.

The argument sits after COPY in the Dockerfile, so changing it rebuilds the binary alone: an ordinary commit does not invalidate any layer, and a release rebuilds once. Keep .git in .dockerignore. Including it to get a version stamped instead would put 18 MB in every build context and invalidate the source copy on every commit — twenty seconds of rebuild for a commit that changes no code.

The image is about 54 MB. It is alpine with git and an ssh client, not the 144 MB alpine/git it used to be: that one also carries git-lfs, git-perl, gnupg and less, none of which the wiki runs. Drop openssh-client from the Dockerfile if the wiki only ever pushes over HTTPS.

Note that the entry point is mojowiki serve, so docker run <image> version serves a directory called version. Use --entrypoint mojowiki to run another command.

Creating the first administrator

Authorisation is on by default, so a new wiki has no administrator and nothing can be edited until one exists:

mojowiki create-admin alice /srv/wiki

The password is read from stdin, so this works from a pipe, a compose file or a Kubernetes job as well as from a shell.

Working on the wiki

There is no CI. tests.sh is the gate: formatting, go vet, the build, the tests, and the tests again under the race detector.

$ ./tests.sh           # everything, about two minutes
$ ./tests.sh --quick   # no race pass, about ten seconds

The race pass is most of the running time, because the auth tests hash passwords with bcrypt and the detector multiplies that. It runs by default: a gate that skipped the slow check unless asked to run it is a gate that ships races.

The formatting check is not gofmt -l . on its own. That command prints the files that need formatting and exits 0 either way — it reports, it does not judge — so a gate that stops on a non-zero exit would pass on unformatted code. tests.sh fails when the output is not empty.

Differences from Mycorrhiza Wiki

  • English only. The interface and the help pages are in English; there is no language setting.
  • Settings are edited in the admin panel, and take effect immediately.
  • One feed format. Recent changes are published as JSON Feed; RSS and Atom are not produced. Their old addresses redirect.
  • The listen address is a startup option, not part of the wiki's own settings: -listen-addr or MOJOWIKI_LISTEN_ADDR.
  • Signing in is required by default. A new wiki has no administrator until you create one.

Licence

AGPL-3.0. See license.txt. The licence is unchanged from upstream Mycorrhiza Wiki.

Thanks

Mojowiki is a fork of Mycorrhiza Wiki, created by Timur Ismagilov and improved by its contributors. Thank you for the engine this is built on.

Official repository: https://codeberg.org/mojosa/mojowiki