Skip to main content

Code style

Beyond linting, SimSwarm has a handful of conventions that keep the codebase consistent and the runtime correct. These come from the project's architecture rules and are worth following in any contribution.

Linting​

Backend code is linted with Ruff at line length 100 ([tool.ruff] in pyproject.toml). Run Ruff and both test suites before opening a PR; see Testing.

Feature co-location​

Organize by feature, not by layer. Each feature owns its models, schemas, API routes, and business logic in one directory (saas/auth/, saas/jobs/, saas/gpu/, …). Keep files under roughly 300 lines; split into focused modules rather than growing one file. See Repository Structure.

App factory and dependency injection​

The FastAPI app is built by a factory, saas.main:create_app(settings=None), which accepts an optional Settings so tests can inject their own configuration. Database access goes through the injectable saas.database:get_session dependency, which tests override with an in-memory SQLite session. Follow this pattern: depend on get_session rather than reaching for a global engine, so the code stays testable.

Sync DB writes from Celery/activities​

When writing to the database from a Celery task or a Temporal activity, use synchronous psycopg2, never the shared async SQLAlchemy pool. Mixing the async pool into worker/activity contexts causes InterfaceError and can wedge the event loop. The job persistence layer (saas/jobs/persistence*.py) exposes sync helpers for exactly this reason, and the workflow activities persist results at the source using them.

Cancel, not terminate, for Temporal​

To stop a running workflow, use workflow cancel, never workflow terminate. Termination skips the workflow's finally block, and that finally is what tears the GPU pod down (fishcloud.terminate_pod in SimulationWorkflow). Skipping it leaves the pod running and billing. Cancel lets the cleanup path execute. See Data Flow and Temporal.

Engine via the adapter layer​

The simulation engine lives in simswarm/. The application talks to it through saas/adapters/. Keep engine concerns out of the application feature directories and vice versa.

No credit gating​

The open-source build has no billing and no credit gating. Job creation does not check or charge a balance; there is no 402 path. Some legacy billing artifacts remain on disk (an empty saas/billing/ directory, the dead credits_charged column, and the retained REFUNDED status), but they are not part of any active path. Do not reintroduce credit checks. See Database Schema.