# DeepSeek TUI Exec Policy Engine: How Tool Execution Decisions Are Made

> Understand DeepSeek TUI exec policy engine tool execution decisions. Learn how it evaluates shell commands against allow deny rules in three stages to ensure safe tool use.

- Repository: [Hunter Bown/DeepSeek-TUI](https://github.com/Hmbown/DeepSeek-TUI)
- Tags: internals
- Published: 2026-05-04

---

**The DeepSeek TUI Exec Policy engine evaluates shell commands against user-defined allow/deny rules in three stages—loading the policy, normalizing the command, and pattern matching—to return an Allow, Deny, or AskUser decision before any external tool executes.**

The DeepSeek TUI employs a stateless **Exec Policy engine** to prevent accidental execution of dangerous commands. According to the `Hmbown/DeepSeek-TUI` source code, this gatekeeper intercepts every tool invocation—from shell commands to Git hooks—and validates them against configurable [`execpolicy.toml`](https://github.com/Hmbown/DeepSeek-TUI/blob/main/execpolicy.toml) rules stored in `~/.deepseek/execpolicy.toml`.

## How the Exec Policy Engine Works

The engine operates as a pure function that transforms a command string into an `ExecPolicyDecision`. It processes each request through three distinct phases implemented across the `execpolicy` crate.

### Loading the Policy Configuration

The process begins in [`crates/tui/src/execpolicy/rules.rs`](https://github.com/Hmbown/DeepSeek-TUI/blob/main/crates/tui/src/execpolicy/rules.rs), where the `load_default_policy` function reads the TOML configuration and returns an `ExecPolicyConfig` struct. This structure holds a map of rule groups (e.g., `[git]`, `[danger]`) to their associated allow and deny pattern vectors.

```rust
// From rules.rs lines 67-78
pub fn load_default_policy() -> Result<Option<ExecPolicyConfig>, ExecPolicyError> {
    // Checks ~/.deepseek/execpolicy.toml by default
    // Returns Ok(None) if file doesn't exist, Ok(Some(cfg)) if parsed
}

```

### Normalizing Commands for Comparison

Before pattern matching occurs, the engine normalizes the raw command string to eliminate superficial differences. The `normalize_command` function in [`crates/tui/src/execpolicy/matcher.rs`](https://github.com/Hmbown/DeepSeek-TUI/blob/main/crates/tui/src/execpolicy/matcher.rs) (lines 5-23) performs three operations:

1. **Strips heredoc bodies** via `strip_heredoc_bodies` (lines 25-99) to remove content between `<<EOF` markers
2. **Tokenizes** the command using *shlex* to handle quoted strings correctly
3. **Collapses whitespace** to ensure `cat > file.txt` matches `cat  >  file.txt`

This guarantees that a rule pattern like `cat > file.txt` successfully matches a heredoc invocation such as `cat <<EOF > file.txt … EOF`.

### Pattern Matching and Decision Logic

The `evaluate` method in [`rules.rs`](https://github.com/Hmbown/DeepSeek-TUI/blob/main/rules.rs) (lines 43-63) implements the decision hierarchy:

1. **Check deny patterns first**—if any deny wildcard matches, return `ExecPolicyDecision::Deny(msg)`
2. **Check allow patterns**—if any allow wildcard matches, return `ExecPolicyDecision::Allow`
3. **Fallback to AskUser**—if no rules match, return `ExecPolicyDecision::AskUser(msg)` to trigger a UI confirmation dialog

The `pattern_matches` function in [`matcher.rs`](https://github.com/Hmbown/DeepSeek-TUI/blob/main/matcher.rs) (lines 2-18) converts glob wildcards (`*`) to `.*` regex fragments for flexible matching against normalized commands.

## Configuring Execution Policies

Users define rules in TOML rule groups. The engine evaluates deny lists before allow lists within each group.

```toml

# ~/.deepseek/execpolicy.toml

[git]
allow = ["git status", "git log *"]
deny  = ["git push --force"]

[danger]
allow = []
deny  = ["rm -rf /"]

```

## Programmatic Usage Examples

You can invoke the policy engine directly from Rust code to evaluate commands before execution.

```rust
use deepseek_execpolicy::{ExecPolicyEngine, ExecPolicyDecision};

fn decide(command: &str) -> ExecPolicyDecision {
    // Load the default policy (if any)
    let policy = deepseek_execpolicy::load_default_policy()
        .expect("policy load failed")
        .unwrap_or_default();

    // Evaluate the command against the loaded policy
    policy.evaluate(command)
}

// Example usage
match decide("git push --force") {
    ExecPolicyDecision::Allow => println!("✅ allowed"),
    ExecPolicyDecision::Deny(msg) => println!("⛔ denied: {}", msg),
    ExecPolicyDecision::AskUser(msg) => println!("❓ ask user: {}", msg),
}

```

## Integration with TUI Tools

The built-in shell tool demonstrates real-time integration. In [`crates/tui/src/tools/shell.rs`](https://github.com/Hmbown/DeepSeek-TUI/blob/main/crates/tui/src/tools/shell.rs), the tool constructs an `ExecPolicyCheckCommand` and evaluates the command before spawning the process:

```rust
// Simplified from shell.rs around line 1554
let decision = execpolicy::load_default_policy()?
    .map(|cfg| cfg.evaluate(&command))
    .unwrap_or(ExecPolicyDecision::AskUser(
        "no execpolicy loaded".into(),
    ));

match decision {
    ExecPolicyDecision::Allow => run_the_command(),
    ExecPolicyDecision::Deny(reason) => return Err(ToolError::Denied(reason)),
    ExecPolicyDecision::AskUser(prompt) => {
        // Store decision for UI rendering and user confirmation
        execpolicy_decision = Some(decision.clone());
    }
}

```

The `ExecPolicyCheckCommand` struct in [`execpolicycheck.rs`](https://github.com/Hmbown/DeepSeek-TUI/blob/main/execpolicycheck.rs) provides the CLI-style interface that bridges the engine with the TUI event loop.

## Summary

- **Three-stage pipeline**: The engine loads TOML rules from `~/.deepseek/execpolicy.toml`, normalizes commands via [`matcher.rs`](https://github.com/Hmbown/DeepSeek-TUI/blob/main/matcher.rs), and evaluates them through `rules.rs::evaluate`.
- **Deny-first logic**: Patterns in deny lists take precedence over allow lists; unmatched commands trigger `AskUser` prompts rather than defaulting to allow.
- **Stateless design**: The engine can be invoked repeatedly with different configurations, making it safe for sub-agents and session compaction.
- **Heredoc awareness**: The `strip_heredoc_bodies` function ensures that verbose shell heredocs match simple rule patterns after normalization.

## Frequently Asked Questions

### Where does DeepSeek TUI store the default execution policy file?

By default, the engine looks for `~/.deepseek/execpolicy.toml`. The `load_default_policy` function in [`crates/tui/src/execpolicy/rules.rs`](https://github.com/Hmbown/DeepSeek-TUI/blob/main/crates/tui/src/execpolicy/rules.rs) handles this path resolution, returning `Ok(None)` if the file does not exist rather than failing.

### How does the Exec Policy engine handle shell heredocs in commands?

The `normalize_command` function in [`crates/tui/src/execpolicy/matcher.rs`](https://github.com/Hmbown/DeepSeek-TUI/blob/main/crates/tui/src/execpolicy/matcher.rs) strips heredoc bodies via `strip_heredoc_bodies` (lines 25-99), tokenizes the remaining command with *shlex*, and collapses whitespace. This ensures that `cat <<EOF > file.txt … EOF` normalizes to match a rule like `cat > file.txt`.

### What happens if a command doesn't match any allow or deny rules?

When no patterns match, the `evaluate` method returns `ExecPolicyDecision::AskUser(msg)`, prompting the TUI to display a confirmation dialog. This deny-by-default approach prevents accidental execution of unvetted commands.

### Can the policy engine be used outside the TUI for other Rust applications?

Yes. The [`crates/execpolicy/src/lib.rs`](https://github.com/Hmbown/DeepSeek-TUI/blob/main/crates/execpolicy/src/lib.rs) re-exports the public API including `ExecPolicyEngine`, `ExecPolicyDecision`, and helper functions. The engine is deliberately stateless and has no TUI dependencies, allowing integration into any Rust project requiring command authorization.