Repository navigation
Releases: beebeeb-io/cli
Release list
bb 0.14.4
bb 0.14.4: downloads straight from storage
bb pull and bb sync can now fetch a file's encrypted chunks directly from Beebeeb's object storage instead of streaming every byte through the API. The server hands out short-lived links for one file at a time. The CLI authenticates and decrypts every chunk on your machine exactly as before: the links carry ciphertext only, and your keys never leave the device. When the server does not offer direct downloads, or refuses a link, the file comes through the API as it did in 0.14.3.
What's New
- Direct downloads. The CLI uses time-limited storage links when the server advertises direct downloads (
GET /api/v1/transfer/capabilities). Chunks are decrypted in order, and the file only appears once it is complete and authenticated. - Automatic fallback. A file that storage cannot serve before the download starts goes through the API instead. A file that fails partway continues on the API's pinned per-chunk route and keeps what was already written.
bb pull --jsonreportstransport(direct,mixedorapi). This is an additive key; existing keys are unchanged.BB_TRANSPORT=api(or--transport api) forces the API for every file.BB_TRANSPORT_TRACE=1prints each transport decision to stderr, never a URL.bb sync --daemonpasses the chosen transport on to its child process.- Uploads still go through the API in this release.
Bug Fixes / Hardening
- A sync pass no longer aborts on a file it cannot read, or on a file that changes during its download. It defers that file and carries on. Under launchd or systemd an aborted pass meant a restart every 30 seconds.
bb pull <file>starts over once from fresh metadata when the file changes mid-download, then says "changed again" if it changes a second time.- The pinned per-chunk route retries rate limits (429), server errors (5xx), a file that is still being written (409) and a broken read: 4 attempts, at most 60 seconds of waiting, honouring
Retry-After. A body of the wrong length, an authorization answer and a vanished version are final. bb syncno longer mistakes a file ID containing409inside a decrypt error for "still uploading". This could make a failed pass exit 0.- Storage requests use an HTTP client of their own, with no cookies, no
Authorizationheader, no redirects and https only. Their error messages never contain a storage URL. bbrefuses to install or remove a LaunchAgent or systemd unit whenHOMEis not your account's home directory (on Linux, also whenXDG_CONFIG_HOMEpoints elsewhere), because the service would run against a different configuration than the one you see. If your home directory is intentionally relocated (for examplesudo -E), run the command again withBB_SERVICE_INSTALL_ALLOW_CUSTOM_HOME=1. Removing a service that is not installed is never refused.- A folder pull reads a file that changed during the pull again once instead of aborting, and the retry does not ask the overwrite question twice.
Compatibility
- This CLI with an older server: the server advertises no direct downloads, so every file uses the API, exactly as in 0.14.3.
- An older CLI with a newer server: unchanged. 0.14.3 and earlier never ask for storage links.
- Dependency change:
beebeeb-core/beebeeb-typespinned to3235dc15(the shared direct-transfer rules). No other dependency versions changed.
Verification
- Full test suite on Linux, at the commit this release is built from, in a sandbox with no network access and an egress recorder: 730 passed, 0 failed, 4 ignored across 24 test binaries; 0 outbound connection attempts; no service manager touched. Clippy with warnings denied and rustfmt are clean.
tests/direct_download.rsruns the realbbbinary against a mock API and a hand-written storage socket. It covers faults, redirects, tampered chunks, expired links, the mixed fallback, and that no link signature appears in any output.tests/service_guard.rsputs recordinglaunchctl/systemctlstubs ahead of the real tools onPATHand scanssrc/for any unguarded call.- Release gates: full required CLI CI, five platform builds, and draft asset readback with checksum assertions before publishing.
Install / Update
bb update
bb --version # bb 0.14.4Homebrew: brew upgrade beebeeb-io/tap/bb. Scoop: scoop update bb. New installs: curl -fsSL https://get.beebeeb.io | sh. Restart a running bb sync daemon after updating.
Full changelog: v0.14.3...v0.14.4
bb 0.14.3
bb 0.14.3 — updates without the GitHub API rate limit
Bug Fixes / Hardening
bb updateand background update checks use the public release manifest instead of GitHub REST API discovery. Shared-IP API rate limits no longer prevent CLI update checks; no GitHub token is required.- Download archives from the exact release tag in the manifest, retaining SHA-256 verification and staged binary version checks.
- Retains CLI0.14.2's effective curl updates, Homebrew/Scoop ownership, explicit JSON/quiet updates and Beebeeb web billing navigation.
Install / Update
If0.14.2 reports403, bootstrap the patch through the public installer:
curl -fsSL https://get.beebeeb.io | sh
bb update
bb --versionRestart a running bb sync daemon after updating. Unmanaged Windows binaries still use release-archive reinstall or Scoop.
Verification
Regression tests cover a rate-limited REST route with an available public manifest and exact request counts. Release gates include the updater suite, full required CLI CI, formatting, Clippy with warnings denied, five platform builds, draft asset readback and native package checks. No dependency versions changed.
Full changelog: v0.14.2...v0.14.3
bb 0.14.2
bb 0.14.2 — reliable updates and web billing
This patch makes updating bb explicit and fixes billing navigation. Both billing commands now take you to Beebeeb's web app to manage your account.
What's New
bb updatechecks for a newer CLI immediately and reports the result. It bypasses the background-check cooldown;BB_NO_UPDATE=1still disables automatic updates.
Bug Fixes / Hardening
- Re-running
curl -fsSL https://get.beebeeb.io | shupdates the existing Beebeeb installation your shell selects. Homebrew installations remain managed by Homebrew, including repair of a stale binary shadowing the formula. bb account billingandbb billing portalopen the Beebeeb web billing page. They no longer initiate a payment-method update or send you directly to Mollie.- Updates retain SHA-256 verification before replacing the executable. This release adds no new dependency or signing-key scheme.
Verification
- Billing navigation: 6 passed; 0 failed. Deliberately restoring Mollie navigation/removing authentication made all six fail; restored tests pass with zero payment API requests.
- Installer: 16 passed; 0 failed, against both the published cargo-dist template and a freshly generated template. Deliberate preflight/version-check mutations were rejected.
- Focused updater run: 21 passed; 0 failed, plus 2 public command tests and 1 package-manager output test. New behavior was checked against deliberate mutations before restoring the passing implementation.
- The release is gated by the full CLI test suite, Clippy with warnings denied, formatting, five platform builds, generated-installer fixtures, and native archive version checks. Final publication evidence is recorded with the release task.
- Of 443 locked packages, only the first-party CLI version changed; 0 dependency versions changed.
Install / Update
curl -fsSL https://get.beebeeb.io | sh
# After installing 0.14.2:
bb update
bb --versionHomebrew users can also run brew upgrade beebeeb-io/tap/bb; Windows users can run scoop update bb; bb update delegates to Scoop for Scoop-managed installations. Unmanaged Windows binaries require reinstalling the release archive or using Scoop. Restart a running bb sync daemon after updating.
Full changelog: v0.14.1...v0.14.2
bb 0.14.1
Beebeeb CLI 0.14.1 — compatibility and packaging refresh
This patch prepares the CLI for the coordinated server 0.1.1 release. It retains the command
behavior of 0.14.0. Since that release, the only change on main updated the Windows Scoop
manifest to 0.14.0; this release adds version metadata and these authored notes.
What's New
- A fresh release package. Existing upload, download, region and sync commands keep their
current behavior. No new command or transfer protocol is introduced.
Bug Fixes / Hardening
- The existing core pin (
337436ae753ba99ac6c4dabd18593543367f1324) and all dependency versions
remain unchanged. The server uses a different reviewed core revision; compatibility must be
checked before publishing this CLI release. - This metadata update does not claim a new runtime or security fix.
Verification
- The existing release-notes guard rejected the stale 0.14.0 notes for a 0.14.1 release before
this update (exit 1); the updated notes passed (exit 0). Locked offline metadata and formatting
checks also passed (exit 0). - Of 443 locked package entries, the first-party CLI package is the only changed version.
No dependency, core pin, source module or release script changes are included. - Not yet verified for 0.14.1: server 0.1.1 compatibility, platform binaries, installer/updater
behavior, the five-target release build, or the sixteen packaged assets and checksums. The
existing release-local procedure must pass those applicable gates before publication. - Previous 0.14.0 test results remain evidence for that earlier source; no new full test-suite
or performance result is claimed here.
Install / Update
0.14.1 is a release candidate until its release gates pass and the release is published.
Once published, use the existing installer or package manager:
curl -fsSL https://get.beebeeb.io | sh
brew upgrade beebeeb-io/tap/bb
scoop update bbThe Scoop manifest is updated through its normal follow-up pull request after the Windows
artifact checksum is available. Until then, Scoop can continue to offer the previous version.
Restart a running bb sync daemon after updating. Windows users update through Scoop.
Full changelog: v0.14.0...v0.14.1
0.14.0 - 2026-10-19
Beebeeb CLI 0.14.0 — storage is chosen by country, and a push you interrupted can be resumed
bb region now works by country, not by city. You choose Europe (the default) or a country, and
bb no longer prints a city name anywhere, including in --json output. This release also lets you
re-run an interrupted bb push to finish it. Since v0.13.6 two pull requests landed on main:
#91 (re-running an interrupted push, task 1950) and #92 (bb region by country, task
2050). #90, the Scoop manifest bump for 0.13.6, does not touch the binary.
What's New
bb region list | get | setwork by country.bb region listshows Europe (the default: no
specific country, Beebeeb places your files in any of its European datacenters), Germany and
Finland, with your current choice marked. Netherlands is listed as coming soon and cannot be chosen
yet.bb region settakes a country code or a name, in any case:bb region set deand
bb region set germanydo the same thing, andeuropereturns to the default. The list comes from
the server, so a country that goes live appears without a newbb. Your choice applies to new
uploads only: files you already uploaded stay where they are.- A city is no longer a choice. If you type one,
bb
refuses it without changing your setting and tells you to choose by country, with the codes from the
list. bb billing usagegroups by country. Usage that has no country is shown under Europe.--jsongainscountryandcountry_code.bb --json region getandsetadd both keys and
keep the existing ones (preferred_region,current,label/name).bb --json billing usage
keepsregionandused_bytes, and addscountry. Itscitykey is kept for scripts that read
it, is deprecated, and now carries the country name.- Re-running an interrupted
bb pushresumes it. (task 1950) Before, a push stopped mid-upload
left a half-uploaded file, and running the same command again refused with "already exists - pass
--replace or --keep-both". Now, when that file is your own unfinished first upload (the local resume
record and the server agree), the same command continues it. The chunks the server already holds are
skipped, or the upload restarts from the first chunk if the chunk formats differ. A completed file is
still a conflict, and so is an interrupted--replace: a plain push never finishes someone's replace.
Bug Fixes / Hardening
- No city name in any output, including
--json.bb account showandbb region liststrip
the server's deprecated city keys, so a server that still sends them does not leak them throughbb.
bb whoami,bb account showandbb speedtestname your choice by country (bb speedtestused
to print a raw datacenter id), andbb billing showalways reads "Europe" for the billing region. A
test scans the production source and the README for place names, and fails if one comes back. - Older servers keep working. A server that still lists one row per datacenter is folded into one
row per country, and a stored datacenter id reads as its country. Old datacenter ids typed by hand
or kept in scripts (the short datacenter ids) are still accepted and sent as they are; the server maps them
andbbshows the resulting country. - Known limit, not changed here:
bb region setsends only the country, which the server reads
as a non-strict choice. Setting a country from the CLI therefore clears a strict choice made in the
web or mobile app. The CLI has no strict flag yet.
Verification
Code under test: 400b212 (cli main, after #92). The release commit on top of it only changes the
version to 0.14.0, Cargo.lock (that one line), this file, and the changelog.
cargo test --no-fail-faston Linux (Legion), from the gate on #92: 19 test binaries, every one
test result: ok, 0 failed. Main unit tests (bb): 511 passed, 3 ignored.region_choice: 18
passed.no_city_copy: 3 passed. The other 16 integration binaries were unchanged and green.cargo clippy --all-targets -- -D warningsandcargo fmt -- --checkwere clean. The GitHub CI
TestsandClippy & Formatjobs passed on #92.- New tests were seen to fail first. Against the previous
main,no_city_copyfailed 2 of 3 (the
README and two place names inbilling.rs) andregion_choicefailed 11 of 18. Eleven mutations on
the final code each turned the intended tests red, among them: no folding of per-datacenter rows,
dropping the country-code match, switching the legacy-id passthrough off, billing readingcity,
and a city name added to the help text. - The #91 resume path was tested with the real
bbbinary killed mid-upload and re-run: 3 new
integration tests, plus a mutation check on thedownload_versionguard. - Real server, local: the lead ran this build (
bb 0.14.0, built from 63345d1, scratch HOME) against a
local server at the production server commit b6bf7fb4.bb region listshowed Europe (default),
Finland, Germany, and Netherlands "coming soon · not selectable".bb --json region listcarried
country/country_codeand no city key. - Production, read-only: the lead ran the same build, not signed in, against production's public list.
It gave the same four rows, and the JSON had no city or provider string. - Not verified:
bb region setagainst production. It needs a signed-in account, and the lead does not
use real accounts for checks. Also,bb.exeis cross-compiled and is not run on a Windows machine by
this release process.
Install / Update
curl -fsSL https://get.beebeeb.io | sh # macOS / Linux
brew upgrade beebeeb-io/tap/bb # macOS, Homebrew
scoop update bb # Windows, Scoop
macOS and Linux installs (shell installer or Homebrew) self-update on next run via the built-in OTA
updater. The updater checks when bb starts, so a running bb sync daemon keeps the old version
until it restarts: restart it after updating. Windows installs do not self-update yet: run
scoop update bb to get 0.14.0. The Scoop manifest (scoop/bb.json) is bumped by a follow-up pull
request; until that pull request is merged, scoop update bb still installs 0.13.6.
Full changelog: v0.13.6...v0.14.0
bb 0.13.6
Beebeeb CLI 0.13.6 — choose where your files are stored, and a stricter download path
This release adds bb region, so you can choose where new uploads are stored: Europe (the default,
any of our European datacenters) or one specific datacenter. It also moves every download onto
beebeeb-core's chunk-format-aware reader, which checks each file's format against its encrypted
metadata before it decrypts anything, and fixes bb push --replace, which failed the second time
you replaced the same file. Since v0.13.5 three pull requests landed on main: #84
(bb region, task 1919), #87 (the new read path, task 1943) and #88 (the --replace fix, task
1951). #86, the Scoop manifest bump for 0.13.5, does not touch the binary.
What's New
bb region list | get | set.bb region(orbb region list) lists where new uploads can
be stored, with your current choice marked. Today that is Europe (the default: no specific
country, Beebeeb places the file in any of its European datacenters) or one datacenter:
Falkenstein (Germany), Helsinki (Finland) or Nuremberg (Germany). Ede (Netherlands) is listed as
coming soon and cannot be chosen yet.bb region set helsinki(a datacenter id or city, or
europe) changes the choice;bb region getshows it. The list comes from the server, so a
datacenter that goes live appears without a newbb. Your choice applies to new uploads only:
files you already uploaded stay where they are.bb whoamiandbb account showname your storage choice (for example "Helsinki, Finland",
or "Europe · default, any datacenter").bb whoami --jsonhas a newregion_idkey (nullfor
the default), andregionis now the name of your choice.bb account showno longer prints a
provider name, andbb billing showno longer names one city for the billing region.
Bug Fixes / Hardening
- A second
bb push --replaceof the same file no longer fails. (task 1951) In every release
since 0.10.0 (the upload change of 2026-06-08), replacing a file that had already been replaced once failed with "stale base version
for replacement upload":bbread the file's version from a field the server does not send, so
it always claimed version 1. Every replace now sends the file's current version and creates the
next one. The same fix applies tobb webdavsaving over an existing file (a PUT with
--read-write). - Every download now goes through core's format-aware reader. (task 1943, beebeeb-core
337436a, task 1908)bb pull(single file, folder,--zip),bb sync,bb webdav,
bb mountandbb repairfirst read the file's chunk-format pin from its encrypted, authenticated
metadata (never from a field the server could change) and open every chunk under that pin. A file
in the newer chunk format opens only as that format, and a truncated one is rejected. This is the
read side of a format change that no client writes yet: uploads from 0.13.6 still use the current
format and are readable by 0.13.5 and earlier. - Interrupted uploads resume only when the format allows it. A resumed upload continues only
when both the interrupted session and thisbbuse the current format. Otherwise the partial
upload is abandoned on the server and the file is uploaded again from the first chunk. A resume
record written by 0.13.5 or earlier has no recorded format, so the first resume after updating
starts that file again from the beginning, with the notice "the interrupted upload cannot be
continued in this chunk format; starting it again". As before, you resume an interruptedbb pushwith
bb push --replace. - Behaviour change: a file whose stored name is not encrypted is refused. Without encrypted
metadata there is no format pin to check, sobbno longer guesses.bb pullof such a file fails
with the reason; a folder pull or--zipskips it with a warning and exits 3;bb syncreports it,
leaves the remote copy alone and exits 3, and tries again on the next pass. We know of no such
files in real accounts (Beebeeb clients encrypt file names); if you see this error, please report
it. Folders with plain names are not affected.
Verification
Code under test: f7cfd95 (cli main, after #88). The release commit on top of it only changes the
version to 0.13.6, Cargo.lock (that one line), this file, and the changelog.
This release is built and published from a maintainer's machine, the same way as 0.13.5, not by the
GitHub Actions release workflow. Artifacts and checksums use the same names and layout dist
produces, built with dist 0.31.0.
cargo teston macOS (Apple Silicon, rustc 1.96.0) on the release commit, scratchHOME:
619 passed, 0 failed, 3 ignored across 17 test binaries: main suite (bb) 501 (3 ignored),
account_email_change2,auth_errors8,ecdh_compat4,mount_availability3,move_parent7,
non_interactive6,onboarding_state9,pull_overwrite5,pull_path_traversal22,
push_replace_versions1,region_choice14,share_resolves_like_pull1,step_up_opaque4,
sync_never_deletes14,webdav_auth14,zero_byte_files4.cargo teston Linux, rustc 1.96.0, from the gated pull requests: 617 passed, 0 failed, 3 ignored
over 16 test binaries for #87, and 619 passed, 0 failed, 3 ignored over 17 binaries for #88 (the new
push_replace_versionsbinary). 0.13.5 had 573.cargo clippy --all-targets -- -D warningsand
cargo fmt -- --checkwere clean on both, and the GitHub CITestsjob passed on #84, #87 and #88.- New tests were seen to fail first. The #87 format tests were red against the previous core, and
each guard was mutation-checked: ignoring the metadata pin, not enforcing the newer format, skipping
the truncation check (buffered and streaming), names not going through core, the wrong writer pin,
resuming unconditionally, not recording the format, not skipping a pin-less file in a folder pull,
and syncing without the pin check each turned the intended tests red. The #88 test was red on the
previousmain("replace #2 ... stale base version") and under a mutation that reads the old field. - Compatibility against a real server (not mocks). The server's
mainran locally with a scratch
database and blob pool. Files uploaded with the releasedbb0.13.5 (a 1 KiB file, a 20 MiB
five-chunk file, a folder with a subfolder, a replaced file) were read back with the #87 build by
bb pull,bb pull --zipandbb sync --once, and two 400 MiB uploads (one interrupted under
0.13.5, one under the #87 build, both resumed by the #87 build) were read back by both builds:
15 of 15 sha256 matches, 0 mismatches. A resume with a 0.13.5 resume record
restarted from chunk 0 and completed; a resume with a new record continued the same session. For
#88, a 6 MiB file pushed and then replaced three times ended at version 4 and pulled back
byte-identical, while the previous build failed every replace against that file.bb region
(#84) was run against a local server with the region API: Helsinki, Nuremberg and Europe uploads
landed in the matching storage pools. - Not verified: none of this was run against production or a real account. Those end-to-end runs
were made on Linux (#87, #88) and macOS (#84), not on every platform.bb webdavcontent reads,
bb mountcontent reads, the interactive (TUI) sync watch loop andbb repair's refusal of a
newer-format file have no dedicated tests yet.bb pushdoes not print which datacenter a file
landed in. Windows: thebb.exeis cross-compiled and is not executed on a Windows machine by
this release process. The Linux binaries are cross-compiled and not executed here either. Please
report a problem if you see one.
Install / Update
curl -fsSL https://get.beebeeb.io | sh # macOS / Linux
brew upgrade beebeeb-io/tap/bb # macOS, Homebrew
scoop update bb # Windows, Scoop
macOS and Linux installs (shell installer or Homebrew) self-update on next run via the built-in OTA
updater. The updater checks when bb starts, so a running bb sync daemon keeps the old version
until it restarts: restart it after updating. Windows installs do not self-update yet: run
scoop update bb to get 0.13.6. The Scoop manifest (scoop/bb.json) is bumped by a follow-up pull
request; until that pull request is merged, scoop update bb still installs 0.13.5.
Full changelog: v0.13.5...v0.13.6
bb 0.13.5
Beebeeb CLI 0.13.5 — bb sync no longer deletes a local file because it is missing remotely
This is a safety release for bb sync, with two fixes. In 0.13.4 and earlier, bb sync and the
background sync daemon deleted any synced local file that was missing from the remote listing, and a
download that failed to decrypt moved the remote copy to the vault Trash. A listing that came back
empty or incomplete, or a sync folder that now pointed at a different remote folder, could therefore
remove local files that nobody had deleted. 0.13.5 removes a local file only when the server reports
that exact file as trashed, and even then moves it into a recovery folder instead of deleting it. A
decrypt failure never touches the remote copy. Since v0.13.4 two pull requests landed on main:
#83 (both fixes, tasks 1915 and 1916) and #82 (the Scoop manifest bump for 0.13.4,
which does not touch the binary).
What's New
.bb-trash/inside your sync folder. Whenbb syncremoves a local file because it was deleted
remotely, the file is moved to.bb-trash/<UTC time>/<path>inside the sync folder, not deleted.
The folder starts with a dot, sobb syncnever scans, uploads or watches it.bbdoes not empty it:
look there if a file disappeared, and delete the folder yourself when you no longer need it.bb sync --allow-mass-delete. If one pass would remove more than 50 files, or more than 10% of
the files the folder tracks (whichever is larger: 51 of 501 trips it), it removes nothing and says
so. Check the Trash in the web app first; if the deletions are intended, run
bb sync --once --allow-mass-deleteonce to let them through (into.bb-trash/). The background
daemon never gets this flag, and the continuous watch loop never removes over the limit.bb sync --rebind. If the remote folder a sync folder points at changed (the old one was trashed
and re-created, or you now sync against a different remote path), every pass keeps local removals
paused, and a file that exists on both sides is reported as a conflict instead of replacing or
overwriting either copy.bb sync --rebindaccepts the new remote folder: it drops the old folder's
sync record, so nothing is removed on its account, and your local files then sync in as new files.
It cannot be combined with--daemon.- Exit code 3 from
bb sync --oncein more cases. A one-shot pass (--once,--json,--quiet)
now exits 3 when the mass-delete limit held removals back, when a download could not be decrypted,
and when--deleteis used while the remote folder is unreconciled. Exit 3 already meant "the run
finished but left items failed or unresolved"; scripts that treat any non-zero exit as a failure will
now see these cases.
Bug Fixes / Hardening
- A file missing from the remote listing is no longer deleted locally. (task 1915) A local file is
removed only when all of these hold:- the server's own record for that file (
GET /files/{id}) says it is trashed. A file that is gone
without such a record (renamed or moved in the web app, permanently purged, or another account) is
kept, andbb syncreports it on each pass; - the local file is still byte-identical to what was last synced, checked again right before the
move, not only at the start of the pass; - the listing can be trusted: it is not empty while the folder tracks files, every remote name
decrypted and was safe to use, it was not cut short by the 50,000-entry limit (a folder of exactly
50,000 entries is no longer treated as cut short), and the remote folder is the one this folder last
synced against; - the pass stays under the mass-delete limit above.
- the server's own record for that file (
- A download that fails to decrypt no longer moves the remote copy to the Trash. (task 1916) In
0.13.4 and earlier,bb synctreated a file it could not decrypt as a corrupt remote copy and trashed
it. Now the remote file is left untouched, no local file or sync record is written, the error names
the file, a one-shot pass exits 3, and the next full pass tries again. bb sync --deleteon a changed remote folder trashes nothing. Its "synced before, missing
locally" entries belong to the old folder, so it prints a notice namingbb sync --rebindand exits 3.
After--rebindit behaves as before.- What is not changed.
--deleteon a folder whose remote root is unchanged still trashes remote
files that you deleted locally, as before.--forcekeeps its meaning for a conflict: the local copy
replaces the same-named remote file, and the remote copy goes to the web Trash first; on a changed
remote folder that applies to every same-named file, so runbb sync --rebindfirst if that is not
what you want. Moves and renames made in the web app are not reconciled: the old local copy stays next
to the new download. A permanently purged file (no record on the server) is kept locally, because it
cannot be told apart from a file in another account.
Verification
Code under test: cab3c86 (cli main, after #83). The release commit on top of it only changes the
version to 0.13.5, Cargo.lock (that one line), this file, and the changelog.
This release is built and published from a maintainer's machine, the same way as 0.13.4, not by the
GitHub Actions release workflow. Artifacts and checksums use the same names and layout dist
produces, built with dist 0.31.0.
cargo teston Linux, rustc 1.96.0: 573 passed, 0 failed, 2 ignored across 15 test binaries: main
suite (bb) 472,sync_never_deletes13,account_email_change2,auth_errors8,ecdh_compat4,
mount_availability3,move_parent7,non_interactive6,onboarding_state9,pull_overwrite
5,pull_path_traversal21,share_resolves_like_pull1,step_up_opaque4,webdav_auth14,
zero_byte_files4. 0.13.4 had 532.cargo clippy --all-targets -- -D warningsclean.cargo fmt -- --checkclean. The GitHub CI
Testsjob passed on the merged pull request (6m02s).sync_never_deletesruns the realbbbinary against an in-process mock API with a scratchHOME.
Every new behaviour test was seen to fail on the code before its fix, and each guard was
mutation-checked: deliberately breaking it (ignoring the trashed flag, allowing an empty listing,
turning the limit off, unlinking instead of moving, restoring the decrypt-failure trash, ignoring a
changed remote folder, skipping the re-check before the move, and others) turned the intended tests
red.- Not verified: none of this was run against production or a real account. The 50,000-entry limit is
tested by feeding 50,001 entries through the listing code, not against a live vault. The plain watch
loop has one end-to-end test (a changed remote folder removes nothing); the interactive (TUI) watch
loop has none and shares the same checks. Windows: thebb.exeis cross-compiled and is not executed on a Windows
machine by this release process. The Linux binaries are cross-compiled and not executed here either.
Please report a problem if you see one.
Install / Update
curl -fsSL https://get.beebeeb.io | sh # macOS / Linux
brew upgrade beebeeb-io/tap/bb # macOS, Homebrew
scoop update bb # Windows, Scoop
macOS and Linux installs (shell installer or Homebrew) self-update on next run via the built-in OTA
updater. The updater checks when bb starts, so a background sync daemon that is already running keeps
running the old version (and the old deletion behaviour) until it is restarted: restart it after
updating. Windows installs do
not self-update yet: run scoop update bb to get 0.13.5. The Scoop manifest (scoop/bb.json) is
bumped by a follow-up pull request; until that pull request is merged, scoop update bb still installs
0.13.4.
Full changelog: v0.13.4...v0.13.5
bb 0.13.4
Beebeeb CLI 0.13.4 — bb account update --email no longer sends your password
This is a one-fix release. In 0.13.3 and earlier, running bb account update --email on a normal
(OPAQUE) account sent your account password to the server, in the body of a request, even though the
email change then failed. 0.13.4 never does. Changing your email from the CLI still does not work for
these accounts; you do it in the web app. Since v0.13.3 two pull requests landed on main:
#80 (the fix) and #79 (the Scoop manifest bump for 0.13.3, which does not touch the
binary).
What's New
Nothing. There are no new commands, flags or changed defaults in this release.
Bug Fixes / Hardening
bb account update --emailno longer sends your password to the server on an OPAQUE account.
Most accounts are OPAQUE accounts: the server is built so that it never receives the password.
bb account update --emailasked for your password and proved it over OPAQUE (that part has been
correct since 0.13.3 and sends no password). It then always went on to call the old email-change
endpoint,PUT /api/v1/auth/account/email, with your plaintext password in the request body. For an
OPAQUE account that endpoint refuses the change, so you saw an error and nothing happened, but the
server had already been sent the password. This is what 0.13.3 and earlier did: the 0.13.3 release
notes saidbb account update"still sends your password to the email-change endpoint itself", and
that was true for every account, including OPAQUE ones. 0.13.4 stops after the OPAQUE check, which
happens on your computer, makes no request to the old endpoint, and prints this instead:
"Changing the email on an OPAQUE account is not yet supported from the CLI (the server does not
expose the key material the re-registration needs). Use the web app for now. Your email was not
changed." The command exits 1. (#80, task 1907)- The email change itself still has to be done in the web app. The CLI cannot do it for an OPAQUE
account yet, as before. - Accounts without an OPAQUE credential behave as before. The server tells
bbwhich kind of
account you have while it checks your password; only an account with no OPAQUE credential still uses
the old plaintext endpoint, because that is the only way it can change its email. - If you ran
bb account update --emailwith 0.13.3 or earlier, the password you typed was sent
to the Beebeeb server over TLS in a request body that the server rejected. This release fixes the
client; it cannot undo a request already made. If you want to be certain, change your password in
the web app. - This release is the client half. The server-side change that makes the old endpoint refuse an
OPAQUE account before it reads a password is a separate change and is not part of this release; the
fix here does not depend on it.
- The email change itself still has to be done in the web app. The CLI cannot do it for an OPAQUE
Verification
Code under test: a3bf683 (cli main, after #80) plus 92f7f05 (the Scoop manifest, no code). The
release commit on top of them only changes the version to 0.13.4, Cargo.lock (that one line), this
file, and the changelog.
This release is built and published from a maintainer's machine, the same way as 0.13.3, not by the
GitHub Actions release workflow. Artifacts and checksums use the same names and layout dist
produces, built with dist 0.31.0.
cargo test --locked: 532 passed, 0 failed, 2 ignored across 14 test binaries: main suite (bb)
444,account_email_change2,auth_errors8,ecdh_compat4,mount_availability3,
move_parent7,non_interactive6,onboarding_state9,pull_overwrite5,
pull_path_traversal21,share_resolves_like_pull1,step_up_opaque4,webdav_auth14,
zero_byte_files4. 0.13.3 had 530.cargo clippy --locked --all-targets -- -D warningsclean.cargo fmt -- --checkclean.- The new
account_email_changetests run the realbbbinary under a pseudo-terminal against a mock
API that records every request, with a scratchHOME. The OPAQUE test was run red against the old
behaviour first (it sawPUT /api/v1/auth/account/emailafter the OPAQUE check) and the legacy test
was mutation-checked afterwards. - Run end to end on macOS (arm64, 2026-10-15) against a local API built from server
main
(e9df0587) on a scratch database, with a scratchHOME, for an OPAQUE account signed in with
bb login --headless:bb account update --email <new address>with the correct password prints the
"Use the web app" message above and exits 1. The requests the API saw wereconfirm-opaque-start
andconfirm-opaque-finish, and nothing else: noPUT /api/v1/auth/account/email. The same run with
bb0.13.3 built from its tag showed the extraPUT /api/v1/auth/account/email(answered 400),
so the check can tell the two apart. This was done with both a debug build of this commit and the
releaseaarch64-apple-darwinarchive this release ships, with the same result. - Not verified: the legacy path (an account with no OPAQUE credential still sends its password to
the old endpoint, by necessity) is covered by a test and was not run against a live API. Windows:
thebb.exeis cross-compiled and is not executed on a Windows machine by this release process. The
Linux binaries are cross-compiled and not executed here either. This release has not been run against
production. Please report a problem if you see one.
Install / Update
curl -fsSL https://get.beebeeb.io | sh # macOS / Linux
brew upgrade beebeeb-io/tap/bb # macOS, Homebrew
scoop update bb # Windows, Scoop
macOS and Linux installs (shell installer or Homebrew) self-update on next run via the built-in OTA
updater. Windows installs do not self-update yet: run scoop update bb to get 0.13.4. The Scoop
manifest (scoop/bb.json) is bumped by a follow-up pull request; until that pull request is merged,
scoop update bb still installs 0.13.3.
Full changelog: v0.13.3...v0.13.4
bb 0.13.3
Beebeeb CLI 0.13.3 — bb webdav now needs a password and is read-only by default
This release closes a hole in bb webdav and changes how bb proves your password for destructive
actions. Until now bb webdav served your decrypted vault on 127.0.0.1 to anything that could reach
the port: a web page in your browser (through DNS rebinding), any other account on the same machine,
with no password and with writes allowed. It now asks for a password, refuses requests that did not
come from a local program you started, and does not allow writes unless you ask for them. Separately,
bb trash empty, bb rm --permanent and bb account update no longer send your password to the
server when they ask you to confirm it. Three pull requests landed on main since v0.13.2:
#76 (bb webdav), #77 (password confirmation) and #75 (release tooling, nothing at run
time), plus the Scoop manifest bump for 0.13.2 (#74), which does not touch the binary.
This release changes what bb webdav does by default. Read "What's New" before you update if you
mount your vault through it.
What's New
bb webdavis read-only by default. Uploads, deletes, renames, copies and property changes
(PUT, DELETE, MKCOL, MOVE, COPY, PROPPATCH) are refused with403and a message that names the
flag. To save files through a mount, start it withbb webdav --read-write.--read-onlyis still
accepted and now does nothing (it is the default); passing it together with--read-writeis an
error. (#76)bb webdavprints a random password at startup. Every client must send it (HTTP Basic, any
user name).bb webdavprints the password and a ready-to-use mount URL,
http://bb:<password>@localhost:<port>/, once, when it starts. A new password is generated on every
run. In Finder (Go, Connect to Server) enterhttp://localhost:<port>and type the password when it
asks; in rclone or Cyberduck use the printed URL, user and password.- If you mount your vault unattended (a login item, a script, a service), it will stop
connecting after you update: the password changes on every start and is only printed on the
terminal. There is no way to set a fixed password in this release.
- If you mount your vault unattended (a login item, a script, a service), it will stop
- Windows Explorer is not supported by
bb webdav. Explorer ("Map network drive") refuses a
password over plain HTTP by default, andbb webdavserves plain HTTP on loopback only. On Windows,
use the Beebeeb desktop app, or connect with rclone, Cyberduck or WinSCP.bb webdav --help, the
README, and a one-line hint thatbb webdavprints when it starts on Windows now say the same.
Windows Explorer is not something we tested; this is what we know from how it handles Basic
authentication, not from a run on a Windows machine.
Bug Fixes / Hardening
bb webdavrefuses requests that are not from a local program. A request whoseHostis not
127.0.0.1:<port>orlocalhost:<port>(DNS rebinding) and any request carrying anOriginheader
(what a browser sends from a web page) get403, and a missing or wrong password gets401. The
gateway listens on127.0.0.1only, and refuses to start with a clear message when the port is
already taken. Before this release, anything that could reach the port could list, read, overwrite
and delete the decrypted vault. Another account on the same machine is stopped by the password, not
by theHostcheck. (#76)- Step-up confirmation no longer sends your password.
bb trash empty,bb rm --permanentand
bb account updateask for your password again before a destructive action.bbnow proves it
over OPAQUE (POST /auth/confirm-opaque-start, then/auth/confirm-opaque-finish), the same way
the web app does, so the server never receives the password for this step. Only an account that has
no OPAQUE credential still uses the old plaintext confirm; the server tellsbbwhich one applies.
The password you type, and the OPAQUE state derived from it, are wiped from memory after use.
(#77)bb account updatestill sends your password to the email-change endpoint itself. That is
unchanged by this release.
- The step-up error says what actually happened. A wrong password prints
incorrect password.
If the server answers 401 to the confirm request, your session has ended, andbbnow prints
"Your session expired or was revoked. Runbb loginto sign in again." instead of blaming your
password. (#77) - Release tooling (#75, nothing at run time). The local release procedure is a script with
checksum and self-update assertions (scripts/release-local.sh,scripts/ota-rung.sh), and the
release workflow now skips a tag whose release already exists.
Verification
Code under test: 3853ee3 (cli main, after #77). The release commit on top of it only changes the
version to 0.13.3, Cargo.lock (that one line), this file, and the changelog.
This release is built and published from a maintainer's machine, the same way as 0.13.2, not by the
GitHub Actions release workflow. Artifacts and checksums use the same names and layout dist
produces, built with dist 0.31.0.
cargo test --locked: 530 passed, 0 failed, 2 ignored across 13 test binaries: main suite (bb)
444,auth_errors8,ecdh_compat4,mount_availability3,move_parent7,non_interactive
6,onboarding_state9,pull_overwrite5,pull_path_traversal21,share_resolves_like_pull
1,step_up_opaque4,webdav_auth14,zero_byte_files4. 0.13.2 had 492.cargo clippy --locked --all-targets -- -D warningsclean.cargo fmt -- --checkclean.- The new
webdav_authandstep_up_opaquetests run the realbbbinary. Each was run red against
the old behaviour first (the webdav tests against the unguarded gateway, the step-up tests against
the plaintext confirm), and the code was mutated afterwards to make sure the tests fail for the
right reason. - Run end to end on macOS (arm64, 2026-10-15) against a local API built from server
main
(e9df0587) on a scratch database, with a scratchHOME:bb login --headlessapproved through the
device-approval flow, two files uploaded into a folder, thenbb webdavmounted with rclone and
checked with curl.- Read-only (default):
rclone lsflists the folder,rclone catreturns the decrypted text; a
copytois refused with403 Forbiddenand the message that names--read-write; a PUT and a
DELETE with the right password are403; no password and a wrong password are401; a foreign
Hostand anOriginheader are403; a PROPFIND with the password is207. The vault was
unchanged afterwards. - With
--read-write: the samecopytosucceeds, a PUT is201, a DELETE is204, and the file
written through the gateway decrypts withbb pulland withrclone cat. - Step-up (
bb trash emptyon a real terminal): a wrong password printsincorrect passwordand
empties nothing; the right password empties the trash; the requests the API saw were
confirm-opaque-start,confirm-opaque-finish, then the delete, and/auth/confirmwas never
called. With the session ended on the server after the prompt,bbprinted the "runbb login"
line, not "incorrect password".
- Read-only (default):
- Not verified: Finder was not run against
bb webdavin this release (rclone and curl were).
Windows: thebb.exeis cross-compiled and is not executed on a Windows machine by this release
process. The Linux binaries are cross-compiled and not executed here either, andbb webdavwas not
run on Linux or Windows. The plaintext fallback of the step-up confirm (an account with no OPAQUE
credential) is covered by tests and was not run against a live API, and neither wasbb account update. This release has not been run against production. Please report a problem if you see one.
Install / Update
curl -fsSL https://get.beebeeb.io | sh # macOS / Linux
brew upgrade beebeeb-io/tap/bb # macOS, Homebrew
scoop update bb # Windows, Scoop
macOS and Linux installs (shell installer or Homebrew) self-update on next run via the built-in OTA
updater, so bb webdav will behave as described above the next time you start it after that. Windows
installs do not self-update yet: run scoop update bb to get 0.13.3. The Scoop manifest
(scoop/bb.json) is bumped by a follow-up pull request; until that pull request is merged,
scoop update bb still installs 0.13.2.
If you mount your vault through bb webdav and save files to it, restart it with bb webdav --read-write and enter the printed password when your client asks.
Full changelog: v0.13.2...v0.13.3
0.13.2 - 2026-10-09
Beebeeb CLI 0.13.2 — bb sync stops when the server has ended your session
A patch release that fixes one problem: a background bb sync service whose session the server
no longer accepts used to be restarted by launchd or systemd every 10 to 20 seconds, forever,
each time asking the server to register the device and being refused. On production this showed
up as bb 0.13.0 clients sending the same refused request around six times a minute. bb sync
now stops, says why in one line, and the service managers are told not to bring it back. Three
pull requests landed on main since v0.13.1: #71 (the fix), #73 (follow-up
hardening of the fix) and #70 (vendored contract data, nothing at run time), plus the Scoop
manifest bump for 0.13.1 (#69), which does not touch the binary. This is a patch release: no new commands, flags or JSON keys.
What's New
- Nothing new to use. The one behaviour change is below, under Bug Fixes.
Bug Fixes / Hardening
bb syncstops, once, when the server has ended the session. If the server answers the
device registration at startup with 401 (session revoked, expired or signed out elsewhere),
bb syncnow prints one line and exits with code 77 (EX_NOPERM) instead of carrying on and
being restarted. Run directly in a terminal the line is "Your session has ended. Runbb login
to sign in again." Whenbb syncruns as a background service it reads "Your session has ended.
Runbb login, thenbb sync --daemonto restart background sync." (#71) The line is written and flushed before the launchd service removes
itself, so it reaches the service's log file (#73).- Background sync services no longer restart blindly.
bb sync --daemonnow writes:- macOS (launchd):
KeepAliverestarts the job only after a failed exit (SuccessfulExit=
false, it was unconditional before),ThrottleInterval30 seconds, and a
BEEBEEB_SYNC_SERVICE=1marker in the job's environment. launchd cannot decline to restart on
one specific exit code, so when a launchd-managedbb syncexits with 77 it runs
launchctl removeon its own job. That call is bounded to 5 seconds; alaunchctlthat does
not return in time is killed and reaped, so it cannot leave a helper process behind
(#73). - Linux (systemd user unit):
RestartPreventExitStatus=77,RestartSec=30(it was 10) and the
same marker.Restart=on-failureis unchanged.
- macOS (launchd):
- Existing sync services are updated in place.
bb syncandbb loginrewrite background
sync services that an earlierbbinstalled (~/Library/LaunchAgents/io.beebeeb.sync.*.plist,
~/.config/systemd/user/beebeeb-sync-*.service) to the same policy. Only the restart policy and theBEEBEEB_SYNC_SERVICEmarker change: the
arguments, paths, log files, and the service's other environment variables (for example
BB_NO_UPDATE) and settings are kept. The rewritten file keeps its trailing newline.bbprints "Updated the background sync service to stop restarting after
sign-out." Only files with Beebeeb's own name and label are touched, and a file already in the
new form is left alone. On Linuxbbalso runssystemctl --user daemon-reload; on macOS it
does not reload the job into launchd. An existing restart loop ends after you upgrade: the next
restart runs the newbb, which gets the same 401, exits with 77 and removes its own launchd
job, so you only need to runbb loginandbb sync --daemonagain. - Not covered yet. A 401 that first appears while
bb syncis already running (the session
ends mid-watch) is not turned into exit 77 by this release; only the refusal at startup is. - Vendored onboarding contract update (#70): the iOS and desktop
pre_accountfixtures now say
signup is web-only. This is test data copied from the server;bbreads the server's live
answer, so nothing changes at run time.
Verification
Code under test: 774667e (cli main, after #73). The release commits on top of it only change
the version to 0.13.2, Cargo.lock (that one line), this file, and the changelog.
This release is built and published from a maintainer's machine, the same way as 0.13.1, not by
the GitHub Actions release workflow. Artifacts and checksums use the same names and layout
dist produces, built with dist 0.31.0.
cargo test --locked: 492 passed, 0 failed, 2 ignored across 11 test binaries: main suite
(bb) 424,auth_errors8,ecdh_compat4,mount_availability3,move_parent7,
non_interactive6,onboarding_state9,pull_overwrite5,pull_path_traversal21,
share_resolves_like_pull1,zero_byte_files4. 0.13.1 had 474.cargo clippy --locked --all-targets -- -D warningsclean.cargo fmt -- --checkclean.- The restart policy and the in-place migration are covered by unit tests on the generated launchd
plist and systemd unit and on the rewrite of old ones. The 401-at-startup exit code is covered
intests/auth_errors.rs. - Verified on a real launchd (macOS, 2026-10-09): a job with the old
KeepAlivepolicy whose
session the server refused made exactly one request, wrote the session-ended message to its log,
removed itself withlaunchctl removeand was not restarted. - Not verified: systemd was checked by unit tests on the generated unit and on the rewrite of old
ones, and by Linux CI only; no live systemd was run. The Windowsbb.exeis cross-compiled and
is not executed on a Windows machine by this release process. This release has not been run
against production. Please report a problem if you see one.
Install / Update
curl -fsSL https://get.beebeeb.io | sh # macOS / Linux
brew upgrade beebeeb-io/tap/bb # macOS, Homebrew
scoop update bb # Windows, Scoop
macOS and Linux installs (shell installer or Homebrew) self-update on next run via the built-in
OTA updater. Windows installs do not self-update yet: run scoop update bb to get 0.13.2. The
Scoop manifest (scoop/bb.json) is bumped by a follow-up pull request; until that pull request is
merged, scoop update bb still installs 0.13.1.
If bb sync was running as a background service and its session has ended, run bb login, then
bb sync --daemon once after updating.
Full changelog: v0.13.1...v0.13.2