fromscratch-pyllm 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fromscratch_pyllm-0.5.0/.github/workflows/ci.yml +14 -0
- fromscratch_pyllm-0.5.0/.github/workflows/docs.yml +16 -0
- fromscratch_pyllm-0.5.0/.github/workflows/release.yml +58 -0
- fromscratch_pyllm-0.5.0/.gitignore +10 -0
- fromscratch_pyllm-0.5.0/.pre-commit-config.yaml +56 -0
- fromscratch_pyllm-0.5.0/CLAUDE.md +72 -0
- fromscratch_pyllm-0.5.0/LICENSE +21 -0
- fromscratch_pyllm-0.5.0/PKG-INFO +231 -0
- fromscratch_pyllm-0.5.0/README.md +194 -0
- fromscratch_pyllm-0.5.0/conftest.py +21 -0
- fromscratch_pyllm-0.5.0/docs/concepts/README.md +20 -0
- fromscratch_pyllm-0.5.0/docs/concepts/attention.md +39 -0
- fromscratch_pyllm-0.5.0/docs/concepts/autograd.md +63 -0
- fromscratch_pyllm-0.5.0/docs/concepts/embeddings.md +28 -0
- fromscratch_pyllm-0.5.0/docs/concepts/grow-your-own-data.md +62 -0
- fromscratch_pyllm-0.5.0/docs/concepts/how-a-model-learns.md +35 -0
- fromscratch_pyllm-0.5.0/docs/concepts/sampling.md +33 -0
- fromscratch_pyllm-0.5.0/docs/concepts/the-referee.md +98 -0
- fromscratch_pyllm-0.5.0/docs/concepts/tokens.md +34 -0
- fromscratch_pyllm-0.5.0/docs/concepts/transformer.md +56 -0
- fromscratch_pyllm-0.5.0/docs/index.md +166 -0
- fromscratch_pyllm-0.5.0/docs/property-testing.md +320 -0
- fromscratch_pyllm-0.5.0/docs/superpowers/plans/2026-06-22-pyllm-01-autograd.md +1139 -0
- fromscratch_pyllm-0.5.0/docs/superpowers/plans/2026-06-22-pyllm-02-nn-tokenizers.md +1891 -0
- fromscratch_pyllm-0.5.0/docs/superpowers/plans/2026-06-22-pyllm-roadmap.md +70 -0
- fromscratch_pyllm-0.5.0/docs/superpowers/plans/2026-07-21-pyllm-03-models-training-generation.md +2250 -0
- fromscratch_pyllm-0.5.0/docs/superpowers/plans/2026-07-21-pyllm-04-pebble-flagship.md +1539 -0
- fromscratch_pyllm-0.5.0/docs/superpowers/plans/2026-07-25-pyllm-05-pystack-integration-docs.md +559 -0
- fromscratch_pyllm-0.5.0/docs/superpowers/plans/2026-10-16-pyllm-06-grammar-constrained-decoding.md +1136 -0
- fromscratch_pyllm-0.5.0/docs/superpowers/specs/2026-06-22-pyllm-design.md +235 -0
- fromscratch_pyllm-0.5.0/docs/superpowers/specs/2026-10-16-pyllm-06-grammar-constrained-decoding-design.md +134 -0
- fromscratch_pyllm-0.5.0/mkdocs.yml +85 -0
- fromscratch_pyllm-0.5.0/overrides/main.html +7 -0
- fromscratch_pyllm-0.5.0/pyproject.toml +146 -0
- fromscratch_pyllm-0.5.0/scripts/build_pebble_corpus.py +81 -0
- fromscratch_pyllm-0.5.0/scripts/train_pebble.py +60 -0
- fromscratch_pyllm-0.5.0/scripts/train_pokemon.py +60 -0
- fromscratch_pyllm-0.5.0/src/pyllm/__init__.py +5 -0
- fromscratch_pyllm-0.5.0/src/pyllm/_types.py +10 -0
- fromscratch_pyllm-0.5.0/src/pyllm/_version.py +24 -0
- fromscratch_pyllm-0.5.0/src/pyllm/api.py +72 -0
- fromscratch_pyllm-0.5.0/src/pyllm/autograd/__init__.py +5 -0
- fromscratch_pyllm-0.5.0/src/pyllm/autograd/gradcheck.py +34 -0
- fromscratch_pyllm-0.5.0/src/pyllm/autograd/tensor.py +378 -0
- fromscratch_pyllm-0.5.0/src/pyllm/checkpoint.py +125 -0
- fromscratch_pyllm-0.5.0/src/pyllm/cli.py +202 -0
- fromscratch_pyllm-0.5.0/src/pyllm/data/__init__.py +18 -0
- fromscratch_pyllm-0.5.0/src/pyllm/data/pebble.npz +0 -0
- fromscratch_pyllm-0.5.0/src/pyllm/data/pebble_corpus.txt +19652 -0
- fromscratch_pyllm-0.5.0/src/pyllm/data/pokemon.npz +0 -0
- fromscratch_pyllm-0.5.0/src/pyllm/data/pokemon_corpus.txt +149 -0
- fromscratch_pyllm-0.5.0/src/pyllm/generate.py +213 -0
- fromscratch_pyllm-0.5.0/src/pyllm/models/__init__.py +44 -0
- fromscratch_pyllm-0.5.0/src/pyllm/models/base.py +27 -0
- fromscratch_pyllm-0.5.0/src/pyllm/models/bigram.py +41 -0
- fromscratch_pyllm-0.5.0/src/pyllm/models/gpt.py +73 -0
- fromscratch_pyllm-0.5.0/src/pyllm/models/mlp.py +56 -0
- fromscratch_pyllm-0.5.0/src/pyllm/nn/__init__.py +34 -0
- fromscratch_pyllm-0.5.0/src/pyllm/nn/attention.py +79 -0
- fromscratch_pyllm-0.5.0/src/pyllm/nn/dropout.py +30 -0
- fromscratch_pyllm-0.5.0/src/pyllm/nn/embedding.py +30 -0
- fromscratch_pyllm-0.5.0/src/pyllm/nn/functional.py +119 -0
- fromscratch_pyllm-0.5.0/src/pyllm/nn/linear.py +37 -0
- fromscratch_pyllm-0.5.0/src/pyllm/nn/module.py +84 -0
- fromscratch_pyllm-0.5.0/src/pyllm/nn/normalization.py +31 -0
- fromscratch_pyllm-0.5.0/src/pyllm/nn/transformer.py +65 -0
- fromscratch_pyllm-0.5.0/src/pyllm/pebble/__init__.py +25 -0
- fromscratch_pyllm-0.5.0/src/pyllm/pebble/ast.py +141 -0
- fromscratch_pyllm-0.5.0/src/pyllm/pebble/corpus.py +70 -0
- fromscratch_pyllm-0.5.0/src/pyllm/pebble/generator.py +145 -0
- fromscratch_pyllm-0.5.0/src/pyllm/pebble/harvest.py +35 -0
- fromscratch_pyllm-0.5.0/src/pyllm/pebble/referee.py +440 -0
- fromscratch_pyllm-0.5.0/src/pyllm/pebble/render.py +109 -0
- fromscratch_pyllm-0.5.0/src/pyllm/pebble/score.py +41 -0
- fromscratch_pyllm-0.5.0/src/pyllm/py.typed +0 -0
- fromscratch_pyllm-0.5.0/src/pyllm/tokenizer/__init__.py +7 -0
- fromscratch_pyllm-0.5.0/src/pyllm/tokenizer/base.py +24 -0
- fromscratch_pyllm-0.5.0/src/pyllm/tokenizer/bpe.py +117 -0
- fromscratch_pyllm-0.5.0/src/pyllm/tokenizer/char.py +33 -0
- fromscratch_pyllm-0.5.0/src/pyllm/training/__init__.py +7 -0
- fromscratch_pyllm-0.5.0/src/pyllm/training/data.py +44 -0
- fromscratch_pyllm-0.5.0/src/pyllm/training/loop.py +51 -0
- fromscratch_pyllm-0.5.0/src/pyllm/training/optim.py +76 -0
- fromscratch_pyllm-0.5.0/tests/autograd/test_gradcheck.py +99 -0
- fromscratch_pyllm-0.5.0/tests/autograd/test_learning.py +43 -0
- fromscratch_pyllm-0.5.0/tests/autograd/test_reshape.py +33 -0
- fromscratch_pyllm-0.5.0/tests/autograd/test_tensor.py +205 -0
- fromscratch_pyllm-0.5.0/tests/autograd/test_transpose.py +28 -0
- fromscratch_pyllm-0.5.0/tests/models/test_bigram.py +45 -0
- fromscratch_pyllm-0.5.0/tests/models/test_build_model.py +60 -0
- fromscratch_pyllm-0.5.0/tests/models/test_gpt.py +81 -0
- fromscratch_pyllm-0.5.0/tests/models/test_mlp.py +74 -0
- fromscratch_pyllm-0.5.0/tests/nn/test_attention.py +56 -0
- fromscratch_pyllm-0.5.0/tests/nn/test_dropout.py +37 -0
- fromscratch_pyllm-0.5.0/tests/nn/test_embedding.py +31 -0
- fromscratch_pyllm-0.5.0/tests/nn/test_functional.py +127 -0
- fromscratch_pyllm-0.5.0/tests/nn/test_linear.py +43 -0
- fromscratch_pyllm-0.5.0/tests/nn/test_module.py +92 -0
- fromscratch_pyllm-0.5.0/tests/nn/test_normalization.py +36 -0
- fromscratch_pyllm-0.5.0/tests/nn/test_public_api.py +25 -0
- fromscratch_pyllm-0.5.0/tests/nn/test_transformer.py +68 -0
- fromscratch_pyllm-0.5.0/tests/pebble/test_bundled_corpus.py +23 -0
- fromscratch_pyllm-0.5.0/tests/pebble/test_generator.py +35 -0
- fromscratch_pyllm-0.5.0/tests/pebble/test_harvest.py +56 -0
- fromscratch_pyllm-0.5.0/tests/pebble/test_pebble_available.py +20 -0
- fromscratch_pyllm-0.5.0/tests/pebble/test_pebble_bundled_checkpoint.py +17 -0
- fromscratch_pyllm-0.5.0/tests/pebble/test_pebble_corpus.py +90 -0
- fromscratch_pyllm-0.5.0/tests/pebble/test_referee.py +208 -0
- fromscratch_pyllm-0.5.0/tests/pebble/test_render.py +67 -0
- fromscratch_pyllm-0.5.0/tests/pebble/test_score.py +41 -0
- fromscratch_pyllm-0.5.0/tests/pebble/test_uses_public_api.py +17 -0
- fromscratch_pyllm-0.5.0/tests/test_api.py +94 -0
- fromscratch_pyllm-0.5.0/tests/test_build_pebble_corpus_script.py +55 -0
- fromscratch_pyllm-0.5.0/tests/test_bundled_checkpoint.py +17 -0
- fromscratch_pyllm-0.5.0/tests/test_checkpoint.py +248 -0
- fromscratch_pyllm-0.5.0/tests/test_cli.py +66 -0
- fromscratch_pyllm-0.5.0/tests/test_cli_pebble.py +69 -0
- fromscratch_pyllm-0.5.0/tests/test_corpus.py +22 -0
- fromscratch_pyllm-0.5.0/tests/test_dependency_pins.py +40 -0
- fromscratch_pyllm-0.5.0/tests/test_docs.py +87 -0
- fromscratch_pyllm-0.5.0/tests/test_generate.py +259 -0
- fromscratch_pyllm-0.5.0/tests/test_overfit.py +26 -0
- fromscratch_pyllm-0.5.0/tests/test_properties.py +575 -0
- fromscratch_pyllm-0.5.0/tests/test_smoke.py +8 -0
- fromscratch_pyllm-0.5.0/tests/tokenizer/test_bpe.py +58 -0
- fromscratch_pyllm-0.5.0/tests/tokenizer/test_char.py +30 -0
- fromscratch_pyllm-0.5.0/tests/training/test_data.py +56 -0
- fromscratch_pyllm-0.5.0/tests/training/test_determinism.py +39 -0
- fromscratch_pyllm-0.5.0/tests/training/test_loop.py +44 -0
- fromscratch_pyllm-0.5.0/tests/training/test_optim.py +67 -0
- fromscratch_pyllm-0.5.0/uv.lock +1161 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
name: Deploy Docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
workflow_dispatch: {}
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
docs:
|
|
10
|
+
uses: robcox2910/robcox2910.github.io/.github/workflows/docs.yml@v1
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
pages: write
|
|
14
|
+
id-token: write
|
|
15
|
+
with:
|
|
16
|
+
coverage-report: false
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*.*.*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
id-token: write
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v7
|
|
17
|
+
with:
|
|
18
|
+
fetch-depth: 0
|
|
19
|
+
|
|
20
|
+
- name: Install uv
|
|
21
|
+
uses: astral-sh/setup-uv@v7
|
|
22
|
+
with:
|
|
23
|
+
version: "latest"
|
|
24
|
+
|
|
25
|
+
- name: Set up Python
|
|
26
|
+
run: uv python install 3.14
|
|
27
|
+
|
|
28
|
+
- name: Build distributions
|
|
29
|
+
run: uv build
|
|
30
|
+
|
|
31
|
+
- name: Upload build artifacts
|
|
32
|
+
uses: actions/upload-artifact@v7
|
|
33
|
+
with:
|
|
34
|
+
name: dist
|
|
35
|
+
path: dist/
|
|
36
|
+
|
|
37
|
+
- name: Upload to GitHub Release
|
|
38
|
+
uses: softprops/action-gh-release@v3
|
|
39
|
+
with:
|
|
40
|
+
files: dist/*
|
|
41
|
+
|
|
42
|
+
publish:
|
|
43
|
+
needs: build
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
environment:
|
|
46
|
+
name: pypi
|
|
47
|
+
url: https://pypi.org/project/fromscratch-pyllm/
|
|
48
|
+
permissions:
|
|
49
|
+
id-token: write
|
|
50
|
+
steps:
|
|
51
|
+
- name: Download build artifacts
|
|
52
|
+
uses: actions/download-artifact@v8
|
|
53
|
+
with:
|
|
54
|
+
name: dist
|
|
55
|
+
path: dist/
|
|
56
|
+
|
|
57
|
+
- name: Publish to PyPI
|
|
58
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
default_language_version:
|
|
2
|
+
python: python3.14
|
|
3
|
+
|
|
4
|
+
repos:
|
|
5
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
6
|
+
rev: v5.0.0
|
|
7
|
+
hooks:
|
|
8
|
+
# Pages paste real pytest output, trailing spaces included.
|
|
9
|
+
- id: trailing-whitespace
|
|
10
|
+
exclude: ^docs/property-testing\.md$
|
|
11
|
+
- id: end-of-file-fixer
|
|
12
|
+
exclude: ^docs/property-testing\.md$
|
|
13
|
+
- id: check-yaml
|
|
14
|
+
args: ['--unsafe']
|
|
15
|
+
- id: check-added-large-files
|
|
16
|
+
- id: check-json
|
|
17
|
+
- id: check-toml
|
|
18
|
+
- id: check-merge-conflict
|
|
19
|
+
- id: debug-statements
|
|
20
|
+
|
|
21
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
22
|
+
rev: v0.15.4
|
|
23
|
+
hooks:
|
|
24
|
+
- id: ruff
|
|
25
|
+
args: [--fix, --exit-non-zero-on-fix]
|
|
26
|
+
- id: ruff-format
|
|
27
|
+
|
|
28
|
+
- repo: https://github.com/RobertCraigie/pyright-python
|
|
29
|
+
rev: v1.1.408
|
|
30
|
+
hooks:
|
|
31
|
+
- id: pyright
|
|
32
|
+
|
|
33
|
+
- repo: local
|
|
34
|
+
hooks:
|
|
35
|
+
- id: pip-audit
|
|
36
|
+
name: pip-audit
|
|
37
|
+
language: system
|
|
38
|
+
pass_filenames: false
|
|
39
|
+
files: ^(pyproject\.toml|uv\.lock)$
|
|
40
|
+
entry: >-
|
|
41
|
+
bash -c 'f=$(mktemp) &&
|
|
42
|
+
uv export --frozen --no-emit-project --all-extras --no-hashes -o "$f" >/dev/null &&
|
|
43
|
+
uvx pip-audit==2.10.0 -r "$f" --disable-pip --no-deps;
|
|
44
|
+
status=$?; rm -f "$f"; exit $status'
|
|
45
|
+
|
|
46
|
+
- repo: https://github.com/rhysd/actionlint
|
|
47
|
+
rev: v1.7.7
|
|
48
|
+
hooks:
|
|
49
|
+
- id: actionlint
|
|
50
|
+
|
|
51
|
+
- repo: https://github.com/commitizen-tools/commitizen
|
|
52
|
+
rev: v4.13.8
|
|
53
|
+
hooks:
|
|
54
|
+
- id: commitizen
|
|
55
|
+
stages: [commit-msg]
|
|
56
|
+
additional_dependencies: [typing_extensions]
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# PyLLM
|
|
2
|
+
|
|
3
|
+
<!-- standard:start -->
|
|
4
|
+
## Code Style
|
|
5
|
+
|
|
6
|
+
- All public functions, methods, classes, and modules **must** have a docstring
|
|
7
|
+
- Use imperative mood: "Return the result." not "Returns the result."
|
|
8
|
+
- One-line docstrings for simple functions; multi-line with summary + details for complex ones
|
|
9
|
+
- Follow the Google docstring convention (D211, D212 selected via ruff)
|
|
10
|
+
|
|
11
|
+
## Linting
|
|
12
|
+
|
|
13
|
+
- Ruff enforces a comprehensive rule set -- run `uv run ruff check .` before committing
|
|
14
|
+
- Pyright runs in strict mode -- run `uv run pyright src tests` before committing
|
|
15
|
+
- All violations must be fixed, not ignored. Exceptions are the repo-owned `ignore` and `per-file-ignores` lists in `pyproject.toml`, which belong to this repo; the series sync never edits them
|
|
16
|
+
|
|
17
|
+
## Testing
|
|
18
|
+
|
|
19
|
+
- TDD workflow: Red-Green-Refactor
|
|
20
|
+
- Coverage is enforced by pytest-cov; the floor in `pyproject.toml` is repo-owned
|
|
21
|
+
- Test classes and methods also require docstrings
|
|
22
|
+
- Use named constants instead of magic values (PLR2004)
|
|
23
|
+
- Run `uv run pytest` before committing
|
|
24
|
+
- Property-based tests (Hypothesis) live in `tests/test_properties.py` and `tests/test_model.py`; the shared profiles are in the root `conftest.py` (owned by `series sync`). Run `uv run pytest --hypothesis-profile=thorough` before a release.
|
|
25
|
+
|
|
26
|
+
## Commits
|
|
27
|
+
|
|
28
|
+
- Use conventional commits: `feat:`, `fix:`, `refactor:`, `test:`, `docs:`, `ci:`, `chore:`
|
|
29
|
+
- All changes go via PR from a feature branch (main is protected); merge when CI is green
|
|
30
|
+
|
|
31
|
+
## Dependencies
|
|
32
|
+
|
|
33
|
+
- Package manager: uv
|
|
34
|
+
- Run `uv sync --all-extras` after modifying dependencies
|
|
35
|
+
- `uv.lock` is committed; CI and pre-commit audit it with pip-audit through `uvx`, so pip-audit is not a project dependency
|
|
36
|
+
- Sibling projects, where used, are pinned release tags in `[tool.uv.sources]` (git + tag); never use `path` sources
|
|
37
|
+
|
|
38
|
+
## Releasing
|
|
39
|
+
|
|
40
|
+
- A release is a `vX.Y.Z` tag on main after the PR is merged
|
|
41
|
+
- Docs-only and tooling-only changes do not get a release tag
|
|
42
|
+
- Docs are built with `mkdocs build --strict` and deployed to GitHub Pages by the docs workflow
|
|
43
|
+
<!-- standard:end -->
|
|
44
|
+
|
|
45
|
+
## Project notes
|
|
46
|
+
|
|
47
|
+
- **Numpy autograd.** There is no torch: `src/pyllm/autograd` is a small reverse-mode
|
|
48
|
+
autodiff engine on numpy arrays (`Tensor`). Layers live in `src/pyllm/nn`, models in
|
|
49
|
+
`src/pyllm/models`, and `pyllm._types` holds the shared `Array` alias. Each op stores a
|
|
50
|
+
backward recipe via `Tensor.set_backward`; check new ops with
|
|
51
|
+
`pyllm.autograd.gradcheck.numerical_grad`.
|
|
52
|
+
- **Bundled checkpoints.** `src/pyllm/data/pokemon.npz` and `src/pyllm/data/pebble.npz` are
|
|
53
|
+
trained models committed to the repo (and force-included in the wheel). Regenerate them with
|
|
54
|
+
`uv run python scripts/train_pokemon.py` and `uv run python scripts/train_pebble.py`. Both
|
|
55
|
+
use fixed seeds, but training changes whenever the model code changes, so rerun them and
|
|
56
|
+
commit the new `.npz` files if you touch the models, optimizers or training loop.
|
|
57
|
+
- **The Pebble referee.** `src/pyllm/pebble/referee.py` is a hand-written, character-by-character
|
|
58
|
+
checker for the canonical slice of Pebble the corpus uses (4-space indents, single spaces
|
|
59
|
+
around operators). `viable(text)` means "could still become valid" and `complete(text)` means
|
|
60
|
+
"valid right now". It must stay a strict subset of real Pebble so anything it accepts, Pebble's
|
|
61
|
+
own parser accepts too (tests check this against `pebble-lang`). `generate(..., referee=...)`
|
|
62
|
+
uses it to veto illegal characters.
|
|
63
|
+
- **Regenerating the Pebble corpus.** `src/pyllm/data/pebble_corpus.txt` is generated, not
|
|
64
|
+
hand-written: `uv run python scripts/build_pebble_corpus.py` grows random valid programs
|
|
65
|
+
(`pebble/generator.py`), mixes in snippets harvested from a sibling `../pebble-lang/docs`
|
|
66
|
+
checkout (kept only if they parse) and canonicalises everything with Pebble's formatter. Use
|
|
67
|
+
`--pebble-docs PATH` to harvest from elsewhere; if the docs folder is missing the script stops
|
|
68
|
+
with an error (it never silently drops the snippets) unless you pass `--no-harvest`. The
|
|
69
|
+
bundled corpus is built *with* the snippets, so only use `--no-harvest` for experiments. A
|
|
70
|
+
similar recipe is available as `pyllm gen-corpus --harvest PATH --canonical` (which also fails
|
|
71
|
+
on a missing `--harvest` folder). It needs the optional `pebble` extra
|
|
72
|
+
(`uv sync --all-extras`). Retrain `pebble.npz` afterwards.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Rob Cox
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: fromscratch-pyllm
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: An educational large language model built from scratch in Python
|
|
5
|
+
Project-URL: Homepage, https://github.com/robcox2910/pyllm
|
|
6
|
+
Project-URL: Repository, https://github.com/robcox2910/pyllm
|
|
7
|
+
Project-URL: Issues, https://github.com/robcox2910/pyllm/issues
|
|
8
|
+
Project-URL: Documentation, https://robcox2910.github.io/pyllm/
|
|
9
|
+
Author: Rob Cox
|
|
10
|
+
License: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: autograd,education,gpt,learning,llm,transformer
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: Education
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Classifier: Topic :: Education
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: >=3.14
|
|
22
|
+
Requires-Dist: numpy>=2.1
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: commitizen>=4.4.0; extra == 'dev'
|
|
25
|
+
Requires-Dist: hypothesis>=6.170; extra == 'dev'
|
|
26
|
+
Requires-Dist: pip-audit>=2.10.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: pre-commit>=4.0.1; extra == 'dev'
|
|
28
|
+
Requires-Dist: pyright>=1.1.400; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest-cov>=6.0.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest>=8.3.4; extra == 'dev'
|
|
31
|
+
Requires-Dist: ruff>=0.9.3; extra == 'dev'
|
|
32
|
+
Provides-Extra: docs
|
|
33
|
+
Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
|
|
34
|
+
Provides-Extra: pebble
|
|
35
|
+
Requires-Dist: fromscratch-pebble>=0.3.0; extra == 'pebble'
|
|
36
|
+
Description-Content-Type: text/markdown
|
|
37
|
+
|
|
38
|
+
# PyLLM
|
|
39
|
+
|
|
40
|
+
An educational large language model built from scratch in Python.
|
|
41
|
+
|
|
42
|
+
Part of the "from scratch in Python" series. Built incrementally with TDD,
|
|
43
|
+
every concept explained with analogies a 12-year-old can follow. The only
|
|
44
|
+
dependency is numpy (for fast array math) — the autograd engine, neural-net
|
|
45
|
+
layers, attention, the Transformer, the tokenizer, the optimizer, the training
|
|
46
|
+
loop, and sampling are all ours.
|
|
47
|
+
|
|
48
|
+
## Quick Start
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
uv sync --all-extras
|
|
52
|
+
uv run pytest
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Dream up new Pokémon (generates instantly)
|
|
56
|
+
|
|
57
|
+
PyLLM ships with a tiny pre-trained GPT, so it invents Pokémon-ish names the
|
|
58
|
+
moment you launch it — no training wait:
|
|
59
|
+
|
|
60
|
+
```console
|
|
61
|
+
$ uv run pyllm --seed 0 --max-new-tokens 40
|
|
62
|
+
machop
|
|
63
|
+
machoke
|
|
64
|
+
machamp
|
|
65
|
+
bellsprout
|
|
66
|
+
weepin
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Turn the boldness dial with `--temperature` (0 = safe/greedy, higher = wilder)
|
|
70
|
+
and add a `--top-k` guardrail. Start from a prompt with `--prompt "pi"`.
|
|
71
|
+
|
|
72
|
+
## Train your own model
|
|
73
|
+
|
|
74
|
+
Pick a rung on the teaching ladder (`bigram`, `mlp`, or `gpt`) and point it at
|
|
75
|
+
any text file (defaults to the bundled Pokémon corpus):
|
|
76
|
+
|
|
77
|
+
```console
|
|
78
|
+
$ uv run pyllm train --model gpt --steps 2000 --out mine.npz
|
|
79
|
+
step 0: loss 3.31
|
|
80
|
+
...
|
|
81
|
+
final loss 0.42; saved checkpoint to mine.npz
|
|
82
|
+
|
|
83
|
+
$ uv run pyllm --checkpoint mine.npz --max-new-tokens 60
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## The flagship: teach PyLLM to write Pebble
|
|
87
|
+
|
|
88
|
+
There's no corpus of [Pebble](https://github.com/robcox2910/pebble-lang) code in
|
|
89
|
+
the wild — so we *grow our own*. A generator emits **random-but-provably-valid**
|
|
90
|
+
Pebble ASTs (100% parse under Pebble's own parser), a harvester scrapes real
|
|
91
|
+
snippets from Pebble's docs, and — because we own the language toolchain — we
|
|
92
|
+
**grade** the trained model by running its output back through Pebble's real
|
|
93
|
+
parser and reporting what percentage parses:
|
|
94
|
+
|
|
95
|
+
```console
|
|
96
|
+
$ uv run pyllm pebble --seed 7 --temperature 0.5 --score
|
|
97
|
+
let result = 62
|
|
98
|
+
}
|
|
99
|
+
if count < 47 {
|
|
100
|
+
let c = 51 + (83 + 32)
|
|
101
|
+
...
|
|
102
|
+
parse rate: 0.0% of 1 programs
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The bundled checkpoint is *tiny* (a few-minute char-level GPT), so it writes
|
|
106
|
+
Pebble-*flavoured* code and only some of it parses — and that's the whole point:
|
|
107
|
+
the parser is an honest, objective judge, so you can watch the score go up as you
|
|
108
|
+
train longer or bigger. Almost no LLM project can grade its own output like this.
|
|
109
|
+
|
|
110
|
+
### Call in the referee: always-valid Pebble
|
|
111
|
+
|
|
112
|
+
Add `--constrained` and a from-scratch grammar **referee** vetoes every character
|
|
113
|
+
that would break Pebble's rules, so the model rolls again until it picks a legal
|
|
114
|
+
one. Same tiny brain — but now every program it returns parses:
|
|
115
|
+
|
|
116
|
+
```console
|
|
117
|
+
$ uv run pyllm pebble --seed 7 --constrained --score
|
|
118
|
+
let total = n * (63 - 99)
|
|
119
|
+
|
|
120
|
+
let result = c
|
|
121
|
+
fount = 55 + (n - b) % (6 - b)
|
|
122
|
+
|
|
123
|
+
parse rate: 100.0% of 2 programs
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
From Python: `generate_pebble(constrained=True)`. See
|
|
127
|
+
[`docs/concepts/the-referee.md`](docs/concepts/the-referee.md).
|
|
128
|
+
|
|
129
|
+
Grow a fresh synthetic corpus with `uv run pyllm gen-corpus`. Live scoring needs
|
|
130
|
+
the optional `fromscratch-pebble` dependency (`uv sync --all-extras`); generation and
|
|
131
|
+
training work without it. See [`docs/concepts/grow-your-own-data.md`](docs/concepts/grow-your-own-data.md).
|
|
132
|
+
|
|
133
|
+
## See how text becomes tokens
|
|
134
|
+
|
|
135
|
+
```console
|
|
136
|
+
$ uv run pyllm tokenize --text "pika"
|
|
137
|
+
'p' -> 16
|
|
138
|
+
'i' -> 9
|
|
139
|
+
'k' -> 11
|
|
140
|
+
'a' -> 1
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## The teaching ladder
|
|
144
|
+
|
|
145
|
+
Each rung is a real, trainable language model that fixes a weakness of the one
|
|
146
|
+
below it, so you feel *why* each idea exists:
|
|
147
|
+
|
|
148
|
+
1. **Bigram** — "what character usually comes next?" A lookup table.
|
|
149
|
+
2. **MLP** — a small neural net over the last few characters (embeddings + a
|
|
150
|
+
hidden layer).
|
|
151
|
+
3. **GPT** — stacked Transformer blocks (multi-head attention + feed-forward +
|
|
152
|
+
LayerNorm + residuals) with positional information. The real thing.
|
|
153
|
+
|
|
154
|
+
## Learn the ideas
|
|
155
|
+
|
|
156
|
+
Kid-friendly explanations live in [`docs/concepts/`](docs/concepts/README.md):
|
|
157
|
+
the breadcrumb trail (autograd), tokens, embeddings, attention, how a Transformer
|
|
158
|
+
is built, how a model learns, sampling, and — the flagship lesson — growing your
|
|
159
|
+
own data.
|
|
160
|
+
|
|
161
|
+
## Developing alongside a sibling
|
|
162
|
+
|
|
163
|
+
PyLLM uses a released version of [Pebble](https://github.com/robcox2910/pebble-lang)
|
|
164
|
+
from PyPI (`fromscratch-pebble`, the optional `pebble` extra). To try an
|
|
165
|
+
unreleased Pebble change, install your local checkout over the released one:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
uv pip install -e ../pebble-lang
|
|
169
|
+
uv run --no-sync pytest
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Use `uv run --no-sync` while you do this: a plain `uv run` (like `uv sync`)
|
|
173
|
+
puts the pinned release back, which is how you undo the override.
|
|
174
|
+
|
|
175
|
+
## Releasing
|
|
176
|
+
|
|
177
|
+
1. Merge the change to `main`.
|
|
178
|
+
2. Tag it: `git tag -a vX.Y.Z -m vX.Y.Z && git push origin vX.Y.Z`.
|
|
179
|
+
A change to the public API bumps the minor version (`v0.1.0` → `v0.2.0`);
|
|
180
|
+
anything else bumps the patch (`v0.1.0` → `v0.1.1`).
|
|
181
|
+
3. Projects that use PyLLM (like [PyStack](https://github.com/robcox2910/pystack))
|
|
182
|
+
upgrade by editing the tag in their `[tool.uv.sources]` and running
|
|
183
|
+
`uv lock --upgrade-package pyllm`, in a pull request so CI checks the pair.
|
|
184
|
+
|
|
185
|
+
## PyLLM inside PyStack
|
|
186
|
+
|
|
187
|
+
PyLLM is **the brain** of a family of educational projects, each building a real
|
|
188
|
+
system from scratch to teach how it works. They're tied together by
|
|
189
|
+
**[PyStack](https://github.com/robcox2910/pystack)**, where a Pebble program can
|
|
190
|
+
even `import "llm"` and ask PyLLM to write more code.
|
|
191
|
+
|
|
192
|
+
Once PyLLM is installed as a PyStack plugin, any Pebble program can call it:
|
|
193
|
+
|
|
194
|
+
```pebble
|
|
195
|
+
import "llm"
|
|
196
|
+
let code = llm_generate("a function that adds two numbers")
|
|
197
|
+
print(code)
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
<!-- series:start -->
|
|
201
|
+
## Related Projects
|
|
202
|
+
|
|
203
|
+
This project is one of a series that builds real systems "from scratch in Python" to teach how they work. See the [series home](https://robcox2910.github.io/) for the full story.
|
|
204
|
+
|
|
205
|
+
| Project | What it teaches | Repository | Docs |
|
|
206
|
+
| --- | --- | --- | --- |
|
|
207
|
+
| PyOS | Operating systems | [py-os](https://github.com/robcox2910/py-os) | [Docs](https://robcox2910.github.io/py-os/) |
|
|
208
|
+
| Pebble | Compilers and programming languages | [pebble-lang](https://github.com/robcox2910/pebble-lang) | [Docs](https://robcox2910.github.io/pebble-lang/) |
|
|
209
|
+
| PyDB | Relational databases | [pydb](https://github.com/robcox2910/pydb) | [Docs](https://robcox2910.github.io/pydb/) |
|
|
210
|
+
| PyKV | Key-value stores | [pykv](https://github.com/robcox2910/pykv) | [Docs](https://robcox2910.github.io/pykv/) |
|
|
211
|
+
| PyDocDB | Document databases | [pydoc-db](https://github.com/robcox2910/pydoc-db) | [Docs](https://robcox2910.github.io/pydoc-db/) |
|
|
212
|
+
| PyGraphDB | Graph databases | [pygraphdb](https://github.com/robcox2910/pygraphdb) | [Docs](https://robcox2910.github.io/pygraphdb/) |
|
|
213
|
+
| PyTSDB | Time-series databases | [pytsdb](https://github.com/robcox2910/pytsdb) | [Docs](https://robcox2910.github.io/pytsdb/) |
|
|
214
|
+
| PyVecDB | Vector databases | [pyvecdb](https://github.com/robcox2910/pyvecdb) | [Docs](https://robcox2910.github.io/pyvecdb/) |
|
|
215
|
+
| PyColDB | Column-family databases | [pycoldb](https://github.com/robcox2910/pycoldb) | [Docs](https://robcox2910.github.io/pycoldb/) |
|
|
216
|
+
| PyCrypt | Cryptography | [pycrypt](https://github.com/robcox2910/pycrypt) | [Docs](https://robcox2910.github.io/pycrypt/) |
|
|
217
|
+
| PyNet | Computer networking | [pynet](https://github.com/robcox2910/pynet) | [Docs](https://robcox2910.github.io/pynet/) |
|
|
218
|
+
| PyWeb | HTTP web servers | [pyweb](https://github.com/robcox2910/pyweb) | [Docs](https://robcox2910.github.io/pyweb/) |
|
|
219
|
+
| PyGit | Version control | [pygit](https://github.com/robcox2910/pygit) | [Docs](https://robcox2910.github.io/pygit/) |
|
|
220
|
+
| PySearch | Search engines | [pysearch](https://github.com/robcox2910/pysearch) | [Docs](https://robcox2910.github.io/pysearch/) |
|
|
221
|
+
| PyMQ | Message queues | [pymq](https://github.com/robcox2910/pymq) | [Docs](https://robcox2910.github.io/pymq/) |
|
|
222
|
+
| **PyLLM** | **Language models (the brain)** | [pyllm](https://github.com/robcox2910/pyllm) | [Docs](https://robcox2910.github.io/pyllm/) |
|
|
223
|
+
| PyScheduler | Job scheduling | [pyscheduler](https://github.com/robcox2910/pyscheduler) | [Docs](https://robcox2910.github.io/pyscheduler/) |
|
|
224
|
+
| PyStack | Full-stack integration | [pystack](https://github.com/robcox2910/pystack) | [Docs](https://robcox2910.github.io/pystack/) |
|
|
225
|
+
<!-- series:end -->
|
|
226
|
+
|
|
227
|
+
<!-- docs:start -->
|
|
228
|
+
## Documentation
|
|
229
|
+
|
|
230
|
+
Full docs (with kid-friendly explanations of every idea): https://robcox2910.github.io/pyllm/
|
|
231
|
+
<!-- docs:end -->
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# PyLLM
|
|
2
|
+
|
|
3
|
+
An educational large language model built from scratch in Python.
|
|
4
|
+
|
|
5
|
+
Part of the "from scratch in Python" series. Built incrementally with TDD,
|
|
6
|
+
every concept explained with analogies a 12-year-old can follow. The only
|
|
7
|
+
dependency is numpy (for fast array math) — the autograd engine, neural-net
|
|
8
|
+
layers, attention, the Transformer, the tokenizer, the optimizer, the training
|
|
9
|
+
loop, and sampling are all ours.
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
uv sync --all-extras
|
|
15
|
+
uv run pytest
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Dream up new Pokémon (generates instantly)
|
|
19
|
+
|
|
20
|
+
PyLLM ships with a tiny pre-trained GPT, so it invents Pokémon-ish names the
|
|
21
|
+
moment you launch it — no training wait:
|
|
22
|
+
|
|
23
|
+
```console
|
|
24
|
+
$ uv run pyllm --seed 0 --max-new-tokens 40
|
|
25
|
+
machop
|
|
26
|
+
machoke
|
|
27
|
+
machamp
|
|
28
|
+
bellsprout
|
|
29
|
+
weepin
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Turn the boldness dial with `--temperature` (0 = safe/greedy, higher = wilder)
|
|
33
|
+
and add a `--top-k` guardrail. Start from a prompt with `--prompt "pi"`.
|
|
34
|
+
|
|
35
|
+
## Train your own model
|
|
36
|
+
|
|
37
|
+
Pick a rung on the teaching ladder (`bigram`, `mlp`, or `gpt`) and point it at
|
|
38
|
+
any text file (defaults to the bundled Pokémon corpus):
|
|
39
|
+
|
|
40
|
+
```console
|
|
41
|
+
$ uv run pyllm train --model gpt --steps 2000 --out mine.npz
|
|
42
|
+
step 0: loss 3.31
|
|
43
|
+
...
|
|
44
|
+
final loss 0.42; saved checkpoint to mine.npz
|
|
45
|
+
|
|
46
|
+
$ uv run pyllm --checkpoint mine.npz --max-new-tokens 60
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## The flagship: teach PyLLM to write Pebble
|
|
50
|
+
|
|
51
|
+
There's no corpus of [Pebble](https://github.com/robcox2910/pebble-lang) code in
|
|
52
|
+
the wild — so we *grow our own*. A generator emits **random-but-provably-valid**
|
|
53
|
+
Pebble ASTs (100% parse under Pebble's own parser), a harvester scrapes real
|
|
54
|
+
snippets from Pebble's docs, and — because we own the language toolchain — we
|
|
55
|
+
**grade** the trained model by running its output back through Pebble's real
|
|
56
|
+
parser and reporting what percentage parses:
|
|
57
|
+
|
|
58
|
+
```console
|
|
59
|
+
$ uv run pyllm pebble --seed 7 --temperature 0.5 --score
|
|
60
|
+
let result = 62
|
|
61
|
+
}
|
|
62
|
+
if count < 47 {
|
|
63
|
+
let c = 51 + (83 + 32)
|
|
64
|
+
...
|
|
65
|
+
parse rate: 0.0% of 1 programs
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The bundled checkpoint is *tiny* (a few-minute char-level GPT), so it writes
|
|
69
|
+
Pebble-*flavoured* code and only some of it parses — and that's the whole point:
|
|
70
|
+
the parser is an honest, objective judge, so you can watch the score go up as you
|
|
71
|
+
train longer or bigger. Almost no LLM project can grade its own output like this.
|
|
72
|
+
|
|
73
|
+
### Call in the referee: always-valid Pebble
|
|
74
|
+
|
|
75
|
+
Add `--constrained` and a from-scratch grammar **referee** vetoes every character
|
|
76
|
+
that would break Pebble's rules, so the model rolls again until it picks a legal
|
|
77
|
+
one. Same tiny brain — but now every program it returns parses:
|
|
78
|
+
|
|
79
|
+
```console
|
|
80
|
+
$ uv run pyllm pebble --seed 7 --constrained --score
|
|
81
|
+
let total = n * (63 - 99)
|
|
82
|
+
|
|
83
|
+
let result = c
|
|
84
|
+
fount = 55 + (n - b) % (6 - b)
|
|
85
|
+
|
|
86
|
+
parse rate: 100.0% of 2 programs
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
From Python: `generate_pebble(constrained=True)`. See
|
|
90
|
+
[`docs/concepts/the-referee.md`](docs/concepts/the-referee.md).
|
|
91
|
+
|
|
92
|
+
Grow a fresh synthetic corpus with `uv run pyllm gen-corpus`. Live scoring needs
|
|
93
|
+
the optional `fromscratch-pebble` dependency (`uv sync --all-extras`); generation and
|
|
94
|
+
training work without it. See [`docs/concepts/grow-your-own-data.md`](docs/concepts/grow-your-own-data.md).
|
|
95
|
+
|
|
96
|
+
## See how text becomes tokens
|
|
97
|
+
|
|
98
|
+
```console
|
|
99
|
+
$ uv run pyllm tokenize --text "pika"
|
|
100
|
+
'p' -> 16
|
|
101
|
+
'i' -> 9
|
|
102
|
+
'k' -> 11
|
|
103
|
+
'a' -> 1
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## The teaching ladder
|
|
107
|
+
|
|
108
|
+
Each rung is a real, trainable language model that fixes a weakness of the one
|
|
109
|
+
below it, so you feel *why* each idea exists:
|
|
110
|
+
|
|
111
|
+
1. **Bigram** — "what character usually comes next?" A lookup table.
|
|
112
|
+
2. **MLP** — a small neural net over the last few characters (embeddings + a
|
|
113
|
+
hidden layer).
|
|
114
|
+
3. **GPT** — stacked Transformer blocks (multi-head attention + feed-forward +
|
|
115
|
+
LayerNorm + residuals) with positional information. The real thing.
|
|
116
|
+
|
|
117
|
+
## Learn the ideas
|
|
118
|
+
|
|
119
|
+
Kid-friendly explanations live in [`docs/concepts/`](docs/concepts/README.md):
|
|
120
|
+
the breadcrumb trail (autograd), tokens, embeddings, attention, how a Transformer
|
|
121
|
+
is built, how a model learns, sampling, and — the flagship lesson — growing your
|
|
122
|
+
own data.
|
|
123
|
+
|
|
124
|
+
## Developing alongside a sibling
|
|
125
|
+
|
|
126
|
+
PyLLM uses a released version of [Pebble](https://github.com/robcox2910/pebble-lang)
|
|
127
|
+
from PyPI (`fromscratch-pebble`, the optional `pebble` extra). To try an
|
|
128
|
+
unreleased Pebble change, install your local checkout over the released one:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
uv pip install -e ../pebble-lang
|
|
132
|
+
uv run --no-sync pytest
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Use `uv run --no-sync` while you do this: a plain `uv run` (like `uv sync`)
|
|
136
|
+
puts the pinned release back, which is how you undo the override.
|
|
137
|
+
|
|
138
|
+
## Releasing
|
|
139
|
+
|
|
140
|
+
1. Merge the change to `main`.
|
|
141
|
+
2. Tag it: `git tag -a vX.Y.Z -m vX.Y.Z && git push origin vX.Y.Z`.
|
|
142
|
+
A change to the public API bumps the minor version (`v0.1.0` → `v0.2.0`);
|
|
143
|
+
anything else bumps the patch (`v0.1.0` → `v0.1.1`).
|
|
144
|
+
3. Projects that use PyLLM (like [PyStack](https://github.com/robcox2910/pystack))
|
|
145
|
+
upgrade by editing the tag in their `[tool.uv.sources]` and running
|
|
146
|
+
`uv lock --upgrade-package pyllm`, in a pull request so CI checks the pair.
|
|
147
|
+
|
|
148
|
+
## PyLLM inside PyStack
|
|
149
|
+
|
|
150
|
+
PyLLM is **the brain** of a family of educational projects, each building a real
|
|
151
|
+
system from scratch to teach how it works. They're tied together by
|
|
152
|
+
**[PyStack](https://github.com/robcox2910/pystack)**, where a Pebble program can
|
|
153
|
+
even `import "llm"` and ask PyLLM to write more code.
|
|
154
|
+
|
|
155
|
+
Once PyLLM is installed as a PyStack plugin, any Pebble program can call it:
|
|
156
|
+
|
|
157
|
+
```pebble
|
|
158
|
+
import "llm"
|
|
159
|
+
let code = llm_generate("a function that adds two numbers")
|
|
160
|
+
print(code)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
<!-- series:start -->
|
|
164
|
+
## Related Projects
|
|
165
|
+
|
|
166
|
+
This project is one of a series that builds real systems "from scratch in Python" to teach how they work. See the [series home](https://robcox2910.github.io/) for the full story.
|
|
167
|
+
|
|
168
|
+
| Project | What it teaches | Repository | Docs |
|
|
169
|
+
| --- | --- | --- | --- |
|
|
170
|
+
| PyOS | Operating systems | [py-os](https://github.com/robcox2910/py-os) | [Docs](https://robcox2910.github.io/py-os/) |
|
|
171
|
+
| Pebble | Compilers and programming languages | [pebble-lang](https://github.com/robcox2910/pebble-lang) | [Docs](https://robcox2910.github.io/pebble-lang/) |
|
|
172
|
+
| PyDB | Relational databases | [pydb](https://github.com/robcox2910/pydb) | [Docs](https://robcox2910.github.io/pydb/) |
|
|
173
|
+
| PyKV | Key-value stores | [pykv](https://github.com/robcox2910/pykv) | [Docs](https://robcox2910.github.io/pykv/) |
|
|
174
|
+
| PyDocDB | Document databases | [pydoc-db](https://github.com/robcox2910/pydoc-db) | [Docs](https://robcox2910.github.io/pydoc-db/) |
|
|
175
|
+
| PyGraphDB | Graph databases | [pygraphdb](https://github.com/robcox2910/pygraphdb) | [Docs](https://robcox2910.github.io/pygraphdb/) |
|
|
176
|
+
| PyTSDB | Time-series databases | [pytsdb](https://github.com/robcox2910/pytsdb) | [Docs](https://robcox2910.github.io/pytsdb/) |
|
|
177
|
+
| PyVecDB | Vector databases | [pyvecdb](https://github.com/robcox2910/pyvecdb) | [Docs](https://robcox2910.github.io/pyvecdb/) |
|
|
178
|
+
| PyColDB | Column-family databases | [pycoldb](https://github.com/robcox2910/pycoldb) | [Docs](https://robcox2910.github.io/pycoldb/) |
|
|
179
|
+
| PyCrypt | Cryptography | [pycrypt](https://github.com/robcox2910/pycrypt) | [Docs](https://robcox2910.github.io/pycrypt/) |
|
|
180
|
+
| PyNet | Computer networking | [pynet](https://github.com/robcox2910/pynet) | [Docs](https://robcox2910.github.io/pynet/) |
|
|
181
|
+
| PyWeb | HTTP web servers | [pyweb](https://github.com/robcox2910/pyweb) | [Docs](https://robcox2910.github.io/pyweb/) |
|
|
182
|
+
| PyGit | Version control | [pygit](https://github.com/robcox2910/pygit) | [Docs](https://robcox2910.github.io/pygit/) |
|
|
183
|
+
| PySearch | Search engines | [pysearch](https://github.com/robcox2910/pysearch) | [Docs](https://robcox2910.github.io/pysearch/) |
|
|
184
|
+
| PyMQ | Message queues | [pymq](https://github.com/robcox2910/pymq) | [Docs](https://robcox2910.github.io/pymq/) |
|
|
185
|
+
| **PyLLM** | **Language models (the brain)** | [pyllm](https://github.com/robcox2910/pyllm) | [Docs](https://robcox2910.github.io/pyllm/) |
|
|
186
|
+
| PyScheduler | Job scheduling | [pyscheduler](https://github.com/robcox2910/pyscheduler) | [Docs](https://robcox2910.github.io/pyscheduler/) |
|
|
187
|
+
| PyStack | Full-stack integration | [pystack](https://github.com/robcox2910/pystack) | [Docs](https://robcox2910.github.io/pystack/) |
|
|
188
|
+
<!-- series:end -->
|
|
189
|
+
|
|
190
|
+
<!-- docs:start -->
|
|
191
|
+
## Documentation
|
|
192
|
+
|
|
193
|
+
Full docs (with kid-friendly explanations of every idea): https://robcox2910.github.io/pyllm/
|
|
194
|
+
<!-- docs:end -->
|