examples/docker:
one container image, two services, one database file.
web(port 8080) — the authoring app: the widget, theme, schema and action designers over the published authoring surface (@widgentic/mcp/authoring), plus write-only secrets, API keys, and Settings (your default themes for light and dark hosts, the resource domains your widgets’ images and stylesheets may load from directly, and the stylesheets every frame links). The widget and theme designers preview in the surface’s/api/preview-frame: the document hosts mount, under the policy the MCP endpoint declares for you, so a preview loads only what a conversation would.mcp(port 8081) — the Streamable HTTP MCP endpoint at/mcp. Mint a key under Keys and connect any MCP host with anx-api-keyheader (or?key=where the host cannot send headers).
createSqliteStore: SQLite compiled
into the Node runtime, so the whole deployment has no runtime dependency to
operate.
The trust shape
The two services mirror the hosted product’s split:Identity without an identity provider
By default the deployment serves one principal with no sign-in. That mode belongs on localhost or a trusted network — treat the app like any admin panel without a login. Multi-user comes from the auth proxy you already run, not from widgentic:Secrets and key custody
Secret values are envelope-encrypted at rest; the database file holds ciphertext and key digests only. The key-encryption key is yours to supply — generated once, handed to both services as a mounted file (WIDGENTIC_KEK_FILE, the compose file uses a docker secret) or the
WIDGENTIC_KEK variable, and never generated at boot: a per-boot key would
write records nothing can read back. With no KEK the Secrets section is off
and everything else works.
Name the trade honestly: here the KEK lives in the process, which is weaker
custody than the hosted product’s, where the key sits in a managed vault and
no process ever holds it. Whoever can read your KEK material can decrypt
every secret this deployment stores, and losing it makes them unreadable
with no recovery. If your threat model needs vault custody, the same cipher
port takes createKeyVaultCipher from @widgentic/mcp/secrets/keyvault.
Configuration
Sample content at boot
PointWIDGENTIC_SEED_FILE at a JSON file of the shape
{ schemas?, themes?, actions?, widgets?, settings? } (entries as the app
imports them, settings sections as the Settings page saves them) and the
single principal gets them at boot, through the same validation as an import.
Each boot skips only what the principal holds then: nothing you hold is
overwritten, but a seeded entry you delete or a settings section you clear
comes back on the next restart, so unset the variable once the content is
yours. Refusals are logged and the service starts anyway; keys and secrets
are never seeded, and multi-user mode ignores the seed.
The image ships seed/demo.json (/srv/docker/seed/demo.json inside it): two
shared schemas, two themes set as the light and dark defaults, three widgets
(an appointment agenda, an email inbox and a project status widget), and two
avatar-service resource domains.
A key that survives an empty store
Keys minted in the app live in the store, so a store that starts empty (an ephemeral volume, a fresh staging deploy) loses them. A deployment key set on themcp service — WIDGENTIC_DEFAULT_KEY_FILE (a mounted secret, preferred)
or WIDGENTIC_DEFAULT_KEY, in the shape the app mints (wgk_ and 64 hex
characters) — resolves to the single principal on every boot, so hosts keep
working across restarts. It is read-only unless WIDGENTIC_DEFAULT_KEY_SCOPES
names execute, and it is never stored, listed in the app or logged. Treat
it like any key: whoever holds it reads this deployment’s catalog.
Building from source
The image installs the published@widgentic/* packages. To run unreleased
changes in a container (a staging deployment of a branch), build
examples/docker/Dockerfile.source from the repository root: it compiles the
packages from the checkout, packs them with npm pack and installs those
tarballs in place of the registry versions.