Configure directory locations for system files, services, and storage.
Help:
{ "command": "admin config paths show" }viasystemprompt_helpRequires: Profile configured -> See Profiles Playbook
PathsConfig defines directory locations for system files, services, binaries, and optional storage.
PathsConfig Struct
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
}
Field Details
| Field | Required | Description |
|---|---|---|
system |
Yes | Project root directory |
services |
Yes | Services configuration directory |
bin |
Yes | Compiled binaries directory |
web_path |
No | Web assets output location |
storage |
No | File storage directory |
geoip_database |
No | MaxMind GeoIP database file |
Derived Paths
PathsConfig provides methods that derive additional paths from the base configuration.
Source: crates/shared/models/src/profile/paths.rs:20-67
Method Reference
| Method | Returns | Purpose |
|---|---|---|
skills() |
{services}/skills |
Skill definitions |
config() |
{services}/config/config.yaml |
Main config file |
ai_config() |
{services}/ai/config.yaml |
AI provider config |
content_config() |
{services}/content/config.yaml |
Content routing config |
web_config() |
{services}/web/config.yaml |
Web generation config |
web_metadata() |
{services}/web/metadata.yaml |
Web metadata |
web_path_resolved() |
web_path or {system}/web |
Resolved web path |
storage_resolved() |
storage if set |
Resolved storage path |
geoip_database_resolved() |
geoip_database if set |
Resolved GeoIP path |
Implementation
impl PathsConfig {
pub fn skills(&self) -> String {
format!("{}/skills", self.services)
}
pub fn config(&self) -> String {
format!("{}/config/config.yaml", self.services)
}
pub fn ai_config(&self) -> String {
format!("{}/ai/config.yaml", self.services)
}
pub fn content_config(&self) -> String {
format!("{}/content/config.yaml", self.services)
}
pub fn web_config(&self) -> String {
format!("{}/web/config.yaml", self.services)
}
pub fn web_metadata(&self) -> String {
format!("{}/web/metadata.yaml", self.services)
}
pub fn web_path_resolved(&self) -> String {
self.web_path.clone().unwrap_or_else(|| {
format!("{}/web", self.system)
})
}
pub fn storage_resolved(&self) -> Option<&str> {
self.storage.as_deref()
}
pub fn geoip_database_resolved(&self) -> Option<&str> {
self.geoip_database.as_deref()
}
}
Path Resolution Functions
Source: crates/shared/models/src/profile/paths.rs:69-108
resolve_path
Resolves relative paths against a base 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())
}
}
expand_home
Expands ~/ to home directory:
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)
}
resolve_with_home
Combines home expansion with relative 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)
}
}
Path Resolution in Profile Loading
When a profile loads, paths are resolved relative to the profile directory:
impl PathsConfig {
pub fn resolve_relative_to(&mut self, base: &Path) {
self.system = resolve_path(base, &self.system);
self.services = resolve_path(base, &self.services);
self.bin = resolve_path(base, &self.bin);
if let Some(ref path) = self.web_path {
self.web_path = Some(resolve_path(base, path));
}
if let Some(ref path) = self.storage {
self.storage = Some(resolve_path(base, path));
}
if let Some(ref path) = self.geoip_database {
self.geoip_database = Some(resolve_path(base, path));
}
}
}
Cloud vs Local Validation
Source: crates/shared/models/src/profile/validation.rs:34-112
Local Profile Validation
For target: local:
fn validate_local_paths(&self) -> Result<()> {
// Required paths must exist
let paths_to_check = [
("system", &self.paths.system),
("services", &self.paths.services),
("bin", &self.paths.bin),
];
for (name, path) in paths_to_check {
if !Path::new(path).exists() {
return Err(ProfileError::PathNotFound(name, path.clone()));
}
}
// Optional paths must exist if specified
if let Some(ref path) = self.paths.storage {
if !Path::new(path).exists() {
return Err(ProfileError::PathNotFound("storage", path.clone()));
}
}
if let Some(ref path) = self.paths.geoip_database {
if !Path::new(path).exists() {
return Err(ProfileError::PathNotFound("geoip_database", path.clone()));
}
}
if let Some(ref path) = self.paths.web_path {
if !Path::new(path).exists() {
return Err(ProfileError::PathNotFound("web_path", path.clone()));
}
}
Ok(())
}
Cloud Profile Validation
For target: cloud:
fn validate_cloud_paths(&self) -> Result<()> {
// Required paths must be non-empty and start with /app
let required = [
("system", &self.paths.system),
("services", &self.paths.services),
("bin", &self.paths.bin),
];
for (name, path) in required {
if path.is_empty() {
return Err(ProfileError::EmptyPath(name));
}
if !path.starts_with("/app") {
return Err(ProfileError::CloudPathMustStartWithApp(name, path.clone()));
}
}
// web_path must start with /app/web (not /app/services/web)
if let Some(ref path) = self.paths.web_path {
if !path.starts_with("/app/web") {
return Err(ProfileError::CloudWebPathInvalid(path.clone()));
}
if path.starts_with("/app/services/web") {
return Err(ProfileError::CloudWebPathInServicesDir);
}
}
Ok(())
}
Configuration Examples
Local Development
paths:
system: "/home/user/my-project"
services: "/home/user/my-project/services"
bin: "/home/user/my-project/target/release"
web_path: "/home/user/my-project/web"
storage: "/home/user/my-project/storage"
geoip_database: "/home/user/my-project/data/GeoLite2-City.mmdb"
Relative Paths (Recommended)
# Profile at .systemprompt/profiles/local/profile.yaml
paths:
system: "../../.." # Resolves to project root
services: "../../../services" # Resolves to services/
bin: "../../../target/release" # Resolves to target/release/
web_path: "../../../web"
storage: "../../../storage"
Home Directory
paths:
system: "~/projects/my-project"
services: "~/projects/my-project/services"
bin: "~/projects/my-project/target/release"
Cloud Deployment
paths:
system: "/app"
services: "/app/services"
bin: "/app/bin"
web_path: "/app/web"
Directory Structure
Expected directory layout:
{system}/
├── services/ # {services}
│ ├── config/
│ │ └── config.yaml # paths.config()
│ ├── ai/
│ │ └── config.yaml # paths.ai_config()
│ ├── content/
│ │ └── config.yaml # paths.content_config()
│ ├── web/
│ │ ├── config.yaml # paths.web_config()
│ │ └── metadata.yaml # paths.web_metadata()
│ └── skills/ # paths.skills()
│ └── *.yaml
├── target/release/ # {bin}
│ └── systemprompt
├── web/ # {web_path}
│ └── dist/
├── storage/ # {storage}
│ └── files/
└── data/
└── GeoLite2-City.mmdb # {geoip_database}
Environment Variables
When using Profile::from_env():
| Env Variable | Maps To |
|---|---|
SYSTEM_PATH |
paths.system |
SYSTEMPROMPT_SERVICES_PATH |
paths.services |
BIN_PATH |
paths.bin |
SYSTEMPROMPT_WEB_PATH |
paths.web_path |
STORAGE_PATH |
paths.storage |
GEOIP_DATABASE_PATH |
paths.geoip_database |
Config Access
After bootstrap, paths are available via Config struct:
let config = Config::get()?;
println!("System: {}", config.system_path);
println!("Services: {}", config.services_path);
println!("Bin: {}", config.bin_path);
println!("Skills: {}", config.skills_path);
println!("Settings: {}", config.settings_path);
println!("Content Config: {}", config.content_config_path);
println!("Web: {}", config.web_path);
println!("Web Config: {}", config.web_config_path);
println!("Web Metadata: {}", config.web_metadata_path);
if let Some(geoip) = &config.geoip_database_path {
println!("GeoIP: {}", geoip);
}
Troubleshooting
"Path does not exist"
- For local profiles, all required paths must exist
- Create missing directories before starting
- Check for typos in path strings
"Path must start with /app"
- Cloud profiles require
/appprefix - Ensure
target: cloudhas cloud-style paths
"web_path invalid"
- Cloud web_path must start with
/app/web - Cannot be
/app/services/web
"Cannot canonicalize path"
- Path contains symlinks that don't resolve
- Directory doesn't exist yet
- Check permissions
"Home directory not found"
HOMEorUSERPROFILEenv var not set- Use absolute paths instead
Quick Reference
Required Paths
| Path | Local | Cloud |
|---|---|---|
system |
Must exist | Must start with /app |
services |
Must exist | Must start with /app |
bin |
Must exist | Must start with /app |
Optional Paths
| Path | Default | Description |
|---|---|---|
web_path |
{system}/web |
Web output |
storage |
None | File storage |
geoip_database |
None | MaxMind database |
Derived Paths
| Method | Pattern |
|---|---|
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 |