Going to production

What to change before your gateway handles real traffic -- storage, audit, validation, and operational concerns.

The defaults are for development

Out of the box, praxec uses an in-memory store and no audit sink. That’s fine for trying things out. It’s not fine for production, because a restart erases all workflow state and you have no record of what happened.

Here’s what to change before you go live.

Durable storage

The default memory store loses everything on restart. Switch to a durable backend:

# SQLite -- the durable backend for production
store:
  kind: sqlite
  path: /var/lib/praxec/workflows.db

SQLite is the durable path. One file, no extra infrastructure, handles thousands of concurrent workflows, and it’s the only backend that keeps Evidence and acknowledgment stores durable. A serve deployment refuses kind: file because a file store persists workflows but keeps governance state (evidence, acknowledgments) in memory — set gateway.allow_ephemeral: true only for development if you want to override that. Multiple processes on the same host can share one SQLite file; there is no networked store backend.

Audit trail

By default, audit events go nowhere. You want them going somewhere:

audit:
  sink: file
  path: /var/log/praxec/audit.jsonl

Every workflow start, transition, executor call, guard evaluation, and error gets written as a structured JSON line. Each line is a self-contained event with a timestamp, workflow ID, event type, and relevant details.

Set up log rotation (logrotate, systemd journal, or your preferred tool) so the file doesn’t grow unbounded. The JSON lines format plays well with any log aggregation system – pipe it to your observability stack and you get full visibility into what every model did, when, and with what inputs.

Validate config in CI

Don’t find out your config is broken when you deploy it. Run the checker in your CI pipeline:

praxec check --config gateway.yaml

This catches problems that YAML syntax checking misses:

It’s fast and deterministic. Add it right next to your linter.

Schema-aware editing

Point your editor’s YAML language server at the config schema for autocomplete and inline validation:

// .vscode/settings.json
{
  "yaml.schemas": {
    "./schemas/gateway-config.schema.json": "gateway.yaml"
  }
}

You get red squiggles for typos, autocomplete for field names, and documentation on hover. Catches mistakes before you even save the file.

Hot reload

You don’t need to restart the gateway to pick up config changes. Send SIGHUP:

kill -HUP $(pgrep praxec)

Definitions, executors, connections, and the discovery index all rebuild and swap atomically. In-flight workflows keep running on their current definitions. A config.reloaded audit event confirms the reload happened. See the hot reload guide for details.

Multi-tenancy

praxec runs as a single-user, same-trust-boundary system. If every model connecting to your gateway is operating on behalf of the same user or within the same trust boundary, you’re good to go.

For cross-trust-boundary deployments – where different users or teams need isolation – put an identity proxy in front of the gateway. Envoy, OAuth2-proxy, or any reverse proxy that injects identity headers will work. The gateway sees the identity from headers and can scope workflows accordingly.

Don’t skip this if you have untrusted callers. The gateway itself doesn’t authenticate requests.

High availability

Multiple gateway processes can run on a single host and share one SQLite store file – any process can serve any request, since all state lives in that shared file. SQLite’s WAL mode and the store’s optimistic locking handle concurrent access.

Cross-host HA is not supported: there is no networked store backend, so state can’t be shared across machines today. If you need a remote/clustered backend, you can implement the WorkflowStore trait yourself – nothing beyond memory, file, and sqlite ships built in.

Monitoring

Every audit event is structured JSON. This is your monitoring surface. Pipe audit output to your observability stack and you get:

You don’t need a custom metrics integration. The audit stream already has everything. Build dashboards from the JSON lines the same way you would from any structured log source.