Documentation

Last updated: 2026-08-26

Everlock 0.8.0

The 0.8.0 release adds file shares: a versioned store mounted as a network drive over WebDAV, from Finder, Windows Explorer, a Linux file manager, or rclone. Every change is a commit, so a share's history reads with git log. Git repositories gained control over how much history they keep, serve git clone --depth, and are swept of unreachable objects daily. Binaries are on the download page; container images are published under the 0.8 tag family (cr.everlock.sh/everlock:0.8-qwen3, cr.everlock.sh/everlock:0.8-smolvlm).

Highlights

  • File shares over WebDAV. A share is a versioned store served as a network drive: browse, open, save, rename, and delete from the file manager already on the machine. Every request that changes something is one commit, so a share's history is a git history — clone the store and read it with git log. Reads and uploads stream, so a large file is never held whole in memory. Authentication is Basic against Everlock users, authorized on http/files/<share>: reader browses and downloads, writer does everything a file manager does. Shares are managed with /files create|list|set|unset|delete, each applying immediately to the running server, and a share on a .local vhost is announced over mDNS as _webdav._tcp, so it appears in the network browser without anyone typing a URL. See the backend reference and the guide.
  • Windows and Finder keep their own properties. PROPFIND answers allprop, propname, and a named list each as asked, reporting a property the resource does not have as 404 inside the multistatus rather than failing the request. PROPPATCH stores what a client sets beside the resource it describes, so those properties travel with a MOVE, are copied by a COPY, and are deleted with the file. ETag and Last-Modified are honoured on the way back in — 304 for a client that already has the current copy, 412 for one writing over a version it has not seen — and the DAV If header is evaluated in full.
  • Per-repository history retention. /git repo set <name> retention=90d keeps ninety days of history and lets the daily git.retention job drop the rest; /git repo list shows each repository's window in a history column. A cut records its boundary in the repository's shallow file rather than rewriting the commits that survive it, so every commit id stays put and existing clones keep working. Inspect a cut before it happens with /git repo size <name> retention=90d, which reports commits dropped and kept, bytes reclaimed, and the refs whose tip predates the window.
  • git clone --depth=<n> is served at that depth. The server understands deepen <n> and packs only what is inside that window, so a shallow clone of a large repository transfers a fraction of it. The reply carries unshallow for a boundary the fetch completes, so git fetch --unshallow fills a shallow clone back in.
  • Unreachable objects are pruned daily. The new git.gc job sweeps every repository under the storage root — the versioned stores included — removing what no ref reaches, with a one-hour grace window that keeps an in-flight push's objects. It needs no configuration and nothing to enable.
  • Guarded writes in versioned storage. Store::commit_checked and write_stream_checked take a Precondition — what a path must still hold for the write to happen — and evaluate it inside the same serialization as the commit. The loser of a race is told its precondition failed rather than silently overwriting the winner. Store::read_stream is the counterpart to write_stream: serving a large file no longer costs its size in memory.

Breaking

  • /git repo gc is gone; the git.gc job replaces it. Pruning needs no decisions — an object goes only when no ref reaches it and it is past the grace window — so it is something that happens rather than something to run. /jobs run git.gc sweeps on demand, /jobs list shows when the sweep next runs, and /git repo size <name> reports what is unreachable without pruning anything. The MCP tool git_repo_gc and the route POST /api/git/repo/gc go with it, so scripts calling either need the job instead.

Fixes

  • A push is no longer reported as failed after it succeeded. The server answers every push with a status report but never advertised report-status, so a client that had not negotiated the report treated those bytes as a failure: the ref moved, the objects arrived, and git push still ended with "failed to push some refs". The capability is now advertised.
  • A push that arrives without its objects is refused instead of leaving a dangling ref that breaks every later clone and prune of that repository. Such an update is answered ng <ref> missing objects and the ref is left as it was.
  • A second image instance no longer locks everyone out of the first. An image instance signs the session cookie it hands out with its own key and checks it against that same key on the way back in. Signing previously read a process-wide key that each instance overwrote as it started, so with more than one instance configured, only the one that happened to start last could read its own cookies: on every other instance an album share link rendered its page and then answered 401 for the stylesheets and scripts that page needs, and a password login bounced straight back to the login form. Sharing and login work on every instance now, and existing links recover as soon as the page is opened again.

Upgrading

Self-updating servers pick 0.8.0 up on their daily check. For a manual upgrade, download the new binary (or pull the new image tag) and restart — stores, mail, and all versioned content carry over untouched. git.gc and git.retention register themselves on first start; git.gc sweeps from then on, while git.retention touches only repositories given a window with /git repo set <name> retention=<window>. Scripts calling /git repo gc, the MCP tool git_repo_gc, or POST /api/git/repo/gc need /jobs run git.gc. The full list of changes is in the changelog.

updates release files webdav git storage