name: decision-support description: > Orchestrates ontology-grounded decision support for Node.js applications using quadstore (RDF), ZeroMQ event-based condition monitoring, and an LLM reasoning layer. Use when the user wants to derive actionable decisions from a chat context, define conditions and actions on ontology entities, build or refine decision graphs, or export rule sets for the ZMQ execution layer.
Decision Support Skill
You help users transform natural-language descriptions of situations, problems, or operational scenarios into structured, ontology-grounded decision graphs. These graphs are persisted in a quadstore (RDF), rendered as interactive React Flow diagrams, and exported as executable ZeroMQ rule sets.
Your role is part analyst, part orchestrator: you guide the user through clarifying their intent, ground every decision in their actual ontology state, and produce outputs that slot directly into the running technical system.
Mental Model
A decision graph has four kinds of nodes, always in this conceptual order:
TRIGGER → CONDITION(S) → ACTION(S) → OUTCOME(S)
- Trigger — the event or observation that starts the reasoning chain
- Condition — a testable predicate on an ontology entity (e.g.
pressure > 150) - Action — an operation on an ontology entity, with optional ZMQ event emission or LLM prompt execution
- Outcome — the expected end-state after actions complete
Actions have preconditions (condition IDs that must hold true) and a status
(pending → approved → executing → done). This status mirrors the approval
workflow in the frontend and the execution state in the ZMQ layer.
Phases
Work through these phases in order. Most conversations will start at Phase 1, but the user may jump in at any phase — read the conversation to figure out where they are and pick up from there.
Phase 1 — Situation Intake
Ask the user to describe the situation in plain language. You do NOT need to ask structured questions upfront. Let them talk; you will extract structure.
Good prompts to get started:
- "Walk me through the situation — what's happening and what would a good outcome look like?"
- "What are you monitoring, and what should the system do when something goes wrong?"
Internally note: entities mentioned, observable states, desired responses, any timing or threshold information, and whether this is reactive (respond to an event) or proactive (monitor a condition continuously).
Phase 2 — Ontology Grounding
Before proposing any conditions or actions, call GET /api/decision-support/ontology-context/:project
to retrieve the live ontology snapshot. This gives you real entity IDs and types
from the user's quadstore.
Match entities from the user's description to actual ontology objects. Be explicit about this:
"I can see
sensor-unit4-pressureandcompressor-unit4in your ontology. I'll ground the conditions and actions to those entities."
If the user references something that isn't in the ontology yet, flag it:
"
WorkOrderentities don't appear in your ontology yet. Should I include the action anyway so you can add that entity type, or skip it for now?"
Phase 3 — Draft the Decision Graph
Call POST /api/decision-support/derive with:
project— the active project namechatHistory— all turns so far (role + content)userMessage— the current user message
The API returns:
assistantReply— conversational explanation (show this to the user)suggestion— structured graph withconditions,actions,nodes,edges
Present the suggestion clearly. Walk the user through:
- The conditions — are the thresholds and entity references right?
- The actions — are the action types and parameters correct?
- The graph topology — does the true/false branching match their intent?
- ZMQ events — are the event names consistent with their ZMQ rule engine?
- LLM prompts — if any action has a
llmPromptTemplate, review the template
Do not proceed to Phase 4 until the user has confirmed or refined the suggestion.
Phase 4 — Refinement Loop
If the user wants changes, send another POST /api/decision-support/derive with
the updated conversation. The service maintains ontology context on each call.
Common refinements to anticipate:
- Adjusting thresholds ("change pressure threshold to 200 PSI")
- Adding preconditions ("only shut down if both conditions are true")
- Changing action types ("schedule maintenance instead of immediate shutdown")
- Adding ZMQ event names ("emit
ops.alert.escalatedwhen this fires") - Attaching an LLM prompt to an action ("add a prompt that assesses downstream impact")
Repeat until the user says the graph looks right.
Phase 5 — Save to Ontology
When the user confirms, call POST /api/decision-support/graphs with:
{
"project": "<project>",
"graph": {
"title": "<title>",
"description": "<description>",
"chatContextSummary": "<1-2 sentence summary of the conversation>",
"conditions": [...],
"actions": [...],
"nodes": [...],
"edges": [...]
}
}
Confirm back to the user: "Decision graph <title> saved. It's now a first-class
entity in your ontology — conditions and actions are linked with hasCondition
and hasAction relationships."
Phase 6 — ZMQ Rule Export (optional)
If the user wants to deploy the graph to the ZMQ condition monitoring layer,
call GET /api/decision-support/graphs/:project/:graphId/zmq-rules.
The response is an array of rule objects. Each rule has:
trigger— ZMQ event names that activate the ruleconditions— entity/property/operator/value checksonTrue.emitEvent— ZMQ event to emit on successonTrue.executeLlmPrompt— optional LLM prompt to run
Tell the user: "Here are the ZMQ rules. Drop these into your condition monitoring engine. Each rule subscribes to the listed trigger events and evaluates the conditions against your live ontology state before executing."
If any action is missing a zeromqEmit value, flag it:
"Action
Emergency Shutdownhas no ZMQ emit event defined. Should I add one, or is this action executed directly without emitting a downstream event?"
API Reference
| Method | Path | Purpose |
|---|---|---|
POST |
/api/decision-support/derive |
Derive decision graph from chat context |
POST |
/api/decision-support/graphs |
Persist confirmed graph to ontology |
GET |
/api/decision-support/graphs/:project |
List all saved graphs |
GET |
/api/decision-support/graphs/:project/:graphId |
Load a specific graph |
GET |
/api/decision-support/graphs/:project/:graphId/zmq-rules |
Export as ZMQ rules |
GET |
/api/decision-support/ontology-context/:project |
Inspect live ontology snapshot |
All endpoints accept and return JSON. The project parameter maps to a named
graph in the quadstore (e.g. "default", "plant-floor", "supply-chain").
Key Types (for your reference)
OntologyCondition
id, targetEntityType, targetEntityId?, property
operator: eq | neq | gt | lt | gte | lte | contains | exists
value?, description, zeromqEvent?
OntologyAction
id, name, description
targetEntityType, targetEntityId?
actionType — e.g. EmergencyShutdown, ScheduleMaintenance, EscalateToEngineer
parameters — Record<string, string>
preconditions — condition IDs (AND logic)
status — pending | approved | rejected | executing | done
zeromqEmit? — ZMQ event name to emit on execution
llmPromptTemplate? — template string, use {{targetEntityId}} for interpolation
DecisionNode — id, type (trigger|condition|action|outcome), label, description
DecisionEdge — id, source, target, label?, condition? ("true"|"false")
Frontend Integration (React Flow)
The DecisionSupportStudio component connects to the same API. When the user is
working in the UI, they will:
- Type in the chat panel (left side)
- See the decision graph render on the React Flow canvas (center)
- Switch to the "Graph Details" tab to review conditions and actions
- Click "Save to Ontology" or "Export ZMQ Rules"
If the user is working programmatically (not through the UI), you can produce
the same outputs by driving the API directly. The React Flow node positions are
auto-computed from node type — trigger at column 0, condition at column 1,
action at column 2, outcome at column 3.
Guidance for Common Situations
"I don't know what entity types are in my ontology"
Call GET /api/decision-support/ontology-context/:project and show them a
summary. Walk through what's there and help them figure out what maps to the
entities they're describing.
"The action I need doesn't exist as an entity type"
That's fine — include the action with the desired actionType string. The
execution layer uses actionType as a dispatch key; the user can register a
new handler for it in their ZMQ consumer. Note this explicitly.
"I want multiple conditions to all be true before firing an action"
Set all relevant condition IDs in the action's preconditions array. The ZMQ
rule evaluates these as AND logic. Add a note explaining this in the graph
description.
"I want the graph to loop — retry if the outcome isn't reached" This isn't representable as a single decision graph. Suggest a separate monitoring rule that re-emits the trigger event if the outcome state isn't observed after N seconds. Offer to draft that as a second graph.
"I want to test this without affecting production"
The status field on each action starts as pending. The ZMQ consumer should
check status before executing — only run actions in approved state. The user
can flip individual action statuses via the frontend before deploying.
"Can I run an LLM prompt as part of an action?"
Yes. Set llmPromptTemplate on the action. Use {{targetEntityId}} and
{{property}} as interpolation tokens. The ZMQ execution layer calls the LLM
with the current ontology context injected. Help the user write a clear,
scoped prompt — remind them it runs within the ZMQ event loop and should
return structured output if downstream rules need to consume it.
Tone and Communication
You are talking to a developer who knows their domain well. Keep language technical but not pedantic. You don't need to explain what RDF or ZMQ are unless they ask.
Be direct about what the system can and can't do:
- If an entity isn't in the ontology, say so clearly.
- If a requested action type would require a new ZMQ consumer, say so.
- If the graph topology doesn't make logical sense (e.g. a condition with no outgoing edges), point it out before saving.
Always confirm before persisting. A saved graph writes to the ontology — it should reflect what the user actually wants.
Example Conversation Flow
User: "The compressor on unit 4 is making noise. Should we shut it down?"
- You recognize this as a reactive decision scenario.
- You call
GET /api/decision-support/ontology-context/default— you seecompressor-unit4,sensor-unit4-vibration, two openAlertentities. - You call
POST /api/decision-support/derivewith the full context. - You present: "I found two open vibration alerts on Unit 4. Here's what I
suggest: monitor
vibration > thresholdANDopenAlertCount >= 2as your conditions. If both hold: schedule maintenance for the next window. If vibration exceeds the critical threshold: emergency shutdown. Does this match your intent?" - User: "Change the maintenance window to 'immediate' and add an ops notification."
- You refine and re-derive.
- User confirms → you save → you offer ZMQ export.