ASGI protocol inspector — validates, traces, and analyzes your ASGI app
Project description
asgion
ASGI protocol inspector — validates your ASGI application against the ASGI specification at runtime. Catches protocol violations, state machine errors, and event schema mismatches before they become production bugs.
Zero runtime dependencies. Python 3.12+.
Quickstart
Python API
pip install asgion
from asgion import inspect
app = inspect(app) # wrap any ASGI app — zero config
Use with any ASGI server:
import uvicorn
uvicorn.run(inspect(app), host="127.0.0.1", port=8000)
CLI
pip install asgion[cli]
asgion check myapp:app
What It Catches
164 rules across 12 layers — scope fields, event schemas, state machines, extensions, and semantic checks for HTTP, WebSocket, and Lifespan.
[G-005] error Message must be a dict
[HE-012] error response.body 'body' must be bytes, got str
[HF-003] error Duplicate http.response.start
[WE-008] warning websocket.send has both 'bytes' and 'text' set
Every rule has an ID, severity, summary, and hint. See the full list: docs/rules.md
CLI Reference
asgion check
asgion check APP_PATH [OPTIONS]
Check an ASGI app for protocol violations.
| Option | Description |
|---|---|
APP_PATH |
Module:attribute path (e.g. myapp:app) |
--path PATH |
Paths to check (repeatable, default /). Prefix with protocol to set scope type: http:/path, https:/path, ws:/path, wss:/path |
--strict |
Exit 1 on any violations |
--format text|json |
Output format (default text) |
--exclude-rules IDS |
Comma-separated rule IDs to skip |
--min-severity LEVEL |
Minimum severity: perf, info, warning, error |
--config FILE |
Path to .asgion.toml or pyproject.toml |
--profile PROFILE |
Rule filter profile: strict, recommended, minimal |
--no-color |
Disable ANSI colors (also respects NO_COLOR env) |
--no-lifespan |
Skip lifespan startup/shutdown checks |
asgion check myapp:app --path /api/users # HTTP (default)
asgion check myapp:app --path ws:/ws/chat # WebSocket
asgion check myapp:app --path /api --path ws:/ws # both
Exit codes: 0 = clean, 1 = violations (with --strict), 2 = runtime error.
asgion rules
asgion rules [OPTIONS]
List all validation rules.
| Option | Description |
|---|---|
--format text|json |
Output format (default text) |
--layer LAYER |
Filter by layer: general, http, websocket, lifespan |
--severity LEVEL |
Filter by severity: perf, info, warning, error |
--no-color |
Disable ANSI colors |
asgion --version
Print version and exit.
Python API
from asgion import AsgionConfig, inspect
cfg = AsgionConfig(
min_severity="warning", # skip perf/info rules
exclude_rules={"HE-012", "G-008"}, # suppress specific rules
ttfb_threshold=2.0, # custom TTFB threshold (seconds)
)
wrapped = inspect(
app,
config=cfg,
strict=False, # True to raise on violations
on_violation=lambda v: print(v), # real-time callback
exclude_paths=["/health", "/metrics"], # skip these paths
)
Or select a built-in profile:
from asgion import BUILTIN_PROFILES, inspect
app = inspect(app, config=BUILTIN_PROFILES["recommended"]) # warning+ only
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
app |
ASGIApp |
required | The ASGI application to wrap |
config |
AsgionConfig |
None |
Rule filter settings and thresholds |
strict |
bool |
False |
Raise ASGIProtocolError on any violation |
on_violation |
callback | None |
Called with each Violation in real-time |
exclude_paths |
list[str] |
None |
Paths to skip validation |
exclude_rules |
set[str] |
None |
Rule IDs to suppress (additive to config) |
registry |
ValidatorRegistry |
None |
Custom validator registry |
AsgionConfig
Can also be loaded from pyproject.toml or .asgion.toml:
[tool.asgion]
profile = "recommended" # base profile: strict / recommended / minimal
exclude_rules = ["SEM-006"] # suppress specific rules (supports globs: "SEM-*")
include_rules = ["HF-*"] # allowlist — only these rules fire
categories = ["http"] # filter by layer prefix ("http" matches http.fsm, http.semantic, …)
ttfb_threshold = 2.0 # SEM-006: TTFB limit (seconds)
lifecycle_threshold = 30.0 # SEM-007: total connection time (seconds)
body_size_threshold = 10485760 # SEM-008: response size (bytes)
Violation
@dataclass(frozen=True, slots=True)
class Violation:
rule_id: str # "HF-001", "G-010"
severity: Severity # error, warning, info, perf
message: str # human-readable description
hint: str # suggestion for fixing
scope_type: str # "http", "websocket", "lifespan"
path: str # "/api/users"
method: str # "GET"
pytest Plugin
pip install asgion[pytest]
async def test_my_app(asgi_inspect):
app = asgi_inspect(my_app)
async with httpx.AsyncClient(transport=ASGITransport(app)) as client:
resp = await client.get("/users")
assert app.violations == []
Auto-check violations with a marker:
@pytest.mark.asgi_validate(min_severity="error")
async def test_strict(asgi_inspect):
app = asgi_inspect(my_app)
# ... drive the app — violations checked automatically at teardown
Or enable globally for all tests using asgi_inspect:
pytest --asgi-strict
pytest --asgi-strict --asgi-min-severity warning
Comparison
| Feature | asgion | asgiref.testing | Manual testing |
|---|---|---|---|
| Scope validation | 71 rules | basic | none |
| Event schema checks | 43 rules | none | manual |
| State machine (FSM) | 34 rules | none | none |
| Semantic checks | 13 rules | none | none |
| Extension validation | 3 rules | none | none |
| pytest plugin | yes | no | n/a |
| Real-time callbacks | yes | no | n/a |
| CLI tool | yes | no | no |
| Zero dependencies | yes | no (asgiref) | n/a |
| Rule suppression | per-rule | no | n/a |
Contributing
git clone https://github.com/ack1d/asgion.git
cd asgion
uv sync --group dev
uv run pytest # run tests
uv run ruff check src/ # lint
uv run mypy src/ # type check
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file asgion-0.3.0.tar.gz.
File metadata
- Download URL: asgion-0.3.0.tar.gz
- Upload date:
- Size: 33.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
60643a8e32a6b1a409eff9e783717765125617ada6de2712dd88fcadb3be8bf2
|
|
| MD5 |
7787dc9aec0be08d81151f7e60281e1d
|
|
| BLAKE2b-256 |
fa815136b133f72573fc6e3439dac63dd747ee4fae4a5a8620bcb273434c6030
|
Provenance
The following attestation bundles were made for asgion-0.3.0.tar.gz:
Publisher:
publish.yml on ack1d/asgion
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
asgion-0.3.0.tar.gz -
Subject digest:
60643a8e32a6b1a409eff9e783717765125617ada6de2712dd88fcadb3be8bf2 - Sigstore transparency entry: 964609192
- Sigstore integration time:
-
Permalink:
ack1d/asgion@93a63fefad1378a66e268bee7cd43552de301485 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/ack1d
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@93a63fefad1378a66e268bee7cd43552de301485 -
Trigger Event:
release
-
Statement type:
File details
Details for the file asgion-0.3.0-py3-none-any.whl.
File metadata
- Download URL: asgion-0.3.0-py3-none-any.whl
- Upload date:
- Size: 47.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fba7d7cc5ffcc6cb35b9a5a15d9f0a7a0302912d27fb33c9a42a6dcaa1333ca2
|
|
| MD5 |
49c1ecbd939d700d7f0c149ed32513b7
|
|
| BLAKE2b-256 |
8be438fb76dccacdb33a9175dbe8eba93d1240b4ddd0ededbd8684c77cc1edd9
|
Provenance
The following attestation bundles were made for asgion-0.3.0-py3-none-any.whl:
Publisher:
publish.yml on ack1d/asgion
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
asgion-0.3.0-py3-none-any.whl -
Subject digest:
fba7d7cc5ffcc6cb35b9a5a15d9f0a7a0302912d27fb33c9a42a6dcaa1333ca2 - Sigstore transparency entry: 964609248
- Sigstore integration time:
-
Permalink:
ack1d/asgion@93a63fefad1378a66e268bee7cd43552de301485 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/ack1d
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@93a63fefad1378a66e268bee7cd43552de301485 -
Trigger Event:
release
-
Statement type: