Configure Profile struct, sub-configs, environment substitution, and validation.
Help:
{ "command": "cloud profile show" }viasystemprompt_help
Profiles are environment configurations stored in .systemprompt/profiles/<name>/profile.yaml.
Profile Struct (Complete)
Source: crates/shared/models/src/profile/mod.rs:88-120
pub struct Profile {
pub name: String, // Profile identifier
pub display_name: String, // Human-readable name
pub target: ProfileType, // Local | Cloud
pub site: SiteConfig, // Site identity
pub database: DatabaseConfig, // Database settings
pub server: ServerConfig, // HTTP server settings
pub paths: PathsConfig, // Directory layout
pub security: SecurityConfig, // JWT configuration
pub rate_limits: RateLimitsConfig, // API rate limiting
pub runtime: RuntimeConfig, // Environment & logging
pub cloud: Option<CloudConfig>, // Cloud credentials paths
pub secrets: Option<SecretsConfig>, // Secrets configuration
pub extensions: ExtensionsConfig, // Extension management
}
ProfileType Enum
pub enum ProfileType {
#[default]
Local, // Development on local machine
Cloud, // Cloud deployment (Fly.io)
}
Sub-Configuration Types
SiteConfig
Source: crates/shared/models/src/profile/site.rs
pub struct SiteConfig {
pub name: String, // Required: Site name
pub github_link: Option<String>, // Optional: GitHub URL
}
DatabaseConfig
Source: crates/shared/models/src/profile/database.rs:5-12
pub struct DatabaseConfig {
#[serde(rename = "type")]
pub db_type: String, // "postgres" or "postgresql"
#[serde(default)]
pub external_db_access: bool, // Default: false
}
ServerConfig
Source: crates/shared/models/src/profile/server.rs:5-22
pub struct ServerConfig {
pub host: String, // Required: "127.0.0.1" or "0.0.0.0"
pub port: u16, // Required: Must be > 0
pub api_server_url: String, // Required: e.g., "http://localhost:8080"
pub api_internal_url: String, // Required: Internal service URL
pub api_external_url: String, // Required: Public/external URL
#[serde(default)]
pub use_https: bool, // Default: false
#[serde(default)]
pub cors_allowed_origins: Vec<String>, // Default: empty
}
PathsConfig
Source: crates/shared/models/src/profile/paths.rs:4-18
pub struct PathsConfig {
pub system: String, // Required: System root directory
pub services: String, // Required: Services directory
pub bin: String, // Required: Binaries directory
pub web_path: Option<String>, // Optional: Web output path
pub storage: Option<String>, // Optional: File storage
pub geoip_database: Option<String>, // Optional: MaxMind .mmdb path
}
Derived Paths (methods on PathsConfig):
| Method | Returns |
|---|---|
skills() |
{services}/skills |
config() |
{services}/config/config.yaml |
ai_config() |
{services}/ai/config.yaml |
content_config() |
{services}/content/config.yaml |
web_config() |
{services}/web/config.yaml |
web_metadata() |
{services}/web/metadata.yaml |
web_path_resolved() |
web_path or {system}/web |
storage_resolved() |
storage if set |
geoip_database_resolved() |
geoip_database if set |
SecurityConfig
Source: crates/shared/models/src/profile/security.rs:4-22
pub struct SecurityConfig {
#[serde(rename = "jwt_issuer")]
pub issuer: String, // Required: JWT issuer claim
#[serde(rename = "jwt_access_token_expiration")]
pub access_token_expiration: i64, // Required: Seconds (max 31,536,000)
#[serde(rename = "jwt_refresh_token_expiration")]
pub refresh_token_expiration: i64, // Required: Seconds
#[serde(rename = "jwt_audiences")]
pub audiences: Vec<JwtAudience>, // Required: Allowed audiences
}
Token Expiration Limits:
access_token_expiration: Maximum 31,536,000 seconds (1 year)- Default: 2,592,000 seconds (30 days)
refresh_token_expiration: Default 15,552,000 seconds (180 days)
RuntimeConfig
Source: crates/shared/models/src/profile/runtime.rs:6-22
pub struct RuntimeConfig {
#[serde(default)]
pub environment: Environment, // Default: Development
#[serde(default)]
pub log_level: LogLevel, // Default: Normal
#[serde(default)]
pub output_format: OutputFormat, // Default: Text
#[serde(default)]
pub no_color: bool, // Default: false
#[serde(default)]
pub non_interactive: bool, // Default: false
}
Environment Enum:
pub enum Environment {
#[default] Development,
Test,
Staging,
Production,
}
LogLevel Enum (with tracing filter mapping):
| Enum Value | Tracing Filter |
|---|---|
Quiet |
error |
Normal (default) |
info |
Verbose |
debug |
Debug |
trace |
OutputFormat Enum:
pub enum OutputFormat {
#[default] Text,
Json,
Yaml,
}
RateLimitsConfig
Source: crates/shared/models/src/profile/rate_limits.rs:58-100
pub struct RateLimitsConfig {
#[serde(default)]
pub disabled: bool, // Default: false
#[serde(default = "default_oauth_public")]
pub oauth_public_per_second: u64, // Default: 10
#[serde(default = "default_oauth_auth")]
pub oauth_auth_per_second: u64, // Default: 10
#[serde(default = "default_contexts")]
pub contexts_per_second: u64, // Default: 100
#[serde(default = "default_tasks")]
pub tasks_per_second: u64, // Default: 50
#[serde(default = "default_artifacts")]
pub artifacts_per_second: u64, // Default: 50
#[serde(default = "default_agent_registry")]
pub agent_registry_per_second: u64, // Default: 50
#[serde(default = "default_agents")]
pub agents_per_second: u64, // Default: 20
#[serde(default = "default_mcp_registry")]
pub mcp_registry_per_second: u64, // Default: 50
#[serde(default = "default_mcp")]
pub mcp_per_second: u64, // Default: 200
#[serde(default = "default_stream")]
pub stream_per_second: u64, // Default: 100
#[serde(default = "default_content")]
pub content_per_second: u64, // Default: 50
#[serde(default = "default_burst")]
pub burst_multiplier: u64, // Default: 3
#[serde(default)]
pub tier_multipliers: TierMultipliers, // Default: TierMultipliers::default()
}
TierMultipliers (rate limit multipliers by user type):
pub struct TierMultipliers {
#[serde(default = "default_admin_multiplier")]
pub admin: f64, // Default: 10.0
#[serde(default = "default_user_multiplier")]
pub user: f64, // Default: 1.0
#[serde(default = "default_a2a_multiplier")]
pub a2a: f64, // Default: 5.0
#[serde(default = "default_mcp_multiplier")]
pub mcp: f64, // Default: 5.0
#[serde(default = "default_service_multiplier")]
pub service: f64, // Default: 5.0
#[serde(default = "default_anon_multiplier")]
pub anon: f64, // Default: 0.5
}
CloudConfig
Source: crates/shared/models/src/profile/cloud.rs:5-35
pub struct CloudConfig {
#[serde(default = "default_credentials_path")]
pub credentials_path: String, // Default: "./credentials.json"
#[serde(default = "default_tenants_path")]
pub tenants_path: String, // Default: "./tenants.json"
pub tenant_id: Option<String>, // Optional: Active tenant
#[serde(default)]
pub validation: CloudValidationMode, // Default: Strict
}
pub enum CloudValidationMode {
#[default] Strict, // Fail on validation errors
Warn, // Log warnings only
Skip, // Skip validation entirely
}
SecretsConfig
Source: crates/shared/models/src/profile/secrets.rs:10-18
pub struct SecretsConfig {
pub secrets_path: String, // Path to secrets file
#[serde(default)]
pub validation: SecretsValidationMode, // Default: Warn
pub source: SecretsSource, // Required: File | Env
}
pub enum SecretsSource {
File, // Load from secrets_path file
Env, // Load from environment variables
}
pub enum SecretsValidationMode {
Strict, // Fail on missing secrets
#[default] Warn, // Log warnings only
Skip, // Skip validation entirely
}
ExtensionsConfig
pub struct ExtensionsConfig {
#[serde(default)]
pub disabled: Vec<String>, // Extension IDs to disable
}
Environment Variable Substitution
Source: crates/shared/models/src/profile/mod.rs:52-68
Profile YAML supports ${VAR_NAME} syntax for environment variable substitution.
Pattern
database:
type: postgres
server:
host: ${HOST:-0.0.0.0}
port: ${PORT}
api_server_url: ${API_URL:-http://localhost:8080}
Implementation
static ENV_VAR_REGEX: LazyLock<Regex> = LazyLock::new(|| {
Regex::new(r"\$\{(\w+)\}").expect("Invalid regex")
});
fn substitute_env_vars(content: &str) -> String {
ENV_VAR_REGEX.replace_all(content, |caps: &Captures| {
let var_name = &caps[1];
std::env::var(var_name).unwrap_or_else(|_| caps[0].to_string())
}).to_string()
}
Rules
- Pattern:
${VAR_NAME}(alphanumeric and underscore only) - If env var not found, original
${VAR_NAME}is retained - Substitution happens at parse time (before YAML parsing)
- Default value syntax
${VAR:-default}is handled by config manager, not profile parser
Path Resolution
Source: crates/shared/models/src/profile/paths.rs:69-108
Relative Path Resolution
Relative paths in profile are resolved relative to the profile directory:
pub fn resolve_path(base: &Path, path: &str) -> String {
let path = Path::new(path);
if path.is_absolute() {
path.to_string_lossy().to_string()
} else {
base.join(path)
.canonicalize()
.map(|p| p.to_string_lossy().to_string())
.unwrap_or_else(|_| base.join(path).to_string_lossy().to_string())
}
}
Home Directory Expansion
Paths starting with ~/ are expanded:
pub fn expand_home(path_str: &str) -> PathBuf {
if path_str.starts_with("~/") {
if let Some(home) = std::env::var_os("HOME")
.or_else(|| std::env::var_os("USERPROFILE")) {
return PathBuf::from(home).join(&path_str[2..]);
}
}
PathBuf::from(path_str)
}
Combined Resolution
pub fn resolve_with_home(base: &Path, path_str: &str) -> PathBuf {
let expanded = expand_home(path_str);
if expanded.is_absolute() {
expanded
} else {
base.join(expanded)
}
}
Profile Validation
Source: crates/shared/models/src/profile/validation.rs:13-32
Validation runs after parsing and path resolution.
Validation Chain
pub fn validate(&self) -> Result<()> {
self.validate_required_fields()?;
self.validate_paths()?;
self.validate_security_settings()?;
self.validate_cors_origins()?;
self.validate_rate_limits()?;
Ok(())
}
1. Required Fields Validation
Lines 113-133
| Field | Rule |
|---|---|
name |
Non-empty string |
display_name |
Non-empty string |
site.name |
Non-empty string |
server.host |
Non-empty string |
server.port |
> 0 |
server.api_server_url |
Non-empty string |
server.api_internal_url |
Non-empty string |
server.api_external_url |
Non-empty string |
2. Paths Validation
Lines 34-112
Local Profiles (target = Local):
system,services,bin: Must exist on filesystemstorage,geoip_database,web_path: Must exist if specified
Cloud Profiles (target = Cloud):
system,services,bin: Must be non-empty, start with/appweb_path: Must start with/app/web(not/app/services/web)
3. Security Settings Validation
Lines 141-149
| Setting | Rule |
|---|---|
access_token_expiration |
> 0 |
refresh_token_expiration |
> 0 |
4. CORS Origins Validation
Lines 151-166
- Each origin must be non-empty
- Each origin must start with
http://orhttps://
5. Rate Limits Validation
Lines 168-200
If disabled: false:
burst_multiplier> 0- All rate limit values > 0
Complete Profile Example
# .systemprompt/profiles/local/profile.yaml
name: local
display_name: "Local Development"
target: local
site:
name: "My Project"
github_link: "https://github.com/org/repo"
database:
type: postgres
external_db_access: true
server:
host: "0.0.0.0"
port: 8080
api_server_url: "http://localhost:8080"
api_internal_url: "http://localhost:8080"
api_external_url: "http://localhost:8080"
use_https: false
cors_allowed_origins:
- "http://localhost:8080"
- "http://localhost:5173"
paths:
system: "/path/to/project"
services: "/path/to/project/services"
bin: "/path/to/project/target/release"
web_path: "/path/to/project/web"
storage: "/path/to/project/storage"
security:
jwt_issuer: "systemprompt-local"
jwt_access_token_expiration: 2592000
jwt_refresh_token_expiration: 15552000
jwt_audiences:
- web
- api
- a2a
- mcp
rate_limits:
disabled: true
runtime:
environment: development
log_level: verbose
output_format: text
no_color: false
non_interactive: false
cloud:
credentials_path: "../../credentials.json"
tenants_path: "../../tenants.json"
tenant_id: local_19bff27604c
secrets:
secrets_path: "./secrets.json"
source: file
validation: warn
extensions:
disabled: []
Troubleshooting
"Required field missing"
- Check all required fields are present in YAML
- Verify field names match exactly (case-sensitive)
"Path does not exist"
- For local profiles, all required paths must exist
- Check for typos in path strings
- Verify relative paths are relative to profile directory
"Invalid CORS origin"
- Origin must start with
http://orhttps:// - Cannot be empty string
"Rate limit validation failed"
- All rate limits must be > 0 if not disabled
- Set
disabled: truefor development
Quick Reference
| Config Type | Source File | Key Fields |
|---|---|---|
| Profile | mod.rs:88-120 |
name, target, site, database, server, paths, security, rate_limits, runtime, cloud, secrets |
| SiteConfig | site.rs |
name, github_link |
| DatabaseConfig | database.rs |
db_type, external_db_access |
| ServerConfig | server.rs |
host, port, api_server_url, api_internal_url, api_external_url, use_https, cors_allowed_origins |
| PathsConfig | paths.rs |
system, services, bin, web_path, storage, geoip_database |
| SecurityConfig | security.rs |
issuer, access_token_expiration, refresh_token_expiration, audiences |
| RuntimeConfig | runtime.rs |
environment, log_level, output_format, no_color, non_interactive |
| RateLimitsConfig | rate_limits.rs |
disabled, 12 rate fields, burst_multiplier, tier_multipliers |
| CloudConfig | cloud.rs |
credentials_path, tenants_path, tenant_id, validation |
| SecretsConfig | secrets.rs |
secrets_path, source, validation |