System One
Shared typed decision provider for AppWeaver apps. Provides system-one:v1 through capability:v1:system-one.evaluate. NR is the first consumer; each app owns its question construction and result interpretation.
Settings
/systemone settings (or /systemone) opens an editable web form:
- API key: blank password field; blank keeps the saved key.
- API base: defaults to
https://api.typesafe.ai. - Default model: defaults to
jev-latest; NR inherits this selection. - Remove saved API key: explicit checkbox.
- Save: updates the form in place without exposing the key.
Only the settings subcommand is exposed. Text transports also support:
/systemone settings --api-key <key>
/systemone settings --api-base https://api.typesafe.ai --model jev-latest
/systemone settings --clear-api-key
API bases must be HTTPS without embedded credentials, query strings, or fragments. The base is followed by /v1/systemone. Settings changes execute immediately.
Secret storage
Keys are stored in systemone_settings.api_key_ciphertext as shared NIP-44 v2 envelopes. Core initializes encryption from the bot's Nostr private key and public key; System One reuses src/security/encrypted-secret.ts, the same helper used by PPQ. Decryption occurs only when the provider needs an inference request credential. Settings pages return only configured/not-configured state, never the plaintext or envelope.
At startup, legacy plaintext api_key rows in the System One database are encrypted and removed atomically. NR's old plaintext Jev key is not used or imported. Changing the bot Nostr identity prevents the old encrypted key from decrypting; replace it in the form if needed.
Capability behavior
Apps submit structured state and typed choice/score questions. The provider validates answer IDs/types, choices, confidence and probability values. Requests have a 30-second total deadline, three attempts for HTTP 429/529, and a 256 KiB UTF-8 payload limit. The API key stays in the request authorization header, not the state or response. State/question contents are sent to the configured inference service.
Provider settings live in plugins/systemone/db.sqlite. This plugin does not provide browser controls, text generation, or generic CRUD tools.
Local inference bridge
The plugin also provides inference-endpoint:v1, explicitly exporting POST /v1/systemone through the shared AppWeaver HTTP bridge. /bot inference-key shows separate LLM and System One bridge settings, repeating the same client-facing Bearer key in both sections. Rotating it invalidates the previous key for both bridges.
Default endpoint URL: http://127.0.0.1:5551/v1/systemone. Send Authorization: Bearer <bot-inference-key> and JSON with structured state and typed questions. The optional model overrides the configured default when supplied as a nonempty string; omitting it or passing null inherits the plugin's configured model. The endpoint normalizes omission to explicit null for the internal decision contract and returns validated { model, answers } output. Invalid requests report the failing field paths.
The client-facing bridge key is separate from the encrypted upstream key entered in System One settings. Core owns authentication, body limits, discovery, and dispatch; the plugin owns decision validation and upstream inference. Requests are limited to 256 KiB. See the core Inference bridge for a complete request example and the reusable endpoint contract.