Connecting to Workflow Services
The fuzzball workflow connect command provides a convenient way to interact with a service
running in a workflow. Depending on the service definition, it can either open the service’s
public endpoint in a web browser or run a client program locally that connects to the service.
The Fuzzball Web UI provides a Connect button that offers one-click access to running workflows that expose service endpoints. The button appears in two locations:
- Workflow detail page — in the toolbar at the top of the page
- Workflows list table — inline in each workflow row
The two locations behave differently while a workflow is starting up.
On the workflow detail page, the button appears once the workflow is running and defines at least one named service endpoint. It stays disabled until a primary endpoint can be resolved from the workflow’s running services. The page polls the workflow’s status every ten seconds while any stage is pending or started, so the button becomes active shortly after the service starts. You do not need to reload the page.
In the workflows list table, the button appears only once it is ready to use.
The button links to the constructed endpoint URL but does not verify that the endpoint is actually reachable. “Running” here means the orchestrator has started the service container, not that the application inside it has finished booting, so the target service may still be starting up when the button becomes clickable.
Clicking the button opens the workflow’s primary endpoint in a new browser tab.
When a workflow defines multiple endpoints across one or more services, the Web UI automatically selects a “primary” endpoint. Only named endpoints are eligible, and they are evaluated in the order the services are defined in the workflow specification (not alphabetically). An endpoint counts as ready, and so makes the Connect button active, only while its service is running:
- Single endpoint — if the workflow has exactly one endpoint, it is the primary endpoint
- Single service — if all endpoints belong to a single service, the first endpoint in that service is primary
- Multiple services — if endpoints span multiple services, the primary endpoint is the first endpoint of the first running service in specification order
For workflows where the automatic selection does not match your preference, use the CLI fuzzball workflow connect command with the --name and --endpoint flags to explicitly select the service and endpoint you want to access.
The Connect button is ideal for quickly accessing web-based services such as Jupyter, RStudio, or other browser-accessible applications. For workflows that require client-script mode (see below) or for selecting a specific non-primary endpoint, use the fuzzball workflow connect CLI command instead.
$ fuzzball workflow connect WORKFLOW_ID [flags] [-- COMMAND...]Arguments:
| Argument | Required | Description |
|---|---|---|
WORKFLOW_ID | Yes | The ID of a running workflow |
COMMAND... | No | Arguments forwarded to the client program when the service is configured for client-script mode |
Flags:
| Flag | Description |
|---|---|
--name | Name of the service to connect to. If omitted and the workflow defines a single service, that service is selected automatically; otherwise the CLI prompts interactively. |
--endpoint | Name of the service endpoint to use. If omitted and the service defines a single endpoint, that endpoint is selected automatically; otherwise the CLI prompts interactively. |
The command waits for the target service to become ready (its readiness probe must pass) before opening the browser or launching the client program. While waiting, container logs for the service are streamed to the terminal.
fuzzball workflow connect supports two modes, selected automatically based on the workflow
definition:
If the service has no fuzzball.io/connect/<service-name> annotation declared on the workflow,
the command resolves the URL of the selected endpoint and opens it in the default web browser.
This is the simplest mode and is well suited to services that expose a web UI such as Jupyter
or RStudio.
If the workflow declares an annotation of the form fuzzball.io/connect/<service-name> whose
value is a command to run inside the service container, that command is executed and its
standard output is treated as a client script. The script is saved to a temporary file, made
executable, and run locally. Any extra arguments supplied after -- on the fuzzball workflow connect command line are forwarded to the script.
This mode is useful when connecting to a service requires more than just a URL — for example, to fetch a generated access token or TLS configuration and then launch a local client with the right parameters.
Connect to the only service in a workflow (auto-select service and endpoint):
$ fuzzball workflow connect <workflow-id>Connect to a specific service by name:
$ fuzzball workflow connect --name jupyter <workflow-id>Select a specific endpoint within a service:
$ fuzzball workflow connect --name api-server --endpoint grpc <workflow-id>Forward arguments to a client script (client-script mode):
$ fuzzball workflow connect --name code-server <workflow-id> -- --workspace /home/user/projectThe start commands accept a --connect flag that starts the workflow and then runs
workflow connect against the new workflow as soon as it is ready.
$ fuzzball workflow start --connect my-workflow.fuzz
$ fuzzball workflow catalog start --connect <template>When invoked this way, and the selected service has a fuzzball.io/connect/<service-name>
annotation, the CLI prompts for arguments to pass to the client script.
To enable client-script mode for a service, add a workflow-level annotation whose key is
fuzzball.io/connect/<service-name> and whose value is the command to execute inside the
service container. The command must write the client script to standard output. The script
itself runs locally on the user’s machine.
When the connect command runs inside the service container, Fuzzball injects a number of environment variables that can be used to render runtime values into the generated client script. The most useful ones are:
| Variable | Description |
|---|---|
FB_WORKFLOW_ID | ID of the running workflow |
FB_ACCOUNT_ID | ID of the account that owns the workflow |
FB_JOB_NAME | Name of the service (matches the service key in the workflow) |
FB_ENDPOINT_URL | Public URL of the first endpoint of the service (e.g. https://...) |
FB_ENDPOINT_HOST | Hostname portion of the first endpoint URL |
FB_ENDPOINT_PATH | Path portion of the first endpoint URL |
FB_ENDPOINT_URL_<NAME> | Public URL of the endpoint named <NAME> (uppercased) |
FB_ENDPOINT_HOST_<NAME> | Hostname portion of the endpoint named <NAME> |
FB_ENDPOINT_PATH_<NAME> | Path portion of the endpoint named <NAME> |
Any user-defined env entries declared on the service are also available to the connect
command. Combined with files embedded via the service’s files section, this is enough to
generate a fully parameterized client script without baking values into the container image.
The example below defines a vLLM service that exposes an OpenAI-compatible API on a public
HTTP endpoint and ships a connect command that emits a shell script to launch a local coding
agent (opencode) wired up to the running model.
The service uses two embedded files:
/app/agent-script.tmpl— the template of the local script, with placeholders such as__ENDPOINT_URL__and__WORKFLOW_ID__that will be substituted at connect time./app/generate-agent-command.sh— invoked by thefuzzball.io/connect/vllmannotation, itsed-substitutes the placeholders with values taken from the runtime environment (FB_ENDPOINT_URL,FB_WORKFLOW_ID, and the user-definedVLLM_API_KEY/VLLM_MODEL) and writes the resulting script to standard output.
version: v4
volumes:
data:
use: ephemeral
size: 5GB
annotations:
fuzzball.io/connect/vllm: "sh /app/generate-agent-command.sh"
services:
vllm:
image:
uri: docker://vllm/vllm-openai:latest
persist: true
network:
ports:
- name: openai-api
port: 8000
protocol: tcp
endpoints:
- name: openai-vllm
port-name: openai-api
protocol: http
type: subdomain
scope: public
mounts:
/home/vllm: data
resource:
cpu:
cores: 8
memory:
size: 32GB
devices:
nvidia.com/gpu: 1
annotations:
nvidia.com/gpu.model: "H100"
env:
- HOME=/home/vllm
- VLLM_API_KEY=replace-me
- VLLM_MODEL=meta-llama/Llama-3.1-8B-Instruct
script: |
#!/bin/sh
cd $HOME && exec vllm serve "$VLLM_MODEL" \
--tensor-parallel-size 1 \
--host 0.0.0.0 \
--port 8000
readiness-probe:
tcp-socket:
port: 8000
initial-delay-seconds: 60
period-seconds: 30
failure-threshold: 60
success-threshold: 1
files:
/app/agent-script.tmpl: |-
#!/usr/bin/env bash
if [ "$#" -ne 1 ]; then
echo "project directory path is missing"
exit 1
fi
mkdir -p /tmp/__WORKFLOW_ID__
base64 -w0 <<EOF |
{
"\$schema": "https://opencode.ai/config.json",
"model": "local/__MODEL__",
"provider": {
"local": {
"npm": "@ai-sdk/openai-compatible",
"name": "LocalAI (local)",
"options": {
"baseURL": "__ENDPOINT_URL__v1",
"apiKey": "__API_KEY__",
"headers": {
"keep_alive": -1
}
},
"models": {
"__MODEL__": {
"name": "__MODEL__",
"options": {
"max_tokens": 16000
}
}
}
}
}
}
EOF
cat > /tmp/__WORKFLOW_ID__/agent.config
docker run --rm -it \
-v $1:/home/agent/workspace \
--entrypoint /bin/bash \
docker/sandbox-templates:opencode \
-c "mkdir -p /home/agent/.config/opencode && \
cat >/home/agent/.config/opencode/opencode.json \
<(echo $(cat /tmp/__WORKFLOW_ID__/agent.config) | base64 -d) && \
exec opencode"
/app/generate-agent-command.sh: |-
sed -e "s|__ENDPOINT_URL__|$FB_ENDPOINT_URL|g" \
-e "s|__API_KEY__|$VLLM_API_KEY|g" \
-e "s|__MODEL__|$VLLM_MODEL|g" \
-e "s|__WORKFLOW_ID__|$FB_WORKFLOW_ID|g" \
/app/agent-script.tmpl
A user can then start the workflow and immediately drop into the local agent, passing the project directory as the only positional argument forwarded to the script:
$ fuzzball workflow start --connect vllm.fuzz
# (prompt) Enter arguments to pass to client script: /home/user/projects/myappOr, against an already-running workflow:
$ fuzzball workflow connect --name vllm <workflow-id> -- /home/user/projects/myappIn both cases Fuzzball:
- Waits for the
vllmservice readiness probe to pass. - Runs
sh /app/generate-agent-command.shinside thevllmcontainer. - Captures the substituted script from standard output, writes it to a temporary file with
executable permissions, and runs it locally with
/home/user/projects/myappas$1.
- Declare the annotation
fuzzball.io/connect/<service-name>on the workflow. - Embed any helper files (template, substitution script, certificates, etc.) under the
service’s
filessection so they are available inside the container. - The annotation command should print the final, ready-to-run client script to standard output. It must not depend on standard input, since the connect machinery does not forward a TTY to the in-container command.
- Use
FB_*environment variables and any service-levelenventries to inject runtime values into the generated script.
Services without this annotation always use browser mode. See the
workflow syntax reference for the
full set of services and network configuration options, and the
workflow endpoints page for details
on how endpoint URLs are constructed.