▍ humdrum codex / custard v0.3.0
license AGPL-3.0
5.3 KB raw

Using jujutsu (jj) with Soft Serve + custard

jujutsu (jj) is a Git-compatible VCS that uses git as its storage backend. This means it works naturally with Soft Serve and custard — no special server support required. Replace your-host with your forge domain throughout.

What works unchanged

jj stores its history in a standard git repo. jj git clone and jj git push speak plain git to Soft Serve over SSH (port 23231). Once pushed, every object — commits, trees, blobs, branches — is ordinary git data. custard reads that data the same way it reads any git repo: commits show in the log, file trees browse normally, blobs highlight with syntax color, refs list cleanly.

custard never knows whether a repo was authored in jj, stock git, or any other tool. There is nothing to configure on the forge side.

# clone via jj
jj git clone soft:<repo>

# push changes
jj git push --bookmark main    # or --all

Concept mapping

jj concept What lands in git / custard
commit git commit — appears in log, tree, blob views
bookmark git branch — appears on the refs page under Branches
jj describe edits the commit message of the working commit
jj git push --bookmark pushes a branch to Soft Serve
change ID (abc123...) local-only; never pushed, never visible in custard
op log local-only; the forge has no concept of it
annotated tag not supported (see below)

jj change IDs and the operation log are entirely local. They exist inside your .jj/ directory and are never transmitted over git push — so custard never sees them and has no way to display them.

The tag gap

jj cannot create or move annotated git tags. This matters because custard's Homebrew release pipeline is triggered when a tag is pushed (via a Soft Serve webhook), and the version pill on a repo's page normally reads from the highest semver tag.

For a pure-jj repo the fix is bookmark mode: instead of tagging a commit to publish a release, you create or move a release/vX.Y.Z bookmark (a plain git branch) to the commit you want to ship, then push it. custard detects the bookmark push and treats it as a release.

Tag-based repos are unaffected — bookmark mode is opt-in.

Cutting a release in bookmark mode

One-time setup

Add brew.source: bookmark to .custard.yaml in the repo:

brew:
  enabled: true
  package: "."              # or ./cmd/<name>
  source: bookmark          # opt in to bookmark-mode releases
  # bookmark_prefix: release/  # default; change only if you need a different prefix

Register the release webhook (same command as tag mode; see MANUAL.md for webhook secret generation and registration details):

ssh soft repo webhook create <name> https://your-host/hooks/release \
  -e branch_tag_create -c json -s "$WEBHOOK_SECRET"

Per-release workflow

# 1. Finish the commit that will ship
jj describe -m "Add the new feature"

# 2. Create or move the release bookmark to the current working commit
jj bookmark set release/v1.2.0

# 3. Push the bookmark
jj git push --bookmark release/v1.2.0

The webhook fires on the branch push. custard strips the prefix (release/) to extract the version (v1.2.0), builds the tarball, writes the formula to the homebrew-tap repo, and publishes. The version pill on the repo's page shows v1.2.0, labelled with the tip commit's subject line (jj bookmarks carry no annotated message — the commit subject stands in).

Versions must be vMAJOR.MINOR.PATCH (no pre-release suffixes).

Installing

brew tap you/tap https://your-host/git/homebrew-tap.git
brew trust you/tap
brew install <name>
brew upgrade <name>

How each jj operation shows up in custard

jj operation Effect in custard
jj commit / jj describe + push new commit(s) appear in log; tree/blob views update
jj bookmark set <name> + push branch appears (or updates) on the refs page
jj bookmark set release/vX.Y.Z + push release publishes; version pill and tap formula update
history rewrite + jj git push --force custard reads the new state (read-only, safe)
jj git push --all all bookmarks land on Soft; all show on the refs page
change ID / op log local-only; never visible in custard

What's intentionally not supported

No auto-detection. custard cannot infer from the objects in a repo that it was authored with jj. Bookmark mode must be enabled explicitly with brew.source: bookmark in .custard.yaml.

One mode at a time. A repo is in either tag mode (default) or bookmark mode. Switching is a one-way config flip — see MIGRATION.md for the procedure. After the flip, the tag path stops triggering releases and the bookmark path takes over. The two modes never mix, and there is no cross-mode version comparison.

Scope limit — the index list. The version shown for each repo on the forge's main index (repo list) is always derived from the highest semver git tag. That code path does not read .custard.yaml and is not mode-aware. For a pure-jj repo this means the index list shows no version; the mode-aware version pill lives on each repo's own page and refs page, which is the primary surface. This is a deliberate tradeoff and is not expected to change unless the index read is refactored.