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

custard — operating manual

Day-to-day use of a custard forge over Soft Serve. Replace your-host with your forge domain and you/tap with your tap namespace throughout.

The pieces

A handy ~/.ssh/config alias:

Host soft
    HostName your-host
    Port 23231
    IdentityFile ~/.ssh/id_ed25519

Everyday git

# new repo
ssh soft repo create thing -d "what it is"
cd thing && git init && git add -A && git commit -m "init" && git branch -M main
git remote add origin soft:thing && git push -u origin main

# clone
git clone soft:thing                              # ssh
git clone https://your-host/git/thing.git         # public, read-only

# admin (run `ssh soft help` for everything)
ssh soft repo list | info <n> | description <n> "…" | private <n> true|false | webhook …

Privacy

ssh soft repo private thing true     # hide from the public forge
ssh soft repo private thing false    # publish

With --soft-serve-db set, only public repos appear on the forge; private/hidden → 404.

Versioning (git tags)

git tag -a v0.2.0 -m "release name"
git push origin v0.2.0

Issues

backlog/tasks/*.md (Backlog.md) render at /r/<repo>/issues. Groups order in progress → paused → backlog → done. Manage with the backlog CLI.

Deploy a web app — the custard CLI

.custard.yaml:

ci:
  - npm test
deploy:
  # any command that prints a deployment URL (netlify/fly/rsync work too).
  # Vercel needs its project pinned — see "What's in the build" below.
  preview: VERCEL_ORG_ID=… VERCEL_PROJECT_ID=… vercel deploy --yes
  promote: VERCEL_ORG_ID=… VERCEL_PROJECT_ID=… vercel promote {{url}} --yes
custard check     # run ci on the working tree (fast loop)
custard preview   # build pushed commit → run ci → deploy preview → URL
custard promote   # promote the last preview → production

What's in the build

custard deploys the newest non-empty, pushed commit — a clean git archive of it, not your working tree. Two consequences:

Preview privacy: Vercel previews are often behind Deployment Protection — the preview URL redirects to an SSO login and is viewable only by your team. Production (your custom domain) is public. Toggle it in Project → Settings → Deployment Protection.

Release a CLI to Homebrew

.custard.yaml:

brew: { enabled: true, package: "." }   # or ./cmd/<name>

Two things are required per repo — .custard.yaml alone publishes nothing. The tag push triggers a release only if the repo also has the webhook registered. Register it once (secret = your WEBHOOK_SECRET):

ssh soft repo webhook create <name> https://your-host/hooks/release \
  -e branch_tag_create -c json -s "$WEBHOOK_SECRET"
ssh soft repo webhook list <name>        # confirm it exists before releasing

Release + install:

custard release v0.2.0          # checks → tag → push → tap publishes
brew tap you/tap https://your-host/git/homebrew-tap.git
brew trust you/tap              # newer Homebrew gates third-party taps
brew install <name> ; brew upgrade <name>

custard release always tags — keep the repo in source: tag (the default). The CLI runs plain git tag + git push, which works even in a colocated jj repo. A repo in source: bookmark ignores tag pushes, so custard release there tags successfully but publishes nothing. Use bookmark mode only if you release by pushing a release/vX.Y.Z bookmark by hand (see JUJUTSU.md).

The CLI's ✓ released means "tag pushed," not "formula published." It can't see whether the webhook fired. After a first release (or any onboarding change), verify the tap actually updated:

ssh soft repo tree homebrew-tap main Formula          # is <name>.rb there?
ssh soft repo webhook deliveries list <name> 5        # did the delivery succeed (✅)?

Empty/missing formula with a pushed tag = missing webhook or wrong source mode.

Updating the forge

cp deploy/deploy.env.example deploy/deploy.env   # first time: fill REMOTE, DOMAIN, secrets…
deploy/deploy.sh                                  # build static binary, ship, restart

Automatic niceties

See MIGRATION.md to move a repo off GitHub.