Write latency, durability, throughput, and residency constraints directly in Python. A Z3-backed planner scores your catalog, selects the cheapest backend path that satisfies them, and generates the runtime, Dockerfiles, and Pulumi programs for whatever target you point it at.
from skaal import App, storage from skaal.storage import Map app = App("todo") @storage( read_latency="< 10ms", durability="strong", throughput="> 100 rps", retention="30d", ) class Todos(Map[str, dict]): pass
Python 3.11+
Z3 solver
SQLite · Postgres · Redis
DynamoDB · Firestore
S3 · GCS · Local FS
Pulumi · Docker · Lambda · Cloud Run
Most frameworks bake an infrastructure choice into your code on day one. Skaal flips that — describe the behavior your code needs, and let the planner resolve a target- specific implementation. Move from local SQLite to DynamoDB by changing a TOML file, not your application.
Express latency, durability, throughput, residency, and access patterns on typed surfaces — Map, Collection, BlobStore, VectorStore.
Per-environment TOML catalogs list available backends with cost, latency, durability, and capability flags. Overlay extends for dev → staging → prod.
Each constraint becomes a satisfiability clause. UNSAT comes with closest-match diagnostics: which constraint failed, and how far off each candidate was.
plan.skaal.lock · skaal plan --explainSkaal emits the runtime entry point, Dockerfile, Pulumi program, and stack metadata under artifacts/. skaal deploy hands the rest to Pulumi.
Skaal ships first-class surfaces for every storage shape a real application reaches for. Backend choice happens at solve time — your code keeps the same generic API from local dev to production.
Generic Store[T] with cursor pagination, secondary indexes, and per-row TTL.
SQLModel-backed entities with Alembic migrations — autogenerate, upgrade, downgrade, drift check, dry-run SQL.
Similarity search with metadata filters. Embeddings declared via __skaal_embeddings__, namespaces per surface.
Object storage with the same constraint vocabulary. Stream uploads, presigned URLs, content-type metadata.
Durable event streams with consumer groups, replay-by-offset, and an Outbox engine for at-least-once relay.
Functions, background jobs, and cron — with per-function retry, circuit breaker, rate-limit, and bulkhead policies.
Catalogs inherit and override. Stage a higher-durability prod stack on top of your
dev catalog with an extends table — Skaal validates the merged result
and surfaces the source of every backend in skaal catalog sources.
Dev defaults — fast feedback, ephemeral storage, no cloud bills.
# base catalog [storage.sqlite] read_latency = "< 5ms" durability = "local" throughput = "> 5000 rps" cost_per_unit = 0.0 supports_ttl = true [storage.redis] read_latency = "< 2ms" durability = "ephemeral"
Inherits local, swaps the storage tier for managed services.
[skaal] extends = "./local.toml" remove = ["storage.sqlite"] [storage.dynamodb] read_latency = "< 8ms" durability = "strong" throughput = "> 10000 rps" residency = "eu-west-1" cost_per_unit = 0.018 [storage.dynamodb.deploy] table_class = "STANDARD_IA" billing_mode = "PAY_PER_REQUEST"
Skaal includes the operational primitives most frameworks leave to the user. Pattern engines and a six-stage migration controller are wired into the runtime — no hand-rolled outbox table, no afternoon spent on Alembic boilerplate.
EventLog, Projection, Saga, and Outbox are real engines started by the runtime — not metadata stubs. Hook them up with decorators; the dispatch loop does the rest.
Move a tier from one backend to another without dropping traffic. Skaal walks plan, dual-write, backfill, dual-read, cutover, and decommission — each stage explicit, each rollback supported.
--dry-run SQL renderer — review the exact statements before they run
pip install to deployed in five commands.
The CLI is shaped around the planner. Every command operates on the same plan.skaal.lock — there are no hidden side effects, and every artifact is regenerable.
$ pip install "skaal[serve,runtime]" $ skaal init todo # scaffolds ./todo/ $ cd todo $ skaal run --reload › watching ./ for changes › using catalog: catalogs/local.toml › solve: 3 candidates → sqlite (selected) ✓ http://127.0.0.1:8000 · ready in 412ms $ skaal plan --catalog catalogs/prod.toml Storage.Todos → dynamodb 7ms p50 $0.018/wu Storage.Sessions → redis 1ms p50 $0.004/wu Compute.create_todo→ lambda cold 280ms ✓ resolved · plan.skaal.lock written $ skaal deploy --target aws --stack prod › artifacts/ written · Pulumi up · 14 resources ✓ deployed → https://api.example.com
pyproject.toml, a base catalog, and a hello-world app.
plan.skaal.lock with reasons and rejected candidates.
--dry-run.
extends overlays, list backend sources.
Real applications, not toy CRUD. Mount any ASGI or WSGI framework — FastAPI, Starlette, Litestar, Flask, Dash — and let Skaal handle the storage, scheduling, and deployment scaffolding around it.
Backends
mount_asgiRAG & AI
VectorStore with metadata filtersInternal tools
mount_wsgi@app.schedule cron jobsDeclare the contract once. Let Skaal pick the stack, generate the artifacts, and keep your code portable from your laptop to whatever cloud you ship to next.