skills/smello-setup/SKILL.md
Explore a Python codebase and propose a plan to integrate Smello — capture HTTP requests, logs, and exceptions in a local web dashboard. Use when the user wants to add Smello to their project, set up request monitoring, debug logging, or capture outgoing API calls and crashes for debugging.
npx skillsauth add smelloscope/smello smello-setupInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
You are helping the user integrate Smello into their Python project. Smello captures outgoing HTTP requests (via requests, httpx, aiohttp, and botocore), gRPC calls (via grpc), unhandled exceptions (via sys.excepthook), and Python log records (via logging). Everything is displayed in a unified timeline in a local web dashboard at http://localhost:5110. Google Cloud libraries (BigQuery, Firestore, Pub/Sub, Analytics Data API, Vertex AI, etc.) use gRPC under the hood and are captured automatically.
Your job is to explore the codebase, then present a plan. Do NOT make any changes until the user approves.
Investigate the project to understand:
pip + requirements.txt, pip + pyproject.toml, uv, poetry, pipenv, or something else?requests, httpx, aiohttp, grpc, botocore, or Google Cloud client libraries? Search for import requests, import httpx, from requests, from httpx, import grpc, from google.cloud, from google.analytics, import boto3, import botocore.logging module? Search for import logging, logging.getLogger, logger.warning, logger.error. This determines whether to suggest capture_logs=True.if __name__ == "__main__": blocksmanage.py, wsgi.py, asgi.py), Flask (app = Flask(...), create_app()), FastAPI (app = FastAPI()), etc.pyproject.toml ([project.scripts])docker-compose.yml, docker-compose.dev.yml, compose.yml, compose.dev.yml, Dockerfile, or similar files. Identify development-specific compose files vs production ones..env files, or settings modules to toggle dev-only features (this informs where to gate smello.init()).After exploring, present a clear plan with these sections:
The recommended approach is to install smello as a regular (not dev) dependency. It has zero dependencies itself, and smello.init() is a safe no-op when SMELLO_URL is not set — no patching, no threads, no side effects. This means users don't need conditional imports or try/except ImportError guards in production.
Based on the package manager detected:
pip install smello (add smello to requirements.txt)smello to [project.dependencies]uv add smellopoetry add smellopipenv install smelloThe server is covered separately in section D below.
Smello can be activated in two ways. Recommend one based on what fits the project; mention the other so the user knows it exists.
Path 1 — code-level activation (smello.init()): explicit, lives next to other bootstrap code, easy to gate by environment. Best when the project owns its entrypoint and a couple of extra lines are welcome.
Path 2 — wrapper (smello run): zero source changes. The user prepends smello run to whatever command they already use (smello run uvicorn app:app, smello run pytest tests/, smello run my_app.py). Best when:
smello run exposes the same SMELLO_* config as flags: --server, --capture-host, --ignore-host, --capture-all/--no-capture-all, --redact-header, --redact-query-param, --capture-exceptions/--no-capture-exceptions, --capture-logs/--no-capture-logs, --log-level, --ignore-logger. Flags win over env vars. Use -- to disambiguate when the wrapped command's flags would collide (smello run --server URL -- python -m mod --debug).
smello.init()Propose the exact file and location. The two lines must go before any HTTP library imports or usage so HTTP patching catches the first request:
import smello
smello.init()
Ordering nuance for the other capture types:
capture_exceptions=True): init() installs sys.excepthook / threading.excepthook immediately. Position doesn't matter beyond running before the exception happens — for unhandled exceptions in the bootstrap path itself, place init() as early as possible. Pass capture_exceptions=False (or SMELLO_CAPTURE_EXCEPTIONS=false) to opt out.capture_logs=True): logging capture works regardless of when handlers and loggers are created — Smello hooks Logger.callHandlers, which all log calls funnel through. So even loggers configured later (Django settings, logging.config.dictConfig, etc.) are captured.Common placement patterns:
manage.py (for runserver) or a custom AppConfig.ready() methodcreate_app() or the app factorylifespan handlerif __name__ == "__main__":Since Smello uses the server URL as its activation signal, the recommended pattern is to always call smello.init() and control activation via the SMELLO_URL environment variable:
import smello
smello.init() # only activates when SMELLO_URL is set
Then in .env or the shell:
SMELLO_URL=http://localhost:5110
This way the code has zero conditional logic — without SMELLO_URL, init() is a safe no-op (no patching, no threads, no side effects).
If the project uses logging extensively, suggest enabling log capture:
import smello
smello.init(capture_logs=True, log_level=20) # capture INFO and above
If the project uses noisy framework loggers (e.g., uvicorn.access, django.request), suggest suppressing them:
smello.init(capture_logs=True, log_level=20, ignore_loggers=["uvicorn.access"])
Or via environment variables:
SMELLO_CAPTURE_LOGS=true
SMELLO_LOG_LEVEL=20
SMELLO_IGNORE_LOGGERS=uvicorn.access
Exception capture is enabled by default — no configuration needed.
smello runNo source edits. The user runs their existing command through the wrapper:
# .py scripts run with the current Python interpreter
smello run my_app.py
# Console scripts work directly; subprocess workers are instrumented automatically
smello run uvicorn app:app
smello run gunicorn app:app
smello run pytest tests/
# `--` disambiguates when the wrapped command and smello share flag names
smello run --server http://localhost:5110 -- python -m my_module --debug
# Enable log + exception capture without code changes
smello run --capture-logs --log-level 20 uvicorn app:app
If the project ships its own smello.init() call already, the wrapper is still safe to use: bootstrap initialization runs first, then the program's init() updates the live config in place (no double-patching, no double-capture).
For long-running commands defined in Procfile, Makefile, justfile, package.json scripts, or compose files, suggest prefixing the command with smello run in dev variants only.
Smello supports full configuration via SMELLO_* environment variables. Suggest adding these to the project's .env, .env.development, or equivalent:
SMELLO_URL=http://localhost:5110 # server URL (activates Smello)
# SMELLO_CAPTURE_HOSTS=api.stripe.com,api.openai.com # only capture these hosts
# SMELLO_IGNORE_HOSTS=localhost,internal.svc # skip these hosts
# SMELLO_REDACT_HEADERS=Authorization,X-Api-Key # headers to redact
# SMELLO_CAPTURE_LOGS=true # capture Python log records
# SMELLO_LOG_LEVEL=20 # minimum log level (INFO=20, WARNING=30)
# SMELLO_IGNORE_LOGGERS=uvicorn.access # suppress noisy loggers
All parameters can also be passed explicitly to smello.init(), which takes precedence over env vars:
SMELLO_CAPTURE_HOSTS=api.example.com or capture_hosts=["api.example.com"]SMELLO_IGNORE_HOSTS=... or ignore_hosts=[...]SMELLO_URL=http://smello:5110 or server_url="http://smello:5110"SMELLO_CAPTURE_LOGS=true with an appropriate SMELLO_LOG_LEVELSMELLO_IGNORE_LOGGERS=uvicorn.access or ignore_loggers=["uvicorn.access"]Authorization and X-Api-Key headers are redacted by defaultBoolean env vars accept true/1/yes and false/0/no (case-insensitive). List env vars are comma-separated.
If the project is a FastAPI or Django web application, suggest adding the Smello middleware to capture incoming HTTP requests. This is the one integration that always requires a code change (it cannot be done via smello run alone).
from smello.integrations.fastapi import SmelloMiddleware
from fastapi import FastAPI
app = FastAPI()
app.add_middleware(SmelloMiddleware, ignore_paths=["/health"])
# settings.py
MIDDLEWARE = [
"smello.integrations.django.SmelloMiddleware",
...
]
SMELLO_IGNORE_PATHS = ["/health/", "/admin/"]
The middleware captures every request your server handles: method, path, status code, duration, route pattern, and client IP. Unhandled exceptions are captured with full tracebacks.
Only suggest this if the project is a web application. For CLI tools, scripts, or background workers, skip this section.
Ask the user which server setup they prefer:
smello-server separately (skip this section)smello-server to their project's dev dependenciespip install smello-server includes the full web dashboard — Docker is not required for the UI.
If the user chooses Docker Compose, propose adding a Smello service:
smello:
image: ghcr.io/smelloscope/smello
ports:
- "5110:5110"
volumes:
- smello-data:/data
And add smello-data to the volumes: section. The app container should set SMELLO_URL=http://smello:5110 (or pass server_url="http://smello:5110" to init()) to reach the Smello server over the Docker network.
Prefer adding this to a dev-specific compose file (docker-compose.dev.yml, compose.dev.yml, compose.override.yml) if one exists. If only a single compose file exists, note that the user may want to create a dev overlay.
If the user chooses to add the server as a dev dependency, use the same package manager pattern from section A:
smello-server to requirements-dev.txtsmello-server to the dev dependency groupuv add --dev smello-serverpoetry add --group dev smello-serverpipenv install --dev smello-serverThen run with smello-server, or as a standalone tool:
# With uv
uv tool install smello-server
# With pipx
pipx install smello-server
After presenting the plan, ask the user which parts they want to proceed with. Do NOT edit any files until explicitly told to do so.
pip install smello (Python >= 3.10, zero dependencies)pip install smello-server (Python >= 3.14, includes web dashboard) or Docker ghcr.io/smelloscope/smellorequests, httpx, aiohttp, grpc, botocore), incoming HTTP requests (FastAPI/Django middleware), unhandled exceptions (sys.excepthook), and Python log records (logging)Authorization, X-Api-Keyhttp://localhost:5110smello run wrapper: zero-code activation via PYTHONPATH bootstrap; subprocess-instrumentation safe; flags mirror SMELLO_* env vars 1:1.| Variable | Type | Default |
|----------|------|---------|
| SMELLO_URL | string | None (inactive) |
| SMELLO_CAPTURE_ALL | bool | true |
| SMELLO_CAPTURE_HOSTS | comma-separated list | [] |
| SMELLO_IGNORE_HOSTS | comma-separated list | [] |
| SMELLO_REDACT_HEADERS | comma-separated list | Authorization,X-Api-Key |
| SMELLO_REDACT_QUERY_PARAMS | comma-separated list | [] |
| SMELLO_CAPTURE_EXCEPTIONS | bool | true |
| SMELLO_CAPTURE_LOGS | bool | false |
| SMELLO_LOG_LEVEL | int | 30 (WARNING) |
| SMELLO_IGNORE_LOGGERS | comma-separated list | [] |
Precedence: explicit init() parameter > env var > hardcoded default.
development
Debug HTTP requests, logs, and exceptions captured by Smello. Use when the user asks to inspect traffic, debug API calls, troubleshoot failed requests, analyze response bodies, check captured logs or exceptions, or understand what their code is doing. Also use when the user wants to run a script or app with Smello instrumentation to start a debugging session. Also use when the user pastes a Smello dashboard URL like http://localhost:5110/#<uuid> or http://localhost:5111/#<uuid> — extract the UUID after the hash as the event ID. Supports gRPC calls from Google Cloud libraries. Requires a running Smello server.
development
Debug HTTP requests, logs, and exceptions captured by Smello. Use when the user asks to inspect traffic, debug API calls, troubleshoot failed requests, analyze response bodies, check captured logs or exceptions, or understand what their code is doing. Also use when the user pastes a Smello dashboard URL like http://localhost:5110/#<uuid> or http://localhost:5111/#<uuid> — extract the UUID after the hash as the event ID. Supports gRPC calls from Google Cloud libraries. Requires a running Smello server.
development
Explore a Python codebase and propose a plan to integrate Smello traffic capture (HTTP and gRPC). Use when the user wants to add Smello to their project, set up request monitoring, or capture outgoing API calls for debugging.
development
Debug HTTP requests captured by Smello. Use when the user asks to inspect traffic, debug API calls, troubleshoot failed requests, analyze response bodies, or understand what requests their code is making. Also use when the user pastes a Smello dashboard URL like http://localhost:5110/#<uuid> or http://localhost:5111/#<uuid> — extract the UUID after the hash as the request ID. Supports gRPC calls from Google Cloud libraries. Requires a running Smello server.