The only AI infrastructure you actually own. Most teams rent this layer: someone else's dashboard holds their prompts, their keys, and their audit trail. This is the version you compile and keep. One Rust binary, one PostgreSQL, four commands from git clone to governed inference. 43 scripted demos prove every claim on your own laptop.
systemprompt.io · Documentation · Guides · Enterprise factsheet (PDF) · Discord
Not a diagram. A live capture of ./demo/governance/06-secret-breach.sh: an agent tries to exfiltrate a GitHub PAT through a tool argument. Denied in under 5 ms, before the tool process spawns. One audit row. The model never saw the key.
git clone https://github.com/systempromptio/systemprompt-template
cd systemprompt-template
just setup-local # prompts: pick a provider (Gemini/Anthropic/OpenAI), enter its key
just start # serves governance + agents + MCP + admin on :8080setup-local prompts for a provider key, or takes keys non-interactively (just setup-local <anthropic_key> [openai_key] [gemini_key]; the first becomes the default provider). Discover the CLI with systemprompt --help. All other install paths, including running a second clone on different ports, are in docs/README.md.
For the CISO: one SQL query answers any AI audit
Five properties, each one demonstrable on your laptop before any procurement call.
- A single query answers every AI audit. Every request, scope decision, tool call, model output, and cost lands in one 18-column Postgres table. Six correlation columns (UserId, SessionId, TaskId, TraceId, ContextId, ClientId) bind identity at construction time, so a row without a trace is a programming error.
- Credentials physically cannot enter the context window. The governance process is the parent of every MCP tool subprocess. Keys are decrypted from a ChaCha20-Poly1305 store and injected into the child's environment by
Command::spawn(). The parent, which owns the LLM context, never writes the value. 35+ regex patterns deny any tool call that tries to pass a secret through arguments. - Self-hosted, air-gap capable, single artifact. One Rust binary. One PostgreSQL. No Redis, no Kafka, no Kubernetes, no SaaS handoff. The same binary runs on a laptop, a VM, and an air-gapped appliance without modification. Zero outbound telemetry by default.
- Policy-as-code on PreToolUse hooks. Destructive operations, blocklists, department scoping, six-tier RBAC (Admin, User, Service, A2A, MCP, Anonymous). Rate limiting at 300 req/min per session with role multipliers. Every deny reason is structured and auditable.
- Certifications-ready, not certification-marketing. Tiered log retention from debug (1 day) through error (90 days). 10 identity lifecycle event variants. SIEM-ready JSON events for Splunk, ELK, Datadog, Sumo. Built for SOC 2 Type II, ISO 27001, HIPAA, and the OWASP Agentic Top 10.
Run the proof: 43 scripted demos, 41 cost nothing
Every claim in this README has a script that executes it against the live binary.
./demo/00-preflight.sh # acquire token, verify services, create admin
./demo/01-seed-data.sh # populate analytics + trace data
# Governance: the audit line
./demo/governance/01-happy-path.sh # allowed tool call, full trace chain
./demo/governance/05-governance-denied.sh # scope check rejects out-of-role call
./demo/governance/06-secret-breach.sh # secret-detection blocks exfiltration
./demo/governance/07-rate-limiting.sh # 300 req/min per session enforced
./demo/governance/08-hooks.sh # PreToolUse policy-as-code
# Observability: the audit table
./demo/analytics/01-overview.sh # conversations, costs, anomalies
./demo/infrastructure/04-logs.sh # structured JSON events, SIEM-ready
# Scale: the overhead budget
./demo/performance/02-load-test.sh # 3,308 req/s burst, p99 22.7 msFull index: demo/README.md. 41 of 43 scripts are free; two cost ~$0.01 each (real model calls).
The governance pipeline: synchronous checks before any tool process spawns
Every tool call passes a chain of in-process checks, synchronously, in under 5 ms. The chain is extensible; these ship built in. Every decision lands in an 18-column audit row.
LLM Agent
│
▼
Governance pipeline (in-process, synchronous, <5 ms p99)
│
├─ 1. JWT validation (HS256, verified locally, offline-capable)
├─ 2. RBAC scope check (Admin · User · Service · A2A · MCP · Anonymous)
├─ 3. Secret detection (35+ regex: API keys, PATs, PEM, AWS prefixes)
├─ 4. Blocklist (destructive operation categories)
└─ 5. Rate limiting (300 req/min per session, role multipliers)
│
▼
ALLOW or DENY → 18-column audit row, always
│
▼ (ALLOW)
spawn_server()
│
├─ decrypt secrets from ChaCha20-Poly1305 store
└─ inject into subprocess env vars only (never parent)
│
▼
MCP tool process credentials live here, never in the LLM context path
Run it: ./demo/governance/05-governance-denied.sh · Feature detail
Why agents cannot leak your keys: the code, twelve lines
Not a policy that asks agents nicely. A process boundary: the parent that owns the LLM context never writes the credential value.
When a tool call passes the pipeline, spawn_server() decrypts credentials from the ChaCha20-Poly1305 store and injects them into the child process environment. Source: systemprompt-core/crates/domain/mcp/src/services/process/spawner.rs.
let secrets = SecretsBootstrap::get()?;
let mut child_command = Command::new(&binary_path);
// Child env only. The parent (LLM context path) never touches the value.
if let Some(key) = &secrets.anthropic {
child_command.env("ANTHROPIC_API_KEY", key);
}
if let Some(key) = &secrets.github {
child_command.env("GITHUB_TOKEN", key);
}
// Detach; parent forgets the child after spawn.
let child = child_command.spawn()?;
std::mem::forget(child);Before spawn, secret detection scans tool arguments for 35+ credential patterns. A tool call that tries to pass a secret through the context window is blocked even if the agent has scope to run the tool. The hero recording above is the scripted proof: ./demo/governance/06-secret-breach.sh.
Performance: 3,308 req/s burst, p99 22.7 ms
Governance that adds more than 1% latency gets bypassed. This one doesn't. Each request performs JWT validation, scope resolution, three rule evaluations, and an async audit write.
| Metric | Result |
|---|---|
| Throughput | 3,308 req/s burst, sustained under 100 concurrent workers |
| p50 latency | 13.5 ms |
| p99 latency | 22.7 ms |
| Added to AI response time | <1% |
| GC pauses | Zero |
Reproduce: just benchmark. Numbers measured on the author's laptop.
Your first five minutes: admin UI, audit trace, live denial
- http://localhost:8080: admin UI, live audit table, session viewer.
systemprompt analytics overview: conversations, tool calls, costs in microdollars, anomalies flagged above 2x/3x of rolling average.systemprompt infra logs audit <request-id> --full: the full trace for any request: identity, scope, rule evaluations, tool call, model output, cost. One query, one row, one answer.- Point Claude Code, Claude Desktop, or any MCP client at it. Permissions follow the user, not the client. Try to exfiltrate a key through a tool argument and watch the secret-detection layer deny it before the tool process spawns.
./demo/governance/06-secret-breach.sh: the scripted version of that denial, recorded above.
Configuration & CLI: everything is a YAML diff, every task has a verb
Runtime configuration is flat YAML under services/, loaded through services/config/config.yaml. Unknown keys fail loudly (#[serde(deny_unknown_fields)]). No database-stored config, no admin UI required. Every change is a diff.
services/
config/config.yaml Root aggregator
agents/<id>.yaml Agent: scope, model, tool access
mcp/<name>.yaml MCP server: OAuth2 config, scopes
skills/<id>.yaml Skill: config + markdown instruction body
plugins/<name>.yaml Plugin bindings (references agents, skills, MCP)
ai/config.yaml AI provider config (Anthropic, OpenAI, Gemini)
scheduler/config.yaml Background job schedule
web/config.yaml Web frontend, navigation, theme
content/config.yaml Content sources and indexing
Eight CLI domains cover every operational surface. No dashboard required for any task.
| Domain | Purpose |
|---|---|
core |
Skills, content, files, contexts, plugins, hooks, artifacts |
infra |
Services, database, jobs, logs |
admin |
Users, agents, config, setup, session, rate limits |
cloud |
Auth, deploy, sync, secrets, tenant, domain |
analytics |
Overview, conversations, agents, tools, requests, sessions, content, traffic, costs |
web |
Content types, templates, assets, sitemap, validate |
plugins |
Extensions, MCP servers, capabilities |
build |
Build core workspace and MCP extensions |
More recordings: infrastructure, integrations, analytics, agents, compliance
Each recording is a live capture of the named script running against the binary.
Infrastructure: one binary, one process, one database. Same artifact runs laptop to air-gap.
All data on your infrastructure, zero outbound telemetry · ./demo/infrastructure/01-services.sh · Feature
Profile YAML promotes environments without rebuilding · ./demo/cloud/01-cloud-overview.sh · Feature
Every operational surface has a CLI verb · ./demo/infrastructure/03-jobs.sh · Feature
MCP, OAuth 2.0, PostgreSQL, Git · zero proprietary protocols · ./demo/mcp/01-mcp-servers.sh · Feature
MCP governance, analytics, closed-loop agents, compliance.
Each MCP server is an isolated OAuth2 resource server with per-server scope validation · ./demo/mcp/02-mcp-access-tracking.sh · Feature
Nine analytics subcommands, anomaly detection, SIEM-ready JSON · ./demo/analytics/01-overview.sh · Feature
Agents query their own error rate, cost, and latency via MCP tools and adjust · ./demo/agents/04-agent-tracing.sh · Feature
Tiered retention, 10 identity lifecycle events, SOC 2 / ISO 27001 / HIPAA / OWASP Agentic Top 10 · ./demo/users/03-session-management.sh · Feature
Integrations: any provider, Claude Desktop, web publisher, extensions.
Anthropic, OpenAI, Gemini swap at the profile level · cost attribution in integer microdollars · ./demo/agents/01-list-agents.sh · Feature
Skills persist across sessions via OAuth2 · ./demo/skills/01-skill-lifecycle.sh · Feature
Same binary serves your website, blog, and docs · systemprompt.io runs on this binary · ./demo/web/01-web-config.sh · Feature
Your code compiles into your binary via the Extension trait · no runtime reflection · ./demo/skills/04-plugin-management.sh · Feature
3,308 req/s burst, p99 22.7 ms · just benchmark
Claude for Work, on your infrastructure
Claude for Work ships with extension points for inference, identity, and audit. Point them at this binary and every prompt, tool call, and cost line lands in a Postgres row you own.
Managed Device Enterprise Gateway Upstream Inference
(Bridge via MDM) (this binary, your VPC) (pluggable)
───────────────── ──────────▶ ───────────────────── ──────▶ ─────────────────
Credential helper /v1/messages Anthropic direct
Managed MCP list Governance pipeline Bedrock / Vertex
Signed plugins Audit to Postgres OpenAI / Groq
On-prem vLLM / Qwen
Air-gap capable
The same governance pipeline described above enforces scope, secrets, policy, and quota before a byte leaves your network, in-process against a cached entitlement table: p99 22.7 ms, <1% of AI response time.
| Dimension | Claude Enterprise | Cloud Custom | + systemprompt.io |
|---|---|---|---|
| Data residency | Anthropic infra | Cloud region | Your datacenter or air-gap |
| Audit trail | Anthropic-held | OTLP only | Prompt → tool → MCP → cost in your Postgres |
| User revocation | SSO / seat removal | Cloud IAM | IDP disable; next TTL fails closed |
| Inference provider | Anthropic only | Bedrock / Vertex (Claude) | Any /v1/messages, per-call routing |
| MCP allowlist | Anthropic-curated | Device-local config | One registry, per-principal policy |
| Plugin catalogue | Anthropic-hosted | Files on disk | Signed, scoped, versioned distribution |
Manual install works end-to-end today; signed installers and MDM packages land in a later release. Full walkthrough: docs/bridge-install.md.
Route any model anywhere: the `/v1/messages` gateway
POST /v1/messages at the Anthropic wire format. Every inference request flows through the same governance pipeline as every tool call. A route maps a requested model pattern to a provider you declared:
gateway:
enabled: true
default_provider: anthropic
routes:
- model_pattern: "claude-*"
provider: anthropic
- model_pattern: "MiniMax-*"
provider: minimaxRoutes evaluate in order; first match wins. Anthropic is a transparent byte proxy; OpenAI-compatible providers get full request/response/SSE conversion. Provider declarations, CLI route configuration, route access control, and the extensible provider registry: docs/gateway-routes.md.
Prerequisites
| Requirement | Purpose | Install |
|---|---|---|
| Docker | PostgreSQL runs in a container; just setup-local starts it |
docker.com |
| Rust 1.75+ | Compiles the workspace binary | rustup.rs |
just |
Task runner | just.systems |
jq, yq |
JSON and YAML processing in the scripts | brew install jq yq / apt install jq yq |
| AI API keys | At least one of Anthropic, OpenAI, or Gemini; the first key you supply becomes the default provider | Provider dashboards |
| Ports 8080 + 5432 | HTTP + PostgreSQL | Free on localhost |
This template is MIT. Fork it, modify it, use it however you like.
systemprompt-core is BSL-1.1: free for evaluation, testing, and non-production use. Production use requires a commercial license. Each version converts to Apache 2.0 four years after publication. Licensing enquiries: ed@systemprompt.io.