Skip to main content

FULLY EXTENSIBLE ARCHITECTURE. YOUR CODE COMPILES INTO YOUR BINARY.

Implement one Extension trait to contribute routes, migrations, jobs, and providers. Your crate compiles into one binary that inherits RBAC middleware, audit_events, and rate limits. Link-time registration, no runtime reflection.

Cargo Dependency, Not SaaS

A governance vendor shipping SaaS owns your upgrade clock. The moment a platform engineer customises it, the customisation is a fork to maintain or a support ticket that blocks a release. systemprompt.io inverts that. It is a Rust crate you pull into your workspace. Add systemprompt = "x.x" to Cargo.toml, implement one trait, run cargo build --release, and the binary you ship contains the governance core and your proprietary plugins in one process. Your code never leaves your build.

The trait the core team uses is the trait you use. The in-tree domain plugins (AI, MCP, Content, Analytics, Agent, Users, OAuth, Files) are ordinary implementations of it, not a privileged host. The AI plugin contributes model providers and schemas. The OAuth plugin contributes HTTP routes and RBAC roles. The MCP plugin contributes tool providers and background jobs. A plugin you write sits alongside them. The build-vs-buy answer for a CTO is "keep the extension model you would have built, without maintaining the host".

Plugins are not a runtime module system with version-skew risk. Registration wires your type into the binary at link time through the inventory crate. If the crate compiles against the workspace, the plugin is present. No dynamic loading, no dlopen, no manifest negotiated over a socket, no "did my plugin start" question at deploy.

  • One Cargo dependency — Pin the version in Cargo.toml. The build is deterministic and offline. A security patch is a Cargo version bump and a rebuild, not a coordinated upgrade across a host and a plugin registry.
  • Your plugins sit beside the core plugins — AI, MCP, Content, Analytics, Agent, Users, OAuth, and Files are ordinary implementations of the same trait. A plugin you write is a peer, not a second-class integration.
  • Link-time registration, no dlopen — Plugins register at link time. If the crate compiles, the plugin is present. No runtime reflection, no dependency on a plugin server to load modules in production.

One Extension Trait

A platform engineer evaluating a plugin model wants one answer. What is the minimum code to ship a new endpoint that inherits the governance library's policy? In systemprompt.io it is one trait. Return a router for HTTP routes. Return schema and migration lists for new database tables. Return job objects for background work. Return AI provider or MCP tool-provider lists for new capabilities. Return role definitions for new RBAC tiers. The governance pipeline (the request-path gate described in Governance Pipeline) applies to every route and every provider your plugin adds, because the gate sits ahead of the dispatcher.

The trait lists these surfaces deliberately so the full contract fits one screen, not a half-dozen "extension point" interfaces. Every method defaults to returning nothing, so a narrow plugin contributing a single route is three lines. A wide plugin contributing schemas, routes, jobs, providers, roles, and admin pages uses the same interface. The only mandatory method is the metadata call that names the plugin and declares dependencies.

Every surface you add inherits cross-cutting behaviour without wiring. A route mounts behind the same JWT and audience middleware that guards core routes. A table runs through the same migration ledger with checksum verification, so schema drift fails at startup. A job runs on the platform scheduler and writes to the same audit log as core jobs. You do not opt into governance. You cannot opt out.

  • Routes, tables, and jobs without glue — A route mounts behind the same RBAC middleware that guards core routes. A table runs through the same migration ledger, so schema drift fails at startup. A job runs on the platform scheduler and writes to the same audit log.
  • Providers inherit the governance pipeline — A model provider contributed by your plugin is called through the same dispatcher as core providers. Scope check, secret scan, blocklist, and rate limit run before your provider sees a call. You write the integration, not the policy layer.
  • Templates, pages, and feeds if needed — Template providers, component renderers, page data providers, prerenderers, sitemap and RSS providers are trait methods. A backend-only plugin returns empty from each. A page-heavy plugin uses them without a second framework.

Typed Narrow Traits

Implementing the full Extension trait for a plugin that only adds one API carries breadth the plugin does not use. For narrow plugins, the crate ships typed variants so the type system enforces what the plugin is for. An API-only trait with a base path and an auth flag. A config-namespace trait with JSON-schema validation. A job-only trait. An AI provider and MCP tool provider trait. A schema-only trait. A plugin that should only add routes cannot return a schema or a job, because the trait has no method for it.

Dependencies between plugins are checked at compile time, not boot. The builder that composes a plugin set uses a type-level list. A plugin whose declared dependencies are not already in the list fails to compile. The error names the missing dependency. "My plugin crashed at startup because a sibling was not registered" becomes "my build fails and the compiler tells me which sibling".

At runtime, every plugin is treated uniformly. The registry stores plugins behind a trait object with downcasting methods, so code that needs "all plugins that contribute a schema" asks once and gets a typed view without reflection. A lookup by string ID serves admin surfaces. A lookup by Rust type serves code composing features at build time. One store, one validation pass, one load order.

  • Narrow traits for narrow plugins — API-only, config-only, job-only, provider-only, and schema-only variants live in a typed module. A routes-only plugin cannot declare a job because the trait has no method for it, so the class of bug where a plugin claims X but does Y is a compile error.
  • Dependencies checked by the compiler — The builder uses a type-level list, so a plugin whose dependencies are not registered fails the build. The error names the missing dependency. A platform engineer acts on a compile diagnostic rather than a deploy-time panic.
  • One registry, two lookup modes — Lookup by string ID serves admin surfaces and diagnostics. Lookup by Rust type serves code composing features at build time. The same plugin serves both without re-registration.

Boot-Time Validation

A plugin that only surfaces a problem under traffic is an incident waiting to happen. systemprompt.io runs the plugin pipeline at startup, before the HTTP listener opens. Every plugin linked into the binary registers through the author's macro. At boot, the registry collects registrations, instantiates each plugin, inserts by ID, and sorts by declared priority (lower priorities load first). If the binary compiled with the plugin, the plugin is present. No directory scan, no manifest volume, no sidecar handshake.

After collection, a validation pipeline runs four checks before the application accepts a request. Dependency resolution walks each plugin's declared dependencies and fails if an ID is missing from the registry. A depth-first cycle check returns the exact cycle path on failure, so a staff engineer reads the ordered loop rather than "circular dependency somewhere". API path validation checks plugin routers against reserved core prefixes (/api/v1/oauth, /api/v1/users, /api/v1/agents, /api/v1/mcp, /api/v1/stream, /api/v1/content, /api/v1/files, /api/v1/analytics, /api/v1/scheduler, /api/v1/core, /api/v1/admin) and rejects collisions. Duplicate IDs fail registration immediately, so a typo never lands silently on top of an existing plugin.

For the two less common shapes (standalone MCP server binaries and CLI extension binaries), the loader scans an extensions directory for manifests, parses them into discovered-plugin records, and runs the same validation pipeline. Dependencies must resolve. The graph must be acyclic. Paths must not collide. IDs must be unique. A CISO asking "what code runs inside this binary" gets one answer from one validation path, whether the plugin compiled in or was discovered from disk.

  • Link-time registration, no directory scan — Plugins linked into the binary register at link time through the macro. The registry collects at boot, sorts by priority, hands off an ordered list. No filesystem scan, no manifest parse, no dynamic load.
  • Four-stage validation before traffic — Dependency resolution, cycle detection returning the exact path on failure, reserved-path check, and duplicate-ID rejection. All four run before the listener opens, so a routing collision or missing dependency is a boot failure, not a 2am page.
  • Same validation for compiled and discovered plugins — For standalone MCP and CLI binaries, the manifest-scanning loader produces plugin records that run the same validation. The audit story is one story.

Your Binary, Open Core

A CTO buying SaaS governance buys the vendor's upgrade clock. Buying systemprompt.io is buying a Cargo dependency. Pin the version, update when the team is ready, and the binary compiled today runs identically in five years as long as the crate sits in your lockfile. The migration struct tracks version, name, SQL, and a checksum, so schema changes are deterministic and auditable. An auditor answers "what DDL ran in production" from the migration ledger, not a vendor's changelog.

Every deployment is shaped by its use case. A healthcare company adds HIPAA audit tables and retention jobs through the schema and job surfaces of the trait. A financial services firm adds compliance reports and RSS feeds through the page-data and feed surfaces. A dev tools company adds a marketplace UI through the router, component renderer, and template data extender. The core provides governance, auth, and observability. Your plugins make it your product, on the same trait and through the same registry.

The model covers three deployment shapes. Library plugins compile into the main binary and inherit everything including the governance pipeline. MCP server plugins run as standalone binaries discovered through manifests, useful when a tool integration has different resource or lifecycle needs. CLI plugins add subcommands for operators who live in a terminal. All three pass the same validation and share the same capability traits. "Will my plugin work" reduces to "does it compile".

  • You own the upgrade clock — Pin the version in Cargo.toml and update when the team decides. The migration ledger tracks every schema change with a checksum an auditor verifies, so 'what DDL ran in production' is answered from your artifacts.
  • Same trait, different products — Healthcare adds HIPAA tables and retention jobs. Finance adds compliance pages and RSS feeds. Dev tools add marketplaces through templates and routes. Each sits on the same trait and inherits the same governance.
  • Three deployment shapes, one validation pipeline — Library plugins compile in and inherit governance. MCP servers run standalone via manifests. CLI plugins add operator subcommands. All three pass the same dependency and path validation.

Founder-led. Self-service first.

No sales team. No demo theatre. The template is free to evaluate — if it solves your problem, we talk.

Who we are

One founder, one binary, full IP ownership. Every line of Rust, every governance rule, every MCP integration — written in-house. Two years of building AI governance infrastructure from first principles. No venture capital dictating roadmap. No advisory board approving features.

How to engage

Build your product on open core.

Clone the template, implement your plugins, compile a binary that is yours. One Extension trait, typed narrow variants, boot-time validation, no runtime reflection.