ZERO-DEPENDENCY PYTHON ASGI
IKAREM
Zero-dependency Python ASGI framework, built for humans and LLMs. FastAPI-style DX (DI, validation, OpenAPI, auth) plus Django/Nest-style structure (plugins, config, RBAC) — on a core that runs on the standard library alone.
Footprint of an origin story: IKAREM started as an answer to Meraki — same decorator shape, working plugins, everything promised but never shipped. The rivalry is archived; the framework stayed.
The original mark — the Meraki rivalry, archived. The framework underneath is all IKAREM.
01 / INSTALL
One line. Zero required deps.
$ pip install ikarem
$ pip install "ikarem[server]" # uvicorn to serve
$ pip install "ikarem[postgres]" # asyncpg strategy
$ pip install "ikarem[test]" # pytest + httpx
Python ≥3.10. Uvicorn, asyncpg, aiomysql and friends are optional extras — the core is pure stdlib + ASGI and runs anywhere.
02 / QUICKSTART
Thirty seconds to a running app.
from ikarem import Ikarem
app = Ikarem(debug=True)
# dicts become JSON. path params are typed.
@app.get("/")
async def home(req):
return {"hello": "ikarem"}
@app.get("/users/{uid:int}")
async def get_user(req, uid: int):
return {"uid": uid}
$ uvicorn myapp:app # any ASGI server works
$ ikarem check myapp:app # static audit: deps, cycles, auth gaps
Every app ships with GET /healthz, GET /readyz,
GET /metrics, GET /openapi.json and GET /docs (Swagger UI).
Validation, JWT + RBAC, sessions + CSRF, rate limiting, caching, background tasks, websockets,
static files and an MCP server (ikarem mcp) are built in — see
Reference. Learn by copying:
20 runnable recipes, every snippet executed in CI.
03 / WHY IKAREM
Stated plainly.
| Meraki | IKAREM answer |
|---|---|
| Hard-requires uvicorn | Zero required deps. Core is stdlib + ASGI. |
| Static paths only, no params | Compiled {param:int/float/uuid/path} routes, 404 vs 405, url_for. |
| Requests can't read bodies | await body()/json()/form() — JSON and multipart uploads. |
| Plugin/config files are empty | Working plugin system (deps sorted, cycles caught) + layered config. Extensions: ecosystem registry. |
| No validation, auth, or docs | Schema + Field(), JWT + RBAC + sessions, OpenAPI + MCP tools. |
| No test story | Cookie-jar TestClient, 208-test suite, ikarem check. |
Migration is a two-line diff (guide):
- from meraki import Meraki
+ from ikarem.meraki_compat import Meraki
04 / BENCHMARKS
Same harness. Same process. No fairy dust.
N=3000 in-process ASGI req/s. Rerun: python bench/bench_switch.py.
| Route | App | req/s |
|---|---|---|
| GET /hello | meraki | ~314,000 |
| GET /hello | ikarem | ~110,000 |
| GET /missing (404) | meraki / ikarem | ~347,000 / ~97,000 |
| GET /users/{id} (params) | ikarem | ~85,000 — meraki: no path params (404) |
| POST /echo 1KB JSON | ikarem | ~71,000 — meraki: no body API |
And the number that matters for production: ~75k sustained requests over real
uvicorn against the Ledger demo app — zero 5xx, zero timeouts (healthz 1567 rps, authed SQLite
reads 1178 rps, concurrent writes 991 rps). Harness: bench/load.py.
05 / LIVE DEMO
Ledger — a real app on stock IKAREM.
Personal finance: session auth + CSRF, dashboard with SVG charts, full CRUD over HTML forms
and JSON API, receipt uploads, CSV export, rate limits, security headers. 21 routes,
all audited by ikarem check.
$ python -m uvicorn ledger.app:app # from the repo root
# open http://127.0.0.1:8000 — demo: demo@example.com / demo1234
Production shape: ledger/Dockerfile +
ledger/docker-compose.yml (app + Postgres 16) + docs/DEPLOY.md.
The app runs on SQLite or Postgres via IKAREM_DB_URL — full suite green on both.
06 / THE STACK
Everything included. Nothing required.
| Need | Answer |
|---|---|
| Routing | Compiled routes, converters, 404 vs 405, include_router, static mounts |
| Input | Schema + Field(ge/le/pattern/email…) for JSON and forms; 400s automatic |
| Logic | Depends() DI — nested, cached, sync/async/yield, cycle-checked, compiled once |
| Auth | HS256 JWT + RBAC + scopes + API keys, pbkdf2 passwords, signed-cookie sessions, CSRF, trusted hosts |
| Ops | Rate limit, timeouts, bulkheads, idempotency, CORS, security headers, request IDs, /healthz /readyz /metrics, cron + durable queues + migrations |
| Data | Async strategy interface: SQLite (stdlib) / Postgres / MySQL / SQLServer |
| Machine clients | OpenAPI 3.1 + Swagger UI; every route as an MCP tool (ikarem mcp) |
| Modularity | Blueprint groups + MethodView classes + abort() |
| Templates | Templates(dir) (Jinja2) + flash() notifications |
| CLI | ikarem run|check|mcp|new|migrate|worker|inspect — serve, audit, expose tools, scaffold, migrate, drain queues, print manifests |
| Recipes | 20 copy-paste recipes — every snippet executed in CI, so the docs can't drift |
07 / OPERATE IT
Boring in production. As it should be.
$ ikarem new myapp && cd myapp # starter: auth + CRUD + tests + Dockerfile
$ pytest -q && uvicorn app:app
$ ikarem check myapp:app # gate deploys on this
Config is layered (defaults < kwargs < dict < IKAREM_* env).
Health checks: liveness /healthz, readiness /readyz (503 while the DB is down).
08 / STRAIGHT ANSWERS
Asked in production. Answered here.
Demo login fails? Check SELECT email FROM users — if the demo row is
missing, delete the SQLite file and reboot (it reseeds), or just register a fresh account.
403 on API POSTs? That's CSRF doing its job. Send the X-CSRF-Token header
(fetch it from GET /api/csrf), or exempt pure token APIs via exempt_paths.
401 or 403? 401 means anonymous — browsers redirect to /login.
403 means authenticated but not allowed.
Rate-limited on localhost? Limits are per client IP (X-Forwarded-For or
socket peer), 240/min default. Tune RateLimitMiddleware(per_minute=…).
SQLite under concurrent writes? Single-lane by design (WAL on, corruption-proof).
Reads stay fast; past toy scale, point IKAREM_DB_URL at Postgres — the suite is green on both.
Postgres + tests? One event loop per thread: TestClient reuses it, so
loop-bound pools survive across requests instead of churning.