Asof is a zero-dependency feature store written in plain Python. It is built around one operation: the point-in-time (as-of) join, which fetches the most recent feature value known as of each label's timestamp and never a microsecond later. This is the map of how the whole thing fits together.
The system map
Try it
Each tick is a feature row with a timestamp and a rolling_7d_spend value. Move the label time t. The as-of join takes the latest event at or before t. The naive join always grabs event #6, even when it sits in the future of t.
Why it is built this way
The join is an O(n+m) two-pointer merge over sorted events. A brute-force O(n*m) reference runs beside it, and the test suite asserts they return identical results on random data every run.
Timestamps normalize to tz-aware UTC and store as epoch microseconds, so sqlite orders them exactly and TTL math is plain integer arithmetic. Ties resolve to the last source row, deterministically.
Sweeping offline rows into the online store upserts latest-wins and refuses to move an entity backwards in time, so re-running a window is idempotent and safe.
The whole API
# register definitions, load history into the offline store store.apply(customer, customer_stats) store.ingest("customer_stats", source="orders.csv") # TRAIN: as-of join, every value known only up to its label time training = store.get_historical_features(labels, "churn_v1") # SERVE: materialize latest values, then fetch them fast store.materialize(start, end) store.get_online_features(["cust_001"], "churn_v1") # the WRONG join, shown so the demo can prove it leaks leaky = naive_last_value_join(labels, feature_rows, "customer_id", ["rolling_7d_spend"])
Measured on the bundled dataset