1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# quire
A personal source forge. Single-user, self-hosted, minimal.
Named after the old bookbinding term: a gathering of folded leaves, sewn together. Your repos are quires; the whole thing is a quire of quires.
## What it is
A Rust binary that runs in a Docker container, fronted by the host's sshd and a TLS-terminating reverse proxy. It gives you:
- **Git hosting over SSH**, via the host's sshd dispatching into the container. Explicit repo creation (`ssh git@host quire repo new <name>`).
- **A read-only web view** for browsing README, tree, history, blame, diffs, and refs.
- **Fennel-based CI** (Fennel is a Lisp that compiles to Lua), with pipelines defined in `.quire/ci.fnl`. Unsandboxed by default since every pipeline is code I've written; a bubblewrap-based opt-in is available for the day quire ever runs code I haven't.
- **Automatic mirroring** to GitHub, Gitea, or any HTTPS remote on every push. Map each remote URL to a push token in `.quire/config.fnl` under `:mirrors` (the value names an entry in the global `:secrets`); quire force-pushes every updated ref to all of them independently of CI.
- **Email notifications** for CI failures and recoveries. SMTP via `msmtp`; plain text; per-repo config for what to send and to whom.
No issues, no PRs, no user management, no webhooks. Use the GitHub mirror for the social stuff; quire is your forge.
Post-v1, the feature I most want to build is a richer line/file history view — blame ladder, range-follow, rename trails — the thing every forge does poorly.
## Creating a repository
Quire requires explicit repository creation — repos are not created automatically on first push.
Create the bare repo on the server:
```
ssh git@host quire repo new foo.git
```
Names must end in `.git`. One level of grouping is supported: `work/foo.git` is valid, `a/b/c.git` is not.
Then add the remote and push:
```
jj git remote add origin git@host:foo.git
jj git push
```
Other management commands: `quire repo list` and `quire repo rm foo.git`, invoked the same way via SSH.
## Design principles
Quire holds to a few principles:
- **The container is pure quire.** SSH auth and TLS/web auth both live on the host (host sshd, reverse proxy). The container runs `quire`, git, and msmtp. One job per surface.
- **Don't own ssh.** The host's sshd handles auth, channels, and key management; `ForceCommand` dispatches authenticated invocations into the container via `docker exec`. Quire's integration point is git hooks and the `quire exec` dispatch target.
- **Web auth at the reverse proxy.** The proxy (Caddy or equivalent) handles authentication and injects a trusted identity header. Quire reads the header and applies per-repo visibility: public repos are world-readable, private repos and CI logs require auth. Any auth mechanism the proxy supports (basic, OAuth, SSO) Just Works — quire stays scheme-agnostic.
- **Git's filesystem is the source of truth.** Bare repos under `/var/quire/repos/` are the primary artifact. CI run history is directories on disk, not a database. A database comes back only if the filesystem approach visibly fails.
- **Built for jj.** The primary client is Jujutsu, which means routine force-pushes, short-lived refs, and unstable SHAs. No git-flow-shaped assumptions in the UI or CI.
- **Push should fail fast, loudly, and correctly.** No silent drift between quire and GitHub. No accepted-but-unreplicated state.
- **Config is code.** Global config is Fennel. CI pipelines are Fennel. If you're going to have a scripting language, have one.
## Layout
Quire's data lives under one volume:
```
/var/quire/
repos/ bare git repos; per-repo config lives in-tree at .quire/config.fnl
runs/ CI run metadata, artifacts, and logs; retention-policied
config.fnl global config; see docs/config.md for the schema
```
Host-side config (sshd_config block, Caddyfile, docker-compose file) lives on the host, version-controlled separately. See `docs/PLAN.md` for the reference layout, `docs/config.md` for the global and per-repo Fennel schemas.
## Status
Early development. SSH dispatch, repo management, Fennel config loading, and mirror push via event socket work; web view, CI, and notifications are still ahead. See `docs/PLAN.md` for the build sequence and open questions.