Coding standards¶
Audience: Anyone writing Python for this repo. Outcome: After reading, you know the style, typing, testing, and review rules a change must satisfy — every one of them is enforced by CI or pre-commit, not by convention. Last verified: 2026-07-05
These are the standards the Agentic Runtime Platform actually enforces. The authoritative gate definitions live in CONTRIBUTING.md and .github/workflows/ci.yml; this page is the summary.
Style and formatting¶
- Black (line-length 88) and isort (profile=black) run via pre-commit; unformatted code never reaches the repo.
- Ruff is the linter, with rules
E, F, W, I, N, UP, S, B, A, C4, SIM, TCH, RUFenabled. CI fails ifruff check --fixwould still change anything — apply autofixes and commit them. - PEP 8 naming:
snake_casefunctions/variables/modules,PascalCaseclasses,UPPER_SNAKEconstants,_privateprefix for internal APIs. - All tool configuration lives in
pyproject.toml; docformatter and pydocstyle run as scoped pre-commit hooks.
Types¶
- Type hints on every function signature.
- mypy runs strict on
agentic_v2/engineandagentic_v2/contracts(--disallow-untyped-defs --warn-return-any); the rest of the runtime runs the relaxed baseline inpyproject.tomlwhile type debt is paid down.
Design rules¶
- Immutable patterns — return new objects; never mutate inputs.
- Files under 800 lines — split before a module grows past this. Existing files above the guide are tracked in the exception register (ADR-055); a file may exceed the guide only while it is listed there.
- Reuse existing infrastructure instead of re-implementing it:
SmartModelRouterfor tier/model selection,ExecutionContextfor run state and checkpoints,ConversationMemoryfor history, the MCP client stack for tool calls, and the shared error classification helpers. - Additive-only contracts — Pydantic v2 models in
contracts/never remove or rename existing fields; any wire-format change must regenerate the committed schemas and TypeScript types (thewire-format-driftCI job enforces this — see ADR-014). - Smallest coherent change; one concern per PR. Match the surrounding code — do not refactor unrelated subsystems.
Errors and logging¶
- No bare
except:— catch the specific exception you expect; every handler must log with context, re-raise, or return a meaningful error. - Structured logging, no
print— use the structlog-based logger;LOG_FORMAT=jsonemits NDJSON in production. - Never log secrets or PII — the sanitization middleware and detect-secrets baseline back this up, but do not rely on them to catch what you should not have logged.
Testing¶
- pytest, Arrange–Act–Assert, behavior over implementation. Full conventions in
.claude/rules/testing.md. - 80% coverage is the floor, not a target range:
[tool.coverage.report] fail_under = 80withprecision = 2(79.93% fails), enforced in a dedicatedcoverage report --fail-under=80CI step. The UI package holds a separate 60% floor. New backend code targets 80% on changed lines. - Unit tests are deterministic and key-free — set
AGENTIC_NO_LLM=1or patch the model client. Mark anything slow or network-bound with@pytest.mark.slow/@pytest.mark.integrationso it stays out of the fast CI pass. Flaky tests are bugs.
Secrets and configuration¶
- Configuration flows through environment variables and
.env.exampleonly. Never read, edit, or commit.env. - Resolve runtime secrets through
agentic_v2.models.secrets.get_secret()/get_first_secret(), notos.environdirectly.
Review¶
This is a single-maintainer repository: correctness is gated by automated evidence, not peer approval. Treat AI-generated code as untrusted input — run the full lint + type-check + test set (just test && just docs && pre-commit run --all-files) before accepting it. Keep PRs small, use conventional-commit subjects (type(scope): subject), and write an ADR when a change meets the criteria in CONTRIBUTING §6.