Skip to content

Coding Standards

Document type: Engineering Standard
Scope: Application services, APIs, AI orchestration, integrations, tests, and supporting infrastructure
Status: Baseline engineering policy

This document defines the coding practices expected across WhiteLotusAI. Its purpose is to keep the codebase maintainable, secure, testable, and consistent as the platform evolves.

These standards complement the repository's existing dependency constraints, configuration, and CI workflows. Where a tool or convention has not yet been formally adopted, follow the existing project implementation rather than introducing an unapproved requirement.

⌘

Readable and maintainable

Prefer explicit interfaces, focused functions, meaningful names, and clear error handling.

🛡

Secure by default

Validate inputs, enforce authorization server-side, and treat external content as untrusted.

✓

Testable by design

Cover regressions, edge cases, failure paths, and provider integrations with deterministic tests.

↗

Review-ready changes

Keep changes scoped, document important decisions, and verify compatibility before merging.

Start with the existing project configuration

Before changing formatting, linting, typing, or testing conventions, inspect the dependency files, tool configuration, and CI workflow. The engineering setup guide should remain the source of truth for the exact commands used by the project.

Engineering Setup Repository Structure


1. Core engineering principles

All contributions should follow these principles.

Principle Expected practice
Clarity Prefer descriptive names, explicit control flow, and typed interfaces over implicit state or clever abstractions.
Separation of concerns Keep API handling, orchestration, policy enforcement, provider adapters, and persistence responsibilities distinct.
Boundary validation Validate external inputs before they enter application logic.
Focused implementation Keep functions and classes cohesive, with clearly defined responsibilities.
Centralized authorization Apply access-control decisions consistently in trusted application code.
Explicit failure handling Propagate or handle exceptions deliberately; never disguise failures as successful operations.
Reproducibility Keep dependency versions, configuration, and test behavior consistent across development and CI.
Data protection Never commit secrets, credentials, unnecessary personal data, or local environment files.

Do not hide failures

Avoid broad exception handlers that silently discard errors. If an exception is handled, the code must have a deliberate recovery or failure response, with appropriate diagnostics and without exposing sensitive information.

2. Code ownership and separation of responsibilities

WhiteLotusAI includes application services, AI orchestration, external integrations, and persistence. Keep responsibilities explicit so that changes remain independently testable.

flowchart TD
    INPUT["External Input"]
    API["API and Boundary Validation"]
    POLICY["Authorization and Policy"]
    ORCH["Application Logic and AI Orchestration"]
    ADAPTER["Provider and Service Adapters"]
    DATA["Persistence Layer"]
    RESPONSE["Validated Response"]

    INPUT --> API
    API --> POLICY
    POLICY --> ORCH
    ORCH --> ADAPTER
    ADAPTER --> DATA
    DATA --> ADAPTER
    ADAPTER --> ORCH
    ORCH --> RESPONSE

    classDef boundary fill:#dbeafe,stroke:#2563eb,color:#172554
    classDef security fill:#ffedd5,stroke:#ea580c,color:#7c2d12
    classDef logic fill:#dcfce7,stroke:#16a34a,color:#14532d
    classDef storage fill:#f3e8ff,stroke:#9333ea,color:#581c87

    class INPUT,API,RESPONSE boundary
    class POLICY security
    class ORCH,ADAPTER logic
    class DATA storage

The diagram illustrates a recommended separation of responsibilities, not a claim about the exact runtime call sequence of every service.

Component Primary responsibility Avoid
API and boundary layer Parse requests, validate inputs, and shape responses. Embedding provider-specific logic in route handlers.
Policy and authorization Enforce permissions, access boundaries, and operation restrictions. Trusting model-generated authorization decisions.
Orchestration Coordinate application workflows, model calls, and approved tools. Duplicating security policy across individual tools.
Provider adapters Encapsulate external API requests, response mapping, and provider-specific failures. Leaking provider-specific assumptions into unrelated services.
Persistence Store and retrieve data under established ownership and access rules. Bypassing access controls or mixing unrelated persistence concerns.
Tests Verify behavior, failure handling, and cross-component contracts. Depending on production accounts or uncontrolled external state.

3. Python coding standards

Follow PEP 8 unless an approved project configuration establishes different conventions. Use the existing Python version, dependencies, and type-checking practices.

3.1 Naming and structure

  • Use snake_case for functions, variables, and modules.
  • Use PascalCase for classes.
  • Use descriptive names that communicate intent.
  • Keep functions focused and avoid unnecessary nesting.
  • Extract repeated logic only when doing so improves clarity and maintainability.
  • Prefer explicit parameters and return types for public or nontrivial interfaces.
  • Keep configuration separate from business logic.
  • Avoid mutable global state unless its lifecycle and synchronization are deliberate.

3.2 Type annotations and validation

Use type annotations to make interfaces easier to understand and maintain. Validate untrusted external data with Pydantic or the validation mechanism already established in the project.

from pydantic import BaseModel, ConfigDict, Field


class SearchRequest(BaseModel):
    model_config = ConfigDict(extra="forbid")

    query: str = Field(min_length=1, max_length=500)
    limit: int = Field(default=10, ge=1, le=100)


def normalize_query(request: SearchRequest) -> str:
    return request.query.strip()

This example demonstrates a strict request schema with bounded fields. Adapt the validation rules to the actual API contract and domain requirements.

def search(payload):
    query = payload.get("query")
    limit = payload.get("limit", 10)
    return run_search(query, limit)

This example does not establish the input type, validate field constraints, or reject unexpected fields before invoking application logic.

Validation is not authorization

A structurally valid request is not necessarily permitted. Validate the schema first, then enforce the relevant identity, ownership, permissions, and operation policy.

3.3 Asynchronous operations and network requests

  • Use asynchronous I/O consistently within asynchronous request paths.
  • Avoid blocking network, file, or database operations on the event loop.
  • Set explicit timeouts for network requests.
  • Bound retries and use backoff where appropriate.
  • Retry only operations whose semantics make retrying safe.
  • Respect provider rate limits and cancellation.
  • Avoid creating unbounded concurrent tasks.

For example, use the HTTP client's configured timeout mechanism rather than allowing requests to wait indefinitely.

import httpx


async def fetch_resource(url: str) -> dict[str, object]:
    timeout = httpx.Timeout(10.0)

    async with httpx.AsyncClient(timeout=timeout) as client:
        response = await client.get(url)
        response.raise_for_status()
        return response.json()

This is an illustrative pattern. Use the HTTP client and timeout conventions already adopted by the repository, and validate the response schema before relying on external fields.

3.4 Exception handling and logging

  • Catch specific exceptions when recovery is possible.
  • Preserve exception causes with raise ... from exc when translating errors.
  • Return safe, consistent public errors.
  • Keep diagnostic details in appropriately protected logs.
  • Never log access tokens, passwords, API keys, or sensitive payloads.
  • Avoid logging complete emails, chat histories, or retrieved documents unless explicitly justified and appropriately protected.
try:
    result = await provider.fetch_resource()
except TimeoutError as exc:
    logger.warning("Provider request timed out")
    raise ProviderUnavailableError(
        "The requested service is temporarily unavailable."
    ) from exc

The exception type and logger are illustrative. Match the actual provider client, error taxonomy, and logging conventions used in the project.

4. AI orchestration and tool safety

AI-generated plans and external content must never replace deterministic application controls.

Security boundaries must remain in trusted code

Model output, retrieved documents, emails, chat messages, issue descriptions, and provider responses are untrusted input. Instructions contained in that content must not override system policy, access controls, or tool restrictions.

4.1 Required safeguards

  • Validate planner and model outputs against explicit schemas.
  • Reject unknown, prohibited, or unsupported fields where appropriate.
  • Authorize every protected operation using trusted application state.
  • Enforce tool allowlists and read-only restrictions in server-side code.
  • Require genuine user confirmation for actions that need it; never infer confirmation from an LLM-generated flag.
  • Verify resource ownership and access permissions before returning or modifying data.
  • Apply appropriate limits to tool arguments, execution time, retries, and returned content.
  • Test prompt injection, malicious documents, malformed tool arguments, and unauthorized requests.
  • Keep deterministic security policy separate from model-based recommendations.

4.2 Safe tool-execution lifecycle

flowchart TD
    REQUEST["Incoming Request"]
    PARSE["Validate Input and Context"]
    PLAN["Generate Proposed Plan"]
    SCHEMA["Validate Plan Schema"]
    AUTH["Authorize Requested Operation"]
    CONFIRM{"Confirmation Required?"}
    APPROVE["Verify Explicit User Confirmation"]
    EXEC["Execute Approved Operation"]
    RESULT["Validate and Filter Result"]
    ERROR["Reject or Return Safe Error"]
    RESPONSE["Return Response"]

    REQUEST --> PARSE
    PARSE --> PLAN
    PLAN --> SCHEMA
    SCHEMA --> AUTH
    AUTH --> CONFIRM
    CONFIRM -- "No" --> EXEC
    CONFIRM -- "Yes" --> APPROVE
    APPROVE --> EXEC
    EXEC --> RESULT
    RESULT --> RESPONSE

    PARSE -. "Invalid input" .-> ERROR
    SCHEMA -. "Invalid plan" .-> ERROR
    AUTH -. "Unauthorized" .-> ERROR
    APPROVE -. "Not confirmed" .-> ERROR

    classDef normal fill:#dbeafe,stroke:#2563eb,color:#172554
    classDef security fill:#ffedd5,stroke:#ea580c,color:#7c2d12
    classDef failure fill:#fee2e2,stroke:#dc2626,color:#7f1d1d
    class REQUEST,PLAN,EXEC,RESULT,RESPONSE normal
    class PARSE,SCHEMA,AUTH,CONFIRM,APPROVE security
    class ERROR failure

The confirmation branch is illustrative. Apply confirmation only where required by the operation's risk and product policy. All operations must still pass the applicable authorization checks.

5. API, integration, and data handling

API design

  • Validate request parameters and payloads at the API boundary.
  • Use consistent status codes and documented response schemas.
  • Keep internal exception messages, stack traces, and implementation details out of public responses.
  • Apply authentication, authorization, and resource ownership checks to protected endpoints.
  • Avoid breaking existing contracts without an explicit migration or compatibility plan.
  • Document material changes to request and response behavior.

Provider integrations

  • Isolate provider-specific behavior behind explicit adapter interfaces.
  • Configure timeouts, retry policies, and rate-limit handling.
  • Handle partial failures and malformed provider responses deliberately.
  • Do not assume that a successful HTTP response guarantees a valid application-level result.
  • Use mocks or fakes for routine unit tests.
  • Reserve live-provider tests for controlled environments with appropriate credentials and safeguards.

Secrets and sensitive data

Data category Required handling
Credentials and API keys Store through approved secret-management mechanisms; never commit them.
Environment configuration Commit safe examples only; exclude real local environment files.
Personal and user content Minimize collection, exposure, retention, and logging.
Authentication tokens Protect in transit and at rest; never expose them in logs or responses.
Error diagnostics Include useful operational context without leaking secrets or sensitive payloads.
Test fixtures Use synthetic or appropriately sanitized data.

Treat repository history as part of the security boundary

Removing a secret from the latest version of a file does not remove it from Git history. Follow the project's incident procedure for exposed credentials, including revocation and rotation where necessary.

6. Testing standards

Every meaningful behavior change should have tests appropriate to its risk and scope. Every fixed bug should have a regression test where practical.

Test category What to verify
Unit tests Business logic, validation, transformations, and error handling.
Integration tests Service boundaries, persistence interactions, and adapter contracts.
Authorization tests Unauthorized access, ownership boundaries, and prohibited operations.
Negative tests Malformed inputs, missing fields, invalid states, and provider failures.
Boundary tests Minimum and maximum values, empty collections, limits, and edge conditions.
Regression tests Previously observed bugs remain fixed.
AI safety tests Prompt injection, hostile retrieved content, invalid plans, and unauthorized tool requests.

Testing expectations

  • Test success and failure paths.
  • Mock external providers in unit tests.
  • Avoid dependence on production accounts, real user data, or unstable external services.
  • Make tests deterministic and isolate shared state.
  • Clean up temporary resources and test-created records.
  • Verify that retries, timeouts, and exceptions behave as intended.
  • Update tests when API contracts or configuration behavior change.
def test_search_request_rejects_empty_query() -> None:
    import pytest
    from pydantic import ValidationError

    with pytest.raises(ValidationError):
        SearchRequest(query="")
async def test_user_cannot_access_another_users_resource(
    client,
) -> None:
    response = await client.get("/resources/another-users-resource")

    assert response.status_code in (403, 404)

These examples are illustrative. Use the repository's actual fixtures, routes, authorization policy, and expected status-code conventions.

7. Formatting, linting, and static analysis

Use the tools already pinned or configured by the project. Do not introduce a new formatter, linter, type checker, or mandatory CI step without agreement on its configuration and adoption.

Area Standard
Formatting Follow the configured formatter or existing repository conventions.
Linting Use the linter and rules already adopted by the project.
Type checking Follow the established typing policy and configured checks.
Tests Run the applicable test suite for the change.
CI Ensure required checks pass before merging.
Documentation Keep examples, configuration references, and setup instructions current.

Where to find exact commands

Refer to the Engineering Setup guide for verified installation steps and command examples. Do not assume a tool is installed simply because it is commonly used in Python projects.

8. Pull request and code review workflow

A pull request should make its purpose, risk, and verification straightforward for reviewers.

Author checklist

  • The scope and purpose of the change are clearly described.
  • Relevant tests cover new behavior and regressions.
  • Invalid inputs, failure paths, and boundary cases are considered.
  • Authorization and tool allowlists are enforced server-side.
  • Secrets and sensitive data are excluded.
  • Logging and public errors are safe and actionable.
  • Documentation and configuration examples are updated.
  • Compatibility and migration implications are documented.
  • Required CI checks pass.
  • Unrelated changes and generated build artifacts are excluded.

Reviewer checklist

  • Responsibilities and interfaces remain clear.
  • Security decisions do not depend on model output alone.
  • Failure handling, timeouts, and retries are appropriate.
  • Tests are meaningful, deterministic, and isolated.
  • Public API and data-handling changes are compatible or documented.
  • The implementation matches the stated purpose and risk.

9. Definition of done

A change is ready to merge when its implementation, verification, and operational impact have been reviewed.

  • Implementation


    The code follows established conventions, preserves separation of concerns, and handles errors explicitly.

  • Security


    Input validation, authorization, secret handling, and applicable tool restrictions are verified.

  • Verification


    Relevant tests pass, regressions are covered, and required CI checks are successful.

  • Documentation


    Relevant engineering guides, examples, and configuration references reflect the change.


Maintenance

Update this document when engineering conventions, security requirements, or the project's adopted tooling materially change. Keep normative requirements aligned with the actual repository and CI configuration.


  1. Examples in this document illustrate recommended patterns. They are not evidence that a specific library, route, exception class, test fixture, or CI command is already implemented in WhiteLotusAI. ↩