Code Guidelines
TL;DR
Skills follow strict typing (Python 3.10+ syntax, never Any), use Pydantic models for structured data, keep functions under 20 lines, catch specific exceptions, and use ruff + mypy for linting and type checking.
Return values
All commands return a dict. The framework wraps it:
# Success
return {"domain": "github.com", "days_left": 42}
# β {"ok": true, "domain": "github.com", "days_left": 42}
# Error (raise exception)
raise ValueError("Invalid domain")
# β {"ok": false, "error": "Invalid domain"}Never return raw strings or print to stdout. Always return structured data.
Type annotations
Complete type annotations are required. Use Python 3.10+ syntax:
# Good
def check(domain: str, timeout: int = 10) -> dict[str, str | int]:
...
# Bad β missing annotations
def check(domain, timeout=10):
...
# Bad β using Any
def check(domain: str) -> Any:
...Pydantic models
Use BaseModel for structured data instead of raw dicts:
from pydantic import BaseModel
class CertInfo(BaseModel):
domain: str
issuer: str
days_left: int
valid: bool
@skill.command
async def check(domain: str = Arg(help="Domain")) -> dict:
info = CertInfo(
domain=domain,
issuer="Let's Encrypt",
days_left=42,
valid=True,
)
return info.model_dump()Function style
- Keep functions under 20 lines
- Use guard clauses over deep nesting
- Prefix private helpers with
_ - Constants:
SCREAMING_SNAKE_CASE - No mutable default arguments
- No global mutable state
# Good β guard clause
async def check(domain: str) -> dict:
if not domain:
raise ValueError("Domain required")
result = await _fetch_cert(domain)
return result.model_dump()
# Bad β deep nesting
async def check(domain: str) -> dict:
if domain:
try:
result = await _fetch_cert(domain)
if result:
return result.model_dump()
else:
raise ValueError("No result")
except Exception:
raise
else:
raise ValueError("Domain required")Error handling
Catch specific exceptions, never bare except::
# Good
try:
resp = await client.get(url)
except httpx.TimeoutException:
raise ValueError(f"Timeout connecting to {url}")
except httpx.ConnectError:
raise ValueError(f"Cannot connect to {url}")
# Bad
try:
resp = await client.get(url)
except:
raise ValueError("Something went wrong")Dependencies
Keep dependencies minimal. Prefer stdlib when possible. Always pin minimum versions:
dependencies = [
"cmdop-skill",
"httpx>=0.27",
"pydantic>=2.0",
]Linting and type checking
[tool.ruff]
line-length = 100
[tool.mypy]
strict = trueRun:
make lint # ruff check
make format # ruff formatBest practices
- Confirm destructive actions β always ask before deleting or modifying
- Idempotent operations β running twice should produce the same result
- Progressive disclosure β simple output by default,
--verbosefor details - Errors as JSON β return structured errors, not stack traces
- Audit trail β log significant actions for debugging
Last updated on