# How to Configure Lieutenant Backend and Override Options in SwarmForge

> Learn to configure SwarmForge Lieutenant backend and override options. Master SwarmForge settings via config files or environment variables for efficient AI management.

- Repository: [Robert C. Martin/swarm-forge](https://github.com/unclebob/swarm-forge)
- Tags: how-to-guide
- Published: 2026-09-01

---

**TL;DR:** SwarmForge configures the lieutenant AI backend through a line-based config file at [`swarmforge/swarmforge.conf`](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/swarmforge.conf), falling back to the `SWARMFORGE_LIEUTENANT_AGENT` environment variable or defaulting to `grok` if neither is set.

SwarmForge uses a lightweight configuration system to determine which AI backend powers the **lieutenant** role. According to the unclebob/swarm-forge source code, this configuration is handled by the `parse-lieutenant-config` function in `swarmforge/scripts/swarmforge.bb` (lines 887-904). Understanding how to configure the lieutenant backend and override its options lets you switch between agents like **grok**, **claude**, or **codex** without modifying the core codebase.

## Configuration File Location and Format

SwarmForge reads lieutenant settings from **[`swarmforge/swarmforge.conf`](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/swarmforge.conf)** at startup. This file uses a simple line-based format:

- Comment lines start with `#` or are blank
- Active configuration lines contain space-separated fields
- The `lieutenant` keyword (case-insensitive) triggers backend selection

A valid `lieutenant` line requires at least two fields:

```

Lieutenant <agent-name> [extra-args...]

```

- **Field 1:** The literal word `lieutenant`
- **Field 2:** The agent name (validated against `known-agents`)
- **Field 3+:** Optional arguments passed verbatim to the agent

Example configuration:

```text

# swarmforge/swarmforge.conf

Lieutenant claude --temperature 0.7 --max-tokens 1024

```

## Priority of Configuration Methods

SwarmForge resolves the lieutenant backend through a three-tier fallback system:

| Priority | Method | When Applied |
|:---------|:-------|:-------------|
| **1 (Highest)** | [`swarmforge.conf`](https://github.com/unclebob/swarm-forge/blob/main/swarmforge.conf) `lieutenant` line | Used whenever present and valid |
| **2** | `SWARMFORGE_LIEUTENANT_AGENT` environment variable | Used when config file lacks a `lieutenant` line |
| **3 (Lowest)** | Default agent `grok` | Used when neither config nor env-var is set |

### Method 1: Edit swarmforge.conf

Add or modify the `lieutenant` line directly in your configuration file:

```text

# swarmforge/swarmforge.conf

Lieutenant codex --verbose

```

This takes precedence over all other methods.

### Method 2: Environment Variable Override

Export `SWARMFORGE_LIEUTENANT_AGENT` before running SwarmForge:

```bash
export SWARMFORGE_LIEUTENANT_AGENT=claude
./swarm

```

The environment variable **only** applies when [`swarmforge.conf`](https://github.com/unclebob/swarm-forge/blob/main/swarmforge.conf) contains no `lieutenant` line.

### Method 3: Default Behavior

With no configuration, SwarmForge launches:

```clojure
{:agent "grok" :extra-args nil}

```

## Code Flow: How Configuration Becomes Execution

The lieutenant backend selection follows this execution path in `swarmforge/scripts/swarmforge.bb`:

1. **`run-host!`** or **`run-project!`** builds the context `ctx`
2. **`lieutenant-row`** calls `parse-lieutenant-config` with `ctx`
3. **`parse-lieutenant-config`** returns a map `{:agent "..." :extra-args "..."}`
4. **`window-row`** constructs a tmux session specification using these values
5. **`launch-command`** spawns the lieutenant pane with the final agent command

The `parse-lieutenant-config` function implements the full fallback logic:

```clojure
;; swarmforge/scripts/swarmforge.bb (lines 887-904)
(defn parse-lieutenant-config [ctx]
  (let [file (:config-file ctx)
        fallback (str/lower-case 
                  (or (not-empty (System/getenv "SWARMFORGE_LIEUTENANT_AGENT")) 
                      "grok"))]
    (if-not (fs/regular-file? file)
      {:agent fallback :extra-args nil}
      (or (some (fn [raw]
                  (let [line (str/trim raw)]
                    (when-not (skip-config-line? line)
                      (let [fields (str/split line #"\s+")]
                        (when (and (>= (count fields) 2)
                                   (= (str/lower-case (first fields)) "lieutenant"))
                          (let [agent (str/lower-case (second fields))]
                            (reject-if (not (known-agents agent))
                                       (str "Unsupported agent '" (second fields)
                                            "' for lieutenant"))
                            {:agent agent
                             :extra-args (extra-args-str (drop 2 fields))}))))))
                (str/split-lines (slurp (str file))))
          {:agent fallback :extra-args nil}))))

```

Key behaviors in this implementation:

- **Agent validation:** Unknown agents trigger an error via `reject-if` against the `known-agents` whitelist
- **Case insensitivity:** Both `LIEUTENANT` and `lieutenant` are valid
- **Extra args preservation:** All fields after the agent name are joined and passed through `extra-args-str`

## Practical Configuration Examples

### Default grok with No Configuration

```text

# swarmforge/swarmforge.conf

# (no lieutenant line)

```

Result: Lieutenant launches with `grok` and no extra arguments.

### Claude with Temperature Control

```text

# swarmforge/swarmforge.conf

Lieutenant claude --temperature 0.7 --max-tokens 1024

```

Result: The tmux pane executes approximately:

```bash
claude --temperature 0.7 --max-tokens 1024 ...

```

### Environment Override for Temporary Switching

```bash

# Ensure no lieutenant line in swarmforge.conf

export SWARMFORGE_LIEUTENANT_AGENT=codex
./swarm my-project

```

Result: Uses `codex` without modifying configuration files.

### Combined Documentation and Active Config

```text

# swarmforge/swarmforge.conf

# Development: use claude with relaxed constraints

Lieutenant claude --thought

# Production (commented out):

# Lieutenant grok --strict

```

## Key Files Reference

| File | Purpose | Location in Repository |
|:-----|:--------|:-----------------------|
| [`swarmforge/swarmforge.conf`](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/swarmforge.conf) | User-editable configuration with optional `lieutenant` line | [[`swarmforge/swarmforge.conf`](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/swarmforge.conf)](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/swarmforge.conf) |
| `swarmforge/scripts/swarmforge.bb` | Core script containing `parse-lieutenant-config` and launch logic | [`swarmforge/scripts/swarmforge.bb`](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/scripts/swarmforge.bb) |
| `swarmforge/roles/lieutenant.prompt` | Prompt template read by the lieutenant at session start | [`swarmforge/roles/lieutenant.prompt`](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/roles/lieutenant.prompt) |

## Summary

- **Primary configuration** happens in [`swarmforge/swarmforge.conf`](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/swarmforge.conf) using a `lieutenant <agent> [args...]` line format
- **Environment variable** `SWARMFORGE_LIEUTENANT_AGENT` serves as fallback when no config line exists
- **Default agent** is `grok` when neither source provides a value
- The `parse-lieutenant-config` function in `swarmforge.bb` enforces agent validation against `known-agents`
- Extra arguments pass through verbatim to the agent command, enabling backend-specific tuning

## Frequently Asked Questions

### What happens if I specify an unsupported agent in swarmforge.conf?

SwarmForge validates the agent name against a whitelist (`known-agents`). If you specify an unknown agent, `parse-lieutenant-config` calls `reject-if` and throws an error with the message `"Unsupported agent '<name>' for lieutenant"`. The session will not start until you correct the configuration.

### Can I use multiple lieutenant configurations for different projects?

The current implementation uses a single global configuration file at [`swarmforge/swarmforge.conf`](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/swarmforge.conf). For per-project overrides, use the `SWARMFORGE_LIEUTENANT_AGENT` environment variable in project-specific wrapper scripts, or maintain separate config files and symlink them before running `./swarm`.

### Why does my environment variable not take effect?

The `SWARMFORGE_LIEUTENANT_AGENT` variable only applies when [`swarmforge.conf`](https://github.com/unclebob/swarm-forge/blob/main/swarmforge.conf) contains **no** `lieutenant` line. Check that your config file does not have an active `lieutenant` entry, as explicit configuration always wins over environment variables according to the priority rules in `parse-lieutenant-config`.