Skip to main content

Stack

Versions are the 1.0 pins, checked against crates.io, npm and GitHub on 2026-10-22. Upgrades are deliberate changes, not drift.

1. Repository layout​

Cargo.toml # workspace
crates/
strataplane/ # bin: server (serve, db, catalog, secrets subcommands)
stratactl/ # bin: CLI
sp-core/ # domain types, selectors, merge engine, provenance
sp-authz/ # embedded Cedar, typed actions/entities, binding projection, authorized query plans
sp-spec/ # spec file parsing, canonical TOML, parsing limits, validation L0/L1
sp-store/ # sqlx queries, tenant scope and RLS settings, migrations, embedded Postgres supervisor, LISTEN/NOTIFY, object storage
sp-api/ # axum routers, auth, tenancy, management, preview and agent endpoints, embedded UI
sp-module/ # AgentModule trait, artifact types, catalog access
sp-telegraf/ # Telegraf module: TOML render, heartbeat ingest, config/secrets endpoints, config import
sp-elastic/ # Elastic Agent module: Fleet protocol, policy render, actions
sp-controllers/ # reconciler, rollout, status scheduler, placement, jobs
sp-secrets/ # deployment and tenant data keys, secret versions, delivery rule, delivery audit
sp-wasm/ # wasmtime host for the parser and VRL modules (server + stratactl)
sp-bundle/ # catalog bundle format: manifest, ed25519 signing, verifying reader, build-bundle bin
sp-commands/ # command registry shared by stratactl and the assistant (help, args, effects)
sp-helper/ # strataplane-agent module: enroll, checkin, config, journey results and evidence
strataplane-agent/ # bin: host helper (Linux, Windows; macOS for local runs), journey runner
sp-journey/ # runner: QuickJS engine, headless Chromium over CDP
sp-build/ # build scripts of the binaries: the git commit of --version and /api/v1/version
web/ # SvelteKit app (UI + assistant)
tools/
telegraf-wasm/ # Go: wasip1 parser module entry point, built against the Telegraf fork
telegraf-schema/ # Go: plugin schema extractor per Telegraf version
vector-vrl/ # Rust: wasip1 VRL preview module per Vector release (own workspace)
build-bundle/ # scripts and inputs for the bundles of each agent kind
packaging/ # container config, systemd unit, Prometheus rule templates
Dockerfile # server image: UI, strataplane, strataplane-agent
rust-toolchain.toml # the Rust of the CI images
deny.toml # cargo deny: advisories, licenses, sources
.woodpecker/ # CI: check, build, release (§6)
docs/

2. Rust crates​

Server core​

AreaChoiceVersionNotes
Async runtimetokio1.x
HTTP serveraxum0.8.90.9 is unreleased. ws feature not needed.
Middlewaretower-http0.7.1compression, timeouts, body limits, CORS off by default. The request span, request id and HTTP metrics are an own layer (sp_api::observe).
TLS listenerhyper-util + tokio-rustls + rustls0.1.21 / 0.26.6 / 0.23.46Own accept loop: PROXY protocol v2, the TLS handshake, the client cert chain into request extensions for mTLS identity, graceful drain on shutdown (hyper-util server-graceful). The server certificate is a ResolvesServerCert that re-reads the files when they change, so renewals need no restart.
Crypto provideraws-lc-rs1.18.2rustls default; FIPS build possible. Needs cmake/NASM for Windows builds of stratactl and strataplane-agent.
Client cert verificationown ClientCertVerifier + rustls-webpki0.103.16The handshake checks key possession only; after the credential names the tenant, the chain is verified with rustls-webpki against that tenant's trust anchors from the DB, CRLs supported. No OCSP for client certs: use CRLs, short-lived certs and the agent_credential/quarantine checks.
X.509 parsingx509-parser0.18.1SAN/CN extraction. Strataplane issues no certificates.
Static UImemory-serve2.4.0Embeds the Svelte build, pre-compressed, ETags, SPA fallback.
CLIclap (derive)4.6.7Both binaries.

Persistence​

AreaChoiceVersionNotes
Embedded Postgrespostgresql_embedded (bundled)0.22.0Archive embedded at build time; pin POSTGRESQL_VERSION to an exact 18.x; set temporary(false), explicit data_dir, socket dir or fixed port. Build-time download needs network or POSTGRESQL_RELEASES_URL mirror in CI.
Queries, migrationssqlx0.9.0Runtime queries (query/query_as with FromRow, dynamic SQL wrapped in AssertSqlSafe after review), each exercised by database tests; PgListener. Migrations are crates/sp-store/migrations/NNNN_<name>.sql, embedded at build time and applied in order by our own runner under an advisory lock, each in a transaction in platform scope. An applied migration whose statements change is refused (the checksum ignores comments and whitespace), and so is a database with migrations of a newer binary unless each is marked compatible. docs/schema.md is rendered from a migrated database's catalogs by a test.
Operationsabsurd (migrations/0001_absurd-0.5.1.sql) + own Rust client0.5.1Durable tasks with checkpointed steps, retries and leases, in Postgres stored functions without extensions; the pinned SQL is part of our migrations (schema absurd). No Rust SDK upstream: the client (spawn, claim, extend claim, checkpoint, complete, fail, cancel, cleanup) runs each call on the caller's transaction, so a step and its writes commit together. Retention cleanup runs from the controllers, not pg_cron. Periodic work (audit export as a FOR UPDATE SKIP LOCKED outbox over audit_sink.cursor_seq, blob sweeper, retention) is controller loops.
Controller shardsown code–One session advisory lock per shard on a dedicated connection; no mature crate.
Object storageobject_store0.14.2LocalFileSystem and AmazonS3 behind one trait; on reqwest 0.13 like the rest of the server.
Sessionsown, over web_session–A random session id in the sp_session cookie (HttpOnly, SameSite=Lax), its data (user, tenant, CSRF token) in the row; no session middleware crate.

Avoid crates pinned to sqlx 0.8 (pg-embed, underway, sqlxmq, pgmq, released tower-sessions-sqlx-store, axum-login 0.18), or two sqlx versions end up in the build.

Spec, rendering, validation​

AreaChoiceVersionNotes
TOMLtoml + toml_edit1.1 / 0.25.17Spec files and imports: TOML 1.0 parsing with the L0 limits applied (size checked before parsing, depth and key counts on the parsed tree). toml_edit is the canonical spec writer (keeps comments) and the Telegraf renderer (deterministic layout, explicit arrays of tables for [[inputs.x]]). No YAML crate in the server.
JSON Schemajsonschema0.60.0Validate plugin options against catalog schemas.
Selector parserown (~150 LOC)–Structured selector + short form. kube-core's selector has no string parser and pulls k8s-openapi.
Diffsimilar3.2.0Unified and inline diffs for change sets and renders.
Compressionzstd0.14.3Artifact storage.
Hashingsha20.11.1SHA-256 for content addressing and token hashes.

Secrets and identity​

AreaChoiceVersionNotes
Authorizationcedar-policy4.14.0Embedded, exact pin, default-features = false; stable authorizer, schema validator and templates. Integration: authorization.md.
Memory hygienesecrecy, zeroize0.10.3 / 1.9.1
Passwordsargon20.6.0Local users only.
Secret encryptionaws-lc-rs AEAD1.18.2AES-256-GCM: data keys under the deployment key, secret versions and objects under the tenant's data key; already the rustls crypto provider.
Backup encryptionage0.12.1db backup --encrypt-to, optional; secret values in dumps are already encrypted.
OIDCopenidconnect4.0.1With our own reqwest client to avoid version clashes. The groups claim is read as an additional claim.

WASM​

AreaChoiceVersionNotes
Runtimewasmtime + wasmtime-wasi (p1)50.0.0Runs Go wasip1 command modules (verified with wasmtime 49 via its Python binding). Precompile with Engine::precompile_module, cache by module hash; fuel or epoch interruption plus memory limits. Monthly major releases: pin and budget upgrades.

Integrations and observability​

AreaChoiceVersionNotes
HTTP clientreqwest (rustls)0.13.5OIDC, audit webhooks. rustls-platform-verifier for OS trust.
Logstracing, tracing-subscriber0.1.44 / 0.3.23serve logs JSON, plain text on a terminal; STRATAPLANE_LOG sets the filter. No trace export.
Metricsmetrics + metrics-exporter-prometheus0.24.6 / 0.18.3/metrics.
OpenAPIutoipa + utoipa-axum6.0 / 0.3Generated from the handlers' #[utoipa::path] attributes and the view types into docs/openapi.yaml (a test fails on drift); routes and operations share one registration. The API tests validate every response against it; the web client's types are generated from it.

Testing​

AreaChoiceNotes
Snapshot testsinsta 1.49Renderer output per fixture (TOML, policy JSON), explain output.
Property testsproptest 1.12Merge laws (associativity per directive), selector parse/print round-trip, canonical TOML idempotence.
Database testspostgresql_embeddedOne cluster per test binary, migrated once into a template that each test's database copies, connected as a non-superuser so row-level security applies; no Docker needed.
Agent conformancecontainers (mise run e2e)Real Telegraf (1.39 → latest) and Elastic Agent (supported minors) against the server image; needs Docker, run before a deploy.

3. Frontend​

AreaChoiceNotes
FrameworkSvelteKit 3.1 (Svelte 5.57, runes), adapter-static SPABuilt into web/build, embedded in the server binary. No Node at runtime.
API clientopenapi-typescript 7.13 + openapi-fetch 0.17Types generated from the OpenAPI spec; CI fails on drift.
Componentsshadcn-svelte 1.7 registry components on bits-ui 2.20, TailwindCopied into web/src/lib/components/ui/<name>/ and used for every control (tables, selects, checkboxes, menus, dialogs, tooltips, toasts, sidebar); no hand-rolled controls, no heavy design system.
EditorCodeMirror 6TOML (spec and rendered), JSON, JavaScript (journey scripts); schema-aware completion from the catalog; diff view (merge extension).
ChartsLayerChart 2.8Fleet health, rollout progress, version distribution.
Live updatesSSE (/api/v1/events)Agent status changes, rollout stage transitions, change set state.
Assistant@earendil-works/pi-durable, pi-ai, chord 1.4.0, just-bash 3.6.0, jq-wasm 3.0.0 (jq 1.8.2), @bjorn3/browser_wasi_shim 0.4.2Same building blocks as grafana-pi-app. Pi Durable is marked experimental upstream: exact pins, the three @earendil-works packages always at the same version. browser_wasi_shim has had no release since 2025-06; vendor it if needed.
TestsVitest 5.0, Playwright 1.64Playwright runs the smoke tests against web/mock (in CI too) and drives the assistant against a local llama-server profile, as in grafana-pi-app's benchmarks.

4. Go tooling​

Small Go programs in tools/, built per Telegraf release tag in CI:

  • telegraf-wasm: wasip1 parser module (agents/telegraf.md §8).
  • telegraf-schema: imports plugins/inputs/all etc., reflects each registered plugin's config struct (toml tags, types, defaults from sample.conf where present) and writes JSON Schema per plugin.

Vector needs no Go program: build-bundle vector splits the output of vector generate-schema into a schema per component type (tools/README.md).

5. Risks​

  1. sqlx 0.8/0.9 split across the ecosystem: stay on 0.9, write the session store, avoid 0.8-only crates.
  2. Bundled Postgres size and build: per-target archives, build-time download (mirror in CI), a cluster of another major version moves by dump and restore.
  3. Embedded Postgres process management: orphaned postmaster after a hard kill, no root.
  4. wasmtime cadence: monthly majors; isolate behind sp-wasm.
  5. Pi Durable is experimental: pin versions, keep the integration in one module (web/src/lib/assistant/durable), as grafana-pi-app does, and run Pi Durable's storage conformance suite against LogStorage over the chat log API.
  6. absurd is pre-1.0 without a Rust SDK: pin the SQL, upgrade with its released migrations, keep our client small and covered by tests against the pinned schema.
  7. Fleet protocol drift: Rust types mirroring the API model of each supported Elastic Agent minor plus the conformance suite (agents/elastic-agent.md §2).
  8. serde_json/preserve_order is enabled by cedar-policy-core, so in every build that links the authorization engine JSON maps keep insertion order. Code whose bytes matter (canonical spec files, rendered artifacts, anything hashed) sorts keys itself (sp_core::json).

6. CI and release​

Woodpecker runs three workflows per main push (.woodpecker/); pull requests run check only.

WorkflowSteps
checkrust: rustfmt, clippy with -D warnings, cargo deny check, the workspace tests against a Postgres service; web: npm audit --omit=dev, the OpenAPI lint (redocly), type check, unit tests; links: the link check; playwright: the smoke tests against web/mock.
buildAt the same time as check: the image of the commit's inputs (UI, MIB wasm, Telegraf reference, binaries appended to the pinned Debian base with crane), pushed under its input key, or reused when that key exists.
releaseAfter both: tags the image sha-<commit> and main-<pipeline> and starts the ops Renovate run, which deploys the highest main- tag.

The Rust is pinned by rust-toolchain.toml to the CI images' version. The binaries' --version and GET /api/v1/version carry the commit (CI_COMMIT_SHA, else git rev-parse HEAD); a reused image reports the commit it was built at. mise run lint, mise run check and mise run test run the same checks locally; mise run e2e (Docker) is not in CI.