A .NET CLI proxy that reduces LLM token usage by filtering the verbose output of dotnet commands
down to only what matters.
Prefix build, test, restore, clean, and format with dtk for 60–90% fewer tokens —
per-command filters, token analytics, and one-command setup for 8 AI coding agents.
When AI coding agents run dotnet build or dotnet test, the output is packed with noise — SDK banners, MSBuild
headers, progress indicators, ANSI escape codes, duplicate messages, and framework internals. A typical dotnet test
run can produce 200+ lines where only 5–10 actually matter. Every extra line burns tokens, inflates cost, and
wastes precious context window space.
Example: 27 lines of raw dotnet test output → 5 lines with dtk
Before (raw dotnet test):
Restore complete (0.4s)
SampleApp.Tests succeeded (0.1s) → bin/Debug/net10.0/SampleApp.Tests.dll
SampleApp succeeded (0.1s) → bin/Debug/net10.0/SampleApp.dll
Build succeeded in 0.8s
Test run for /home/user/samples/SampleApp.Tests/bin/Debug/net10.0/SampleApp.Tests.dll (.NETCoreApp,Version=v10.0)
VSTest version 17.13.0 (x64)
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
Failed AlwaysFails [5 ms]
Error Message:
Intentional failure
Stack Trace:
at SampleApp.Tests.IntentionallyFailingTests.AlwaysFails() in /home/user/samples/SampleApp.Tests/IntentionallyFailingTests.cs:line 8
Failed! - Failed: 1, Passed: 3, Skipped: 0, Total: 4, Duration: 42 msAfter (dtk dotnet test):
FAILURES (1):
SampleApp.Tests.IntentionallyFailingTests.AlwaysFails [5 ms]
Intentional failure
at samples/SampleApp.Tests/IntentionallyFailingTests.cs:line 8
dotnet test: 1 failed, 3 passed (1 project, 0.07s)DTK strips all the noise and returns a compact, signal-only result. Fewer tokens in means lower cost and less context consumed.
- Build filtering — strips MSBuild noise, keeps only errors, warnings, and a compact summary (~78% savings)
- Test filtering — removes adapter banners, license warnings, and reflection stack frames (~84% savings)
- Restore/Clean filtering — condenses output to essentials (~47–98% savings)
- Format filtering — shows only violations with workspace-relative paths
- 8 AI agent integrations — Claude Code, GitHub Copilot, GitHub Copilot CLI, Gemini CLI, Cursor, Windsurf, Aider, JetBrains AI
- Token analytics — tracks per-command savings over time with
dtk gain - Self-diagnostics —
dtk doctorvalidates your setup in one command - Shell completion — bash, zsh, fish, and PowerShell
- Log teeing — optionally saves raw output to disk for post-mortem inspection
# Requires .NET 10 SDK (https://dotnet.microsoft.com/download) — full SDK, not just runtime
dotnet tool install -g DotnetTokenKillerTo update an existing installation:
dotnet tool update -g DotnetTokenKillerTo uninstall:
dotnet tool uninstall -g DotnetTokenKillerPrefix any supported dotnet command with dtk:
dtk dotnet build
dtk dotnet test --filter "Category=Unit"
dtk dotnet restore
dtk dotnet clean
dtk dotnet format
dtk dotnet format --verify-no-changesUnknown subcommands pass through to dotnet unchanged.
Install integration artifacts with one command. Installing globally is the recommended way to set dtk up — do it once and every project your agent touches picks it up automatically, with no per-repo setup.
For the providers with a home config, add --global (-g) to install into your home directory so
the integration applies across all projects:
dtk integrate claude --global # ~/.claude
dtk integrate gemini --global # ~/.gemini
dtk integrate aider --global # ~/.aider.conf.yml
dtk integrate copilot-cli --global # ~/.copilot/hooksRun this once per machine and you're done — new projects need no extra setup. --global is supported
for claude, gemini, aider, and copilot-cli (the providers with a home config).
For the other providers — or when you want dtk scoped to a single repository — run
dtk integrate <provider> inside the project (without --global):
| Provider | Command | What it creates |
|---|---|---|
| Claude Code | dtk integrate claude |
Skill file, PreToolUse hook, settings merge |
| GitHub Copilot | dtk integrate copilot |
Section in .github/copilot-instructions.md |
| GitHub Copilot CLI | dtk integrate copilot-cli |
preToolUse hook in .github/hooks/ + instructions section |
| Gemini CLI | dtk integrate gemini |
BeforeTool hook, settings merge, GEMINI.md section |
| Cursor | dtk integrate cursor |
.cursor/rules/dtk.mdc |
| Windsurf | dtk integrate windsurf |
.windsurf/rules/dtk.md |
| Aider | dtk integrate aider |
Instructions file, .aider.conf.yml section |
| JetBrains AI | dtk integrate jetbrains |
Section in .junie/guidelines.md |
copilot, cursor, windsurf, and jetbrains are repository-scoped and have no global mode.
copilot-cli is distinct from copilot (instruction-only, Copilot IDE) and supports --global.
--global cannot be combined with --dir.
All commands are idempotent — re-running is safe. Pass --force to refresh existing files.
On machines that also run the rtk hook, dtk integrate claude automatically excludes dotnet from rtk so the two proxies don't both rewrite dotnet commands.
See AI Agent Setup for per-provider details and manual installation steps.
dtk gain # last 30 days
dtk gain --days 7
dtk gain --project # current project only
dtk gain --jsonExample:
DTK Token Savings (Global Scope)
════════════════════════════════════════════════════════════
Total commands: 1059
Without tool: 1.0M
Used by tool: 92.9K
Tokens saved: 911.2K (90.7%)
Total exec time: 26m28s (avg 1.5s)
Efficiency meter: ██████████████████████░░ 90.7%
By Command
──────────────────────────────────────────────────────────────────────
Command Runs Without Tool Used by Tool Saved Avg% Impact
build (ok) 151 104.5K 2.3K 102.2K 97.8% ██░░░░░░░░
build (fail) 37 47.7K 6.9K 40.8K 85.5% █░░░░░░░░░
clean (ok) 3 241.9K 18 241.9K 100.0% ██████░░░░
format (ok) 103 0 1.0K -1.0K 0.0% ░░░░░░░░░░
restore (ok) 89 12.3K 6.5K 5.8K 47.2% █░░░░░░░░░
test (ok) 442 420.6K 7.8K 412.8K 98.1% ██████████
test (fail) 234 177.1K 68.4K 108.7K 61.4% ███░░░░░░░To reset tracking data: dtk reset (or dtk reset --force to skip confirmation).
dtk doctorChecks dotnet SDK, config file, tracking database, and tee directory. Exits 1 if any check fails.
Manage settings via CLI or edit ~/.config/dtk/config.json directly:
dtk config show # display all current values
dtk config set tracking.enabled false
dtk config set tracking.retentionDays 30
dtk config set display.emoji false
dtk config set tee.mode AlwaysSupported keys: tracking.enabled, tracking.retentionDays, tracking.dbPath, tracking.tokenizer,
display.emoji, tee.mode, tee.directory, tee.maxFiles, tee.maxFileSizeBytes.
See Configuration for defaults, valid values, and the full JSON schema.
bash — write to a dedicated file (preferred) or to the system-wide completions directory:
dtk completion bash > ~/.bash_completion
# or system-wide:
dtk completion bash > /etc/bash_completion.d/dtkzsh — the script must live in $fpath, not be sourced inline:
mkdir -p ~/.zfunc && dtk completion zsh > ~/.zfunc/_dtkThen add these two lines to ~/.zshrc (before any existing compinit call):
fpath=(~/.zfunc $fpath)
autoload -Uz compinit && compinitfish
dtk completion fish > ~/.config/fish/completions/dtk.fishPowerShell
dtk completion powershell >> $PROFILEDTK saves raw command output to disk for failed runs by default (tee.mode = failures). Pass --show-log to print the
log path after any run:
dtk dotnet test --show-logInspired by rtk. DTK takes the same idea — filtering noisy CLI output for AI
agents — and rebuilds it natively in .NET with per-command filters, a richer feature set (token analytics, shell
completion, multi-agent integration), and first-class support for the full dotnet CLI surface.
For more details see the full documentation.