How to Configure the Freebuff CLI Terminal Command Broker for Headless Operation
Set FREEBUFF_HEADLESS=1 to force the Freebuff CLI's terminal command broker into headless mode, bypassing terminal UI detection in CI pipelines, Docker containers, and other display-less environments.
The terminal command broker is a core component of the Freebuff CLI that manages how external commands are spawned and executed. By default, it attempts to attach to an interactive terminal for richer output handling. In headless environments—such as continuous integration systems, containerized deployments, or remote servers—the broker must be explicitly configured to operate without a display.
Understanding the Terminal Command Broker Architecture
The broker implementation resides in [cli/src/utils/terminal-command-broker.ts](https://github.com/CodebuffAI/freebuff/blob/main/cli/src/utils/terminal-command-broker.ts). This module handles command execution lifecycle, including process spawning, output streaming, and error aggregation.
Before executing commands, the broker checks whether it can run in interactive mode. The detection logic lives in [cli/src/utils/env.ts](https://github.com/CodebuffAI/freebuff/blob/main/cli/src/utils/env.ts) (lines 22–30), which examines:
- Presence of
DISPLAYenvironment variable (X11) - Presence of
WAYLAND_DISPLAYenvironment variable (Wayland) - The explicit override
FREEBUFF_HEADLESS
When no display environment is detected, the broker automatically initializes in headless mode. However, automatic detection occasionally fails—particularly in nested containers or SSH sessions with forwarded X11. The FREEBUFF_HEADLESS variable provides deterministic control.
Method 1: Environment Variable Configuration (Recommended)
Setting FREEBUFF_HEADLESS=1 is the standard approach for configuring terminal command broker headless operation. This method works across all invocation patterns and overrides any automatic detection.
Shell Export Pattern
# Unix/Linux/macOS
export FREEBUFF_HEADLESS=1
freebuff run my-agent --target production
# Windows PowerShell
$env:FREEBUFF_HEADLESS=1
freebuff run my-agent --target production
# Windows Command Prompt
set FREEBUFF_HEADLESS=1
freebuff run my-agent --target production
Docker Container Pattern
FROM node:20-alpine
ENV FREEBUFF_HEADLESS=1
RUN npm install -g @codebuffai/freebuff
CMD ["freebuff", "run", "my-agent"]
Or via compose:
services:
freebuff-agent:
image: codebuff/freebuff-cli:latest
environment:
- FREEBUFF_HEADLESS=1
command: ["freebuff", "run", "my-agent"]
Method 2: Disabling the Broker Entirely
For scenarios where you want the CLI to spawn processes directly without any broker mediation, pass the --no-terminal-command-broker flag. This flag is defined via TERMINAL_COMMAND_BROKER_FLAG in [cli/src/utils/terminal-command-broker.ts](https://github.com/CodebuffAI/freebuff/blob/main/cli/src/utils/terminal-command-broker.ts).
freebuff run my-agent --no-terminal-command-broker
Trade-off: Disabling the broker removes output buffering, structured error handling, and retry logic. Use this only when the broker itself causes compatibility issues.
Method 3: Programmatic SDK Configuration
When using the Freebuff SDK directly, instantiate the broker with headless mode enforced through environment injection:
// src/runner.ts
import { createTerminalCommandBroker } from 'freebuff/cli/src/utils/terminal-command-broker';
import { runTerminalCommand } from 'freebuff/sdk/src/tools/run-terminal-command.ts';
const broker = createTerminalCommandBroker({
env: {
...process.env,
FREEBUFF_HEADLESS: '1'
},
headless: true // Explicit option if available in your version
});
const result = await runTerminalCommand({
executable: ' terraform',
args: ['apply', '-auto-approve'],
broker // Inject configured broker
}, {
timeout: 300000
});
The SDK's [sdk/src/tools/run-terminal-command.ts](https://github.com/CodebuffAI/freebuff/blob/main/sdk/src/tools/run-terminal-command.ts) accepts an optional broker instance, falling back to default initialization if omitted.
Verifying Headless Operation
Confirm your configuration is active by checking broker initialization logs. When FREEBUFF_HEADLESS=1 is respected, logs contain entries such as:
[terminal-command-broker] Initializing in headless mode
[terminal-command-broker] Skipping terminal UI attachment (FREEBUFF_HEADLESS=1)
[terminal-command-broker] Command spawned without PTY allocation
Enable verbose logging if messages are suppressed:
FREEBUFF_HEADLESS=1 FREEBUFF_LOG_LEVEL=debug freebuff run my-agent
Key Source Files Reference
| File | Responsibility |
|---|---|
[cli/src/utils/terminal-command-broker.ts](https://github.com/CodebuffAI/freebuff/blob/main/cli/src/utils/terminal-command-broker.ts) |
Broker implementation, flag definitions (--terminal-command-broker, --no-terminal-command-broker) |
[cli/src/utils/env.ts](https://github.com/CodebuffAI/freebuff/blob/main/cli/src/utils/env.ts) |
Headless detection logic (DISPLAY, WAYLAND_DISPLAY, FREEBUFF_HEADLESS parsing) |
[sdk/src/tools/run-terminal-command.ts](https://github.com/CodebuffAI/freebuff/blob/main/sdk/src/tools/run-terminal-command.ts) |
Public API for command execution with broker injection support |
[cli/src/utils/codebuff-client.ts](https://github.com/CodebuffAI/freebuff/blob/main/cli/src/utils/codebuff-client.ts) |
High-level client that wires broker into CLI commands |
Summary
- Preferred method: Export
FREEBUFF_HEADLESS=1to configure the terminal command broker for headless operation without code changes - Alternative: Use
--no-terminal-command-brokerto bypass the broker entirely (sacrifices reliability features) - Detection: The broker auto-detects headless environments via
DISPLAYandWAYLAND_DISPLAYabsence, but explicit configuration is more reliable - SDK usage: Pass environment configuration or headless flag to
createTerminalCommandBroker - Verification: Check initialization logs for "headless mode" confirmation messages
Frequently Asked Questions
What happens if I don't configure headless mode in a CI environment?
The terminal command broker attempts to allocate a pseudo-terminal (PTY), which fails with "inappropriate ioctl for device" or similar errors. The CLI may hang waiting for terminal input or crash during initialization. Setting FREEBUFF_HEADLESS=1 prevents PTY allocation and forces streaming output handling.
Can I use FREEBUFF_HEADLESS with the VS Code extension or other IDE integrations?
Yes. The environment variable is respected regardless of how the CLI is invoked. Configure it in your IDE's terminal settings, task definitions, or launch configurations. For VS Code tasks, add "options": { "env": { "FREEBUFF_HEADLESS": "1" } } to your task definition.
Does headless mode affect command output formatting?
Output remains fully captured and streamed. What changes is the presentation layer—progress bars become line-based logs, interactive prompts are bypassed or fail fast, and color codes may be suppressed unless FORCE_COLOR is also set. The underlying command execution and exit code handling are unchanged.
Is there a performance difference between headless mode and disabled broker?
Headless mode maintains the broker's process supervision, retry logic, and structured output parsing with minimal overhead (typically <5ms per command). Disabling the broker (--no-terminal-command-broker) removes this overhead but also loses resilience features. For most CI pipelines, headless mode is the optimal balance.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →