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 engineTeeConfig: 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:truemode:TeeMode::Failures(writes files only when exit code is non-zero)max_files:20max_file_size:1MiBdirectory: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.tomlfrom platform-specific user configuration directories at startup, usingConfig::load()insrc/core/config.rs. - Hooks configuration allows command exclusion via the
exclude_commandsvector, which the rewrite registry insrc/discover/registry.rschecks 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=0override 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →