Fuzzball Documentation
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

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.

Usage

Connecting via the Web UI

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.

Primary endpoint selection

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:

  1. Single endpoint — if the workflow has exactly one endpoint, it is the primary endpoint
  2. Single service — if all endpoints belong to a single service, the first endpoint in that service is primary
  3. 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.

When to use the Web UI vs. CLI

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:

ArgumentRequiredDescription
WORKFLOW_IDYesThe ID of a running workflow
COMMAND...NoArguments forwarded to the client program when the service is configured for client-script mode

Flags:

FlagDescription
--nameName 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.
--endpointName 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.

Connection modes

fuzzball workflow connect supports two modes, selected automatically based on the workflow definition:

Browser mode

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.

Client-script mode

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.

Examples

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/project

Connecting at workflow start

The 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.

Configuring a service for client-script mode

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.

Runtime variables available in the service container

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:

VariableDescription
FB_WORKFLOW_IDID of the running workflow
FB_ACCOUNT_IDID of the account that owns the workflow
FB_JOB_NAMEName of the service (matches the service key in the workflow)
FB_ENDPOINT_URLPublic URL of the first endpoint of the service (e.g. https://...)
FB_ENDPOINT_HOSTHostname portion of the first endpoint URL
FB_ENDPOINT_PATHPath 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.

Example: vLLM server with a generated agent client

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 the fuzzball.io/connect/vllm annotation, it sed-substitutes the placeholders with values taken from the runtime environment (FB_ENDPOINT_URL, FB_WORKFLOW_ID, and the user-defined VLLM_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/myapp

Or, against an already-running workflow:

$ fuzzball workflow connect --name vllm <workflow-id> -- /home/user/projects/myapp

In both cases Fuzzball:

  1. Waits for the vllm service readiness probe to pass.
  2. Runs sh /app/generate-agent-command.sh inside the vllm container.
  3. Captures the substituted script from standard output, writes it to a temporary file with executable permissions, and runs it locally with /home/user/projects/myapp as $1.

Pattern recap

  1. Declare the annotation fuzzball.io/connect/<service-name> on the workflow.
  2. Embed any helper files (template, substitution script, certificates, etc.) under the service’s files section so they are available inside the container.
  3. 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.
  4. Use FB_* environment variables and any service-level env entries 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.