How RTK Handles config.toml Configuration for Hooks and Tee

RTK reads user settings from a per-user 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 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, 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 handles file detection and deserialization:

// 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 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, the rewrite pipeline loads these exclusions once per execution:

// 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. 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:


# ~/.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 defines raw output capture behavior:

// 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 implements the filtering logic:

// 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:


# ~/.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. The tee_raw function checks the RTK_TEE environment variable:

// 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 from platform-specific user configuration directories at startup, using Config::load() in src/core/config.rs.
  • Hooks configuration allows command exclusion via the exclude_commands vector, which the rewrite registry in 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. 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 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/.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →