Constants and Secrets
Constants and secrets solve the same broad problem:
how should a Main Sequence workflow receive configuration at runtime?
They are both small pieces of runtime configuration, but they are not interchangeable.
Use the split below:
Constant: safe operational configurationSecret: sensitive configuration
If leaking the value would create an incident, it should not be a constant.
Quick Decision Rule
Use a Constant for things like:
- feature flags
- model windows and thresholds
- dataset names
- vendor identifiers
- small JSON mappings
- mode switches such as
production,paper, orsandbox
Use a Secret for things like:
- API keys
- bearer tokens
- passwords
- webhook signing secrets
- connection credentials
- private vendor access tokens
In practice:
MODEL__DEFAULT_WINDOW = 252is a constantFEATURE__ENABLE_VALIDATION = trueis a constantPOLYGON_API_KEY = "..."is a secretAWS_SECRET_ACCESS_KEY = "..."is a secret
Mental Model
Think of constants and secrets as runtime inputs, not workflow outputs.
Jobs, resources, dashboards, agents, and notebooks often need configuration that should not live directly inside code. Constants and secrets give you a place to store that configuration in the platform.
A useful mental split is:
- code defines behavior
- constants define non-sensitive runtime settings
- secrets define protected credentials
That keeps the repository cleaner and reduces the amount of environment-specific data hardcoded into scripts and jobs.
RBAC and Shareable Resources
Constants and secrets sit inside a broader platform access model.
Main Sequence applies resource-level access control, so the real operational question is not only "what is this value?" but also:
- who can see it
- who can edit it
- which team or project boundary it belongs to
- whether it is safe to expose through a deployed release
In practice, the current SDK exposes sharing behavior across several resource types:
ProjectDataNodeStorageConstantSecretBucketArtifactResourceRelease
Why these matter:
Projectdefines an important collaboration and execution boundaryDataNodeStorageis the published table boundary for shared datasetsConstantstores shareable, non-sensitive runtime configurationSecretstores protected credentialsBucketholds artifacts and files that may themselves contain sensitive or controlled contentArtifactis the individual stored object that may need controlled visibilityResourceReleaseis the deployment-facing wrapper for resources such as dashboards and agents
IMPORTANT
Constant and Secret are not the only shareable resources in the SDK.
Project, DataNodeStorage, Bucket, Artifact, and ResourceRelease also participate in the same shareable-object model.
This guide focuses on constants and secrets because they are the simplest place to learn the pattern.
That is the practical reason this topic matters early:
- constants and secrets teach the access-control model in its simplest form
- the same idea scales later to projects, shared tables, buckets, artifacts, and deployed resources
Constants
The client model is:
from mainsequence.client import Constant
A constant is a small, readable, organization-level configuration value.
The current SDK model exposes:
idnamevaluecategory
What constants are good for
Good fits:
- default windows such as
252 - tuning parameters such as confidence thresholds
- external dataset names
- reusable small lookup dictionaries
- environment-independent configuration values
Bad fits:
- passwords
- API keys
- secrets copied from other systems
- anything that should not be casually displayed in a UI, notebook, or log
Naming and categories
Constants are expected to use UPPER_SNAKE_CASE.
You can also group constants with a double underscore:
ASSETS__MASTER
MODEL__DEFAULT_WINDOW
FEATURE__ENABLE_VALIDATION
BROKER__DEFAULT_ACCOUNT
This does not create a nested object. It is just a naming convention.
Main Sequence treats the prefix before __ as a human-readable category. For example:
ASSETS__MASTERis displayed under categoryASSETSMODEL__DEFAULT_WINDOWis displayed under categoryMODEL
This is useful when you want the constants table to stay readable without inventing a more complex hierarchy.
Constant examples
Simple scalar value:
Constant.create(
name="MODEL__DEFAULT_WINDOW",
value=252,
)
Boolean flag:
Constant.create(
name="FEATURE__ENABLE_VALIDATION",
value=True,
)
Small JSON object:
Constant.create(
name="BROKER__DEFAULTS",
value={
"execution_venue": "paper",
"account_type": "margin",
},
)
Reading constants
Read one constant:
from mainsequence.client import Constant
default_window = Constant.get(name="MODEL__DEFAULT_WINDOW").value
Read just the value:
default_window = Constant.get_value("MODEL__DEFAULT_WINDOW")
Read multiple constants by name:
constants = Constant.filter(
name__in=[
"MODEL__DEFAULT_WINDOW",
"FEATURE__ENABLE_VALIDATION",
]
)
Current client-side supported filters are:
namename__in
When to prefer a constant over code
Use a constant instead of hardcoding when:
- operators may need to change the value without editing source
- the value is reused across several jobs or scripts
- the value is environment or organization specific
- the value is business configuration, not program logic
Examples:
- a rebalance threshold
- a default benchmark name
- a vendor dataset alias
- a list of supported external identifiers
Secrets
The client model is:
from mainsequence.client import Secret
A secret is protected configuration. The platform should treat it differently from normal application settings.
The current SDK model exposes:
idnamevalue
In practice, some backend responses may only return the secret name rather than echoing the value back.
What secrets are good for
Use a secret for:
POLYGON_API_KEYOPENAI_API_KEYAWS_SECRET_ACCESS_KEY- broker credentials
- database passwords
- signed webhook tokens
If you would be uncomfortable seeing the value in a screenshot, error email, or notebook output, it should be a secret.
Secret examples
Create a secret:
from mainsequence.client import Secret
Secret.create(
name="POLYGON_API_KEY",
value="***",
)
Read a secret:
polygon_key = Secret.get(name="POLYGON_API_KEY").value
Filter secrets by name:
secrets = Secret.filter(name__in=["POLYGON_API_KEY", "OPENAI_API_KEY"])
Current client-side supported filters are:
namename__in
Operational rules for secrets
Secrets need a different operational standard than constants:
- do not commit them to the repository
- do not copy them into constants
- do not print them in logs
- do not paste them into dashboards or notebooks casually
- rotate them when external systems require it
A good working rule is:
- constants may be read frequently and discussed openly
- secrets should be accessed only where they are required
Human-Readable Examples
Example 1: Market data integration
You are integrating a vendor feed.
Use constants for:
- the vendor dataset name
- a default universe identifier
- a feature flag enabling a fallback path
Use secrets for:
- the vendor API key
- the vendor bearer token
Example split:
VENDOR__DATASET = "us_equities_realtime"as a constantVENDOR__DEFAULT_EXCHANGE = "XNYS"as a constantVENDOR_API_KEYas a secret
Example 2: Model configuration
You have a job that computes signals using a rolling window and a threshold.
Use constants for:
- rolling window
- minimum signal score
- default region
Do not use secrets here unless an external protected service is involved.
Example:
MODEL__DEFAULT_WINDOW = 252MODEL__MIN_SCORE = 0.85MODEL__REGION = "US"
Example 3: External execution venue
You have a workflow that talks to a broker or exchange.
Use constants for:
- default account alias
- execution mode such as
paperorlive - venue configuration labels
Use secrets for:
- API secret
- refresh token
- signing private key
CLI Usage
The CLI exposes both resources directly.
Constants:
mainsequence constants list
mainsequence constants create MODEL__DEFAULT_WINDOW 252
mainsequence constants create BROKER__DEFAULTS '{"mode":"paper"}'
mainsequence constants delete 42
Secrets:
mainsequence secrets list
mainsequence secrets create POLYGON_API_KEY your-secret-value
mainsequence secrets delete 42
Important behavior:
- constants display the category derived from the prefix before
__ - secrets are shown by metadata only in CLI tables and delete previews
- delete commands require typed verification
CLI sharing examples for constants
These commands show the resource-level sharing model directly:
mainsequence constants can_view 42
mainsequence constants can_edit 42
mainsequence constants add_to_view 42 7
mainsequence constants add_to_edit 42 7
mainsequence constants remove_from_view 42 7
mainsequence constants remove_from_edit 42 7
Interpretation:
42is the constant id7is the user id receiving or losing access
This is the most concrete CLI example of Main Sequence RBAC at the resource level.
Recommended Practice
A good configuration layout usually looks like this:
- constants contain readable runtime settings
- secrets contain credentials only
- application code reads both, but does not redefine them
A healthy split is:
- store business and runtime configuration in constants
- store credentials and protected tokens in secrets
That gives you:
- better readability
- safer operations
- fewer credentials hardcoded in project code
Anti-Patterns
Avoid these:
- storing API keys in constants
- storing large application config blobs in secrets
- hardcoding credentials in source files
- using secrets for ordinary non-sensitive flags
- creating many nearly identical constants when one small JSON object would do
Final Rule
If the value is safe to read, review, and discuss as part of ordinary project configuration, use a Constant.
If the value must be protected, use a Secret.