# How to Use Goose's External Editor Mode for Composing Prompts

> Learn how to use Goose's external editor mode to compose prompts efficiently. Configure your favorite editor like vim or VS Code for enhanced prompt writing.

- Repository: [Block Open Source/goose](https://github.com/block/goose)
- Tags: how-to-guide
- Published: 2026-04-05

---

**To use external editor mode in Goose, set the `GOOSE_PROMPT_EDITOR` environment variable or configuration key to your preferred editor (e.g., `vim` or `code --wait`), and Goose will open a temporary markdown file for each prompt instead of using the built-in REPL line editor.**

The Goose CLI from block/goose supports an **external editor mode** that replaces the default line-based input with a full-featured text editor workflow. When enabled, Goose orchestrates a round-trip pipeline that creates a temporary markdown template, launches your configured editor, and extracts only your newly typed content while preserving conversation context. This allows you to compose complex prompts, code snippets, or multi-line instructions in familiar editing environments like vim, nano, or VS Code.

## How External Editor Mode Works

According to the block/goose source code, enabling external editor mode triggers a six-step pipeline for every user turn. The implementation spans [`crates/goose-cli/src/session/input.rs`](https://github.com/block/goose/blob/main/crates/goose-cli/src/session/input.rs) and [`crates/goose-cli/src/session/editor.rs`](https://github.com/block/goose/blob/main/crates/goose-cli/src/session/editor.rs), with configuration defined in [`crates/goose/src/config/base.rs`](https://github.com/block/goose/blob/main/crates/goose/src/config/base.rs).

### Step 1: Detecting the Editor Configuration

When the session loop needs input, [`input.rs`](https://github.com/block/goose/blob/main/input.rs) checks for the `GOOSE_PROMPT_EDITOR` key using `config.get_goose_prompt_editor()` (lines 95–100). This method queries both the environment variable and the user configuration file, returning an `Option<String>` that determines whether to invoke external editor mode or fall back to the built-in readline implementation.

### Step 2: Creating the Markdown Template

If an editor is configured, `editor.rs::create_temp_file` generates a temporary markdown file containing:
- A title (`# Goose Prompt Editor`)

- A `# Your prompt:` section where you type your message

- A `# Recent conversation for context` section with the newest messages first (lines 9–24)

This template ensures you always see the latest exchange while drafting your next prompt.

### Step 3: Launching the Editor via Symlink

To provide a stable path for editors that require specific file extensions or locations, Goose creates a symlink named **[`.goose_prompt_temp.md`](https://github.com/block/goose/blob/main/.goose_prompt_temp.md)** pointing to the temporary file. The `SymlinkCleanup` RAII guard in [`editor.rs`](https://github.com/block/goose/blob/main/editor.rs) (lines 31–48) ensures this symlink is removed even if Goose panics or crashes.

The `launch_editor` function (lines 49–68) then constructs a `std::process::Command` from your configured editor string, passes the symlink path as an argument, and inherits stdio so the editor runs interactively.

### Step 4: Extracting the User Input

After the editor process exits, Goose reads the file back and calls `extract_user_input` (lines 27–34, 56–60) to trim away the template. This function keeps only the text appearing after the `# Your prompt:` heading, discarding the conversation history and boilerplate. If the remaining text is non-empty, `get_editor_input` returns it as the prompt; otherwise, Goose falls back to the normal line editor (lines 101–107 in [`input.rs`](https://github.com/block/goose/blob/main/input.rs)).

## Configuring the External Editor

You can specify your editor via environment variable for temporary sessions or via configuration file for persistent settings.

### Environment Variable (Session-Only)

Set `GOOSE_PROMPT_EDITOR` before starting Goose:

```bash

# Use vim for this session

export GOOSE_PROMPT_EDITOR=vim

# Or use VS Code (requires --wait to block until window closes)

export GOOSE_PROMPT_EDITOR="code --wait"

```

### Configuration File (Persistent)

Add the key to `~/.config/goose/config.yaml`:

```yaml
GOOSE_PROMPT_EDITOR: nano

```

The configuration system uses the `config_value!` macro in [`crates/goose/src/config/base.rs`](https://github.com/block/goose/blob/main/crates/goose/src/config/base.rs) (lines 60–61) to store this as an `Option<String>`. Environment variables override file settings.

### Important: GUI Editor Requirements

For graphical editors like VS Code or Sublime Text, you must include a `--wait` (or equivalent) flag. Terminal editors like `vim` or `nano` block the terminal automatically, but GUI editors return immediately unless told to wait. Without this flag, Goose will read the file before you finish editing.

## Practical Examples

### Using vim for a Single Session

```bash
export GOOSE_PROMPT_EDITOR=vim
goose session

```

When prompted, vim opens a file resembling:

```markdown

# Goose Prompt Editor

# Your prompt:

# Recent conversation for context (newest first):

## User: How do I list files?

## Assistant: You can use `ls -la`.

```

Type your message under `# Your prompt:`, save and quit. Goose extracts your input and continues the conversation.

### Using VS Code Persistently

Edit `~/.config/goose/config.yaml`:

```yaml
GOOSE_PROMPT_EDITOR: "code --wait"

```

All future sessions open VS Code for prompt composition. The `--wait` flag ensures Goose pauses until you close the editor window.

### Programmatic Usage (for Developers)

To invoke the editor logic directly in Rust code:

```rust
use goose_cli::session::editor::get_editor_input;

let recent = vec!["## Assistant: Sure!", "## User: List files?"];

let (prompt, ok) = get_editor_input("vim", &recent)?;
if ok {
    println!("Captured prompt: {}", prompt);
}

```

This opens the configured editor with the provided conversation history and returns the extracted user input.

## Summary

- **External editor mode** in Goose swaps the REPL line editor for any text editor by setting `GOOSE_PROMPT_EDITOR`.
- The workflow creates a temporary markdown template with conversation context, launches your editor via a stable symlink ([`.goose_prompt_temp.md`](https://github.com/block/goose/blob/main/.goose_prompt_temp.md)), and extracts content from the `# Your prompt:` section.

- Configure via environment variable for one-off sessions or `~/.config/goose/config.yaml` for permanent defaults.
- GUI editors require a `--wait` flag; terminal editors block automatically.
- Key implementation files: [`crates/goose-cli/src/session/editor.rs`](https://github.com/block/goose/blob/main/crates/goose-cli/src/session/editor.rs) (orchestration), [`crates/goose-cli/src/session/input.rs`](https://github.com/block/goose/blob/main/crates/goose-cli/src/session/input.rs) (detection), and [`crates/goose/src/config/base.rs`](https://github.com/block/goose/blob/main/crates/goose/src/config/base.rs) (configuration).

## Frequently Asked Questions

### What file format does Goose use for the external editor template?

Goose generates a temporary markdown file containing specific headings. The template includes `# Goose Prompt Editor` as a title, `# Your prompt:` where you type your input, and `# Recent conversation for context` with the latest messages injected for reference. After you save and close the editor, Goose parses this markdown to extract only the text under the prompt heading.

### How do I use VS Code with Goose's external editor mode?

Set `GOOSE_PROMPT_EDITOR` to `code --wait` (including the quotes if your shell requires them). The `--wait` flag is mandatory because VS Code launches as a background process by default; the flag forces the CLI to block until you close the editor window, allowing Goose to read your changes. Without this flag, Goose would read an empty file immediately.

### Where does Goose store the external editor configuration?

Goose stores the `GOOSE_PROMPT_EDITOR` key in the user configuration file at `~/.config/goose/config.yaml`, or temporarily via the `GOOSE_PROMPT_EDITOR` environment variable. The configuration is defined in [`crates/goose/src/config/base.rs`](https://github.com/block/goose/blob/main/crates/goose/src/config/base.rs) using a `config_value!` macro, and the resolution logic in [`input.rs`](https://github.com/block/goose/blob/main/input.rs) checks the environment variable first, then the config file, then falls back to the built-in line editor if neither is set.

### What happens if I save the external editor file without typing anything?

If you save the file but leave the section under `# Your prompt:` empty, Goose detects this condition via `get_editor_input` and returns a flag indicating the content is not meaningful. In this case, Goose automatically falls back to the normal line-based REPL flow, allowing you to enter a prompt directly in the terminal instead.