thecommons/spicemine sub public
spicemine
thecommons
640 files17.3 MB in thembiggest 5.2 MBcore/src/dist/static/mermaid.min.js112.5 MB on disk, history and all
vitality newempty: no commit. new: made less than 30 days ago. active: a commit in the last 30 days. steady: in the last 90. quiet: in the last year. dormant: nothing in a year.309 commits in 90 daysone pair of hands
no terms stated, which reads as all rights reserved
AI: ask first · automated collection is not permitted until the owner is asked and says so · this instance's default; nobody has said yet
README.mdiREADME The file a repository's page shows as its front page, if there is one at the top of the default branch. Write it for the person arriving without context: what this is, who it is for, and what to do first.
spicemine
spicemine is a self-hosted home for version-controlled work: repositories in Fossil, git, Mercurial and Jujutsu, served over HTTPS and SSH, with spaces, invitations, scoped tokens, cross-engine mirrors, verified backups, and a browser UI in English and Japanese. One JVM, one directory, one thing to back up.
It is written in Common Lisp on the JVM, on a framework of its own called mélangej (ABCL on Jooby and Netty, no Lisp dependencies). The book that documents the framework is served by every instance at /melangej, and is in core/src/dist/book/.
The premise is in the first feature below: you can't look at everyone's code without signing in. It is your data, your code, your choice.
What it does
- Four engines, one host. Fossil, git, Mercurial and Jujutsu behind one adapter protocol (
core/src/main/lisp/spice-scm.lisp). Your own client talks to the real engine over HTTPS or SSH; nothing here is a dialect. - Spaces and roles. Everyone gets a personal space; a group space has members, writers and admins, and a repository is private, members only or public. Members only shows its showcase to anyone and the rest to members of the space. What you may not see is absent, not refused: its URL answers 404.
- Credentials that do not cross. A session signs a browser into the pages, a token signs a program into the API and the wire, an SSH key signs a machine into the transport. A token can be scoped to one repository or one space; write includes read. See
AUTH.md. - For people who make things, not only programmers. Files go in by dragging them onto the files view, and each drop is one commit by the person who dropped it. A text file is edited from its own page, and a directory of pictures shows as a contact sheet. A repository states its terms from a catalog, with a plain sentence beside the formal name. Anyone may save a repository, and the count is two numbers, never one. See
CREATORS.md. - Editions, and your work when you leave. Name the files as they are now, "first printing", and the showcase offers a zip of exactly that revision for good. "Take your work with you" makes one zip of every repository you administer, each in its engine's own form, with a manifest of what this instance knew about it.
- One search box, and a sounding board. Search finds spaces, projects and issues by what they say, and only what you may see. The sounding board turns what you say into questions, Eliza-style, with no model behind it; a conversation worth keeping is saved into the project.
- A journal beside the work. A project's owners write short posts, 280 characters, from its showcase; they sit in a column to the left or right of the work, public or for members only, and a deleted post is gone, not hidden.
- Issues that travel with the project. An issue is a Markdown file in the project's own issues repository,
<project>~issues, one commit per action, with a status, a resolution, a severity and a thread; the database only indexes it. Clone the issues repository and the conversation comes along, while the project's branch and its CI never see a comment (TRACKERS.md,ISSUES.md§10). - Mirrors and subs. A repository can be served in another engine's format (
/space/repo.git,/space/repo.hg), rebuilt on every push; a sub is a read-only copy of a repository hosted elsewhere. SeeMIRRORS.md. - Fetch a project in. An existing project at an address is fetched into an empty repository from its setup page or the API, project code and all for Fossil, which refuses a push from a different project code.
- Backups that prove themselves. A backup is restored into a throwaway instance before it counts, encrypted with
ageto any rclone remote, and the audit fails loudly when anything is missing. Seedeploy/README.md. - A showcase per repository. Title, byline, hero image, README, and a public page that works without JavaScript. Ten skins; every string in two languages. See
WEBUI.md,SKINS.md,I18N.md. - The AI/crawler Guardian (designed, not built). The plan: repository content readable by a person who signed in, or by an agent carrying that person's token, named, rate-limited, logged and revocable, with anonymous bulk reading refused. Today tokens are scoped and revocable; nothing is rate-limited. See
GUARDIAN.mdand FEATURES.md.
Dependencies
On the host, found on PATH or named with a -D property:
- a JDK, 17 or newer, to run (the build provisions its own)
fossil2.25 or newer,git,hg(Mercurial),jj(Jujutsu): one per engine you host; an instance that hosts no Mercurial needs nohgsqlite3is not needed: SQLite is embedded; PostgreSQL is optional and configured withspice.db.url(credentials come from the environment, never from that URL). SeeDATABASE.md.
In the distribution, 29 jars, 39 MB, all from Maven Central:
| what | which | why |
|---|---|---|
| ABCL 1.9.2 | org.abcl:abcl, abcl-contrib | the Common Lisp; contrib is on the classpath and loaded by nothing |
| Jooby 3.9.1 | jooby, jooby-netty | routing and the HTTP server; Netty 4.2 under it |
| JGit 7.3 | org.eclipse.jgit | the git engine's smart-HTTP, in-process |
| sqlite-jdbc 3.49, PostgreSQL 42.7, HikariCP 5.1 | metadata: users, spaces, repositories, tokens, events | |
| minimal-json 0.9.5 | JSON where Java reads it | |
| slf4j-simple 2.0 | the logging the libraries above expect |
No Lisp dependencies. No Quicklisp, no ASDF system, nothing vendored: twenty-five Lisp files loaded in order by boot.lisp. The Markdown renderer, HTML emitter, template compiler, JSON codec and migration machinery are in the tree, a few hundred lines each, and you can read all of it. MELANGEJ.md says which files are the framework and which are this service.
Building
core/gradlew -p core installDist # -> core/build/install/spicemine/
That is the whole build: Gradle fetches the jars, compiles the seven Java files, copies the Lisp, and compiles it to fasls with warnings fatal (compile-all.lisp). The result is a directory with bin/spicemine-server, bin/spicemine-admin, bin/spicemine-ssh-keys, bin/spicemine-ssh-serve, lib/ and lisp/. A tarball of it is a release.
Run it from the checkout:
JAVA_HOME=/path/to/jdk17+ core/build/install/spicemine/bin/spicemine-server
# or, loading .lisp sources without the compile step:
core/gradlew -p core runCore -Pport=8643
First boot prints the instance admin's token once; spicemine-admin is how an operator with a shell gets back in. Everything is a -Dspice.* property or an environment variable; deploy/nixos/spicemine.nix lists them all with their meaning.
The gate that every change has to pass:
JAVA_HOME=/path/to/jdk17+ core/run-tests-all.sh
It builds, proves the build fails on an unreadable source, evaluates the NixOS module, runs the deploy script suites, the Lisp suites, and then starts a real instance and runs the setup instructions, the wire-mount authorisation, the scope form, self-hosting, and the SSH transport against it with the real clients. The browser suites run too when PLAYWRIGHT is set. core/run-tests-pg.sh repeats the suites on PostgreSQL.
Deployment
A release is a directory; the service is one JVM behind your TLS terminator; the state is one directory (spice.home), which is the one thing to back up.
- NixOS is the supported shape:
deploy/nixos/spicemine.nixis a module with the service, the user, the SSH transport, backups, offsite copies and their timers, and assertions that refuse a configuration with a secret in the store.deploy/README.mdis the runbook, from first boot to restore. - Anything else that can run a JVM: unpack the release, point
-Dspice.homeat a directory, put traefik or nginx in front, and runbin/spicemine-serverunder your supervisor.deploy/deploy.shanddeploy/upgrade.share the reference for what a deploy does, in forty lines of shell each.
No address, hostname or credential appears in this repository; every script takes them from the environment.
Documents
SPEC.md | the system, section by section |
AUTH.md | sessions, tokens, scopes, SSH keys |
MIRRORS.md | mirrors, subs, what converts to what |
DATABASE.md | SQLite and PostgreSQL, migrations, the pool |
WEBUI.md, SKINS.md, I18N.md, TEMPLATES.md | the pages |
GUARDIAN.md, TENANCY.md, MOBILE.md, POLICY.md, LICENSING.md, LINKS.md, TRACKERS.md, MERGE.md, ISSUES.md, JOURNAL.md, VERSIONING.md | the rules and what is planned |
MELANGEJ.md | the framework's version and the split |
SECURITY.md | the monthly audit checklist, the pinned bill of materials, the findings; deploy/security-audit.sh runs the half a script can |
deploy/README.md | the runbook |
Support
There is no commercial release and there will not be one: the platform is the platform, and everyone gets every feature. What may be paid for is services around it. Fork it, host it; that is what we do.
License
Copyright 2026 IoTone, Inc.
spicemine is licensed under the Apache License, Version 2.0: see LICENSE and NOTICE. You may use, change and redistribute it, in source or built, under that licence's terms; it comes with no warranty.
Each source file says so in two lines (Copyright 2026 IoTone, Inc., SPDX-License-Identifier: Apache-2.0), and the gate fails when one does not (core/src/test/sh/license-headers.sh). What spicemine ships that others wrote keeps its own licence: SBOM.md lists every component with it. The licence of a project hosted on an instance is its owner's choice and a different subject: LICENSING.md.
Inspirations
- Forgejo's published API (
https://codeberg.org/api/swagger) - gitblit, for what a self-hosted git server got right a decade earlier
- Fossil, for being one file
about this project
- clone
https://spicemine.iotj.cc/thecommons/spicemine- engine
- Sub (a mirror of something hosted elsewhere)
- visibility
- publicivisibility Who can see a repository. Private: only the writers and admins of its space. Members only: anyone can find it in its space and read its showcase - the title, the description, the public journal posts - and the files, history and clone address are for members of the space. Public: anyone at all, everything. New repositories are private, because a store that holds unreleased work should not be the kind of place where something escapes by accident. What you may not see is not listed at all - not greyed out, not refused.
- created
- last change
- visits
- 56 · 2 peopleRequests for this page since 0.112.0, and how many the guardian took for people: signed in, or anonymous with a client it could name, standing allowed, and no crawler's user agent. A request it could not judge counts as a request and not a person.
- mirrors
- none
- tags
- none
- rating
- not counted yetRatings will come from links between projects, which do not exist yet.
- history sent
- not counted yeta clone or a pull from here
- history received
- not counted yet