ntdrive
ntdrive
Drive a Windows guest on VMware Workstation the way a person sitting at the machine would, but from an LLM agent. ntdrive gives an agent power and snapshot control, KDNET kernel debugging, and a real-time terminal on the guest, all behind one local daemon and one set of tools.
It is built for the kernel driver and Windows security loop: build, deploy to the guest, load, hit a crash or breakpoint, analyze in the debugger, revert a snapshot, repeat. Each of those steps is a tool call, and the daemon keeps the pieces consistent so the agent does not have to.
Windows only. The name is the point: NT is the Windows kernel, and ntdrive drives it.
Why it exists
An agent that wants to debug a driver needs three windows at once: the VMware controls, WinDbg, and an SSH or RDP session into the guest. ntdrive exposes all three as tools and, more importantly, keeps their state in sync. Revert a snapshot and the debugger reattaches and the terminal reconnects on its own. Break into the debugger and the terminal tools refuse to hang, because the guest is frozen. That cross-tool consistency is the part existing debugger-only or VM-only tools leave to you.
How it fits together
Claude Code (agent) Human / CI (shell) pytest / automation
| stdio | argv | import
v v v
ntdrive-mcp ntdrive CLI Python SDK (NtDrive)
| | |
+------------------------+-----------------------+
| HTTP + WebSocket, 127.0.0.1, token
v
+------------- ntdrived (daemon, holds every session) -------------+
| ToolRegistry -> StateStore -> Orchestrator -> AuditLog |
| VmwareAdapter (vmrun) KdSession (kd.exe) TermManager (SSH) |
+---------+------------------------+-----------------------+--------+
| vmrun.exe | UDP KDNET | TCP 22 (SSH PTY)
v v v
+------------------------ VM (Windows guest) -----------------------+
| KDNET (boot-time) OpenSSH -> PowerShell PTY VMware Tools |
+-------------------------------------------------------------------+The daemon owns the sessions. The MCP server, the CLI and the SDK are thin, stateless clients of it,
so an agent, a person at a shell, and a test script all see the same live sessions. Every tool is
declared once in a single registry (ntdrive.core.registry) and the three front doors are generated
from it, so they never drift apart.
What an agent can do
VM power and snapshots: start, stop, suspend, three reboot modes, and live snapshots with a tree listing, revert, and delete.
KDNET kernel debugging: set up KDNET in the guest, attach
kd.exe, break in, run debugger commands, wait for a bugcheck or breakpoint, and detach.Real-time terminal: open SSH PTY sessions, stream output, render the screen, wait on a regex, and send keys including
{ctrl+c}.Console and files: capture a console screenshot (for a BSOD or login screen) and copy files both ways with checksum verification.
Unified state: one
sys_statecall returns VM power, debugger state and terminal sessions, and compound actions like snapshot revert run as a single orchestrated step.
Requirements
Host:
Windows 11
VMware Workstation Pro 17.6 or newer (provides
vmrun.exe)Debugging Tools for Windows (
kd.exe,kdnet.exe) from the Windows SDK or WDKPython 3.12 and uv
For
netkernel debugging only: a firewall rule that letskd.exereceive UDP (admin, once). Theserialtransport needs no firewall and no admin. See "Kernel debugging" below.
Guest (Windows 10 or 11 x64):
UEFI Secure Boot turned off in the VM settings (needed for
bcdedit /debug on)VMware Tools installed
OpenSSH Server running, with PowerShell as the default shell (see "Guest setup" below)
A local user account for SSH
For
netkernel debugging only: the virtual NIC set toe1000e(the Intel 82574L, which KDNET supports on every Windows 10/11 build).vmxnet3works only on Windows 11 23H2 and later.
scripts/setup-host.ps1, scripts/setup-guest.ps1 and scripts/probe-guest.ps1 automate most of
this.
Guest setup
The terminal, file transfer and screenshot tools work as soon as the guest has VMware Tools, an account, and OpenSSH Server. The recommended way to install OpenSSH:
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Set-Service sshd -StartupType Automatic; Start-Service sshd
New-ItemProperty -Path HKLM:\SOFTWARE\OpenSSH -Name DefaultShell `
-Value C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -PropertyType String -ForceIf Add-WindowsCapability fails (some offline images and Insider builds have no Feature-on-Demand
source), install the standalone build instead: download OpenSSH-Win64.zip from the
Win32-OpenSSH releases, expand it to
C:\Program Files\OpenSSH, and run its install-sshd.ps1, then start the sshd service.
scripts/setup-guest.ps1 does the Add-WindowsCapability path for you, and with -Serial (or
-HostIp for KDNET) it also runs the bcdedit step that kd_setup_guest would otherwise do over
SSH.
Install
git clone https://github.com/jiy2745/ntdrive
cd ntdrive
uv sync
uv run pre-commit install
copy vms.example.yaml vms.yaml
# edit vms.yaml: vmx path, guest user and password env var, VMnet8 host IP,
# and encryption_password_env if the VM is encryptedRegister the MCP server with an MCP client. Claude Code picks up the bundled .mcp.json, or add the
same entry to your own config:
{ "mcpServers": { "ntdrive": { "command": "uv", "args": ["run", "ntdrive-mcp"] } } }Allow the tools with one permission rule: mcp__ntdrive__*. Because the wait tools long-poll, set the
MCP tool-call timeout above the server cap (600 s by default).
Kernel debugging: pick a transport
ntdrive can attach the kernel debugger two ways. Set kd_transport per VM in vms.yaml.
serial (recommended, no admin). kd.exe talks to the guest over a VMware serial port exposed as
a host named pipe (\\.\pipe\ntdrive-<vm>). A named pipe is local IPC, so there is no network, no
host firewall, and no administrator step. It is a little slower than net, which rarely matters.
One-time setup (the VM must be powered off to add the serial port):
uv run ntdrive kd setup-host win11 # VM off: adds the named-pipe serial port to the vmx (idempotent)
uv run ntdrive vm start win11
uv run ntdrive kd setup-guest win11 # runs bcdedit /dbgsettings serial in the guest over SSH
uv run ntdrive vm reboot win11 --mode soft --confirm
uv run ntdrive kd attach win11 # running at once; kd break syncs with the targetsys health tells you when the vmx still lacks the pipe entry, and kd attach refuses with a
clear hint when the pipe is not open on the host (the VM is off or was started before the vmx
edit).
net (KDNET, faster, needs admin once). kd.exe receives UDP from the guest, so the host firewall must allow it. On many machines Windows has a leftover inbound Block rule for kd.exe that silently drops KDNET (a Block rule beats an Allow rule). Run the host setup as Administrator once. It removes any such Block rule and adds an Allow rule:
# Administrator PowerShell, once:
powershell -ExecutionPolicy Bypass -File scripts\setup-host.ps1The guest also needs a KDNET-capable NIC (e1000e) and kd_transport: net in vms.yaml.
Quick start (CLI)
The CLI has the same tools as subcommands. The first call auto-starts the daemon. This assumes the guest is already set up for your chosen transport (see above).
The daemon and the vmrun and kd.exe processes it starts run without console windows, so nothing
pops up on the desktop. uv run ntdrive daemon status says whether it is up, and its own output
goes to %LOCALAPPDATA%\ntdrive\logs\daemon.out.log.
uv run ntdrive sys health # host binaries and config, then each VM live: power, SSH, debugger transport
uv run ntdrive vm start win11
uv run ntdrive term open win11 # prints a session id and a CoView URL
uv run ntdrive kd attach win11 # serial: attaches at once; net: connects as the guest boots
uv run ntdrive kd break win11 # freezes the guest at a kd> prompt
uv run ntdrive kd exec win11 "!process 0 0"
uv run ntdrive kd go win11 # resume the guestAdd --json to any command for the raw tool result. Exit codes: 0 ok, 1 error, 2 bad arguments,
3 confirmation required, 4 guest frozen by the debugger, 5 timeout.
A person can sit down in a session the agent opened:
uv run ntdrive term attach <session-id> # Ctrl+] to detach, your keystrokes are logged as humanThe state model to respect
While the debugger is broken in (
kd_state == broken) the whole guest is frozen. Terminal, file and screenshot tools returnguest_frozen_by_debuggerat once instead of hanging. Runkd gofirst.snap revertandvm rebootdetach the debugger and drop terminal sessions, then reattach and reopen them unless you pass--no-reattach-kdor--no-reopen-term.After a reconnect the old terminal session id is kept and points to its successor.
Encrypted VMs
Set encryption_password_env (the name of an environment variable, preferred) or
encryption_password (inline, acceptable because vms.yaml is git-ignored) and every operation
that opens the vmx passes -vp to vmrun. Power, snapshot list, revert, delete, screenshot, guest IP and
file copy all work on an encrypted VM, including the partial encryption that a Windows 11 vTPM
requires.
The one rough edge is a live snapshot of a running encrypted VM. vmrun refuses to encrypt the
running memory directly and returns an authentication error, even though the password is correct
(verified: deleteSnapshot and every other op accept the same password, and a snapshot of the
same VM while powered off succeeds). Two ways to get a live-state snapshot anyway:
snap_take <vm> <name> --allow-suspend. ntdrive suspends the VM (its memory is written to the encrypted.vmss), snapshots the saved state, then resumes. The snapshot includes the running state and it is fully headless with just the encryption password. The guest pauses for a few seconds during the suspend and resume. Likevm_suspendthis refuses while the debugger is broken in, drops terminal sessions (reopen them withterm_open) and reattaches the debugger afterwards. The result liststerms_droppedand thekdreattach status.Or take the snapshot from the VMware UI, which snapshots the running VM in place.
A plain powered-off snap_take always works. snap_take without --allow-suspend on a running
encrypted VM returns a specific hint instead of a raw error. Deleting a memory snapshot of a
running encrypted VM has the same limitation, and snap_delete --allow-suspend handles it the
same way (suspend, delete, resume).
Safety
The daemon binds only to
127.0.0.1and checks a per-daemon token on every request.Secrets (guest password, KDNET key, VM encryption password, daemon token) live only in
vms.yaml, environment variables, and the daemon state file. They never appear in tool arguments, results or logs, and the audit log masks them.The guest's SSH host key is pinned per VM on first use under
%LOCALAPPDATA%\ntdrive\hostkeys. A different key later is refused before the password is sent. Delete that file after reinstalling a guest.The CoView URL carries a view token, a second secret that only lists terminal sessions and opens their streams. That is still a shell in the guest, so treat it like a password and do not paste it into chat or tickets. Terminal transcripts under the log directory record everything typed into a session, by the agent or by a person, so passwords typed interactively land there too.
kd_execexecutes any debugger command, and kd's.shellruns commands on the host. The policy file can setkd_exec: denyfor agents that should not have that.Destructive actions (
snap_delete, hardvm_stop, hardvm_reboot) requireconfirm=trueand go through a policy gate you can tune inpolicy.yaml.
Documentation map
File | Read it if you are |
| a human setting up or using ntdrive |
| an agent using the tools. State model, standard procedures, and moves to avoid |
| any coding agent changing this repo. Conventions, commands and where things live |
| Claude Code. Points at |
| anyone who wants the full requirements and design rationale |
SKILL.md is written for the agent. MCP clients that read skill files pick it up, and any agent can
be pointed at it. It covers the state model, the setup and debug-loop and BSOD-recovery procedures,
and the forbidden moves (such as touching the terminal while the debugger is broken in).
Development
uv sync
uv run pytest # 47 unit tests, all fakes, no real VM needed
uv run pre-commit run --all-files # ruff format + lint, mypy, prettier, ASCII/style checkConventions live in AGENTS.md and pyproject.toml. Ruff is the only Python formatter and linter,
mypy is strict for ntdrive.core, and Prettier runs on the CoView web assets only. A pre-commit hook
rejects non-ASCII characters and semicolons in Markdown prose, which keeps every document English and
plain. Tests that need a real VM are marked @pytest.mark.vm and skip when none is configured.
Only the VMware backend is implemented. Hyper-V and VirtualBox sit behind the same
HypervisorAdapter interface and are planned for a later version.
Layout
src/ntdrive/
config.py vms.yaml and policy.yaml models
errors.py NtDriveError with code, hint and backend reason tags
paths.py host path helpers shared by the CLI, SDK and file tools
core/ registry, state store, policy gate, audit log, orchestrator, service
core/tools/ tool handlers: vm, snap, kd, term, console, file, sys
hypervisor/ HypervisorAdapter interface and the VMware (vmrun) adapter
kd/ KdSession around kd.exe
term/ terminal transports, sessions, key tokens
daemon/ ntdrived HTTP and WebSocket app, lifecycle, client, CoView page
mcp/ cli/ sdk/ the three generated front doors
scripts/ host and guest setup, the ASCII/style check hook
tests/ unit tests with fake vmrun, fake kd.exe and fake terminal channelsLicense
MIT. See LICENSE.