# How DCG History and Telemetry Tracking Works in Destructive Command Guard

> Learn how DCG history and telemetry tracking works. Destructive Command Guard logs commands to SQLite asynchronously, ensuring pipeline efficiency and detailed record-keeping.

- Repository: [Jeff Emanuel/destructive_command_guard](https://github.com/Dicklesworthstone/destructive_command_guard)
- Tags: internals
- Published: 2026-07-16

---

**Destructive Command Guard (dcg) records every evaluated command in a lightweight SQLite database using an asynchronous writer that batches entries to avoid blocking the main pipeline.**

The dcg history and telemetry tracking system provides comprehensive audit capabilities for command-line operations in the `Dicklesworthstone/destructive_command_guard` repository. This subsystem captures execution metadata, outcomes, and analytical data while maintaining minimal performance overhead through asynchronous I/O workers and configurable redaction policies.

## Core Architecture of DCG History and Telemetry

The history subsystem resides in `src/history/` and consists of three primary components that work together to provide durable, queryable records of all command evaluations.

### HistoryDb SQLite Backend

The `HistoryDb` struct in [`src/history/mod.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/history/mod.rs) manages persistent storage using SQLite. It creates and maintains two tables: the `commands` table for raw entries and a virtual `commands_fts` table for full-text search capabilities. The database also stores a `schema_version` row to facilitate migrations. As implemented in the source code, `HistoryDb` provides the `log_commands_batch()` method for bulk inserts and implements recovery logic through `recover_history_db()` when corruption is detected.

### HistoryWriter Async Pipeline

The `HistoryWriter` struct handles non-blocking command logging. According to [`src/history/mod.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/history/mod.rs), the writer spawns a dedicated `history_worker` thread that receives `CommandEntry` structs through an mpsc channel. The writer batches entries until reaching either the `batch_size` threshold (default 50) or the `flush_interval` duration (100 ms), then persists them via `flush_batch()`. This architecture ensures that the main dcg pipeline never blocks on I/O operations.

### CommandEntry Data Model

Defined in [`src/history/schema.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/history/schema.rs), the `CommandEntry` struct captures:
- UTC timestamp
- Agent type (e.g., "claude_code")
- Working directory
- Command string (with optional redaction)
- Outcome enum (`Allow` or `Deny`)
- Session ID generated via `generate_session_id()`

## The History Tracking Workflow

When dcg evaluates a command, the tracking workflow follows this pipeline:

```

dcg evaluates a command → HistoryWriter::log(entry) → mpsc channel →
history_worker thread → batch → HistoryDb::log_commands_batch()

```

The writer initializes through `HistoryWriter::new(db_path, &config)`, which reads configuration from [`src/config.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/config.rs). If the `DCG_HISTORY_DISABLED` environment variable is set, the function returns a no-op writer that discards entries without database interaction.

Each `log()` call processes the command through `redact_for_history()` according to the `HistoryRedactionMode` setting—supporting `None`, `Full`, or `Pattern` modes to mask sensitive arguments. The worker thread accumulates entries until flush conditions are met. If `flush_batch()` encounters errors, it falls back to single-row inserts; fatal storage errors trigger database recovery attempts via `recover_history_db()`. Persistent failures cause the writer to disable further writes for that process to prevent cascading errors.

## Telemetry Features and Data Management

Beyond simple logging, the dcg history and telemetry tracking system provides automated maintenance and analytical capabilities.

### Auto-Pruning and Retention

The `history_worker` periodically checks `HistoryDb::should_auto_prune()` when `auto_prune` is enabled in the configuration. When triggered, it executes `prune_older_than_days(retention_days)`, maintaining a default 90-day retention window to bound database size. This automated cleanup runs without user intervention while preserving recent analytical data.

### Session Tracking

Each `HistoryWriter` instance generates a unique session identifier using SHA-256 via `generate_session_id()`, producing values prefixed with `ses-`. This identifier attaches to every `CommandEntry` in that session, enabling retrospective grouping of all events from a single dcg run for debugging or audit trails.

### Command Redaction

Security-sensitive data protection occurs through the `redact_for_history` helper, which delegates to the logging subsystem in [`src/logging.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/logging.rs). When configured with `HistoryRedactionMode::Pattern`, the system applies regex patterns to mask passwords, tokens, or other confidential arguments before persistence, ensuring compliance with security policies while maintaining audit functionality.

### Export and Analytics

`HistoryDb` implements comprehensive export APIs supporting `ExportOptions` and `ExportFilters` to produce JSON, SARIF, or CSV outputs. Security teams can query aggregated statistics using `analyze_pack_effectiveness()`, which returns `PackEffectivenessAnalysis` containing metrics such as most-frequent blocked patterns and outcome distributions. The CLI `dcg stats` command in [`src/main.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/main.rs) leverages these APIs to surface pack effectiveness and denial trends.

## Implementation Examples

The following examples demonstrate interacting with the history system from Rust code.

Logging a command evaluation:

```rust
use destructive_command_guard::history::{HistoryWriter, CommandEntry, Outcome};

let config = HistoryConfig::load()?;               // reads ~/.config/dcg/config.toml
let writer = HistoryWriter::new(None, &config);   // default DB path

let entry = CommandEntry {
    timestamp: chrono::Utc::now(),
    agent_type: "claude_code".into(),
    working_dir: std::env::current_dir()?.to_string_lossy().into(),
    command: raw_command.clone(),
    outcome: Outcome::Deny,
    ..Default::default()
};

writer.log(entry);

```

Synchronous flushing before process termination:

```rust
// Usually called in Drop, but can be explicit for a graceful shutdown.
writer.flush_sync();

```

Retrieving analytical data:

```rust
use destructive_command_guard::history::{HistoryDb, PackEffectivenessAnalysis};

let db = HistoryDb::open(None)?;                 // default location
let analysis = db.analyze_pack_effectiveness()?; // returns `PackEffectivenessAnalysis`
println!("Most frequent block: {}", analysis.most_frequent_block);

```

## Summary

- **Destructive Command Guard** maintains a SQLite-based history system in `src/history/` that records every command evaluation with metadata and outcomes.
- **Asynchronous architecture** using `HistoryWriter` and a dedicated `history_worker` thread ensures zero blocking of the main evaluation pipeline through batch processing (default 50 entries or 100ms intervals).
- **Data protection** via configurable `HistoryRedactionMode` settings and automatic session ID generation enables secure audit trails grouped by execution context.
- **Maintenance automation** includes auto-pruning (default 90-day retention) and database recovery mechanisms to ensure long-term reliability.
- **Export capabilities** support JSON, SARIF, and CSV formats for compliance reporting and security analytics through `PackEffectivenessAnalysis`.

## Frequently Asked Questions

### How does DCG store command history?

DCG persists command history in a lightweight SQLite database managed by the `HistoryDb` struct. The system creates the `commands` table for raw entries and a `commands_fts` virtual table for full-text search. Storage operations occur asynchronously through a dedicated worker thread that batches writes to minimize I/O impact on the main process.

### What happens if the history database becomes corrupted?

The `HistoryWriter` implements error handling in `flush_batch()` that attempts single-row insert fallback when bulk operations fail. For fatal storage errors, the system invokes `recover_history_db()` to restore database integrity. If recovery fails, the writer disables further persistence for that process to prevent crash loops while allowing dcg to continue operating.

### Can I disable history tracking in DCG?

Yes. Setting the `DCG_HISTORY_DISABLED` environment variable causes `HistoryWriter::new()` to return a no-op writer that immediately discards all entries without database interaction. Alternatively, configuration options in `HistoryConfig` allow tuning redaction levels and disabling auto-pruning without stopping history collection entirely.

### How does DCG protect sensitive data in command history?

The `redact_for_history` helper in [`src/logging.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/logging.rs) processes commands according to `HistoryRedactionMode` before persistence. The `Pattern` mode applies configurable regex patterns to mask sensitive arguments like passwords or API keys, while `Full` mode redacts the entire command string. This ensures audit trails remain useful without exposing confidential information.