Skip to main content
Preview
DEFINE AGENT is a preview feature. It ships in broker 2.22. The syntax and behaviour may still change.
An agent runs on a TYPE LLM connector. See Agents Overview for how the two fit together, and AI Connectors for the connector itself.

Define an agent

USES LLM CONNECTOR is the first line of the body. DEFAULT_USER is required. Every other line can follow in any order. Add the block with -addAgent. -addConnector refuses an agent block.
Create line-ops before you add the agent. GUARDRAILS is prompt text. It steers the model. Grants and permissions are what stop a tool call. AGENT_MODE, TOOL_EXECUTION_MODE, and EXTERNAL_ACCESS accept only their defaults (agent, auto, and false). Other values are refused at -addAgent. Numbers may be bare or quoted. Any value may use GET ENV or GET SECRET.
Models that reason before answering spend part of each completion on hidden reasoning. If the connector’s MAX_TOKENS is 1024, the agent can get an empty answer. Set the TYPE LLM connector’s MAX_TOKENS to 4096 or more for these models. The agent’s own MAX_TOKENS is the budget for the whole tree, not one completion.
An agent that loads a large built-in skill resends that context on every model call. A panel-building run can need a MAX_TOKENS budget of several hundred thousand.

Tools

Nothing is granted until ADD TOOL says so. Grants of the same tool are merged. A grant never adds a permission the user lacks, and a permission never widens a grant. WITH TOPICS is refused on tools that are not MQTT. WITH TARGET is refused on the MQTT tools. + and # must fill a whole topic level. Every agent can also read a built-in LoT skill. That read changes no broker state and needs no ADD TOOL. The skills meant for external coding agents are also published as Coreflux agent skills. Declaring skills with WITH SKILLS is not available yet.
A writing tool (write_mqtt, create_lot, execute_routes, execute_actions) must say WITH LEVEL "write". Omitting LEVEL means write_confirm, and -addAgent refuses that until approvals exist. Read tools do not take LEVEL.
create_lot with TARGET "skill" or "agent" is refused. write_mqtt cannot publish anywhere under $SYS/Coreflux/Agents/. execute_routes refuses events on agents and events whose names start with _.

Who a task runs as

Two checks run on every tool call. RBAC (unauthorized) asks whether this user may do it. Scope (out_of_scope) asks whether ADD TOOL granted it. Both the user the task runs as and the agent’s DEFAULT_USER must be allowed. An agent never does more than its DEFAULT_USER may, and never more than the person who asked. Publishing to an agent’s topics does not lend the publisher the agent’s DEFAULT_USER. A cancel is honoured only from the user the task runs as. For read_mqtt, write_mqtt, and execute_routes, a call that fails both checks reports out_of_scope.

Insight mode

A request body can ask for a read-only run:
"mode": "insight" refuses every writing tool as out_of_scope, including inside delegated peers. This is the HUB Insight toggle. A per-agent default of insight mode is not available yet. The agent’s AGENT_MODE stays agent.

Delegation: WITH AGENTS

WITH AGENTS is the allow-list. Each registered peer is offered to the model as a delegation tool. An agent with no WITH AGENTS reaches no one. A peer that is not registered yet is offered once it registers.
Declare AlertAnalyst and MaintenancePlanner the same way, each with the grants its job needs. The whole tree shares the root task’s token budget and deadline. MAX_CHAIN_DEPTH and cycle detection bound it. Each hop publishes a hop event on the caller’s stream. The child runs with its own task id on the peer’s stream, and every tool call in the tree authorizes as the user who started the chain. In-process delegation needs no extra PublishSys rule. An explicit DENY on the peer’s …/task/+/request topic for that user still refuses the hop as unauthorized. Share one TYPE LLM connector across agents that use the same model. Changing the key or the model on the connector updates every agent that names it. Set prices once and every agent’s run_end can report cost. Match the model to the job: a local model for high-volume classification, a cloud model where the answer has to be sharper. WITH MEMORY "none" on a classifier so an earlier conversation cannot steer it.

Agent topics

The broker publishes these topics. Reading them needs SubscribeSys on the path. The card includes schemaVersion, name, description, status, llmRoute, provider, model, hubVisible, interactionTopic, peers, tools, and memory. Ignore unknown fields. read_lot with no TARGET appears as an empty object. The card never carries the API key or the guardrail text. -removeAgent clears the card and the status with empty retained payloads. At startup the broker also clears retained topics under $SYS/Coreflux/Agents/ that no running or defined agent owns (skipped in a cluster), including leftovers from a removed TYPE AGENT connector.

How work arrives

Task topic. Publish to $SYS/Coreflux/Agents/<agent>/task/<id>/request. Subscribe to that task’s status, stream, and response first. Publishing under $SYS is default-deny, including for root. Without a PublishSys rule the publish is dropped before the agent sees it.
Cancel needs the same rule on …/task/+/cancel. Interaction topic. With INTERACTION_TOPIC "plant/operator", publish plain text or JSON to plant/operator/<session>/ask. These are ordinary topics, so ordinary publish rules apply. Restrict who may subscribe to {INTERACTION_TOPIC}/# when answers are sensitive. A request body is plain text, or JSON with text, optional session_id, optional mode, and optional image or pdf data URIs (image/* or application/pdf, at most 10 MiB decoded). A bad attachment is dropped with a broker warning and the question is still answered. CALL AGENT. See below. Stream events are QoS 0 and not retained. Each one has v: 1 and a type: run_start, delta, tool_call, tool_result, hop, or run_end. Ignore unknown types. run_start.requestPreview is the request text, redacted and cut at 200 characters. It is the only copy of a CALL AGENT task argument or a delegated child’s question, because those do not publish a …/request. A refusal before the run starts publishes a rejected status and no stream events. …/task/<id>/status uses done when the model answered, canceled when someone published to …/cancel, failed with a code such as deadline_exceeded or budget_exhausted, and rejected with a code such as unauthorized, unknown_agent, agent_busy, out_of_scope, cycle_detected, or hop_limit. An agent on an Ollama connector can also fail with llm_timeout, llm_unreachable, model_not_found, or context_overflow. The message names the model and the URL. See Ollama context and timeouts.

Working memory

MEMORY "individual" keeps one conversation per session. The session is the /ask topic segment, or session_id in a task-request body. A request with neither is stateless. A conversation belongs to the user it runs as: another user who reuses the session id starts a separate conversation. Each agent keeps up to 256 sessions (least recently used are dropped), each at most 256 KiB and 40 messages. Memory is saved on shutdown and loaded at the next agent start. -removeAgent forgets that agent’s sessions. A task still running when the agent stops is cancelled and its turn is not kept. CALL AGENT "<agent>.clear_history" forgets one of the DEFAULT_USER’s sessions. Delegated children do not inherit the caller’s conversation. A second question on a session whose task is still running is refused as agent_busy.

Call an agent from an Action

CALL AGENT waits until the task finishes. It runs as the agent’s DEFAULT_USER, through the same limits, status, and stream as any other task. execute returns the answer text, or a JSON object { "success": false, "status", "code", "message" } when the task is refused or fails. use_history on the call is ignored. The session is the memory.
A name that is not a DEFINE AGENT, or an agent that exists but is offline or in error, returns unknown_agent. Read a failure with GET JSON:
On success {result} is plain text, so code is empty. On failure it is the JSON object above.

Disable an agent

Add DISABLE true on its own line to keep an agent defined but not started:
A disabled agent stays listed and keeps its definition, but takes no tasks. -disableAgent <name> and -enableAgent <name> switch it without editing the code. In a cluster, agents are local to each node, so these two commands change only the node that receives them.

Managing agents

-addAgent needs AgentManagementCreation. -removeAgent needs AgentManagementRemove. Seeded rules allow root, admin, and AllowedSystemConfiguration, the same gate as connectors. See Rules syntax. Agents are absent from -listConnectors, -checkConnectorConnection, and $SYS/Coreflux/Routes/. Their source is retained on $SYS/Coreflux/Agents/<name>. Ask an agent on its task topic or its interaction topic. Do not publish to $SYS/Coreflux/Routes/<agent>/Events/…/Trigger. -removeConnector and -removeAllConnectors refuse to remove a TYPE LLM connector an agent uses, and they name those agents. Point the agents at another connector, or remove them, first. To change the model, key, or provider, send -addConnector with the new block. The connector updates in place and its agents stay bound. They show error for the moment the connector restarts, then come back online. -loadProject and -loadFolder skip a project’s agents, with a warning, when the caller lacks AgentManagementCreation. Projects deploy agents after connectors.

Troubleshooting

Read $SYS/Coreflux/Agents/<agent>/status. The usual reason is that the LLM connector is missing, stopped, or not a running TYPE LLM connector. Add or fix the connector. The agent comes online on its own.
USES LLM CONNECTOR or DEFAULT_USER is missing, a writing tool has no WITH LEVEL "write", a scope setting is missing, or the name is already a connector or an agent. Agents and connectors share one namespace.
No PublishSys rule for that user on …/task/+/request, so the broker dropped the publish. Add the rule in How work arrives, or use the interaction topic.
unauthorized: grant the permission to the user the task runs as (the originator, for a delegated task). out_of_scope: widen ADD TOOL. A tool the model never calls was never granted, or the task is in insight mode.

Last modified on October 21, 2026