Docs menu

Workbenches Build on Each Other

Goal: Let one workbench call another's hosted mode, without hard-coding addresses.

A release-check workbench that needs your triage workbench's API shouldn't carry its URL in code. Declare the dependency, and OpenX hands it the address when it deploys.

Declare it

  1. Open the workbench that will do the calling, and its Consumes tab.
  2. Add dependency: pick the target workbench, the mode to use (it must be enabled), and optionally an alias.
  3. Save, then redeploy the calling workbench.

OpenX checks each dependency when you save, accept or deploy: a target that doesn't exist, or a mode that isn't enabled, is refused.

Each dependency is one row with three fields:

FieldWhat it is
TargetThe other workbench, by its APISlug. Only other workbenches that have an APISlug set are offered
ModeThe mode of that workbench to use. It has to be turned on
AliasOptional. A name that is safe in an environment variable. Left blank, the target's APISlug is used

You can list the same target more than once to use two of its modes, say API and MCP. Give those rows different aliases: two rows with the same alias share one variable name, and only one of them survives.

What gets refused

A save, or a deploy of the calling workbench, answers 400 with a list of what is wrong:

SituationMessage
The target is not in the workspace"Workbench '<lookup>' declares Consumes on '<target>' which does not exist in this workspace."
The target's mode is not turned on"... declares Consumes on '<target>' mode '<mode>' which is not enabled on the target."

A target removed after the calling workbench was deployed leaves the old address in place, and calls to it fail. Redeploy the calling workbench: the deploy checks again and stops with a message naming the missing target or mode. A target set to No public access (below) must itself be deployed before the workbench that consumes it.

Read it

At deploy, each of the calling workbench's containers, one per mode, gets two environment variables:

WB_CONSUMED_<alias>_URL      the target mode's address (the alias defaults to the target's APISlug)
FATHYM_OX_CONSUMES_JSON      every dependency as {"alias": "url"}

With no dependencies, FATHYM_OX_CONSUMES_JSON is {} and no WB_CONSUMED_..._URL is set. To go through every dependency without knowing the aliases in advance, read the JSON one:

const consumes = JSON.parse(Deno.env.get('FATHYM_OX_CONSUMES_JSON') ?? '{}') as Record<
  string,
  string
>;

for (const [alias, url] of Object.entries(consumes)) {
  // call each dependency
}
const triage = Deno.env.get('WB_CONSUMED_triage_URL');
const res = await fetch(`${triage}/classify/run`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${Deno.env.get('TRIAGE_TOKEN')}`,
  },
  body: JSON.stringify({ arg0: 'Checkout returns 500 for EU cards' }),
});

The call goes through the same address and the same access check as any outside caller: the calling workbench presents a key like anyone else and is not trusted because it runs in your workspace. Composition wires workbenches together; apart from the exception below, it bypasses nothing.

One exception, which you choose. A target set to No public access in its Hosting tab has no ox-api address at all: it is reachable only by other workbenches and services in the same environment. A workbench that consumes it is given the target's in-environment address (http://<app name>:<port>) instead, with no key check in between.

The calling workbench needs its own key. OpenX issues none to it, so add a key from APIs -> API Keys to the workbench's environment settings (TRIAGE_TOKEN above) and rotate it yourself.

Custom modes

MCP, API and Web are built in. A workbench package can also declare a mode of its own, such as a scheduled job, and the workbench offers it in its Modes tab like any other: there is nothing to register in the workspace. A custom mode has no web address; it runs in its own container and is kept running. How to write one is on Custom Modes.

Next steps

On this page