원클릭으로
extension-infrastructure
Jobs, Schemas, Router, Assets, Storage Paths, Site Auth, and Config Validation trait implementations
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Jobs, Schemas, Router, Assets, Storage Paths, Site Auth, and Config Validation trait implementations
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Search the web for information using the WebSearch tool
Demonstrates governance blocking when plaintext secrets are detected in tool inputs
A simple demonstration skill that searches the web for information
Demonstration skill that attempts to use a plaintext secret, designed to be blocked by governance hooks
List, message, configure, and restart agents via the systemprompt CLI
View traffic, costs, agent stats, and bot detection via the systemprompt CLI
| name | Extension: Infrastructure |
| description | Jobs, Schemas, Router, Assets, Storage Paths, Site Auth, and Config Validation trait implementations |
Infrastructure traits provide background processing, database schemas, API routes, asset management, authentication, and config validation.
Background tasks that run on schedule or on demand.
#[async_trait]
pub trait Job: Send + Sync {
fn name(&self) -> &'static str;
fn schedule(&self) -> &'static str;
fn tags(&self) -> Vec<&'static str>;
async fn execute(&self, ctx: &dyn JobContext) -> Result<JobResult>;
fn enabled(&self) -> bool { true }
fn run_on_startup(&self) -> bool { false }
}
Cron syntax: seconds minutes hours day_of_month month day_of_week
| Example | Meaning |
|---|---|
0 0 * * * * | Every hour |
0 0 3 * * * | Daily at 3 AM |
0 */15 * * * * | Every 15 minutes |
systemprompt infra jobs run {job_name}
systemprompt infra jobs list
impl Extension for MyExtension {
fn jobs(&self) -> Vec<Arc<dyn Job>> {
vec![Arc::new(MyJob)]
}
}
Database table definitions embedded in extensions at compile time.
impl Extension for MyExtension {
fn schemas(&self) -> Vec<SchemaDefinition> {
vec![SchemaDefinition::inline("my_table", include_str!("../schema/my_table.sql"))]
}
fn migration_weight(&self) -> u32 { 100 }
fn dependencies(&self) -> Vec<&'static str> {
vec!["users"]
}
}
| Convention | Rule |
|---|---|
| Primary key | id UUID PRIMARY KEY DEFAULT gen_random_uuid() |
| Timestamps | Always TIMESTAMPTZ, never TIMESTAMP |
| Indexes | Create for frequently queried columns |
| Naming | snake_case for tables and columns |
| Schema file | {crate}/schema/{table_name}.sql |
HTTP API endpoints provided by extensions.
impl Extension for MyExtension {
fn router(&self, ctx: &dyn ExtensionContext) -> Option<ExtensionRouter> {
let db = ctx.database().clone();
let router = axum::Router::new()
.route("/my-endpoint", axum::routing::get(handle_get))
.route("/my-endpoint", axum::routing::post(handle_post))
.with_state(db);
Some(ExtensionRouter::new("/api/ext/my-extension", router))
}
}
Extension routes should mount under /api/ext/ to avoid colliding with core routes.
CSS, JavaScript, fonts, and images provided by extensions.
impl Extension for MyExtension {
fn declares_assets(&self) -> bool { true }
fn required_assets(&self, paths: &dyn AssetPaths) -> Vec<AssetDefinition> {
vec![
AssetDefinition::css("my-styles.css", include_bytes!("../assets/my-styles.css")),
]
}
}
storage/files/css/ <- CSS source
storage/files/js/ <- JS source
extensions/web/src/assets.rs <- Register assets
web/dist/ <- Output (generated by copy_extension_assets)
Directories required by the extension under storage/files/.
impl Extension for MyExtension {
fn required_storage_paths(&self) -> Vec<String> {
vec!["documents".into(), "exports".into()]
}
}
impl Extension for MyExtension {
fn site_auth(&self) -> Option<SiteAuthConfig> {
Some(SiteAuthConfig {
protected_paths: vec!["/admin".into()],
login_redirect: "/admin/login".into(),
exclude_paths: vec!["/admin/login".into()],
})
}
}
impl Extension for MyExtension {
fn config_prefix(&self) -> Option<&str> { Some("my_extension") }
fn validate_config(&self, config: &Value) -> Result<ValidationReport> {
let mut report = ValidationReport::new();
if config.get("api_key").is_none() {
report.add_error("my_extension.api_key is required");
}
Ok(report)
}
}
| Rule | Rationale |
|---|---|
Jobs must return JobResult | Enables tracking in scheduler |
Schemas use include_str!() | Compile-time embedding |
| Migration weight 100+ for extensions | Core uses 1-40 |
Router endpoints under /api/ext/ | Avoid collisions |
All SQL uses TIMESTAMPTZ | Never TIMESTAMP |