the Leviathan programmability...
- A Rule (db('rules')) wires { trigger: { type, props }, actions: [{ type, props }] } with a runtime: server rules arm in the API on boot (re-arm: POST /api/automation/rearm); client rules arm in the...
Build-knowledge — the Leviathan programmability layer
How Triggers · Actions · Chatbots · Functioncalls · Toolbanks · Providers · the Capability SDK fit together, and how an agent extends each one. This is the build-knowledge entry for the layer that makes Leviathan programmable from the frontend and Studio.
The mental model
TRIGGER (fires) ──rule──-> ACTION(s) (do) ← @leumas/triggers + @leumas/actions (+ rule engine)
CHATBOT = persona + provider + voice + TOOLBANKS of FUNCTIONCALLS ← @leumas/chatbots
PROVIDER = the LLM brain (ollama/openai/claude/gemini/realtime/…) ← @leumas/providers
CAPABILITY = a live functioncall a PAGE registers at runtime ← @leumas/capability-sdk
- A Rule (
db('rules')) wires{ trigger: { type, props }, actions: [{ type, props }] }with a
runtime: server rules arm in the API on boot (re-arm: POST /api/automation/rearm); client rules arm in the browser (capability-sdk TriggerRuntime). Server rules reach the browser through the SSE stream GET /api/automation/stream as directive events.
- A Chatbot (
db('chatbots')) resolves itsprovider('auto' → first available) and its tools
(toolbanks ∪ functioncalls ∪ the live client capabilities sent with the request) and runs the tool loop (@leumas/chatbots runProgrammedTurn): server tools execute in the API; client tools pause the turn (clientToolCalls + turnId) and resume with toolResults.
- A Functioncall (
db('functioncalls')) is a named tool{ parameters: JSON-Schema, executor };
executor.kind = adapter ("system.fn") · http · grid-cell · action · client.
- A Toolbank (
db('toolbanks')) is a named group of functioncall names assigned to bots.
Where everything lives
| Piece | Path | Contract | |
|---|---|---|---|
| Doc schemas + validators | shared/packages/schemas/src/programmability.js | zod; defineFunctioncall/… + validate* | |
| Trigger engine | shared/engines/triggers | defineTrigger({ id, metadata, arm(onFire, props) → disarm }); seeds in seeds/ | |
| Action engine + rules | shared/engines/actions | defineAction({ id, metadata, inputs, run(props) }); createRuleEngine({ triggers, actions, onEvent }) | |
| Chatbots engine | shared/engines/chatbots | runProgrammedTurn, bindExecutor, createTurnStore; seeds (bots/banks/functioncalls) in seeds/ | |
| Providers | shared/engines/adapters/providers | `defineProvider({ id, capabilities, available, adapter | complete, realtimeSession }); registry resolve(bot)` |
| Capability SDK (frontend) | shared/packages/capability-sdk | CapabilityProvider + useRegisterCapability(caps, { scopeId }) + TriggerRuntime + createClientActionRegistry + useRealtimeVoice + shared bus | |
| Leviathan widget | shared/packages/leviathan | picks up capabilities, executes clientToolCalls, voice modes | |
| Leviathan runtime | shared/engines/leviathan | /leviathan/chat (tool loop), /leviathan/realtime/session (SDP, key stays server-side) | |
| Studio admin | products/leumas-studio/src/admin/{Chatbots,Triggers,ActionsManager,ToolbanksManager,FunctionCallsManager}.jsx | FunctionCallsManager anatomy; demos in admin/demos/ | |
| MCP exposure | shared/engines/mcp/mcp-servers/leumas-automation | thin HTTP adapters over /api/automation/* | |
| EXE distribution | ops/tools/exe-builder | builds Studio dist + packages the API |
How to add one of each (the agent recipes)
- New server trigger: add
shared/engines/triggers/src/adapters/<id>.jsexporting a
defineTrigger factory with arm(onFire, props), register it in src/index.js. It appears in GET /api/automation/triggers automatically.
- New client trigger: implement
{ id, arm(onFire, props) → disarm }in
capability-sdk/src/triggers/adapters.js (CLIENT_TRIGGER_ADAPTERS), and add the matching manifest to shared/engines/triggers/src/manifests.js so Studio lists it.
- New action: same split — server:
actions/src/adapters/*+ register; client:
capability-sdk/src/actions/registry.js + actions/src/manifests.js.
- New provider: folder under
shared/engines/adapters/providers/src/<id>/exporting
provider = defineProvider({...}) (lazy SDK imports, cheap available()), then add it to the barrel src/index.js. GET /api/providers and Studio's Chatbots picker list it automatically.
- New page capability: inside any React page under the
CapabilityProvider:
useRegisterCapability([{ name, description, parameters, call }], { scopeId, pageTitle }) — registers on mount, unregisters on unmount. simulateHear('<phrase>') tests wakeword rules mic-free.
- New seeds: add records to the owning engine's
seeds/(data-only ESM) — hydration runs on API
boot via hydrateCollection (idempotent; userModified: true docs are never clobbered).
Catalogs shipped (hydration)
triggers_catalog + actions_catalog hold the not-yet-implemented manifests (implemented: false, greyed out in Studio) so the CRM shows the full roadmap surface. Live counts: see GET /api/automation/triggers|actions, GET /api/providers, and /index/capabilities|chatbots|automations (the registry entries that make functioncalls/toolbanks/bots/rules searchable and priceable in the CRM).