Project Structure
How a Singularity project is organized and how the framework discovers your services, tasks, and middleware.
Your Project
Inside a freshly initialized project directory, running singularity new lays
down the following layout (existing files are left untouched):
my-project/
├── app.py # Entry point (4 lines)
├── settings.py # Your settings (extends SingularitySettings)
├── .env # Environment variables
├── services/ # Your services (auto-discovered)
│ └── users/
│ └── service.py
├── tasks/
│ └── executable/ # Your background tasks
├── models/ # SQLAlchemy models
├── schemas/ # Pydantic schemas
├── middlewares/ # Custom middleware (auto-discovered)
└── tests/app.py
from singularity import Singularity
from settings import Settings
app = Singularity(settings=Settings())The Singularity class handles everything: creates the FastAPI app, discovers your services, registers routes, sets up middleware, initializes the RPC registry, and manages the application lifecycle.
settings.py
from singularity import SingularitySettings
class Settings(SingularitySettings):
stripe_api_key: str = ""Extends the framework's base settings. All fields are loaded from environment variables and .env automatically via Pydantic.
How Discovery Works
The framework scans your project directories at startup:
services/— Every directory containing aservice.pywith a class ending inServicebecomes an API endpoint at/api/{directory_name}middlewares/— Every.pyfile containing aMiddlewareclass is registered as ASGI middlewaretasks/executable/— Every.pyfile with a@taskdecorator is registered as a background task
No manual registration needed. Drop files in the right place and they are discovered.
Framework Package
The singularity package (installed via pip install singularity-fm) contains:
| Module | Purpose |
|---|---|
singularity.core | Manager, Acquire, hooks, discovery, generator, webhook |
singularity.rpc | RPC registry, proxy, client, service discovery |
singularity.microservices | Remote microservice descriptor |
singularity.common | Logger, cache, error, WebSocket, Celery |
singularity.db | SQLAlchemy engine factories, CRUD mixin |
singularity.security | JWT bearer, auth utilities |
singularity.middleware | Exception handler, rate limiter |
singularity.tasks | @task decorator, TaskRunner, notifications |
singularity.scripts | BaseScript, ScriptRunner |
singularity.testing | ServiceTestClient, TestAcquire, mocks |
singularity.cli | CLI commands (new, generate, dev) |
Import Conventions
from singularity.core.acquire import Acquire
from singularity.core.hooks import HookContext
from singularity.core.webhook import BaseWebhookfrom singularity.rpc import rpc, get_registry
from singularity.rpc.proxy import RemoteServiceDescriptor
from singularity.rpc.exceptions import RPCServiceNotFound, RPCAccessDeniedfrom singularity.tasks import task, TaskRunner
from singularity.scripts.base_script import BaseScriptfrom singularity.config import get_settings
from singularity.common.logger import log
from singularity.common.cache import Cache, CacheInterface
from singularity.common.error import NotFoundError, BaseCustomErrorCLI Commands
# pyproject.toml (in the singularity-fm package)
[project.scripts]
singularity = "singularity.cli:cli"| Command | Purpose |
|---|---|
singularity new [name] | Scaffold framework files into the current directory |
singularity dev | Start dev server with hot reload |
singularity generate service <name> | Generate service boilerplate |
singularity generate task <name> | Generate task boilerplate |
Next Steps
- Configuration -- Understand the settings system and environment variables
- Services -- Build your first service
Installation
Step-by-step guide to installing Singularity, configuring your environment, and running the development and production servers.
Configuration
Walkthrough of the Pydantic Settings class, environment modes, all environment variables, logging configuration, and how to extend settings with custom fields.