Getting Started
ms-markets 2.x requires Python 3.13, Main Sequence SDK >=9.0.29,<10, and
the MetaTables client mainsequence-metatable>=0.1.51,<0.2 (imported as
metatables). It cannot run against an SDK 8 or earlier contract and does not
provide compatibility aliases or a mixed-version mode. Install a 1.x
ms-markets release when maintaining an SDK 8 project.
Install the project in editable mode with development dependencies:
uv sync --extra dev
Or with pip:
python -m pip install -e ".[dev]"
The project-level FastAPI surface is optional. Install it only for public API work:
uv sync --extra public_api
Verify that the import package is available:
import msm
from msm.api.http import ResourceCollection, build_resource_discovery_spec
Provider FastAPI projects should use the installable
msm.api.http boundary for shared
collection, discovery, preflight, operation, and error behavior.
Install ms-markets agent skills into a host CodeRepository only through the explicit CLI command:
msm copy-msm-skills --path .
This copies the packaged skill bundle into .agents/skills/ms_markets/ and
writes .agents/skills/ms_markets/PINNED_FROM.txt with the ms-markets version
that supplied the installed skills. Importing msm does not write files,
create .agents/, or auto-install skills.
Run this command only from a separate host CodeRepository. The CLI blocks
msm copy-msm-skills --path . inside the ms-markets source checkout because
the destination would overlap the package's own skill source.
Documentation
Serve the documentation locally:
mkdocs serve
Build the static documentation site:
mkdocs build
Architecture Decisions
Implementation decisions should be recorded under docs/ADR.
First Market Setup
Start with the typed row API for simple workflows. Apply the migrations to your local runtime first:
metatables --local migrations upgrade --provider msm_migrations:migration head
Hosted environments are migrated by the deployment workflow's migration Job, not from a developer session; see Hosted Deployments.
import msm
from msm.api.assets import Asset, AssetCategory, AssetType
msm.start_engine(models=["AssetType", "Asset", "AssetCategory"])
AssetType.upsert(asset_type="crypto", display_name="Crypto")
asset = Asset.upsert(unique_identifier="example-asset-btc", asset_type="crypto")
assets = Asset.filter(asset_type="crypto")
category = AssetCategory.upsert(
unique_identifier="example-crypto",
display_name="Example Crypto",
)
This follows the library-wide convention: user code works with Pydantic row
objects, while schema code works with SQLAlchemy *Table declarations.
Asset.upsert(...) and Asset.filter(...) use the active markets runtime.
They do not attach to MetaTables or create schemas on first use.
For application startup that wants a controlled runtime preflight, attach directly:
import msm
runtime = msm.start_engine()
context = runtime.context
asset_table = runtime.table("Asset")
That startup preflight resolves already-registered backend MetaTable and
TimeIndexMetaTable resources by each selected model's SQLAlchemy table name.
Missing backend tables fail startup and should be fixed through the
MetaTables migration upgrade flow.
For development examples that should use an example namespace, set
MSM_AUTO_REGISTER_NAMESPACE before importing msm.api, then call
msm.start_engine(...) during startup. That namespace also becomes the default
namespace for markets TimeIndexTableUpdater identifiers and hash_namespace values created
in the same process.
Every markets MetaTable now has a user-facing row model under msm.api.*.
Legacy imports such as from msm.models import Asset have been removed; use
from msm.api.assets import Asset for row operations and
from msm.models import AssetTable for SQLAlchemy schema declarations.
Treat explicit runtime attachment as process startup work: run it once during application initialization after admin migrations are current. Repeated calls with the same arguments return the cached runtime; different arguments are rejected for that process. See MetaTable Registration, Migrations, and Tutorial.
Local Django backend
For the Mac/workstation development stack, set
MAINSEQUENCE_ENDPOINT=http://local-backend:8000 in the ignored local .env.
Map local-backend to the machine running the Django Compose stack with that
stack's maintenance/switch_local_backend.py, after stopping the old stack and
starting the selected one. Restart clients after switching.
Use this base URL for the platform API and connection-contract examples. Application APIs, local MetaTables and test fixtures retain their own addresses. The endpoint change does not alter package APIs, deployment configuration or permissions. Credentials stay out of Git.