IKAREM — Meraki, reversed. And crushed.
Industry-grade Python ASGI backend framework. Pip-installable, zero-dep core.
FastAPI-style DX (DI, validation, OpenAPI, auth) + Django/Nest-style structure (plugins, config, RBAC) + a core that runs on stdlib alone.
Install
pip install -e . # core only, zero dependencies
pip install -e ".[server,test]" # uvicorn + pytest + httpx for dev
pip install -e ".[postgres]" # asyncpg strategy
pip install -e ".[mysql]" # aiomysql strategy
pip install -e ".[sqlserver]" # aioodbc strategy
30-second example
from ikarem import Ikarem
app = Ikarem(debug=True)
@app.get("/")
async def home(req):
return {"hello": "ikarem"} # dict auto-becomes JSON
@app.get("/users/{uid:int}")
async def get_user(req):
return {"uid": req.path_params["uid"]}
if __name__ == "__main__":
app.run() # needs `pip install ikarem[server]`
python examples/basic.py
# or
ikarem run examples.basic:app --reload
Industry-grade example
from ikarem import (
BackgroundTasks,
Depends,
Ikarem,
Schema,
CORSMiddleware,
RateLimitMiddleware,
create_token,
require_roles,
)
app = Ikarem(auth_secret="secret")
app.use(CORSMiddleware())
app.use(RateLimitMiddleware(per_minute=120))
class Item(Schema):
name: str
qty: int = 1
def get_prefix():
return "hi"
@app.post("/items")
async def create(req, item: Item, bg: BackgroundTasks, prefix=Depends(get_prefix)):
bg.add(print, f"created {item.name}")
return {"msg": f"{prefix} {item.name}", "qty": item.qty} # validated + coerced
tok = create_token("u1", "secret", roles=["admin"])
@app.get("/admin")
async def adm(req, claims=Depends(require_roles("admin"))):
return {"sub": claims["sub"]} # 401 without token, 403 without role
Built-ins on every app: GET /healthz, GET /metrics,
GET /openapi.json (OpenAPI 3.1 auto-gen), GET /docs (Swagger UI).
Production web apps
ikarem new myapp && cd myapp # auth + sessions + SQLite CRUD (HTML + JSON), tests + Dockerfile
pytest -q && uvicorn app:app
from ikarem import SessionMiddleware, CSRFMiddleware, Field, Schema
app.use(SessionMiddleware()) # signed cookies: req.session["uid"] = ...
app.use(CSRFMiddleware()) # unsafe routes need X-CSRF-Token or _csrf_token field
class Signup(Schema):
email: str = Field(..., email=True, max_length=254)
password: str = Field(..., min_length=8, max_length=128)
@app.post("/notes")
async def add(req, note: NoteIn): # validates JSON *and* HTML form bodies
form = await req.form() # urlencoded + multipart, UploadFile files,
f = form.get("doc") # 413 past size caps
await f.write(f"/uploads/{f.filename}")
TestClient keeps a cookie jar (login flows just work) and speaks
get/post/put/patch/delete. ikarem check audits handlers, ikarem mcp
serves every route as an LLM tool.
Live proof it all works: ledger/ — a personal-finance app
(auth, dashboard with SVG charts, CRUD, receipt uploads, CSV export, JSON API)
running on stock IKAREM + uvicorn.
Switching from Meraki? 5 minutes
-from meraki import Meraki
+from ikarem.meraki_compat import Meraki
Your app runs unchanged (same routes, middleware, 404/405 bodies) on the
IKAREM engine — then migrate handler-by-handler. Full guide:
docs/MIGRATING_FROM_MERAKI.md ·
honest benchmarks: bench/RESULTS.md ·
install: pip install ikarem (dist/ikarem-1.0.0-py3-none-any.whl builds offline).
Why IKAREM beats Meraki Phase 1 — and the industry
| Rival feature | IKAREM answer |
|---|---|
| pip package, minimal deps | Zero required deps. uvicorn/asyncpg/etc are optional extras. Core is pure stdlib + ASGI. |
| ASGI + Uvicorn boundary | Strict server boundary: Ikarem exposes __call__(scope, receive, send). Any ASGI server works (uvicorn, hypercorn, daphne). HTTP + WebSocket + lifespan. |
| Central app + lifecycle | Ikarem() + on_startup / on_shutdown + lifespan. Plugins hook in with priority + topological dependency order. |
| Request/Response | Lazy Request (query, headers, cookies, await body()/json()), Response helpers (JSON, text, html, stream, redirect, File). Handlers never touch raw ASGI. |
| Routing | Compiled routes with {param} + {param:int/float/uuid/path} converters, 404 vs 405 distinction, url_for, include_router(prefix), static mounts. |
| Middleware | Onion pipeline, short-circuitable, global + composable: CORS, security headers, rate limiting (429 + Retry-After), request-ID/timing, metrics. |
| Plugins | Plugin protocol (name, requires, priority, register, on_startup/shutdown/request/response). Manager sorts dependencies, detects cycles. |
| Config | Layered Config: defaults < kwargs < dict < IKAREM_* env vars. Typed config.get(key, default, cast=...). |
| Errors | HTTPException hierarchy + @app.exception_handler(ExcType) with MRO most-specific match. Tracebacks only when debug=True. |
| DB Strategy (pg/mysql/sqlite/mssql) | DatabaseConnector async ABC (connect/disconnect/execute/fetch_one/fetch_all/execute_many/transaction). Lazy driver imports. SQLite runs on stdlib today. DatabasePlugin proves the extension model. |
| DI (FastAPI parity) | Depends() with nesting, per-request cache (+ opt-out), sync/async/yield deps, finalizers guaranteed after response send and on the exception path, circular-dep rejection. |
| Validation (Pydantic-lite) | Schema models from type hints: coercion, required/optional, nested models, ValidationError → 400. Zero deps. |
| Auth | Stdlib HS256 JWT (algorithm-confusion resistant, sub required, expiry enforced), pbkdf2 passwords, BearerAuth, require_roles() RBAC. |
| Caching | MemoryCache + @cached (Redis-swappable CacheBackend interface). |
| Background work | BackgroundTasks param — runs after the response is sent, never fails the response. |
| Realtime / files | app.websocket(path) + WebSocket helper; mount_static() + FileResponse. |
| Observability | JSON logging, x-request-id + x-process-time-ms, /healthz, Prometheus-style /metrics. |
Verification
108 tests, all green — including exhaustive branch matrices:
tests/test_di.py Depends() x12 (nesting, cache on/off, sync/async/yield,
cleanup after send — send-order proved — after exception,
failure mapping, cycles)
tests/test_jwt.py JWT x7 (valid, expired, bad sig, malformed, alg=none +
RS256-confusion attacks, missing sub, wrong secret)
tests/test_ratelimit.py Rate limit x7 (limit, 60s window reset, 429 + Retry-After,
countdown, headers everywhere, per-IP, 10-way concurrency)
tests/test_app.py routing, converters, 405, echo
tests/test_middleware.py after-hooks, short-circuit
tests/test_plugins.py hooks, dep order, missing dep, lifecycle
tests/test_db.py factory routing, SQLite CRUD, plugin lifecycle
tests/test_industry.py validation, DI+body, RBAC, security stack, background, cache, docs
tests/test_mcp_openapi.py requestBody/query/auth in OpenAPI, MCP list/call/errors/JSON-RPC
tests/test_forms.py urlencoded, multipart uploads, 413 caps
tests/test_session.py login cookies, tamper/expiry, CSRF allow/deny/exempt
tests/test_fields.py Field() ranges/lengths/patterns/emails, json_schema output
python -m pytest tests/ -q # 108 passed
Layout
ikarem/
__init__.py public exports (v1.0.0)
app.py Ikarem core + ASGI callable + DI/background/cleanup wiring
routing.py compiled routes + converters
http.py Request (+forms/uploads) + Response family (+cookies)
session.py signed-cookie sessions + CSRF
validation.py Schema models + Field() constraints (zero-dep validation)
middleware.py Middleware base + stack
plugins.py Plugin protocol + dependency-sorted PluginManager
config.py layered Config
errors.py HTTPException hierarchy + handler registry
validation.py Schema models (zero-dep validation)
di.py Depends + cycle detection + run_cleanups
openapi.py OpenAPI 3.1 builder + /openapi.json + /docs
auth.py JWT + passwords + BearerAuth + require_roles
security.py CORS + security headers + rate limiting
cache.py CacheBackend + MemoryCache + @cached
background.py BackgroundTasks
websocket.py WebSocket + WSRouter
static.py FileResponse + static mounts
observability.py logging + request-ID + metrics + /healthz + /metrics
db/ DatabaseConnector ABC + sqlite/postgres/mysql/sqlserver + plugin + factory
cli.py `ikarem run|check|mcp|new` helper
testing.py TestClient (cookie jar, all verbs — no server needed)
compiled.py one-time handler plans (perf) + check/describe IR
mcp.py routes-as-MCP-tools + stdio server
openapi.py OpenAPI 3.1 builder + /openapi.json + /docs
scaffold.py `ikarem new` starter generator
tests/ 108-test suite (see Verification)
examples/basic.py CRUD + DB plugin app
docs/PHASE1.md Phase 1 spec (rival crusher)
Release files for ikarem 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ikarem-1.0.0.tar.gz | 70.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ikarem-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 135.3 kB
Release files / ikarem-1.0.0.tar.gz
| Download URL | ikarem-1.0.0.tar.gz |
|---|---|
| Size | 70.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d34f7c20ebf1db20eb236811abda5d46aec68a88d0f6e9764b31f88811d38acd
|
|
BLAKE2b-256 checksum How to use checksums |
97f3e59f7e5ccd9be3d7fc4e86a0d154e0914fd3f744fe049744c8a091dfb762
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.15
|
Release files / ikarem-1.0.0-py3-none-any.whl
| Download URL | ikarem-1.0.0-py3-none-any.whl |
|---|---|
| Size | 65.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c234a83d037f81e547b9eb86a474fb6c4c448ddc954ce44533c79b1bffddcbf0
|
|
BLAKE2b-256 checksum How to use checksums |
c6a00f8519119f956aac9e817c4791fdf855ed016c6137bd900d57a307b80c8d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.15
|