diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index b76dcf7..ef46f18 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -2,8 +2,11 @@ +Closes # + ## Checklist (CONTRIBUTING.md) +- [ ] I was assigned the issue before opening this (or it's a maintainer change) - [ ] `make lint` and `make test` pass (CI runs both); `make test-gpu` too if training code changed - [ ] The engine (`src/slmkit/`) doesn't reference any project (rule 2); a Project API change has an ADR - [ ] Docs in the same change: the concept page and runbook for what was built, with real output diff --git a/CHANGELOG.md b/CHANGELOG.md index 690785b..69d811e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,9 @@ interfaces; each entry says what moved. Milestones (M0, M1, …) are described i `info` says `"engine": "browser"`; project viewers work unchanged (ADR 0011). - `slm runs list --project NAME` lists one project's runs (#8, thanks @KeuqS). - `abc-folk` on the Hugging Face Hub ([m87techlabs/abc-folk](https://huggingface.co/m87techlabs/abc-folk)), - and a runbook for publishing an export there (`docs/runbooks/hf-hub.md`). + with a [live demo](https://huggingface.co/spaces/m87techlabs/abc-folk) that runs the model in the + browser, and a runbook for publishing an export there (`docs/runbooks/hf-hub.md`). +- `CONTRIBUTING.md`: how to pick up an issue (comment, get assigned, then open a pull request). ## [0.1.0] - 2026-10-13 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d1aadaa..593c867 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -139,6 +139,7 @@ uv run slm pretrain abc_music/micro_v1 --set train.lr=6e-4 uv run slm eval uv run slm runs list # tokens done/target, GPU-hours, last checkpoint uv run slm runs list --project abc_music # only runs for one project +uv run slm runs list --json # the same, as JSON for scripts; accepts --project uv run slm runs compare uv run slm export --name --version uv run slm serve --model : @@ -193,6 +194,25 @@ part of the current milestone — implement it rather than inventing a different - **No co-author or generated-by trailers.** Commits carry the repository author only. - Never commit anything under `$SLM_HOME`; artifacts stay out of git by design. +## Picking up an issue + +New here? Issues labelled +[`good first issue`](https://github.com/m87techlabs/slmkit/labels/good%20first%20issue) each say what +to change, which files, and when it's done. + +1. **Comment on the issue first**, with a short plan, and **wait to be assigned** before opening a pull + request. An issue with an assignee is taken. This keeps two people from doing the same work: two pull + requests for one issue means one of them gets closed. +2. Maintainers reply to requests within a few days. If an assigned issue sees no activity for two + weeks, ask on it and it can be freed up. +3. Open the pull request from a branch, with `Closes #N` in its description. The pull-request template's + checklist mirrors this file. +4. **Run `make lint` and `make test` before opening it.** The music grader tests need `abc2midi` + (`sudo apt install abcmidi`). CI runs both again; for a first contribution, a maintainer has to + approve the CI run, so expect a short wait. +5. Using an AI assistant is fine. Say so in the pull request, and make sure you understand and have + run what you submit; you're answering for it in review. + ## Workflow expectations - **Changes arrive as pull requests** from a branch; CI (`.github/workflows/ci.yml`) runs `make lint` diff --git a/README.md b/README.md index 8354491..02c8e3c 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,11 @@ **A framework for building small language models from scratch on a single consumer GPU — and a guided way to learn how language models actually work.** +**[Try it in your browser →](https://huggingface.co/spaces/m87techlabs/abc-folk)** A folk-tune model +trained with slmkit (864K parameters, under a minute of GPU time) writes a tune on request, draws it as +sheet music and plays it. The model runs in your browser; there is no server +([how](docs/concepts/browser-inference.md)). + ``` ingest → prepare → tokenizer → pack → pretrain → SFT → eval → export → serve ``` @@ -111,7 +116,7 @@ uv run slm studio start # "See it in action": everything you built, in your br | [`docs/DESIGN.md`](docs/DESIGN.md) | Architecture, contracts, and the rules the code enforces | | [`docs/ROADMAP.md`](docs/ROADMAP.md) | Milestones and their exit criteria | | [`docs/decisions/`](docs/decisions/) | ADRs — what was decided, and what was rejected | -| [`CONTRIBUTING.md`](CONTRIBUTING.md) | The rules every change follows: hard rules, conventions, commits | +| [`CONTRIBUTING.md`](CONTRIBUTING.md) | The rules every change follows: hard rules, conventions, commits. **Want to help?** Start with a [`good first issue`](https://github.com/m87techlabs/slmkit/labels/good%20first%20issue), and see "Picking up an issue" there | | [`CHANGELOG.md`](CHANGELOG.md) | What changed in each release | ## Status diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index a6f0b82..ce2795c 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -163,7 +163,7 @@ Goal: a public repo a newcomer can evaluate in a minute and contribute to withou --- -## Hugging Face Hub: the folk-tune model and a live demo ◐ +## Hugging Face Hub: the folk-tune model and a live demo ☑ Goal: anyone can load `abc-folk` with `transformers`, or try it in a browser, without installing anything. *No GPU.* Decisions: ADR 0010. Runbook: `runbooks/hf-hub.md`. @@ -176,7 +176,8 @@ anything. *No GPU.* Decisions: ADR 0010. Runbook: `runbooks/hf-hub.md`. anonymously with `transformers` (runbook H.4). - [x] `slm site`: the model runs in the browser from static files, parity-tested against PyTorch in headless Chrome (ADR 0011). Docker Spaces turned out to need a paid plan; static Spaces are free. -- [ ] The static Space is live, and the README links to it. +- [x] The static Space is live (huggingface.co/spaces/m87techlabs/abc-folk), and the README links + to it (runbook H.5). --- diff --git a/docs/runbooks/README.md b/docs/runbooks/README.md index dbafd98..c7492d9 100644 --- a/docs/runbooks/README.md +++ b/docs/runbooks/README.md @@ -25,7 +25,7 @@ must match exactly and which are only ballpark figures. | [`m1-engine.md`](m1-engine.md) | M1 | ☑ | | [`m2-abc-music.md`](m2-abc-music.md) | M2 | ☑ | | [`studio.md`](studio.md) | Studio | ◐ phases 1–3 done; last criterion proved by M3 | -| [`hf-hub.md`](hf-hub.md) | Publishing on the Hugging Face Hub, and `slm site` | ◐ model live; static Space next | +| [`hf-hub.md`](hf-hub.md) | Publishing on the Hugging Face Hub, and `slm site` | ☑ model and Space live | **In `slm studio`.** The studio lists each project's runbooks next to its runs. A runbook that belongs to one project says so near its top with `` (a comma-separated diff --git a/docs/runbooks/hf-hub.md b/docs/runbooks/hf-hub.md index 32c9a68..ebe3e53 100644 --- a/docs/runbooks/hf-hub.md +++ b/docs/runbooks/hf-hub.md @@ -269,6 +269,39 @@ hf upload m87techlabs/abc-folk README.md --type space \ A model and a Space can share a name: they are different repository types. A static Space has no build step; it is live within a minute. +**Check the live Space**, from anywhere, with no token: the Space's metadata, the page's `info` file, +and the weights it serves (the same SHA-256 as the export, H.4): + +```bash +curl -s https://huggingface.co/api/spaces/m87techlabs/abc-folk | python3 -c " +import json, sys +d = json.load(sys.stdin) +print(d['id'], d['sdk'], d['runtime']['stage'], 'model:', ', '.join(d['models']))" +curl -s https://m87techlabs-abc-folk.static.hf.space/info | python3 -c " +import json, sys +d = json.load(sys.stdin) +print(d['model'], d['engine'], d['device'])" +curl -sL https://m87techlabs-abc-folk.static.hf.space/model/model.safetensors | sha256sum | cut -d' ' -f1 +``` + +``` +m87techlabs/abc-folk static RUNNING model: m87techlabs/abc-folk +abc-folk:3 browser your browser +0ff22be8daed1a48fc80205f4fe484774a95e2f23762e2e9ed86b2cb99024af9 +``` + +Then open the Space, click **jig-G** and **Generate**. Measured from here in Chrome: seed 3 gives the same +jig as the local site, 189 tokens in 0.11 s. + +**Two things the Hub does to a static Space**, both harmless: + +- It serves large files (the weights) by redirecting to its file storage, on another domain. `fetch` + follows the redirect, and the storage allows cross-origin reads, so the page loads the model as it + does locally. +- It adds one `