# How the Freebuff CLI Entry Point Dispatches Commands: A Deep Dive

> Explore the Freebuff CLI entry point and its two-stage command dispatch system. Learn how it handles broker mode, argument parsing, and command routing to specific handlers or the interactive TUI.

- Repository: [Codebuff/freebuff](https://github.com/CodebuffAI/freebuff)
- Tags: deep-dive
- Published: 2026-09-01

---

**The Freebuff CLI uses a two-stage dispatch system: [`cli/src/entry.ts`](https://github.com/CodebuffAI/freebuff/blob/main/cli/src/entry.ts) first detects broker mode versus normal CLI invocation, then [`cli/src/index.tsx`](https://github.com/CodebuffAI/freebuff/blob/main/cli/src/index.tsx) parses arguments and routes to specific command handlers (`login`, `publish`, `--clear-logs`) or launches the interactive TUI.**

The Freebuff command-line interface, from the [CodebuffAI/freebuff](https://github.com/CodebuffAI/freebuff) repository, implements command dispatching through a lightweight entry script that delegates to a central router. This architecture separates process-lifecycle detection from argument parsing and UI initialization, making the code maintainable and testable. Below, we'll trace exactly how a command flows from shell invocation to execution.

## Entry Point Detection in [`cli/src/entry.ts`](https://github.com/CodebuffAI/freebuff/blob/main/cli/src/entry.ts)

The dispatch chain begins in [`cli/src/entry.ts`](https://github.com/CodebuffAI/freebuff/blob/main/cli/src/entry.ts), which performs a single binary decision before any heavy code loads.

```ts
// cli/src/entry.ts
if (isTerminalCommandBrokerInvocation(process.argv)) {
  await serveTerminalCommandBroker()      // ← broker mode
} else {
  await import('./index')                 // ← normal CLI
}

```

**`isTerminalCommandBrokerInvocation`** checks `process.argv` to determine if the process was spawned as a *terminal-command-broker*—a special-purpose child process used by the Freebuff UI for isolated command execution. If broker mode is detected, the script immediately starts `serveTerminalCommandBroker()`. Otherwise, it dynamically imports [`cli/src/index.tsx`](https://github.com/CodebuffAI/freebuff/blob/main/cli/src/index.tsx) to handle standard CLI operations.

This conditional import keeps startup time fast for the broker path, which avoids loading React, OpenTUI, and other UI dependencies.

## Argument Parsing and Command Routing in [`cli/src/index.tsx`](https://github.com/CodebuffAI/freebuff/blob/main/cli/src/index.tsx)

Once the normal CLI path is taken, [`cli/src/index.tsx`](https://github.com/CodebuffAI/freebuff/blob/main/cli/src/index.tsx) orchestrates the full dispatch pipeline. The flow divides into three phases: parsing, early-command shortcuts, and TUI initialization.

### Phase 1: `parseArgs()` Extracts Structured Commands

The CLI calls `parseArgs()` from [`cli/src/cli-args.ts`](https://github.com/CodebuffAI/freebuff/blob/main/cli/src/cli-args.ts) to transform raw `process.argv` into a typed command object:

```ts
// cli/src/index.tsx (simplified)
const args = parseArgs(process.argv)  // Returns { command, agent, initialPrompt, ... }

```

This function recognizes flags such as `--login`, `--publish`, `--clear-logs`, and positional arguments for agent names or prompts.

### Phase 2: Early Command Shortcuts

Before any UI renders, [`index.tsx`](https://github.com/CodebuffAI/freebuff/blob/main/index.tsx) inspects `args.command` and executes matching handlers immediately:

| Command | Condition | Handler | Exit Behavior |
|---------|-----------|---------|---------------|
| **Login** | `command === 'login'` | `runPlainLogin()` from [`cli/src/login/plain-login.ts`](https://github.com/CodebuffAI/freebuff/blob/main/cli/src/login/plain-login.ts) | Exits after authentication |
| **Publish** | `command === 'publish'` | `handlePublish()` from [`cli/src/commands/publish.ts`](https://github.com/CodebuffAI/freebuff/blob/main/cli/src/commands/publish.ts) | Exits with success/failure summary |
| **Clear logs** | `--clear-logs` flag | `clearLogFile()` | Continues to TUI (unless combined with other commands) |

**Login dispatch** (lines 17-30 in [`index.tsx`](https://github.com/CodebuffAI/freebuff/blob/main/index.tsx)):

```ts
// cli/src/index.tsx
if (args.command === 'login') {
  await runPlainLogin();
  process.exit(0);
}

```

**Publish dispatch** (lines 66-88):

```ts
// cli/src/index.tsx
if (args.command === 'publish') {
  const results = await handlePublish(args.agents);
  printPublishSummary(results);
  process.exit(results.success ? 0 : 1);
}

```

**Clear logs execution** (lines 91-94):

```ts
// cli/src/index.tsx
if (args.clearLogs) {
  await clearLogFile();
}

```

These shortcuts bypass the full application initialization—no React root, no agent registry, no TUI rendering—yielding fast, predictable behavior for automation and scripting.

### Phase 3: TUI Initialization for Default Mode

If no early command matches, [`index.tsx`](https://github.com/CodebuffAI/freebuff/blob/main/index.tsx) proceeds through:

1. **Analytics setup** – telemetry initialization
2. **Project loading** – workspace and configuration discovery
3. **Agent registry initialization** – skill loading and validation
4. **OpenTUI renderer creation** – `createCliRenderer()` plus React root mount

```ts
// cli/src/index.tsx (conceptual)
const renderer = createCliRenderer();
const root = createRoot(renderer.container);
root.render(<App initialPrompt={args.initialPrompt} agent={args.agent} />);

```

This is the path taken when users run `freebuff` with no arguments or with only UI-relevant flags.

## Practical Command Examples

Here is how common invocations flow through the dispatch system:

```bash

# Default: Launch interactive TUI

# Path: entry.ts → index.tsx → parseArgs() → TUI initialization

freebuff

# Login: Direct handler, no TUI

# Path: entry.ts → index.tsx → parseArgs() → runPlainLogin() → exit

freebuff --login

# Publish: Batch agent deployment with result summary

# Path: entry.ts → index.tsx → parseArgs() → handlePublish() → exit

freebuff publish my-agent another-agent

# Clear logs: Utility flag, then TUI

# Path: entry.ts → index.tsx → parseArgs() → clearLogFile() → TUI initialization

freebuff --clear-logs

```

## Key Files in the Dispatch Chain

| File | Purpose | Critical Functions |
|------|---------|-------------------|
| [`cli/src/entry.ts`](https://github.com/CodebuffAI/freebuff/blob/main/cli/src/entry.ts) | Broker detection and initial branch | `isTerminalCommandBrokerInvocation()`, `serveTerminalCommandBroker()` |
| [`cli/src/index.tsx`](https://github.com/CodebuffAI/freebuff/blob/main/cli/src/index.tsx) | Central dispatcher and TUI launcher | `parseArgs()`, conditional command handlers, React root creation |
| [`cli/src/cli-args.ts`](https://github.com/CodebuffAI/freebuff/blob/main/cli/src/cli-args.ts) | Argument parsing logic | `parseArgs()` |
| [`cli/src/commands/publish.ts`](https://github.com/CodebuffAI/freebuff/blob/main/cli/src/commands/publish.ts) | Publish command implementation | `handlePublish()` |
| [`cli/src/login/plain-login.ts`](https://github.com/CodebuffAI/freebuff/blob/main/cli/src/login/plain-login.ts) | Login command implementation | `runPlainLogin()` |

## Summary

- **Two-stage dispatch**: [`entry.ts`](https://github.com/CodebuffAI/freebuff/blob/main/entry.ts) selects broker or normal mode; [`index.tsx`](https://github.com/CodebuffAI/freebuff/blob/main/index.tsx) handles all normal CLI routing.
- **Conditional shortcuts**: `login`, `publish`, and `--clear-logs` execute dedicated handlers and exit before TUI costs are paid.
- **Parser separation**: `parseArgs()` in [`cli/src/cli-args.ts`](https://github.com/CodebuffAI/freebuff/blob/main/cli/src/cli-args.ts) isolates argument logic from dispatch decisions.
- **Dynamic import**: The entry script uses `import('./index')` to defer loading the full CLI stack until confirmed necessary.

## Frequently Asked Questions

### What happens if I run `freebuff` with both `--login` and `--publish`?

The Freebuff CLI evaluates commands in a fixed precedence order within [`cli/src/index.tsx`](https://github.com/CodebuffAI/freebuff/blob/main/cli/src/index.tsx). `login` is checked first, so it would execute and exit before `publish` is considered. For atomic multi-command sequences, invoke the CLI separately for each operation.

### Why does the entry point use a dynamic import for the normal CLI path?

Dynamic `import('./index')` prevents the Node.js loader from parsing and executing [`cli/src/index.tsx`](https://github.com/CodebuffAI/freebuff/blob/main/cli/src/index.tsx) and its dependency tree when running in terminal-command-broker mode. This keeps broker process startup fast and memory-light, as brokers never need React or TUI components.

### Where is the `isTerminalCommandBrokerInvocation` check implemented?

The detection logic resides in [`cli/src/entry.ts`](https://github.com/CodebuffAI/freebuff/blob/main/cli/src/entry.ts) alongside the entry script itself. The function inspects `process.argv` for broker-specific signatures—typically a hidden flag or process title set by the parent UI process when spawning isolated command executors.

### Can I add custom commands to the Freebuff dispatch chain?

The current architecture in [`cli/src/index.tsx`](https://github.com/CodebuffAI/freebuff/blob/main/cli/src/index.tsx) uses hardcoded conditional checks against `args.command`. Adding custom commands would require modifying this file to include a new handler import, a new conditional branch, and appropriate exit logic—similar to how `login` and `publish` are implemented.