Skip to main content

kindling

A hybrid recommender that grows with your data — closed-form, no training loop, no GPU. One fused base score per (user, item) built from EASE / wilson-cooccurrence plus auto-gated z-normalized channels (trend, last-item, transitions, user-CF), with a Rust core for the numerics.

Design goals (learned the hard way — see docs/EXPERIMENTS.md):

  1. A wheel that imports is a wheel that works. numpy / pandas / scipy only; the linear algebra that matters (the EASE inversion) runs on a pure-Rust core (kindling_core). No PyTorch, no BLAS system deps.
  2. Closed-form shallow models, gated per dataset, beat speculative complexity. Every channel is closed-form or a counting statistic; every channel is activated by a measurable property of the data; every gate exists because the ungated version measurably hurt somewhere.

Install

pip install kindling-rec           # from PyPI
pip install -e ".[dev]"            # dev / from source
pip install -e ".[dev,bench]"      # + benchmark harness

Quickstart

from kindling import Engine
from kindling.loaders import movielens

interactions = movielens.load_1m()       # entity_id, item_id, timestamp[, rating]

engine = Engine()
engine.fit(interactions)

for rec in engine.recommend(entity_id=42, n=10):
    print(rec.item_id, rec.score, rec.base_kind)

# Many users at once — runs in parallel in the Rust core (GIL released).
batches = engine.recommend_batch([42, 99, 7], n=10)

Recommendation is served end-to-end by the Rust core (kindling_core): the EASE/cooc base, the channel blend, the boost layer, and cold-slots all run natively. Single recommend is sub-millisecond; batch is the parallel path.

New / anonymous users (absent from training) are served from ad-hoc seed items with no per-user training — and a zero/all-unknown seed set falls back to popularity:

engine.recommend_for_items(item_ids=[101, 205], n=10)   # personalized from seeds
engine.recommend_for_items(item_ids=[], n=10)           # → popularity fallback

Intelligent activation

Channels turn on by regime, not configuration. The base is EASE for catalogs ≤ 20k items and wilson-normalized cooccurrence above that; the trend channel needs timestamps; transitions additionally need the data not to be a rating-burst; user-CF activates only on sparse-history data; rating-weighting engages only when true ratings are present. Each decision is made from the data at fit() time. See docs/REFERENCE.md §2 for the gate table.

Where it stands (full-ranking NDCG@10, engine defaults)

Full results — discovery growth and the repeat-regime dominance — in docs/RESULTS.md.

dataset NDCG@10 notes
movielens-1m 0.293 rating-weighted EASE
amazon-beauty 0.033 + user-CF channel
steam (realistic tier) 0.066 open-catalog + cold slots
amazon-book-chrono 0.032 timestamps activate trend/transitions

Strongest personalized model on all four; beats implicit ALS everywhere; wins cold-user buckets on cold-heavy catalogs. The full benchmark record — including the negative results, which are half the value — is in docs/EXPERIMENTS.md.

On repeat-regime datasets (grocery/retail), a held-out gate turns on reorder recommendation; under repeat-aware eval kindling separates from the field — e.g. Dunnhumby 0.48 NDCG@10 vs ~0.05 for every baseline — while correctly declining on fake-repeat data like Steam (re-logs aren't repurchase). See docs/REPEAT-GATE.md. An opt-in EASE+ (EDLAE) base is available but off by default (docs/EASE-VARIANTS-ASSESSMENT.md).

Growth curves

How accuracy grows from cold to hot, against the standard baselines (bench/plot_growth_curves.py):

growth curves

Serving performance (native engine, bench/final_state_perf.py)

dataset fit single recommend p50 batch throughput NDCG@10
movielens-1m 4.2 s 0.17 ms 15.4k recs/s 0.2928
amazon-beauty 13.1 s 1.21 ms 3.0k recs/s 0.0328
steam 110 s 5.81 ms 0.8k recs/s 0.0659

The recommend path is pure Rust with the GIL released for the batch path — single recommend dropped from ~200 ms (the earlier Python path) to sub-millisecond, with byte-identical rankings.

Large-catalog fit got the same treatment (v1.0.4): the cooccurrence base is built and returned across the Rust boundary as zero-copy numpy arrays (not Python lists), and its pair accumulation is rayon-parallel over users — a fit that previously swap-thrashed a 24 GB box now runs in stable memory, and a 250k-basket / 15M-interaction fit dropped 250 s → 35 s (7.2×), byte-identical.

Serving

Persist a fit as a self-contained artifact and serve it with no re-fit:

from kindling.serving import KindlingServer
KindlingServer.from_engine(engine).save("artifact/")
# ── in the serving process ──
server = KindlingServer.load("artifact/")
server.recommend("user-42", n=10)

A FastAPI example (kindling.serving_app) ships behind the optional serve extra: pip install 'kindling[serve]'.

Project layout

src/kindling/      library source (engine, serving, Rust bindings, loaders)
native/kindling_core/  Rust core (EASE, cooccurrence, channel blend, recommend)
bench/             regression gate (bench/verify.py) + frozen reports + plots
docs/              RESULTS.md (what it brings) · REFERENCE.md (architecture) ·
                   EXPERIMENTS.md (record) · LESSONS.md (what the build taught)
tests/             unit, property, integration

License

Apache 2.0.


kindling is an Awry Labs project — independent software, a little off on purpose.

Also from Awry Labs: Gravel — a C++/Python network-fragility library for measuring and stress-testing graph resilience. (GitHub)

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

kindling_rec-1.0.4.tar.gz (128.4 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

kindling_rec-1.0.4-cp311-abi3-win_amd64.whl (725.2 kB view details)

Uploaded CPython 3.11+Windows x86-64

kindling_rec-1.0.4-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (816.6 kB view details)

Uploaded CPython 3.11+manylinux: glibc 2.17+ x86-64

kindling_rec-1.0.4-cp311-abi3-macosx_11_0_arm64.whl (668.8 kB view details)

Uploaded CPython 3.11+macOS 11.0+ ARM64

File details

Details for the file kindling_rec-1.0.4.tar.gz.

File metadata

  • Download URL: kindling_rec-1.0.4.tar.gz
  • Upload date:
  • Size: 128.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for kindling_rec-1.0.4.tar.gz
Algorithm Hash digest
SHA256 23d375d4c0000cdca68fb4f982e88ccdf82920af4f3c9949649163091180435c
MD5 12c788bee8f8fcd939ce7dafe0613b5e
BLAKE2b-256 4584facd25ad5be5f8edf523e8e20633f7434b16cb337f9c2a7fb8192c7ba1bb

See more details on using hashes here.

Provenance

The following attestation bundles were made for kindling_rec-1.0.4.tar.gz:

Publisher: release.yml on rhoekstr/kindling

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file kindling_rec-1.0.4-cp311-abi3-win_amd64.whl.

File metadata

  • Download URL: kindling_rec-1.0.4-cp311-abi3-win_amd64.whl
  • Upload date:
  • Size: 725.2 kB
  • Tags: CPython 3.11+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for kindling_rec-1.0.4-cp311-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 f9520ad4fe7eb92bbea57c66eb80f384af55fc8bbea68969c1f2bd36b0dc8511
MD5 d5f81640aa280870a5f1b9baa4059e62
BLAKE2b-256 10a3f0262b9e1adc617226ac8db93a46905d0cde141c601cabadf53563a740a1

See more details on using hashes here.

Provenance

The following attestation bundles were made for kindling_rec-1.0.4-cp311-abi3-win_amd64.whl:

Publisher: release.yml on rhoekstr/kindling

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file kindling_rec-1.0.4-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for kindling_rec-1.0.4-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 09f99dea8ee3415941cd8088fc5aec4475a303d2e900bb5a48fb86c009a982e9
MD5 67ef389a986fabe07a298d5066d49ccb
BLAKE2b-256 123a8efdf7bf950e49616463a06a27cf7abb63a1a48e69160ad076a1d88cddca

See more details on using hashes here.

Provenance

The following attestation bundles were made for kindling_rec-1.0.4-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on rhoekstr/kindling

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file kindling_rec-1.0.4-cp311-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for kindling_rec-1.0.4-cp311-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 7a4dd2a39586421e8dbdf07b0b0cb76f81afa87f3ea9e24ecca222276959c2fc
MD5 8b90c7a0e11e10b841cad542ea5a1e0b
BLAKE2b-256 f6ed604e796b6bfeed28047aebf4473d86d77a2dda024725585b4fb23b0c464e

See more details on using hashes here.

Provenance

The following attestation bundles were made for kindling_rec-1.0.4-cp311-abi3-macosx_11_0_arm64.whl:

Publisher: release.yml on rhoekstr/kindling

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

1.0.4 This release

4 files

1.0.3

4 files

1.0.1

4 files

1.0.0

3 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page