Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Publishing Packages

An Account

Publishing needs an account on the registry. Installing needs none.

zuri account create

That asks for a username, an email address and a password, creates the account, and signs the command line in. It also prints a recovery key, once: the only way back into the account if the password is lost. An account can be made on the registry’s website just as well, and signed in to afterwards:

$ zuri account login
$ zuri account whoami
ada on https://pub.zurilang.org

Signing in exchanges the password for a token, and the token is what every later command sends. The password is never stored. Tokens are kept one per registry in $ZURI_HOME/credentials.toml, readable by you alone.

Tokens

$ zuri account token ci --scopes publish --days 90
$ zuri account tokens
  id                name                 scopes                          expires
  74fed0927f53cc20  ci                   publish                         2026-10-28
  544af66ae6171536  zuri account create  publish, yank, owners, account  2027-09-28
$ zuri account revoke 74fed0927f53cc20

A token carries scopes that bound what it can do:

ScopeAllows
publishpublishing new versions
yankyanking and restoring versions
ownersadding and removing a package’s owners
accountissuing and revoking tokens

A token is shown once, when it is issued, and the registry keeps only a digest of it. It lasts 365 days unless --days says otherwise, and zuri account logout revokes the saved one and forgets it.

A build server signs in with a token rather than a password, read from standard input so it never lands in the shell history or the process list, or taken from the environment:

echo "$PUBLISH_TOKEN" | zuri account login --token-stdin
ZURI_TOKEN="$PUBLISH_TOKEN" zuri publish

Give it a token with the publish scope alone, and nothing it leaks can yank, change owners or issue more tokens.

What Goes In

A package is the project’s files, packed. Inside a git repository that is what git tracks or would track; outside one, every file below the project. .git and .zuri never go. include and exclude in [project] narrow or widen that with globs, * within one directory and ** across any number:

[project]
exclude = ["docs/drafts/**", "*.log"]

Files that look like they hold secrets, such as .env, private keys and credential files, are left out, and the publish stops and names them. A file that is meant to go is named in include.

See exactly what would be sent first. This project leaves its tests out with exclude = ["tests"]:

$ zuri publish --dry-run
Would publish weather 0.1.0

  53 B   .gitattributes
  217 B  .gitignore
  461 B  README.md
  541 B  app/index.zu
  376 B  index.zu
  206 B  project.toml

6 files, 1.8 KiB unpacked, 1.6 KiB packed
sha256:0a6b340e81682bde7e4364e2209333ba32c1f3852ff10558bf513550e2758b30

The archive is built the same way every time: sorted entries, fixed times and owners, normalised permissions. The same files always make the same bytes and the same checksum, on any machine.

Publishing a Version

zuri publish

Before anything is sent, the project must have a valid name and version, git must have no uncommitted changes (--allow-dirty goes ahead anyway), and the package must hold at most 20,000 files that unpack to at most 256 MiB. A license that does not read as an SPDX expression is a warning. The registry then checks the archive again for itself, and refuses anything unsafe to unpack.

A published version never changes. Publishing the same files again is reported as already published; publishing different files under a version that exists is refused. To fix a version, publish the next one.

The first account to publish a name owns it.

Yanking

zuri yank http-extra@1.4.1
zuri yank http-extra@1.4.1 --undo

A yanked version stays on the registry, and every project whose lockfile already names it keeps installing it, so yanking never breaks a build. It is only left out when versions are chosen anew. Yank a version with a serious bug; do not yank it to hide that it existed.

Owners

zuri owner list http-extra
zuri owner add http-extra grace
zuri owner remove http-extra ada

Every owner may publish, yank and change the owners. A package always keeps at least one.

Another Registry

publish, yank, owner and account work with the default registry unless --registry names another, by address or by alias:

zuri account login --registry company
zuri publish --registry company

A dependency from another registry must say which in project.toml, so that whoever installs the package finds it. A dependency naming no registry comes from the registry the package itself is published on.