Repo: https://github.com/celbridge-org/celbridge-hub-api-client
Client to connect to Celbridge-hub API for ZIPed package upload and download
- (see celbridge-hub package API server: https://github.com/celbridge-org/celbridge-hub)
v5 client — targets the Celbridge Workshop API server (v9 + v10 + v11). Authentication is via a Workshop Key (
cel_…); the old admin-login/password flow is gone. Pages are published as their own ZIP uploads, independent of packages (seeTDDS/version 5 design document.md).
Create a .env with the server URL and your organisation Workshop Key:
BASE_URL=https://yourusername.pythonanywhere.com
API_KEY=cel_xxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
The Workshop Key is issued once by your organisation admin (it is stored only
as a salted hash on the server, so it cannot be recovered later — keep it safe).
Every request the client makes sends Authorization: Api-Key <key>; there is no
separate login step. Keys start with the cel_ marker — older kpf_ keys are
rejected by the v11 server and must be re-issued. See .env.example for a template.
Optionally set AUTHOR=yourname in .env to record yourself as the publisher of
packages and pages you upload (otherwise an org service key publishes as service).
On startup the client calls GET /api/whoami to confirm the key and report which
workshop it binds to, so a rejected key is distinguishable from an unreachable host.
An interactive menu makes it easy to browse packages, upload new versions from the
files_to_upload/ directory, download to downloads/, manage aliases, and publish
web pages.
Single-file uploads (the old upload.py / /api/upload/) were removed in v7.
To upload, use the menu's Upload option or package_upload.py.
% python menu.py
Connected to Workshop Acme (acme) at https://yourusername.pythonanywhere.com.
=== Packages API ===
1 - Packages (list / show / register / delete)
2 - Versions (list / detail / upload / download / tombstone)
3 - Aliases (list / set / remove)
4 - History (full / as-of-version)
5 - Pages (publish / list / detail / unpublish)
6 - Download latest version (GET /api/packages/{name}/latest)
7 - Upload a package (POST /api/packages/{name}/versions)
0 - Exit
Select option: Select option: 1
--- Packages ---
1 - List all packages (GET /api/packages)
2 - Show package metadata (GET /api/packages/{name})
3 - Register a new (empty) package (POST /api/packages)
4 - Delete entire package (DELETE /api/packages/{name})
0 - Back
Select option: 1
GET https://yourusername.pythonanywhere.com/api/packages/
Name Latest Vers Author Uploaded
------------------------------------------------------------------------------------------
fred-chess 2 2 popeye 2026-05-09 14:19:01
space-chess24 1 1 chris 2026-05-09 14:22:26
Select option: 2
...
Enter number (or press Enter to cancel): 1
GET https://yourusername.pythonanywhere.com/api/packages/fred-chess/
Package: fred-chess
Created: 2026-05-09 14:11:38
Ver Author Uploaded Del Summary
------------------------------------------------------------------------------------------
2 popeye 2026-05-09 14:19:01 added feature - should become version 2
1 mattilda 2026-05-09 14:11:38 forked to create new package fred-chess
Alias Version
------------------------------
latest 2Pages are independent of packages. A page is its own ZIP upload whose root is the
served site, plus a page.toml manifest naming the publish path (the plural
pages.toml is still accepted):
[publish]
path = "dev/chess24"The bundle is served at /pages/<org-slug>/<path>/ (public, unauthenticated).
Re-uploading the same path replaces it; uploading, tombstoning, or deleting a
package never affects a page.
Select option: 5
--- Pages ---
(pages are independent of packages: each page is its own ZIP upload
containing a page.toml with [publish].path; served at /pages/<org>/<path>/)
1 - Publish a page (upload ZIP) (POST /api/pages)
2 - List published pages (GET /api/pages)
3 - Show page detail (GET /api/pages/{path})
4 - Unpublish a page (DELETE /api/pages/{path})
0 - Back
Select option: 1
...
This bundle publishes to path: dev/chess24
POST https://yourusername.pythonanywhere.com/api/pages
Published page: dev/chess24
Page: https://yourusername.pythonanywhere.com/pages/acme/dev/chess24/package_upload.py uploads a single package ZIP (must contain package.toml with a
name):
python package_upload.py ./files_to_upload/mysite.zip --summary "my change"The tests are live integration tests — they run against the server in BASE_URL
using the API_KEY from .env (and skip if the server is unreachable or the key is
rejected):
pip install -r requirements-dev.txt
pytest -q