Skip to content

JASIL

Just Another Substrate & Infrastructure Library — a framework-agnostic infrastructure substrate for Python services.

Your domain code depends on small capability protocols — state, storage, events, locks, a clock — instead of on Redis, S3, or Postgres directly. Which implementation backs each one is a URI in your configuration, so the same code runs single-process on a laptop and multi-replica in production.

Status: 0.1.0

The API is still settling. Expect breaking changes on minor versions until 1.0.0; see API stability.

What you get

Layer What it does
Providers Protocols your domain code depends on: StateProvider, StorageProvider, EventBusProvider, LockProvider, ClockProvider, GeocodingProvider.
Backends A working implementation of each, selected by URI.
Deployment profiles local needs no infrastructure at all. distributed requires shared backends and refuses to guess them.
Event pipeline One envelope, one publish seam, payload versioning that survives a rolling deploy.
Durable jobs A transactional outbox relayed into leased per-subscriber jobs, with backoff and a dead-letter queue.
Observability An event lifecycle log and bounded retention pruning.

Install

pip install jasil                    # core: memory / local disk / in-process
pip install "jasil[redis,s3]"        # distributed state, events and storage
pip install "jasil[all]"             # every optional backend

A core install depends on sqlalchemy and pydantic only. Every backend client lives behind an extra and is imported lazily, so a single-process deployment never loads redis, boto3, or requests.

Three things JASIL does not do

These are deliberate, and they are what make it embeddable:

It does not own your database. You own the declarative base and the engine; JASIL maps its tables into your registry. One metadata object, one create_all, one migration run.

It does not read your configuration. No environment variables, no secret files. You build a settings object from whatever source you like and install it.

It does not own a web framework. Nothing in the core imports FastAPI. The Depends helpers are behind an extra you may ignore entirely.

Quick start

from sqlalchemy import create_engine
from sqlalchemy.orm import DeclarativeBase, sessionmaker

import jasil.orm as jasil_orm
import jasil.settings as jasil_settings
from jasil.container import build_platform
from jasil.runtime import set_active_platform


class Base(DeclarativeBase):
    """Your application's declarative base."""


# 1. Map JASIL's tables into your registry, before any database use.
jasil_orm.map_models(Base)

# 2. Hand JASIL a session factory bound to your engine.
engine = create_engine("postgresql+psycopg://...")
jasil_orm.configure_sessionmaker(sessionmaker(bind=engine))

# 3. Configure, build, publish process-wide.
jasil_settings.configure(jasil_settings.JasilSettings(data_dir="/srv/data"))
set_active_platform(build_platform())

Then depend on capabilities rather than infrastructure:

from jasil.runtime import get_active_platform

platform = get_active_platform()
platform.state.set("session:abc", b"...", ttl_seconds=3600)
platform.storage.save("avatars", "42.webp", image_bytes)

with platform.lock.try_acquire("nightly-backfill") as acquired:
    if acquired:
        run_backfill()

Nothing above changes when you move to Redis and S3 — only the configuration does.

Where to go next

Licence

MIT.