# How RTK Handles config.toml Configuration for Hooks and Tee

> Learn how RTK uses config.toml to manage hook exclusions and tee file options, ensuring flexible and safe default configurations for your projects.

- Repository: [rtk-ai/rtk](https://github.com/rtk-ai/rtk)
- Tags: how-to-guide
- Published: 2026-04-24

---

**RTK reads user settings from a per-user [`config.toml`](https://github.com/rtk-ai/rtk/blob/main/config.toml) file and loads them into a `Config` struct that controls hook exclusions and tee file behavior, falling back to safe defaults when the file is absent.**

RTK (from the `rtk-ai/rtk` repository) stores runtime customization in a TOML configuration file. Understanding how the tool parses this file for the **hooks** and **tee** sections allows you to control which commands get rewritten and when raw output gets persisted to disk.

## Configuration File Location and Structure

RTK looks for [`config.toml`](https://github.com/rtk-ai/rtk/blob/main/config.toml) in standard user configuration directories: `~/.config/rtk/config.toml` on Linux and `~/Library/Application Support/rtk/config.toml` on macOS.

The configuration maps to a `Config` struct defined in [`src/core/config.rs`](https://github.com/rtk-ai/rtk/blob/main/src/core/config.rs), which contains two primary sub-structures:

- **`HooksConfig`**: Controls command exclusion patterns for the rewrite engine
- **`TeeConfig`**: Defines when and how command output is written to log files

If the configuration file does not exist, `Config::default()` initializes both sections with compiled-in defaults, ensuring the program always runs with a valid configuration.

## Loading the Configuration

The `Config::load()` function in [`src/core/config.rs`](https://github.com/rtk-ai/rtk/blob/main/src/core/config.rs) handles file detection and deserialization:

```rust
// src/core/config.rs
pub fn load() -> Result<Self> {
    let path = get_config_path()?;
    if path.exists() {
        let content = std::fs::read_to_string(&path)?;
        let config: Config = toml::from_str(&content)?;
        Ok(config)
    } else {
        Ok(Config::default())
    }
}

```

This implementation guarantees that RTK always has a valid configuration object. If [`config.toml`](https://github.com/rtk-ai/rtk/blob/main/config.toml) is missing or unreadable, the binary continues using default values.

## Configuring Hooks with exclude_commands

### How Hook Exclusions Work

The `HooksConfig` struct contains a single user-customizable field: `exclude_commands: Vec<String>`. This vector stores command patterns that the hook engine must never rewrite.

In [`src/hooks/rewrite_cmd.rs`](https://github.com/rtk-ai/rtk/blob/main/src/hooks/rewrite_cmd.rs), the rewrite pipeline loads these exclusions once per execution:

```rust
// src/hooks/rewrite_cmd.rs
let excluded = crate::core::config::Config::load()
    .map(|c| c.hooks.exclude_commands)
    .unwrap_or_default();

```

The `excluded` vector passes to the rewrite registry in [`src/discover/registry.rs`](https://github.com/rtk-ai/rtk/blob/main/src/discover/registry.rs). If a command matches any pattern in this list, the registry skips rewriting and executes the original command unchanged.

### Example: Adding Hook Exclusions

To prevent RTK from rewriting specific commands, add them to the `hooks` section:

```toml

# ~/.config/rtk/config.toml

[hooks]
exclude_commands = [
    "curl",
    "git push",
    "^npm install$",
]

```

This configuration ensures that invocations like `curl http://example.com` execute without modification.

## Configuring Tee Output Logging

### TeeConfig Fields and Defaults

The `TeeConfig` struct in [`src/core/tee.rs`](https://github.com/rtk-ai/rtk/blob/main/src/core/tee.rs) defines raw output capture behavior:

```rust
// src/core/tee.rs
pub struct TeeConfig {
    pub enabled: bool,
    pub mode: TeeMode,
    pub max_files: usize,
    pub max_file_size: usize,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub directory: Option<PathBuf>,
}

```

Default values initialize via `TeeConfig::default()`:

- `enabled`: `true`
- `mode`: `TeeMode::Failures` (writes files only when exit code is non-zero)
- `max_files`: `20`
- `max_file_size`: `1` MiB
- `directory`: `None` (uses runtime data directory)

### The Tee Decision Logic

The `should_tee` function in [`src/core/tee.rs`](https://github.com/rtk-ai/rtk/blob/main/src/core/tee.rs) implements the filtering logic:

```rust
// src/core/tee.rs
fn should_tee(
    config: &TeeConfig,
    raw_len: usize,
    exit_code: i32,
    tee_dir: Option<PathBuf>,
) -> Option<PathBuf> {
    if !config.enabled { return None; }

    match config.mode {
        TeeMode::Never => return None,
        TeeMode::Failures => {
            if exit_code == 0 { return None; }
        }
        TeeMode::Always => {}
    }

    if raw_len < MIN_TEE_SIZE { return None; }

    tee_dir
}

```

`MIN_TEE_SIZE` represents approximately 500 bytes. Files smaller than this threshold are not written regardless of other settings.

### Example: Customizing Tee Behavior

To capture all command output regardless of exit status:

```toml

# ~/.config/rtk/config.toml

[tee]
enabled = true
mode = "always"
max_files = 10
max_file_size = 2000000
directory = "/tmp/rtk_tee"

```

This writes every command output exceeding `MIN_TEE_SIZE` to `/tmp/rtk_tee`, rotating files when the count exceeds 10.

## Runtime Environment Overrides

Users can disable tee output at runtime without editing [`config.toml`](https://github.com/rtk-ai/rtk/blob/main/config.toml). The `tee_raw` function checks the `RTK_TEE` environment variable:

```rust
// src/core/tee.rs
pub fn tee_raw(raw: &str, command_slug: &str, exit_code: i32) -> Option<PathBuf> {
    if std::env::var("RTK_TEE").ok().as_deref() == Some("0") { return None; }
    let config = Config::load().ok()?;
    // ... subsequent logic
}

```

Setting `RTK_TEE=0` short-circuits the tee operation, useful for CI environments where disk writes should be avoided.

## Summary

- **RTK** loads [`config.toml`](https://github.com/rtk-ai/rtk/blob/main/config.toml) from platform-specific user configuration directories at startup, using `Config::load()` in [`src/core/config.rs`](https://github.com/rtk-ai/rtk/blob/main/src/core/config.rs).
- **Hooks** configuration allows command exclusion via the `exclude_commands` vector, which the rewrite registry in [`src/discover/registry.rs`](https://github.com/rtk-ai/rtk/blob/main/src/discover/registry.rs) checks before modifying commands.
- **Tee** configuration controls raw output logging through `TeeConfig`, with defaults enabling failure-only capture up to 1 MiB per file and 20 files total.
- **Environment variables** like `RTK_TEE=0` override tee settings at runtime without file modification.

## Frequently Asked Questions

### How do I stop RTK from rewriting specific commands?

Add the command patterns to the `exclude_commands` array under the `[hooks]` section in your [`config.toml`](https://github.com/rtk-ai/rtk/blob/main/config.toml). Patterns support regex syntax, and matching commands execute without modification by the hook engine.

### What happens if I delete my config.toml file?

RTK falls back to compiled defaults via `Config::default()`. Hooks will have no exclusions, and tee will remain enabled in Failures mode with 20 files of 1 MiB each stored in the default data directory.

### Can I disable tee logging temporarily without editing the configuration file?

Yes. Set the environment variable `RTK_TEE=0` before running RTK. This overrides the [`config.toml`](https://github.com/rtk-ai/rtk/blob/main/config.toml) setting and prevents any tee file writes for that session.

### Where does RTK store tee files by default?

When the `directory` field is `None`, RTK stores tee files in the platform-specific runtime data directory. On Linux, this typically resides under `~/.local/share/rtk/`.