FastAPI application that orchestrates agents on MorphCloud VMs or Docker containers.
cd server
uv sync
uv run druids-server
The server starts on port 8000. It requires a .env file in this directory (see the root README for setup).
These supplement the shared Python conventions in CLAUDE.md.
Domain objects use @dataclass. API models use Pydantic BaseModel. Database models use SQLModel with table=True.
Constraints that are not obvious from the code:
- No ORM relationship fields on database models. Use explicit joins.
- Timestamps use
sa_column=sa.Column(sa.DateTime(timezone=True)). Always timezone-aware. - Use
model_dump(by_alias=True)when serializing for external APIs (e.g. MorphCloud). Plainmodel_dump()for internal use. - Configuration uses
BaseSettingswithDRUIDS_env prefix. External service keys usevalidation_aliasto accept their standard env var names without the prefix.
HTTPException messages must include the resource identifier so the caller knows what failed:
raise HTTPException(404, f"Execution {slug} not found")Validate inputs at API boundaries (route handlers). Trust inputs in internal code.
Dependency flow: config -> lib / db -> api. Lower-level modules must not import higher-level modules. lib/__init__.py re-exports the public API with __all__.
uv run pytest
Tests mirror source structure: tests/lib/, tests/api/, tests/db/, tests/integration/. Integration tests require a running server and sandbox VMs; they are skipped by default.
Gotchas:
- Prefer the shared API test helpers in
tests/api/conftest.py:make_api_app(),api_app,authed_app,authed_client,unauthed_client,execution_registry,make_mock_session(), andmake_execution_record(). - The execution registry (
_executionsindeps.py) is shared mutable state. Use theexecution_registryfixture so it is cleared before and after each test. - Patch config through
tests.conftest.patch_settings(...)ormake_settings(...), which overridedruids_server.config.get_settings. Do not patch module-localsettingsaliases. - Shared app fixtures clear
app.dependency_overridesfor you. If a test builds a custom app manually, it still needs to clear overrides in teardown. - Only tests that genuinely need a custom app should create their own
FastAPI()instance. Most API tests should reuse the shared fixtures instead.
Execution traces are logged to ~/.druids/executions/{user_id}/{slug}.jsonl. Each line is a JSON object with timestamp, event type, agent name, and event-specific fields.