Pin knowledge the way you pin software.
The Hub CLI surface lives in @knolo/cli (knolo-core). Hub ships HTTP. Downloads go to Vercel Blob, never through Hub.
01knolo add
GET the version manifest from https://hub.knolo.dev (Cache-Control: no-store), refuse 410 unless --force, refuse an empty url, GET the Blob URL, SHA-256 the body, compare to manifest.sha256, then mount locally. Do not send Hub tokens to Blob. Do not increment anything on Hub — pulls increment on the manifest GET.
knolo search refunds knolo info acme/refund-policy knolo add acme/refund-policy@1.2.0 # or: knolo search refunds --registry https://hub.knolo.dev
02Lockfile
Keep the version and digest together so an application can reproduce the same artifact.
{
"name": "acme/refund-policy",
"version": "1.2.0",
"sha256": "21a9d04e…7a12",
"stateRoot": "0x4d19…f0bc",
"license": "Apache-2.0"
}03Login stores a Bearer token
Create a kno_… token at /dashboard/tokens (GitHub session). knolo login stores it locally. Every write call must send Authorization: Bearer kno_… — the Bearer scheme is required. Omitting it yields 401 Sign in required even when the secret is valid. knolo whoami does not call Hub.
knolo login --token kno_… curl -sS -H "Authorization: Bearer kno_…" https://hub.knolo.dev/api/v1/account
04knolo publish is not wired yet
@knolo/cli 5.2.0 still stubs knolo publish / knolo yank with “Hub write APIs do not accept CLI tokens yet”. Hub does accept Bearer tokens. Treat that CLI error as a missing command, not as Hub policy. Until the CLI ships publish, use /publish in the browser or the HTTP sequence below. Do not call POST /api/v1/tokens with the CLI key (session only).
05Publish over HTTP
Hash the .knolo, POST /api/upload/token with the Bearer header, PUT bytes to the returned public upload.url (abort if the host is .private.), then complete / verify / draft / release. complete rejects private Blob URLs. Do not send the kno_ token to Blob.
POST /api/upload/token { sha256, contentLength }
PUT <upload.url> .knolo bytes
POST /api/upload/complete { sha256, url, sizeBytes, pathname }
POST /api/v1/publish/verify { sha256 }
GET /api/v1/publish/jobs/:id until passed
POST /api/v1/publish/drafts { sha256, slug, version, license, attested: true, … }
POST /api/v1/publish/drafts/:id/release