how the code stays changeable

Strong boundaries.
Few surprises.

The design favors small domain contracts, explicit failure behavior, and composition over inheritance. Add an implementation without making the core know about your infrastructure.

Module boundaries

  • schema.py owns validated wire and domain data.
  • graph.py owns pure graph transformations and invariants.
  • adapter.py owns runtime orchestration around a host solver.
  • llm.py owns provider I/O, timeouts, bounded output, and retries.
  • repo.py owns durable persistence behind protocols.
  • jobs.py owns durable evolution records and workers.
  • service.py owns HTTP DTOs, auth, readiness, and transport errors.

Structural polymorphism

Runtime dependencies are substituted through typing.Protocol contracts: Solver, LLMClient, Repository, VectorIndex, and ActionExecutor. This is the OOP seam: behavior is replaceable without forcing every host into a class hierarchy.

class Solver(Protocol):
    async def step(self, state: AgentState) -> str: ...

class TestSolver:
    async def step(self, state: AgentState) -> str:
        return "answer"

Style and naming

Public APIs use Google-style snake_case, PascalCase, and UPPER_SNAKE_CASE. Implementation-only state uses one leading underscore, such as self._pool. Double-leading underscores are reserved for language protocols and name-mangling cases.

Ruffmypyabsolute imports__all__no lazy imports

Testing contract

The quality gate includes linting, formatting, typing, unit/API tests, Postgres integration, browser accessibility, container startup, load smoke tests, backup/restore, SBOM, and vulnerability scanning. The local integration recipe is on the testing guide.

uv run ruff check .
uv run ruff format --check methodos tests scripts eval/hotpotqa/*.py examples
uv run mypy methodos tests scripts eval/hotpotqa/*.py examples
uv run pytest -q --cov=methodos --cov-fail-under=95