Skip to main content
Version: 1.0.4

External Systems New in 1.0.0

A Named Endpoint lets the assistant look something up in a system QUBIQ does not own — an ERP, a CMMS, a maintenance API — so "is there stock for that seal?" can be answered.

The whole design turns on three properties. They are what make this safe enough to exist:

  1. The model never names a destination. It selects an operation by name. The host comes from an endpoint you authored, and the path from a template you wrote.
  2. The model never composes the payload. Parameters are declared, typed and pattern-constrained by you. Anything undeclared is refused rather than passed through.
  3. The reachable set is your artifact, not a model's choice.

Because of those three, this is not treated as the assistant "having internet access". It is a fixed, admin-authored menu.

Configuring one

Settings → AI Assistant → External Access.

The card carries one master switch — Let the assistant call external systems — separate from per-endpoint access, so an incident can be stopped in one click without losing how anything was configured. It is off by default, and while it is off no outbound call is made whatever is configured below it.

The system

FieldNotes
NameHow it is referred to.
Base URLThe host and root path. A private address is fine — see below.
What this system isFor your team. Never sent to the model.
Authenticationnone, bearer, basic, apiKey (in a header or the query string), or a custom header.
Let the assistant use thisOff while you set it up. Test it first — you can, without opening it.

The credential is write-only from the interface's point of view: the form shows the scheme and whether a secret is set, and there is no route anywhere that returns the secret itself. Leaving the field blank on edit keeps what is stored.

Authorization and Host may not be set through the custom-header scheme. The first because there is already a scheme for it and two competing values would be resolved by whichever ran last; the second for a sharper reason — the transport sets Host from the resolved address to defeat DNS rebinding.

The operations

An endpoint is useless until it has operations. Each one is a single named call.

FieldNotes
NameThe only identifier that crosses to the model. Lower-case letters, digits and underscores, 3–64 characters.
TitleYour label. Never sent to the model.
DescriptionIs sent to the model, and is the entire basis on which it picks this operation over another.
MethodGET. Nothing else.
PathA template hung off the base URL, with {param} placeholders.
ParamsWhat the model may fill.

Write the description as if it were the only documentation — because to the model, it is. "ERP integration" tells it nothing; say what comes back and when to use it.

GET only, and not by oversight

PUT/PATCH/DELETE are obviously writes. POST is the one worth explaining: a POST to an ERP can create a purchase order, so "read-only" is a claim about the remote system and not just about QUBIQ. And the useful kind of POST carries a query body — which the model would have to compose, defeating property 2 above.

Parameters

FieldNotes
NameThe {placeholder} it fills, or the query-string key.
Inpath or query. A path parameter must be required — an absent value would leave a hole in the URL.
PatternAn anchored regular expression the value must match.
DescriptionShown to the model, so it knows what to put here.
MeansLinks the value to something real — a plant-vocabulary kind (equipment, area, …) or a temporal role.

Write a real pattern. It is your only actual control over what a model-supplied string can be. Containment (below) refuses the characters that would let a value escape its slot; a pattern like ^[A-Z0-9-]{3,20}$ also refuses the ten thousand strings that are merely wrong. Leaving it empty is legal and lazy.

Means is advisory, unlike the pattern: it says what the value means, not what it may contain. Setting it lets the assistant resolve what the operator called something into what the system calls it, exactly as a saved query's parameter does.

The editor refuses a definition that cannot be coherent: a {slot} with no declared parameter, a path parameter with no slot, a query string typed into the path, a duplicate name, an invalid pattern, a means that is not a real vocabulary kind.

Containment — the rule that keeps a value in its slot

A template like /inventory/{sku}/stock looks scoped. It is not, unless the value substituted into {sku} can never introduce structure of its own. These characters are refused outright in a parameter value:

Because
/A new path segment — /inventory/../../admin/users/stock
?A query string you never authored
#A fragment, which truncates everything after it
@A userinfo section, which can relocate the host entirely: https://erp.internal/x/{sku} with sku=@evil.example is a request to evil.example
\A separator some parsers fold to /
%Percent-encoding, which can re-introduce any of the above after a decode
..Traversal

The last two are the ones that get missed. The value is also percent-encoded on substitution — both, because encoding alone has been defeated by double-decoding proxies more than once.

Reaching something on the plant network

The usual advice for outbound HTTP is "refuse private ranges". That is exactly wrong here: the whole point is to reach an ERP at 192.168.10.40, or erp.internal on a plant LAN. The legitimate targets are the private ranges.

So the defence is built from what remains:

  • Resolve, then pin. The host is resolved once, the decision is made on the resolved IP, and that IP is dialled. Resolving twice — once to check, once to connect — is a DNS-rebinding hole.
  • Redirects are never followed. A 30x elsewhere is the cheapest bypass there is.
  • An always-deny set no configuration can widen: loopback, 0.0.0.0/8, link-local 169.254.0.0/16 (which is where cloud metadata hands out instance credentials), multicast, and the IPv6 equivalents. An endpoint pointed at QUBIQ's own loopback interface would be a confused-deputy path around every authorization check in the system.
  • Caps on the response: 256 KiB, hard-truncated with a note rather than silently; 10 seconds by default and 60 at most; and only application/json, text/plain, text/csv, text/html, text/xml and application/xml are accepted.

Testing

Test runs the operation with values you supply and shows what came back — including the resolved IP, which nothing the model sees ever includes. You can test an endpoint before opening it to the assistant, which is the intended order.

Using one

FromHow
The assistantPlug the External Systems skill, and put the endpoint in the instance's endpoint fence.
A playbookA Call external system step, naming the operation. → Playbooks
A playbook checkAn External system input, so a figure is computed from the response.
An AI nodeThe endpoints fence, one endpoint at a time.

The endpoint fence is fail-closed and has no * on a pipeline node: a node's prompt is a vendor webhook or an email body nobody read, so text inside it can steer which system gets called. Give a node the one endpoint it needs.

Gotchas

  • The master switch and the per-endpoint switch are different things. An endpoint marked Let the assistant use this still makes no call while the capability is off.
  • An operation the model cannot tell apart from another will be picked wrongly. Two operations described as "look up a part" is a coin flip; describe what each returns.
  • A response over 256 KiB is truncated and says so. If an operation routinely returns more, it is the wrong operation — add a parameter that narrows it.
  • The description reaches the model; the title and the system description do not. Putting the useful sentence in the wrong field is the most common reason an operation is never selected.

See also