Skip to content

feat: slm site (the model runs in the browser) and the Hugging Face publishing runbook - #9

Merged
sandeeps85 merged 6 commits into
mainfrom
docs/hf-runbook
Oct 15, 2026
Merged

sandeeps85 merged 6 commits into
mainfrom
docs/hf-runbook

Conversation

@sandeeps85

@sandeeps85 sandeeps85 commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

What and why

abc-folk:3 is live at https://huggingface.co/m87techlabs/abc-folk. The demo was planned as a Docker
Space running slm serve, but Hugging Face returned 402 Payment Required for both the organisation
(Team plan) and the personal account (PRO). Static Spaces are free. slmkit's models are small enough
to run in a browser, so this PR adds that, plus the runbook for publishing.

slm site: the model runs in the browser

  • serve/static/model.js is the same network as model/llama.py, written out in plain JavaScript:
    RMSNorm, rotate-half RoPE with float32 angle tables, grouped-query attention, SwiGLU, a tied head.
    It reads the export's own files and keeps a key/value cache. At the context limit it re-reads the
    last block, the way generate.py crops.

  • The playground page: one branch. When info says "engine": "browser", it generates in a Web
    Worker and gets the same JSON as POST /generate, so project viewers work unchanged.

  • slm site <name:version> writes an immutable, content-addressed site artifact (lineage back to
    the raw data): the page, the engine, a static info, the model's files and the viewer. Char-level
    models only; BPE models are refused.

  • Parity in headless Chrome (tests/unit/test_site.py):

    • logits at every position within 1e-4 of PyTorch, multi-head and grouped-query;
    • greedy generation token for token, past the context length.

    Skipped without Chrome; CI's Ubuntu runners have it.

  • Measured on abc-folk:3:

    • max logit difference 2.4e-6;
    • greedy text identical to transformers and slm serve;
    • about 1,500 tokens/s in Chrome, against about 450/s for slm serve on the CPU.

Docs

  • docs/runbooks/hf-hub.md covers:
    • one-time setup and the model upload;
    • public-API checks with real output: metadata, tag, SHA-256 of the weights matching the export, an
      anonymous transformers load;
    • building and publishing the static site, updating, and taking everything down;
    • pitfalls: an organisation's display name vs its username, password-manager autofill, the 402.
  • docs/concepts/browser-inference.md: why it works at this size, model.js mapped to llama.py, the
    key/value cache worked through, parity, and why seeds differ across engines.
  • ADR 0011, which replaces ADR 0010's Docker Space.
  • Updates to serving.md §9, DESIGN §6.9, MODEL.md (there is now a second implementation to keep in
    step), STACK, GLOSSARY (Web Worker, static site, Space), CONTRIBUTING, README, CHANGELOG and ROADMAP.

Rejected:

  • paying for a Docker Space;
  • transformers.js with an ONNX export (a second model format standing in for the part slmkit writes
    out);
  • WebGPU (needless at this size);
  • an embedded V8 for the parity test (a new dependency that doesn't test a browser).

Checklist (CONTRIBUTING.md)

  • make lint and make test (246 passed, including the browser parity tests) pass locally
  • Engine change has an ADR (0011)
  • New terms in GLOSSARY; STACK updated (headless Chrome's new use, static Spaces)
  • Concept page and runbook ship in the same change; runbook output captured by running it
  • Conventional commits; no trailers

…verified live

Every milestone-sized piece gets a runbook, and publishing is the one outward-facing step, so it
gets the same treatment: what goes where, the exact commands, and checks a stranger can run
against the public API with real output (metadata, tag, SHA-256 of the weights against the
export, an anonymous transformers load). It also records the pitfalls met on the way (an
organisation's display name versus its username, a password manager filling the account form),
because those cost real round trips. The Space section stays open until the Space is live.
Creating a Docker Space under the organisation returned 402 Payment Required: Hugging Face now
charges organisations for Docker Spaces, while personal accounts can still use the free CPU tier.
The Space moves to the personal namespace and still serves the organisation's model. Recorded in
ADR 0010 with the alternative (a static Space with in-browser inference) and as a runbook pitfall.
Hugging Face now charges for Docker Spaces, organisations and personal accounts alike; static
Spaces stay free. slmkit's models are small enough to run in a visitor's browser, so a static
site can serve one with no server at all.

model.js is the same Llama-style network as model/llama.py, written out in JavaScript and reading
an export's own files (config, tokenizer, safetensors), with a key/value cache so each token costs
one position. The playground page is unchanged except that, when its info file says
"engine": "browser", it generates in a Web Worker and gets back the same JSON /generate returns,
so project viewers work as they are. slm site writes the page, the engine, the info file and the
model's files as an immutable artifact.

Parity is tested the way export is: in headless Chrome, logits at every position within 1e-4 of
PyTorch (multi-head and grouped-query), and greedy generation token for token past the context
length. On abc-folk:3 the difference is 2.4e-6, and the browser generates ~1,500 tokens/s.

Rejected: transformers.js with an ONNX export (a second model format and a library standing in for
the part slmkit writes itself); WebGPU (needless at 0.86M parameters); an embedded V8 in the tests
instead of Chrome (a new dependency, and it wouldn't test a browser).
…lishing runbook

browser-inference.md explains why a 0.86M-parameter model can run in a browser and a 7B one can't,
maps every piece of model.js to llama.py, works through the key/value cache (300 positions instead
of ~45,000 for a 300-token tune), how parity is proved and why the test scales its random weights
only to x3, and why a seed can't reproduce PyTorch's samples. ADR 0011 replaces ADR 0010's Docker
Space after both organisation and personal accounts returned 402. The runbook's H.5 now builds and
checks the static site, with real output.
@sandeeps85 sandeeps85 changed the title docs: runbook for publishing on the Hugging Face Hub feat: slm site (the model runs in the browser) and the Hugging Face publishing runbook Oct 13, 2026
@sandeeps85
sandeeps85 merged commit 1e65fb6 into main Oct 15, 2026
6 of 7 checks passed
@sandeeps85
sandeeps85 deleted the docs/hf-runbook branch October 15, 2026 18:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant