Skip to content

About

Blygger Studio — the reference client for the Blygger protocol. Publish, subscribe, thread, transclude, respond. Cloudflare Worker + D1 + R2.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

283 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Blygger Studio

The reference client for the Blygger protocol — a Cloudflare Worker that publishes a blyg, subscribes to others, and threads, transcludes and responds across them.

Protocol implemented: blyg 0.3, level 2 · Client version: 0.10.0 · generator: blygger-studio/0.32.2 · releases + upgrading

The Blygger spec defines the protocol. As of 2026-09-28, at least seven clients publish live blygs. Six are other implementations. Blygger uses static files and RSS. You can write your own client if this client's choices do not suit you. Several people already do.

What it does

  • Studio is the private interface for composing fragments and threads, hoppers, subscriptions, signals, and TK generation. The protocol leaves these features to each client. Other clients can implement them differently.
  • Page is the public protocol output: manifest, feed, item documents, permalinks, pinned snapshots, and archives. The Worker serves this output directly. You can also export identical bytes to a static host. Identical output is a protocol requirement.

Installation

Use the latest GitHub release for a live deployment. Release downloads start with Studio 0.9.0. Older releases only have GitHub's source archives. You need:

  • Node.js 22.18 or newer.
  • A Cloudflare account with D1 and R2 enabled.
  • A domain on that account to use a custom domain.

SDK generation uses a pinned Hey API npm package.

The Worker limits API work, AI calls and stored OAuth clients. Outbound fetches allow public destinations by default. See security configuration for defaults and the explicit LAN opt-in.

Draft uploads require an owner cookie or an API token with owner:read. Studio sends the cookie for previews. Publication makes used images public and keeps images needed by published snapshots and pins available.

Contributors: see tests and their limits for verification commands, oracle replay, and the upgrade test.

Install the Worker download

Download blygger-worker-VERSION.tar.gz and SHA256SUMS from the same release. Replace VERSION below with the release number, without the v prefix.

shasum -a 256 blygger-worker-VERSION.tar.gz
# Compare the result with this file's line in SHA256SUMS.
# On Linux, use sha256sum if shasum is unavailable.
tar -xzf blygger-worker-VERSION.tar.gz
cd blygger-worker-VERSION
npx wrangler@4 login
npx wrangler@4 whoami
npx wrangler@4 d1 create blyg-myname
npx wrangler@4 r2 bucket create blyg-myname-media

Check the account in whoami. Edit the included wrangler.jsonc:

  • Set name to your Worker name and add your account_id.
  • Set the D1 database name and ID from d1 create. Keep its binding named DB.
  • Set the R2 bucket name. Keep its binding named MEDIA.
  • Add routes: [{ "pattern": "blyg.example.com", "custom_domain": true }], using your domain. Keep vars.MOUNT as "" for a subdomain.
  • Keep main: "worker.js", no_bundle: true, and migrations_dir: "migrations".

Then provision the schema, set secrets through Wrangler's prompts, and deploy:

npx wrangler@4 d1 migrations apply DB --remote
npx wrangler@4 secret put OWNER_PASSWORD
npx wrangler@4 secret put COOKIE_SECRET
npx wrangler@4 deploy

Use a strong owner password and a separate random cookie secret (at least 32 random bytes, such as 64 hex characters generated by a password manager). Keep both out of the config. To check the setup:

  1. Open https://blyg.example.com/studio.
  2. Sign in.
  3. Set your title and author name in Settings.
  4. Add subscriptions.
  5. Publish a fragment.

AI is optional. Each AI function (TK generation, changelog notes, and later feed scoring) takes its own model in Settings → AI models, chosen from models.json. Set the key for each provider you use: AI_PROVIDER_KEY (Anthropic), OPENAI_API_KEY (OpenAI) or GOOGLE_AI_KEY (Google), e.g. npx wrangler@4 secret put AI_PROVIDER_KEY. To change the model list without upgrade conflicts, copy entries into a models.local.json (gitignored, same shape; see the comment in models.json) and redeploy.

The archive includes the Worker bundle, migrations, licenses, and a deployment README. It needs no npm ci or source build. Wrangler's Cloudflare setup instructions cover login and bucket creation.

Install from source

Choose this path to change Studio or use its provisioning and export scripts. Replace vVERSION with a published release tag.

git clone --branch vVERSION https://github.com/blygger/blygger-studio.git
cd blygger-studio
git switch -c my-blyg
npm ci
npx wrangler login
npm run init
npm run deploy

npm run init asks you to choose the account and domain, creates D1 and R2, writes deployment config, applies migrations, and sets secrets. It can resume after a failed step. It does not deploy. npm run deploy does that afterward. Keep your deployment config in your own checkout. Contributors should use the ignored wrangler.private.jsonc. Build before a direct Wrangler deploy:

npm run build
npx wrangler deploy --config wrangler.private.jsonc

Keep the committed template generic.

To export an existing site's public pages for a static host:

npm run export -- --out exported-blyg --base https://blyg.example.com/

Local development

Clone the repository and run npm ci. Create an ignored .dev.vars file with local-only OWNER_PASSWORD and COOKIE_SECRET values, then run:

npx wrangler d1 migrations apply DB --local
npm run dev

Open http://localhost:8787/studio and sign in with your local password. Local D1 and R2 data are separate from your live deployment. Tests use their own in-memory fixtures and do not need .dev.vars or a Cloudflare login.

npm run build
npm run typecheck
npm run test:ui -- --maxWorkers=2
npm test -- --maxWorkers=2
npx playwright install chromium
npm run test:e2e

Public page caching

Public HTML pages use a shared Cloudflare cache for 60 seconds. After expiry, Cloudflare can serve the saved page for another 300 seconds while it refreshes in the background. Browsers validate their saved HTML with a content ETag. Changes, including withdrawals and collection visibility, can appear after this cache window. Studio, API, media, and XML routes keep their existing behavior.

New installations and Worker archives include the cache configuration. Existing installations must add this block to their deployment config, including any ignored private config, and deploy with Wrangler 4.107.0 or later:

"cache": { "enabled": false },
"exports": {
  "PublicHtml": { "type": "worker", "cache": { "enabled": true } }
}

The default router stays uncached. Only public HTML GET/HEAD requests enter the cached PublicHtml entrypoint. Its cache key includes the full origin and path, so aliases do not share origin-dependent HTML. Browser reloads validate the saved edge copy without forcing another render. Query parameters do not change public HTML and do not create separate cache entries. Errors and missing pages use no-store.

No migration, dashboard cache rule, extra binding, or scheduled job is needed. Without the config block, ETags still work but each request renders the page. Local Wrangler and native tests exercise routing and validators. Cloudflare's production cache supplies shared hits and background refresh.

After deployment, inspect Cf-Cache-Status for HIT or UPDATING. Test repeat GET requests. If-None-Match with the returned ETag should produce a bodyless 304. See Workers Cache configuration.

The public Webmention endpoint

{mount}/webmention accepts POST requests without a password. Another blyg uses this endpoint to report that it quotes or responds to one of your items. The Worker checks that the source item names your item. It stores no source content.

Webmention is optional at every level of protocol 0.3 (§15). Disable Settings → Accept Webmentions to remove it. The Worker then omits the manifest key and page links, and the endpoint returns 404. Your blyg still sends mentions when you quote other people.

When enabled, hourly rate limits apply to each source host, each registrable domain, and the endpoint as a whole. See src/mentions/store.ts for the limits and their reasons.

Releases and upgrading

Every release has a v{version} tag and a changelog entry with an explicit Migrations: line. Read all entries between your installed version and the target before upgrading.

Coming from 0.8.x or earlier? 0.9–0.11 rebuilt the Studio and changed the owner API. Read Upgrading to 0.11 first. It covers both upgrade paths, path mounts, checks, rollback, and the old-to-new route table for third-party tools. Your running version is the generator in https://blyg.example.com/blyg.json (for a path mount, include that path before blyg.json).

Release downloads

Download assets from the same release so the SDK and contract match the Worker.

Download Use
blygger-worker-VERSION.tar.gz Deploy the bundled Worker with migrations and generic config. See installation.
blygger-openapi-VERSION.json Import into an OpenAPI viewer, API tool, or client generator.
blygger-sdk-SDK_VERSION.tgz Install the JavaScript/TypeScript SDK in your app.
release.json Check the Studio, SDK, and API versions, source commit, and generator pin. These versions are independent.
SHA256SUMS Compare the SHA-256 digest of each downloaded file before using it.

Install the SDK archive, then use it from an app on the same origin as Studio:

npm install ./blygger-sdk-0.1.1.tgz
import { BlyggerApi, createBlyggerClient, unwrap } from "@blygger/sdk";

const client = createBlyggerClient({ baseUrl: window.location.origin });
const reading = await unwrap(BlyggerApi.listReading({ client, query: { offset: 0, limit: 25 } }));

Sign into /studio first: API calls use its owner session cookie. The SDK does not create a login session. Node clients must supply a session cookie in headers or a custom transport. See SDK usage. Never embed an owner cookie in browser source. Cross-origin clients can use resource-bound bearer tokens from Studio’s access page. See client access for scopes, revocation, and the mounted OAuth/MCP discovery profile. Install the downloads locally. The SDK is not published to the npm registry.

The downloaded OpenAPI file describes /api paths. Its default server is http://localhost:8787. Select your deployed origin in the API tool or generator. The deployed contract is also available to a signed-in owner at /api/openapi.json. Downloading the spec does not grant access to the API. See the owner API guide for resource routes, partial edits, creation, and pagination.

Interface experiments that should not become the reference design ship as Studio extensions: first-party code an operator compiles in with extensions.local.json and the owner turns on in Settings. None is compiled in or on by default.

Upgrade a Worker archive installation

Download the new Worker archive. Check its checksum. Extract it into a new directory. Keep your existing deployment config and secrets. Copy the new worker.js and migrations/ into your deployment directory. Do not replace your config with the archive's generic template. Keep main: "worker.js" and no_bundle: true. Save a D1 backup before any required schema changes. Run these commands from your deployment directory:

npx wrangler@4 d1 migrations apply DB --remote  # if the changelog lists migrations
npx wrangler@4 deploy

Deploying replaces code. It does not reset D1, R2, or stored Cloudflare secrets. The archive does not include npm run upgrade. Use these steps for each release.

Upgrade a source installation

Commit or stash local changes first, including your deployment config, then run:

npm run upgrade

The script downloads upstream tags, merges the newest release, preserves your wrangler.jsonc on conflicts, installs dependencies, applies new migrations, and runs type checks and tests. It asks before deploying. git pull tracks a branch. It does not select the latest release. A GitHub source ZIP has no Git history, so it cannot use this script. Clone the target release. Copy your config into the new checkout.

For installations from the old blygger-spec/worker/ tree, clone this repository fresh and copy your account, D1, R2, routes, and vars into its config. Git history changed during the split. Pulling the old repository will not upgrade Studio. Keep your fork's CLIENT name if you changed it.

Publishing a release

A release is cut by pushing a v{version} tag. Release CI runs the full checks and then publishes the downloads at that tag. Merges to main do not release. Before tagging, bump package.json, the root versions in package-lock.json, and CLIENT.version in src/client.ts. Add a matching changelog entry with a Migrations: line. Bump sdk/package.json when its public API changes. Release CI rejects a tag that does not match package.json, or a version that is not newer than existing release tags.

GitHub Actions must be enabled and allow the release job's contents: write permission. CI checks types, contract/SDK drift, Worker and browser tests, and extracted release artifacts. It needs no Cloudflare or npm publishing credentials. Publishing a release does not deploy anyone's Worker.

Build and check the downloads locally with:

npm run release:check
npm run release:build
npx playwright install chromium
npm run release:verify

Release verification installs the SDK in a temporary project and tests Node and Chromium. It also checks data after a fresh local Worker process starts.

The commands write downloads to build/release/. release:check requires a new unreleased version. For an already published checkout, use only the build and verification commands.

Layout

src/index.ts        routes — studio and /api registered before the public sub-app
src/protocol.ts     the wire: manifest, feed, item documents
src/model.ts        publish/withdraw/pin/restore, the state machine
src/importer/       subscribe side — resolve, feed parse, poll, hoppers, L0
src/mentions/       Webmention in and out, structural verification
src/tk.ts           TK scope grammar · src/tk-generate.ts  instructed generation
src/stub.ts         stubs (respond) · src/fork.ts  forks and lineage
src/pages.ts        public server-rendered pages
src/spa.ts          Studio shell, login/logout, embedded browser assets
src/ui/             React Studio, Router loaders, DB collections and Base UI
migrations/         D1 schema, 0001–0017
scripts/            export, deploy-all
wrangler.jsonc      your deployment — generic here; `npm run init` fills it in
deploy-targets.json your live deployments (gitignored; see the .example)

Those last two are the only files that describe an instance. Nothing under src/ should ever need editing to configure yours — if it does, that is a bug in this client, because it would put your changes in the way of every upgrade. Please report it rather than working around it.

Versioning

Client version and protocol version are independent, deliberately. This client is 0.10.0 and implements protocol 0.3. The manifest carries both — blyg is the protocol version, generator is this client's identity — and per the spec's decision #18d generator is informative: no reader may gate behaviour on it.

Nodes running the older blyg-ref/0.3.0 build keep working and report that version string. It is the same software. The name changed when the client moved out of the spec repo at session 26 (2026-09-28).

If you fork this

People already do, and that is fine. Three requests, all so that the upgrade path keeps working for you:

  1. Change CLIENT in src/client.ts. A fork that keeps reporting blygger-studio/0.10.0 makes the ecosystem census wrong for everyone, and it is the census that drives update notices. Give your fork its own name and version — that is what Blynger, blyg-publisher and the rest do.
  2. Tell us it exists, so it can be listed at blygger.org and so a breaking change to an extension point can be announced rather than discovered. Copies outside GitHub forks can be hard to discover.
  3. Number your own migrations from 9000_. Upstream migrations are numbered 0001_ upwards and will never use 9000_–9999_; that range is reserved for local changes (studio#10). D1 records applied migrations by filename, so a local 0011_… worked but collided in name with upstream's 0011_…, and an upgrade became a careful three-way merge. With local migrations at 9000_ and up, wrangler d1 migrations apply runs upstream's new ones in order and leaves yours alone. Two consequences to plan for:
    • Your migrations sort after every upstream one, so a local migration must not depend on an upstream schema change that hasn't shipped yet.
    • When upstream adds a column or table you also added locally, the upstream migration will fail on your copy. Read each release's Migrations: line before applying, and drop or rename your local equivalent first.

A stable publishing API — so that tools can write to a blyg without changing its client — is the open design question tracked as item 1.8 in roadmap-tracks.md. Studio 0.9.0 replaces older private write routes and request forms. Third-party authoring tools must adopt the new contract. See the owner API guide for the replacement routes.

The private Studio API now has a checked-in OpenAPI contract and a generated JavaScript/TypeScript SDK. The owner can download the same contract at /api/openapi.json. It uses the existing session cookie. This API does not define a public publishing protocol.

npm run openapi updates the contract. npm run sdk:generate rebuilds the SDK with a pinned Hey API generator on Node 22.18+, using the unchanged spec. Dependency installation builds the SDK and Studio assets, including during upgrades from 0.8.3. The npm dev, test, and deploy scripts also run npm run build for you. Build first when you run TypeScript, Vitest, or Wrangler directly. CI checks types, contract and SDK drift, Worker tests, and Chromium browser tests. Studio 0.10.0 uses React, TanStack Router, TanStack DB, and Base UI. Route loaders preload collections through the SDK. Active views poll the D1-backed API every 15 seconds, pause while the tab is hidden, and refresh on focus. Polling keeps unsaved editor text. The Worker embeds the browser assets. Deployment needs no extra asset binding. For a mounted installation, forward {mount}/* and /api/*, including {mount}/studio/app.js and {mount}/studio/app.css.

See the migration plan for the completed SPA cutover and the OAuth and MCP client access.

Browser tests

npx playwright install chromium
npm run test:e2e

The browser suite runs an in-memory Worker, D1 database, and R2 bucket. Outbound requests use a local fixture response. The tests need no deployment config or host credentials.

History

This repository separated from blygger/blygger-spec at session 26 (2026-09-28). git subtree split preserved all 59 commits from worker/. The spec repository now contains only normative protocol material.

The split separates protocol issues from bugs in this client. A report such as "transclusion is broken" could refer to either. Six other implementations also use the protocol.

License

MIT. The protocol documents live in blygger-spec under CC-BY-4.0.

About

Blygger Studio — the reference client for the Blygger protocol. Publish, subscribe, thread, transclude, respond. Cloudflare Worker + D1 + R2.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages