Skip to content

0.6.0

Choose a tag to compare

@prom3theu5 prom3theu5 released this 19 Sep 22:31
dd8d1ac

What's changed

  • Make Keryx deployable with pluggable storage, OCI sharing, Postgres and a config file by @prom3theu5 in #12

Full changelog: 0.5.1...0.6.0


Highlights

Keryx 0.6.0 removes the reasons Keryx needed a local disk, and adds a way to hand a plan to someone who has no Keryx at all. An existing installation upgrades in place: replace the binary and start it. Everything new is opt-in.

Share a plan through any OCI registry

keryx share <draft-id> --to ghcr.io/acme/plans
oras pull ghcr.io/acme/plans/<draft-id>:v3     # the recipient needs no Keryx
  • A draft version becomes a single text/html layer, so a plain oras pull writes a usable HTML file, named from the draft's title. It works with GHCR, ECR, Harbor, zot, Artifactory and Docker Hub.
  • Pushes happen on your machine with your own Docker credentials. The Keryx server holds no registry secrets and makes no outbound connection.
  • Versions are immutable and explicit. Keryx pushes :v<n> and nothing else, never reads :latest, and refuses to overwrite a tag that holds something different unless you pass --force.
  • keryx inspect reads a reference's metadata without downloading the document. keryx pull brings one into your Keryx as a new draft or a new version, or writes it to a file with --output.
  • A pulled document is untrusted HTML. Its sha256 is checked against the artifact, then it passes the same HTML policy as an upload. There is no flag to skip that.

Draft HTML in S3

  • --storage s3 stores drafts in AWS S3 or any S3-compatible store: RustFS, MinIO, Ceph RGW, Cloudflare R2, Backblaze B2. Credentials come from the standard AWS chain, never from Keryx flags.
  • The server writes and deletes a probe object at startup and refuses to boot if it cannot, so a wrong bucket or a read-only credential never shows up as a 500 on the first upload.
  • keryx storage migrate --from disk --to s3 is a verified copy in either direction. Every object is read back and checked against the sha256 recorded at upload, an interrupted run resumes by re-running it, and any failure leaves the source untouched.
  • keryx storage gc lists stored objects that no version owns, and never touches anything younger than one hour.
  • Disk writes are safer too. They are now synced before being renamed into place, so a power loss can no longer leave an empty draft file.

Postgres

  • --database-url postgres://... runs Keryx on Postgres, for deployments with no persistent volume. SQLite on local disk stays the default and needs no new flags.
  • TLS is set in the URL with sslmode and sslrootcert, including a private cluster CA. Pooled connections are checked before use, so Keryx heals after a failover without a restart.
  • Two pods starting together are safe: migrations run under an advisory lock.
  • Keryx never prints the URL's credentials. The banner and errors show only postgres://host:port/database.

A config file

Every setting now resolves as flag > environment variable > config.toml > built-in default. The file is optional and lives at $XDG_CONFIG_HOME/keryx/config.toml, or ~/.config/keryx/config.toml on every platform. --config or KERYX_CONFIG names another.

[client]
api_url  = "http://plans.internal:7812"
share_to = "ghcr.io/acme/plans"

[server]
port = 7812
public_base_url = "https://plans.example.com"
max_html_bytes = 10000000
allow_font_links = true
  • Every existing environment variable and flag keeps its name and meaning.
  • The file is validated before any command runs. An unknown key or a wrong type stops Keryx with the file and the entry named, so a typo can never silently do nothing.
  • keryx serve --help shows the values in effect, including those from the file, and never prints a secret.

Fixes

  • Ctrl-C with a dashboard open. The server hung on shutdown while a dashboard tab held its live-update stream open. Shutdown now ends those streams, and the browser reconnects when the server is back. SIGTERM now shuts down gracefully too, so a systemctl restart no longer waits out the stop timeout. A second Ctrl-C exits immediately.
  • A version whose HTML file is missing now serves a clean 404, and PDF publishing answers not found. It used to be a 500.

Under the hood

  • The single crate is now a workspace of internal crates, so boundaries such as "the TUI cannot touch the database" are enforced by the compiler.
  • The hand-written SQLite layer is replaced by SeaORM behind a DraftStore trait, and blob storage sits behind a BlobBackend trait built on OpenDAL. The whole store test suite runs against both SQLite and Postgres in CI.
  • ring stays the only TLS and crypto backend. aws-lc-rs and OpenSSL are kept out of the build, and CI fails if either appears.
  • supply-chain/README.md records how dependencies are vetted and which ones are knowingly unreviewed. cargo vet exemptions fell from 763 to 501 through imported audits, per-crate publisher trust and hand audits.

Upgrade

Replace the binary and restart keryx serve with the same flags and environment. No data is moved.

On its first start, 0.6.0 takes a consistent snapshot of your database next to it, keryx.db.backup-<timestamp>, then brings the database under managed migrations in place. The startup banner says exactly what it did:

database: ~/.keryx/keryx.db (adopted a legacy database at user_version 2; backup at ~/.keryx/keryx.db.backup-20260919T211828Z; schema already current)
blobs: file://~/.keryx (probe ok, 0 ms)

Later starts say schema up to date. --no-backup skips the snapshot, which is yours to delete once you are happy.

Rollback is supported. Stop 0.6.0, reinstall 0.5.1 and start it on the same files. This was tested in both directions with the released 0.5.1 binary: every version served at each step, including ones uploaded on the other release.

Things to know:

  • Client API URL. The first client command moves the API URL from ~/.keryx/config.json into config.toml and deletes the JSON. Your API key stays in ~/.keryx/credentials.json. If you roll back, run keryx auth set <key> --api-url <url> once, because 0.5.1 does not read config.toml.
  • Read-only data directory. 0.5.1 would start on one. 0.6.0 refuses at boot, because of the startup probe.
  • A new .staging directory appears in the data directory and is emptied at every start. It must be on the same filesystem as the data directory.
  • The startup banner changed. The database: and blobs: lines have a new shape. Adjust anything that parses them.
  • TLS trust. HTTPS connections now trust the operating system's certificate store instead of a bundled root list, so a private CA installed on the machine is honoured.
  • Postgres starts empty. There is no SQLite to Postgres copy. Every draft is a complete HTML document, so re-upload what you want to keep.
  • Still one server. Neither S3 nor Postgres makes Keryx multi-node. Run exactly one server per database.
  • If you moved drafts to S3, run keryx storage migrate --from s3 --to disk with 0.6.0 before rolling back. 0.5.1 only reads local disk.
  • Agent skills. The release archives carry updated keryx-read and html-communication skills that know the sharing commands.

Install

Binaries are attached below for three targets. If yours is not one of them, build from source. The release archives also include the README, licence, and ready-made Keryx agent skills.

Released binaries include S3 storage and OCI sharing.

Platform Asset
Linux, x86-64 (glibc 2.35+) keryx-0.6.0-x86_64-unknown-linux-gnu.tar.gz
macOS, Apple Silicon keryx-0.6.0-aarch64-apple-darwin.tar.gz
Windows, x86-64 keryx-0.6.0-x86_64-pc-windows-msvc.zip

Linux (x86-64)

gh release download 0.6.0 --repo SimCubeLtd/keryx \
  --pattern 'keryx-0.6.0-x86_64-unknown-linux-gnu.tar.gz*'

sha256sum -c keryx-0.6.0-x86_64-unknown-linux-gnu.tar.gz.sha256
tar -xzf keryx-0.6.0-x86_64-unknown-linux-gnu.tar.gz

sudo install -m755 keryx-0.6.0-x86_64-unknown-linux-gnu/bin/keryx /usr/local/bin/
keryx --version

For a single-user install with no sudo, use ~/.local/bin instead and make sure it is on your PATH.

macOS (Apple Silicon)

gh release download 0.6.0 --repo SimCubeLtd/keryx \
  --pattern 'keryx-0.6.0-aarch64-apple-darwin.tar.gz*'

shasum -a 256 -c keryx-0.6.0-aarch64-apple-darwin.tar.gz.sha256
tar -xzf keryx-0.6.0-aarch64-apple-darwin.tar.gz

sudo install -m755 keryx-0.6.0-aarch64-apple-darwin/bin/keryx /usr/local/bin/
keryx --version

The binary is not code-signed or notarised. Downloading through a browser can attach a quarantine flag and cause Gatekeeper to refuse it. Clear the flag once with:

xattr -d com.apple.quarantine /usr/local/bin/keryx

Intel Macs do not have a native binary. Build from source, or run the Apple Silicon build under Rosetta 2. Rosetta 2 is unsupported and untested for this release.

Windows (x86-64)

Run these commands in PowerShell:

gh release download 0.6.0 --repo SimCubeLtd/keryx `
  --pattern 'keryx-0.6.0-x86_64-pc-windows-msvc.zip*'

# Compare the archive against the published checksum.
Get-FileHash keryx-0.6.0-x86_64-pc-windows-msvc.zip -Algorithm SHA256
Get-Content keryx-0.6.0-x86_64-pc-windows-msvc.zip.sha256

Expand-Archive keryx-0.6.0-x86_64-pc-windows-msvc.zip -DestinationPath $env:LOCALAPPDATA\Programs

$dir = "$env:LOCALAPPDATA\Programs\keryx-0.6.0-x86_64-pc-windows-msvc\bin"
[Environment]::SetEnvironmentVariable(
  'Path', [Environment]::GetEnvironmentVariable('Path','User') + ";$dir", 'User')

Open a new terminal, then run keryx --version.

The executable is unsigned, so SmartScreen can warn on first run. The installation does not require administrator rights.

Build from source (any platform)

Install the pinned Rust nightly toolchain, then run:

rustup toolchain install nightly-2026-08-20 --profile minimal
git clone --branch 0.6.0 --depth 1 https://github.com/SimCubeLtd/keryx.git
cd keryx
cargo +nightly-2026-08-20 build --release --locked
./target/release/keryx --version

To install the tagged release into ~/.cargo/bin, run:

cargo +nightly-2026-08-20 install --git https://github.com/SimCubeLtd/keryx \
  --tag 0.6.0 --locked keryx

--locked uses the dependency versions in the committed Cargo.lock. Add --no-default-features for a lean build with neither S3 storage nor OCI sharing. The build needs Python 3 on the PATH, as earlier releases did, for the PDF renderer's style engine.