gGodspeed CLI

Publishing

A package is signed on your machine, by a key only you hold, and uploaded with a token only you hold. Anyone can then download it and check, offline, that you published it and nobody changed it.

Once: your key and your token
Publishing a release
Publishing from CI
Verifying anyone's package
What a verified package means
Rotating or losing a key
When publishing fails

The official registry is live at https://godspeed-registry.bankole-422.workers.dev, and it is the CLI's default, with its root of trust built in. (The address is temporary: it moves to a custom domain, and the default moves with a CLI release.) --registry, GODSPEED_REGISTRY or godspeed login choose another. Publishers are approved by hand for now, by the registry's maintainer.

Once: your key and your token

Publishing needs two things, and they are deliberately separate. Your signing key proves which key signed a release. Your token proves to the registry who is uploading. Losing one never gives away the other.

  1. Make your signing key

    $ godspeed key generate
    Generated a signing key.
      public key: ed25519:b79a6e807483491aef81606ca45acfa2b4aa943522d693213b5439a26f7d0975
      stored in:  ~/.config/godspeed/signing-key.toml (readable by you alone)

    Back that file up: a lost key cannot be recovered. Send the public key - never the file - to the registry maintainer. They list it, signed offline, as a key allowed to sign for your namespace.

  2. Make your token

    $ godspeed login
    Made a publisher token for https://godspeed-registry.bankole-422.workers.dev, stored in
    ~/.config/godspeed/credentials.toml (readable by you alone).
    Its fingerprint:
      sha256:7555d1395fd4b16f16db195c707335aa748c4f5c84d7c2b27db0a5f87ca2a917
    Send the registry maintainer this fingerprint - never the token itself - and your account name.

    Like an SSH key, the token is made on your machine and never leaves it. The maintainer approves only its fingerprint - its SHA-256 - which is all the registry ever stores. Running login again is always safe: it says whether the token is still waiting, and makes a new one only if the old one can never work again.

  3. Check it

    $ godspeed whoami
    alice on https://godspeed-registry.bankole-422.workers.dev
      may publish under: alice/
      token expires:     2027-01-14T10:34:09Z
      token from:        stored credentials
      fingerprint:       sha256:7555d1395fd4b16f16db195c707335aa748c4f5c84d7c2b27db0a5f87ca2a917

On Windows the two files are in %APPDATA%\godspeed\.

Publishing a release

Name your namespace in godspeed.toml - publisher = "alice" makes the package alice/hello - and publish:

$ godspeed publish
Creating package...
Verifying package...
Signing with ed25519:b79a6e80...
Authenticating with https://godspeed-registry.bankole-422.workers.dev...
Reserving alice/hello@0.1.0...
Reserved until 2026-10-16T10:51:53Z.
Uploading contract.toml (439 bytes)...
Uploading manifest.sig (243 bytes)...
Uploading x86_64.elf (18952 bytes)...
Uploading aarch64.elf (78760 bytes)...
Uploading armv7.elf (16644 bytes)...
Uploading riscv64.elf (30968 bytes)...
Finalising publication...
Published alice/hello@0.1.0 (2026-10-16T10:36:55Z)
Install, on a Godspeed machine:
  godspeed fetch alice/hello
  godspeed install alice/hello
Verify it from the registry, as a client would: godspeed fetch alice/hello@0.1.0

Publishing from CI

CI gets its own token, printed once and stored nowhere:

$ godspeed token new
gsp_...
Fingerprint: sha256:...
The token above is shown once and saved nowhere. Put it in your CI's secrets as GODSPEED_TOKEN, and
send the registry maintainer the fingerprint - never the token - and your account name.

Send the fingerprint to the maintainer as before, then give the job two secrets and nothing else:

.github/workflows/publish.yml (excerpt)
env:
  GODSPEED_REGISTRY: https://godspeed-registry.bankole-422.workers.dev
  GODSPEED_TOKEN: ${{ secrets.GODSPEED_TOKEN }}             # the token from `token new`
  GODSPEED_SIGNING_KEY: ${{ secrets.GODSPEED_SIGNING_KEY }} # the secret line of signing-key.toml
steps:
  - run: godspeed publish

Every command runs without prompts, with the same checks as on your machine.

Verifying anyone's package

Downloading needs no account. fetch checks a release the way a Godspeed machine will before installing it, and keeps nothing it could not verify:

$ godspeed fetch godspeed/hello@0.1.0
Checking https://godspeed-registry.bankole-422.workers.dev's trust metadata...
First contact with the official registry: its root 1 matches the one built into this CLI.
Downloading contract.toml...
Downloading x86_64.elf...
...
Fetched godspeed/hello@0.1.0 into ./godspeed-hello-0.1.0
  verified: root 1 -> timestamp 2 -> snapshot 2 -> namespaces 1 -> index -> manifest -> files
  signed by ed25519:b79a6e80... (an active key of godspeed/)
  requests: log_write

The official registry's root of trust is built into the CLI: the first time this machine talks to it, its root is accepted only if its digest is sha256:d769d1a64c3105c8da0ffcc2f54aba1c3a16ce4ae707a6d206556f08824a146d. For any other registry, --trust-root pins its root the same way; without it, the CLI trusts the root it is given on first contact and prints its digest for you to compare. After that, a new root is accepted only if the old one signed it.

A package directory - downloaded any way you like - can also be checked with no registry at all:

$ godspeed verify ./godspeed-hello-0.1.0

What a verified package means

CheckedIt meansIt does not mean
Size and SHA-256 of every fileThese are exactly the bytes the manifest namesWho made them
The manifest's signatureThe named key signed this releaseThat the key is the publisher's
The registry's signed namespacesThat key may sign for this namespace, and was not revokedThat the software is safe
Timestamp and snapshotYou see the registry's current state, not an old one replayedAnything about the code

The design follows The Update Framework: the keys that decide who may sign for whom are kept offline, so even the registry cannot change them. Details: trust metadata.

A signature is not a safety check, and installing is not a grant. A package's contract requests authority. What it is actually given is decided by the operating system on the machine it runs on.

Rotating or losing a key

When publishing fails

Every refusal says what happened, why, and what to do next, and exits with a code a script can act on (all of them):

Cannot publish alice/hello@0.1.0
Stage: upload
Reason:
  alice/hello@0.1.0 was already published on 2026-10-16T10:36:55Z with a different manifest.
  Published versions never change.
Next:
  Increment the version (in the contract and Cargo.toml) and publish again.

If the connection drops while finalising, publish does not guess: it reads the registry's index and reports what it finds. If it still cannot tell, it says the outcome is unknown (exit 25), and running publish again is always safe.