API reference¶
Auto-generated Python API reference for the surfaces a third-party caller is likely to hit:
- Configuration models — load and validate
stellar.yamlfrom code. - Module contract — write your own module.
- Stores — read the on-disk LanceDB + DuckDB layer.
- Orchestration — run an end-to-end ingest from Python.
- Backend app factory — build the FastAPI app.
- IO helpers — Seurat
.rds→ h5ad conversion. - Doctor — programmatic validation.
- Deploy — programmatic deploy.
The deeper config-model reference (per-field tables and minimal / full YAML examples) lives at Configuration.
Configuration models¶
stellar.config holds the Pydantic schema for stellar.yaml. The
field-by-field tables are at Configuration; the
loader is documented here for code use.
The root model is rendered at Configuration → Top-level; the loader and the most-called helper are documented here.
load_config¶
stellar.config.load_config ¶
Parse path as YAML and validate against :class:StellarConfig.
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If |
ValidationError
|
On any schema violation. The error message points at the exact
bad key + value (e.g. |
StellarConfig.enabled_modules¶
Return the list of module keys (e.g. ['de', 'hdwgcna']) where
enabled is truthy. Used internally by stellar ingest / stellar
serve to decide what to run.
Module contract¶
Adding a new module is one subclass of Module plus a folder under
stellar/modules/<name>/. The full worked example
(SCENIC) is in Extending; the canonical reference
follows.
Module¶
stellar.module_api.Module ¶
Bases: ABC
Base class for an opt-in STELLAR analysis module.
Subclasses set class-level attributes:
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Slug used in URLs and config keys (e.g. |
title |
str
|
Human-readable name shown in nav / docs. |
extras_key |
str | None
|
If set, the optional-deps group that gates this module (matches the
key under |
config_key |
str
|
Key under |
ingest ¶
Read raw inputs (per :attr:config_key in stellar.yaml) and
write parquet under ctx.parquet_dir. Must be idempotent.
duckdb_schema ¶
Return extra SQL to run after parquet load — typically views that
join module tables to cells_v. Empty string means no-op.
routes ¶
Return a FastAPI router or None. Mounted under /api so the
router's own prefix (e.g. /de) becomes /api/de/....
claude_tools ¶
Anthropic tool schemas exposed when the copilot module is on.
claude_dispatch ¶
{tool_name: callable} matching the names in :meth:claude_tools.
Each callable is invoked with the JSON arguments Claude emitted.
stores is the live :class:stellar.core.stores.StoreRegistry
— close over it to read the DuckDB / Lance backing this atlas.
Pass-through stores=None is allowed for modules that don't
need atlas state (e.g. Enrichment, which only calls EnrichR).
Example::
def claude_dispatch(self, stores):
duck = stores.duck
return {
"list_things": lambda: duck.query("SELECT …").to_pylist(),
}
claude_system_prompt ¶
Optional prompt fragment appended to the copilot's system prompt. Keep it concise (3–10 lines) and module-scoped.
frontend_tabs ¶
Tabs to surface in the SPA nav. The frontend reads /api/config
and renders only the tabs declared here for enabled modules.
ModuleContext¶
stellar.module_api.ModuleContext
dataclass
¶
Read-only build-time context passed to :meth:Module.ingest.
Attributes:
| Name | Type | Description |
|---|---|---|
config |
StellarConfig
|
Parsed |
project_root |
Path
|
Directory containing |
parquet_dir |
Path
|
Destination for module parquet output ( |
TabDef¶
stellar.module_api.TabDef ¶
Bases: TypedDict
One entry in the SPA nav. Returned by :meth:Module.frontend_tabs.
Fields
path : str
URL path under the SPA base, e.g. /de/conditions.
label : str
Display text in the nav bar.
icon : str
Optional emoji / glyph rendered before the label.
order : int
Sort key — lower numbers appear first. Core tabs sit at 0..9.
Stores¶
The read-only data-access layer. Both stores are constructed once per
process by create_app() and shared by every request.
LanceStore¶
The gene-major matrix accessor.
stellar.core.stores.LanceStore ¶
Gene-major matrix accessor.
Each Lance row holds (gene_id, cell_idx, values) — a sparse
representation of one gene's expression across all cells. Coloring a
UMAP by any gene is one row lookup, no scan.
A sibling Lance table maps row index ↔ cell_id so the API can translate between client-facing string ids and dense vector indices.
cell_pos
property
¶
cell_id → row index. Built once, reused by every request.
Reads cell_ids before taking the lock — cell_ids itself
acquires the same non-reentrant lock and would deadlock here.
get_gene ¶
Return a dense expression vector of length n_cells for one gene.
Cached per-instance. Raises :class:KeyError if the gene isn't in
this matrix.
Gene names with apostrophes (rare for HGNC symbols, possible for
user-loaded var indices) are escaped before going into the Lance
filter — O'Connor's-marker'; DROP TABLE becomes a literal
non-match rather than a parser break.
get_genes ¶
Return a (n_cells, k) dense matrix plus the gene order.
DuckStore¶
stellar.core.stores.DuckStore ¶
Read-only DuckDB connection, thread-safe via cursor copies.
Every cursor we hand out also has a TEMPORARY VIEW cells_v
installed on it — this is the cohort-cleaned view (condition remap +
exclusions) every downstream route reads. The SQL comes from
:func:stellar.core.cells_v.cells_v_sql so it's driven by project
config, never hard-coded.
cursor ¶
Cheap per-request cursor — DuckDB cursors are session-isolated.
Reinstalls the cells_v view per cursor because TEMPORARY VIEWs
live on the connection they were created on; a child cursor is
effectively a new session.
StoreRegistry¶
stellar.core.stores.StoreRegistry ¶
Per-project handle holding every store the API needs.
Constructed once at startup by :func:stellar.backend.app.create_app
from a :class:stellar.config.StellarConfig; routes call
request.app.state.stores to reach it.
resolve_gene ¶
Pick the matrix that holds gene (primary first, then any wide).
Returns (store, matrix_name). Raises :class:KeyError if the
gene is in none of the matrices.
Orchestration¶
The build pipeline behind stellar ingest.
run_ingest¶
stellar.core.orchestrate.run_ingest ¶
run_ingest(
config: StellarConfig,
project_root: Path,
*,
modules: Iterable[Module] = (),
paths: BuildPaths | None = None,
verbose: bool = True,
) -> BuildPaths
Build all data artifacts for a project.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
StellarConfig
|
Validated :class: |
required |
project_root
|
Path
|
Directory containing |
required |
modules
|
Iterable[Module]
|
Optional iterable of :class: |
()
|
paths
|
BuildPaths | None
|
Override the default layout. Mostly for tests. |
None
|
BuildPaths¶
stellar.core.orchestrate.BuildPaths
dataclass
¶
default_paths¶
Backend app factory¶
The FastAPI app behind stellar serve.
create_app¶
stellar.backend.app.create_app ¶
create_app(
config: StellarConfig,
project_root: Path,
*,
modules: Iterable[Module] = (),
) -> FastAPI
Construct the FastAPI app for one project.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
StellarConfig
|
Parsed :class: |
required |
project_root
|
Path
|
Directory containing |
required |
modules
|
Iterable[Module]
|
Optional iterable of module instances. Each module's
:meth: |
()
|
IO helpers¶
convert_rds_to_h5ad¶
stellar.core.io.seurat.convert_rds_to_h5ad ¶
convert_rds_to_h5ad(
rds_path: Path,
*,
cache_dir: Path | None = None,
force: bool = False,
) -> Path
Convert a Seurat .rds to .h5ad via R + SeuratDisk/sceasy.
Caches the result next to the source (or under cache_dir if
given) and short-circuits when the cache is fresher than the source.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
rds_path
|
Path
|
Source Seurat object. Must exist. |
required |
cache_dir
|
Path | None
|
Where to write the cached h5ad. Defaults to |
None
|
force
|
bool
|
Re-run even if a cached h5ad exists and is up-to-date. |
False
|
Returns:
| Type | Description |
|---|---|
Path
|
The cached |
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
|
SeuratConversionError
|
|
resolve_input_path¶
stellar.core.io.seurat.resolve_input_path ¶
Normalise an input matrix path.
If path ends in .rds (case-insensitive), convert it via
:func:convert_rds_to_h5ad and return the cached .h5ad.
Otherwise return path unchanged.
This is what builder code (Lance + cells ingest) calls to get the h5ad they actually open. Users with Seurat objects never have to convert manually.
SeuratConversionError¶
stellar.core.io.seurat.SeuratConversionError ¶
Bases: RuntimeError
Raised when an .rds → .h5ad conversion fails.
Doctor¶
The pre-flight validator behind stellar doctor.
run_doctor¶
stellar.core.doctor.run_doctor ¶
Run every check; return the populated report (caller decides on
exit code based on report.errors).
DoctorReport¶
Diagnostic¶
Deploy¶
The rsync + snippet renderer behind stellar deploy.
run_deploy¶
stellar.core.deploy.run_deploy ¶
run_deploy(
config: StellarConfig,
project_root: Path,
*,
target_dir: Path | None = None,
dry_run: bool = False,
) -> int
Sync stellar/frontend/dist/ and the project's pre-baked static
artifacts to target_dir. Render the matching nginx + systemd
snippets to stdout.
Returns the rsync exit code (or 2 if any precheck fails).
Usage examples¶
Ingest from Python¶
from pathlib import Path
from stellar.config import load_config
from stellar.core.orchestrate import run_ingest
from stellar.modules.registry import builtin_modules
project_root = Path("/srv/atlases/my_atlas").resolve()
config = load_config(project_root / "stellar.yaml")
run_ingest(
config,
project_root,
modules=builtin_modules(),
verbose=True,
)
Serve a project as an embedded FastAPI app¶
from pathlib import Path
import uvicorn
from stellar.backend.app import create_app
from stellar.config import load_config
from stellar.modules.registry import builtin_modules
project_root = Path("/srv/atlases/my_atlas").resolve()
config = load_config(project_root / "stellar.yaml")
app = create_app(config, project_root, modules=builtin_modules())
# Mount the app inside a larger uvicorn deployment, or run standalone:
if __name__ == "__main__":
uvicorn.run(app, host="127.0.0.1", port=18901)
Run only your own modules (no built-ins)¶
from my_lab_modules import RegulonModule, TrajectoryModule
app = create_app(
config,
project_root,
modules=[RegulonModule(), TrajectoryModule()],
)
The built-in registry is convenience, not a chokepoint — the
orchestrator and app factory both accept any iterable of Module
instances. See Extending for the contract.