Windows standalone deployment

Install the standalone DefenseClaw enterprise services on Windows x64 with the standalone Setup or the lifecycle CLI, check the result, and remove them.

The standalone profile installs DefenseClaw machine-wide on Windows x64 as four Windows services. It does not need Cisco Secure Client. Standard users cannot stop the services or change the config, and the hook guardian restores DefenseClaw's hooks if a user removes them. For the terms used on this page, see Concepts.

Deploying with an MDM?

This page installs on one computer from an administrator shell. To deploy to many computers with Intune, Configuration Manager, Workspace ONE or another MDM, start with Install with an MDM. It uses the same Setup and the same config.

Requirements

RequirementDetail
WindowsNative Windows x64. The lifecycle refuses ARM64, including x64 emulation on ARM64, and refuses to run from a 32-bit process. It does not check the Windows version. The MDM kit's requirement rule uses Windows 10 22H2 or later.
PowerShell 7A stable PowerShell 7 x64, installed from Microsoft's MSI. The lifecycle finds it only through HKLM\SOFTWARE\Microsoft\PowerShellCore\InstalledVersions, requires it under Program Files with a valid Microsoft signature, and ignores PATH. Without it, the run stops with powershell7_required. Install 7.4 or later: the lifecycle accepts any stable 7.x, but the MDM wrapper requires 7.4.
Language modePowerShell FullLanguage mode. Under a WDAC or AppLocker script policy, allow the DefenseClaw signer, or the run stops with powershell_constrained_language.
PrivilegesAn elevated administrator token, or SYSTEM (for example an MDM agent).
Disk spaceFree space on the ProgramData volume for about three copies of the Setup payload plus 256 MB to install, upgrade, repair or ensure (one copy plus 256 MB for the other actions). Setup refuses at once, before it stages anything, and names the volume, its free space and the space it needs.
Other profilesNo Secure Client DefenseClaw deployment. The two profiles share service names, so the lifecycle refuses with profile_conflict.

Layout

Binaries go under Program Files and state under ProgramData. Standard users cannot change either tree.

ItemPath
BinariesC:\Program Files\Cisco\DefenseClaw\bin (defenseclaw.exe, defenseclaw-gateway.exe, defenseclaw-hook.exe, defenseclaw-acp.exe, defenseclaw-sensor-helper.exe)
Lifecycle scriptsC:\Program Files\Cisco\DefenseClaw\libexec (install-enterprise.ps1, DefenseClawEnterprise.psm1)
ConfigC:\ProgramData\Cisco\DefenseClaw\etc\config.yaml
SecretsC:\ProgramData\Cisco\DefenseClaw\secrets
Target manifestC:\ProgramData\Cisco\DefenseClaw\hook-guardian\targets.yaml (the enumerator writes it)
Lifecycle stateC:\ProgramData\Cisco\DefenseClaw\install
Gateway dataC:\ProgramData\Cisco\DefenseClaw\runtime
Authorization ledgerC:\ProgramData\Cisco\DefenseClaw\hook-guardian-state
Service logsC:\ProgramData\Cisco\DefenseClaw\logs
Hook runtimeC:\ProgramData\Cisco\DefenseClaw-HookRuntime, readable by users. It holds, for each per-user connector, the enrollment list and runtime selector, and machine-policy.json, the public machine-policy summary.
Lifecycle log%WINDIR%\Logs\DefenseClaw: enterprise-lifecycle.log, last-result.json and, for MDM runs, mdm-wrapper.log. Users can read these files.

The lifecycle also registers the deployment with Windows:

RegistrationValue
Deployment markerHKLM\SOFTWARE\Cisco\DefenseClaw\Enterprise, with Profile, ProductVersion, InstallRoot, StateRoot, TrustMode, UpdatedAt and DisableSelfUpdate
Add/Remove ProgramsHKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\CiscoDefenseClawEnterprise, shown as "Cisco DefenseClaw Enterprise"
Event logThe DefenseClaw event log, source DefenseClaw Lifecycle, which only LocalSystem and Administrators can write. A legacy copy of each event still goes to the Application log, source DefenseClaw Enterprise
Self-update policyHKLM\SOFTWARE\Policies\Cisco\DefenseClaw\DisableSelfUpdate = 1, written only when the value is absent. The lifecycle records that it wrote the value and removes it on uninstall only in that case, so your own Group Policy value is never changed. Set enterprise.coexistence.disable_self_update: false to opt out.

The four services:

ServiceIdentityRole
DefenseClawGatewayNT SERVICE\DefenseClawGateway, with SeChangeNotifyPrivilege onlyRuns the policy engine and the hook API on 127.0.0.1:18970
DefenseClawSensorHelperLocalSystem, with SeChangeNotifyPrivilege onlyAnswers the gateway's fixed AI Discovery requests
DefenseClawHookGuardianLocalSystem, with a fixed privilege listWrites and repairs each enrolled user's hook registrations, using that user's token
DefenseClawHookEnumeratorLocalSystem, with the same privilege listFinds eligible profiles (local, domain and Microsoft Entra ID accounts) and writes the target manifest

The Service Control Manager restarts each service after a failure.

How a hook reaches the gateway:

starts
runs per tool call
asks over loopback TCP
TrustedZ0 · Admin and OS (SYSTEM)
UntrustedZ4 · User session (the user)
RestrictedZ2 · Gateway (virtual account)
Service Control Managerknows the gateway's PID
AI agentruns as the user
defenseclaw-hook.exechecks the listener
Gatewayallows or blocks

List view for small screens. Use the expand button to open the drawing.

TrustedZ0 · Admin and OS (SYSTEM)

  1. Service Control Managerknows the gateway's PID
    • startsGatewayZ2

UntrustedZ4 · User session (the user)

  1. AI agentruns as the user
    • runs per tool calldefenseclaw-hook.exe
  2. defenseclaw-hook.exechecks the listener
    • asks over loopback TCPGatewayZ2

RestrictedZ2 · Gateway (virtual account)

  1. Gatewayallows or blocks
Windows. The hook calls the gateway on 127.0.0.1:18970. Before it sends any bytes, it checks that the process behind the connection is the one the Service Control Manager reports for DefenseClawGateway. The hook's credential is bound to the user's SID, so the gateway knows who is calling.

How the hooks stay in place:

writes
reads
repairs, as the user
PrivilegedZ1 · Services (LocalSystem)
ProtectedZ3 · Admin-owned files
UntrustedZ4 · User session (the user)
Enumeratorlists the users
Guardianchecks every minute
Target manifesttargets.yaml
Agent configin the user's profile

List view for small screens. Use the expand button to open the drawing.

PrivilegedZ1 · Services (LocalSystem)

  1. Enumeratorlists the users
    • writesTarget manifestZ3
  2. Guardianchecks every minute
    • readsTarget manifestZ3
    • repairs, as the userAgent configZ4

ProtectedZ3 · Admin-owned files

  1. Target manifesttargets.yaml

UntrustedZ4 · User session (the user)

  1. Agent configin the user's profile
Windows. The enumerator lists the users to protect in hook-guardian\targets.yaml. The guardian puts back DefenseClaw's hooks in each listed user's agent config, writing under that user's own token and only while the user has an active session. It also writes the Claude Code, Cursor, Copilot and OpenCode machine policy; the lifecycle writes Codex's.

See Threat model for what each zone may do.

Install

Install in four steps: get and check the release, write the config, run Setup, then add the AI Defense key if you use it.

1. Get and check the release

Download these assets from the same GitHub release:

  • DefenseClawSetup-Enterprise-Standalone-x64.exe, the standalone Setup.
  • checksums.txt and checksums.txt.bundle, the signed checksum list.

DefenseClawSetup-Enterprise-x64.exe is the Secure Client Setup. Do not use it for the standalone profile.

Check the checksum list's signature with cosign, then compare the Setup's hash with its line in the list:

cosign verify-blob --bundle checksums.txt.bundle `
  --certificate-identity 'https://github.com/cisco-ai-defense/defenseclaw/.github/workflows/release.yaml@refs/heads/main' `
  --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' `
  checksums.txt
(Get-FileHash .\DefenseClawSetup-Enterprise-Standalone-x64.exe -Algorithm SHA256).Hash.ToLower()
Select-String -Path .\checksums.txt -Pattern 'DefenseClawSetup-Enterprise-Standalone-x64\.exe$'

The two hashes must match. Keep the hash: MDM recipes pin it.

2. Write the config

The config is an ordinary DefenseClaw config.yaml with the standalone profile. This example protects Codex and Claude Code in observe mode:

config.yaml
config_version: 8
deployment_mode: managed_enterprise
enterprise:
  profile: standalone
gateway:
  api_bind: 127.0.0.1
  api_port: 18970
guardrail:
  enabled: true
  mode: observe
  connectors:
    codex: {}
    claudecode: {}

Each key under guardrail.connectors turns on protection for that agent. A config with no connectors protects nothing. See Choose the agents to protect and the settings reference.

Without guardrail.rule_pack_dir or policy_dir, as here, the gateway uses the rule packs built into it. A rule-pack directory you name must exist, be writable only by administrators, and be readable by the gateway service account NT SERVICE\DefenseClawGateway (for example, leave the inherited Users read and execute entry in place, and add no Deny entry for that account). Every parent folder of it needs Read & execute for that account too, because the gateway reads each parent's permissions and lists it. So do not put the rule pack inside the locked staging folder below; give it its own folder:

$Packs = 'C:\ProgramData\DefenseClaw-RulePacks'
New-Item -ItemType Directory -Path $Packs -Force | Out-Null
icacls $Packs /inheritance:r /grant:r '*S-1-5-18:(OI)(CI)F' '*S-1-5-32-544:(OI)(CI)F' '*S-1-5-32-545:(OI)(CI)RX' | Out-Null
Copy-Item -Recurse .\my-pack "$Packs\my-pack"

Setup checks these permissions for the service account before it changes anything, and stops with exit code 1639 naming the folder and the icacls grant that fixes it. Setup checks the config with the gateway's own compiler, and loads every rule pack the gateway would load, before it changes anything. When the gateway could not load the file, Setup stops with exit code 1639 and names the line and the reason.

Setup accepts the config only from an absolute local path that standard users cannot change. Stage it in a folder that only SYSTEM and Administrators can write:

$Stage = 'C:\ProgramData\DefenseClaw-Staging'
New-Item -ItemType Directory -Path $Stage -Force | Out-Null
icacls $Stage /inheritance:r /grant:r '*S-1-5-18:(OI)(CI)F' '*S-1-5-32-544:(OI)(CI)F' | Out-Null
Copy-Item .\config.yaml "$Stage\config.yaml"

3. Run Setup

From an elevated PowerShell session:

& .\DefenseClawSetup-Enterprise-Standalone-x64.exe /ensure "CONFIG=$Stage\config.yaml" JSON=1
$LASTEXITCODE

/ensure installs when nothing is installed, upgrades an older version, re-applies a changed config, repairs a deployment that fails verification, and otherwise does nothing. Setup unpacks its embedded payload into a protected folder, checks every file against its embedded manifest, and runs the lifecycle from there. See Payload trust for how the lifecycle decides which files to trust. It also generates the target manifest from the profiles on the computer, so you never write targets.yaml.

With JSON=1, Setup prints the lifecycle result document on standard output. The exit code follows Windows Installer conventions:

CodeMeaning
0Success, or nothing to do
1603Failure. A failed install, upgrade or repair is rolled back, and a refusal before any change leaves the computer as it was. When the rollback itself cannot finish, the transaction stays pending (see Recover a pending transaction). For status and verify, 1603 means the deployment is unhealthy.
1618Another lifecycle run holds the lock. Retry later.
1639Invalid arguments: a malformed command line (such as a relative CONFIG= path or an unknown property), or arguments the lifecycle rejected (for example /ensure without CONFIG= on a computer with no deployment, a config the gateway cannot load, or a run that enterprise.trust refuses). Retrying does not help.
3010Reserved. The lifecycle never requests a restart.

Setup properties use NAME=value. Names are case-insensitive and ignore dashes, so ALLOWEDSIGNERS= and allowed-signers= are the same.

PropertyMeaning
CONFIG=<path>The administrator config. Required for the first install. Later runs reuse the installed config when you leave it out.
MANIFEST=<path>A target manifest you publish yourself. Required for /install, and for a first install with enterprise.enrollment.mode: manifest.
ATTESTCLAUDEEFFECTIVEPOLICY=1With /repair: record that Claude Code runs DefenseClaw's managed hooks on this computer. See Verify the install.
ALLOWEDSIGNERS=<sha256>,<sha256>Accept only these Authenticode signer certificates (SHA-256 thumbprints). Applies to a signed Setup.
JSON=1Print the result document on standard output
NOSTART=1Install or update with the services stopped and disabled. A later /repair starts them.
PURGE=1With /uninstall, also remove each enrolled account's %USERPROFILE%\.defenseclaw, and the DefenseClaw files of a per-user install in %USERPROFILE%\.local\bin with that folder's user Path entry once it is empty. The result names each account
TIMEOUTSECONDS=<n>Lifecycle timeout, from 60 to 7200 seconds. The default is 1800.

The other actions are /install, /upgrade, /repair, /reconcile, /status, /verify and /uninstall. Prefer /ensure: /install also requires MANIFEST=, a target manifest that /ensure generates for you. /quiet and /norestart are accepted and have no effect.

4. Add the AI Defense key

Without a key, the local policy engine decides alone. To add Cisco AI Defense, turn it on in the config. Add these keys before you run Setup, or run /ensure again with the updated config:

config.yaml (excerpt)
enterprise:
  profile: standalone
  inspection:
    ai_defense:
      enabled: true
      credential: ai-defense-api-key

Then store the key. The deployment must be installed first:

& 'C:\Program Files\Cisco\DefenseClaw\bin\defenseclaw.exe' enterprise secret set `
  --name ai-defense-api-key --from-file 'C:\ProgramData\DefenseClaw-Staging\ai-defense.key' --json
Remove-Item 'C:\ProgramData\DefenseClaw-Staging\ai-defense.key'

The command runs only from an elevated prompt. It writes C:\ProgramData\Cisco\DefenseClaw\secrets\ai-defense-api-key and restarts the gateway. See AI Defense key for the config keys and for rotation.

Verify the install

Run from an elevated PowerShell 7 session:

$Cli = 'C:\Program Files\Cisco\DefenseClaw\bin\defenseclaw.exe'
& $Cli enterprise windows status --profile standalone --json
& $Cli enterprise windows verify --profile standalone --json

status reports the state. verify also checks every file, permission, service and hook, and returns a nonzero exit code when anything fails. Look for these fields:

FieldHealthy value
oktrue
installed, installed_versiontrue and the version you deployed
readinessgateway, guardian, enumerator and sensor_helper all true
coverage_completetrue: installed, the guardian is ready, and no transaction is pending
security_completetrue: see below
enrollment.targetsThe number of entries (one per user and connector) in the target manifest. 0 means nobody is protected yet.
errorsEmpty

On Windows, security_complete needs at least one of Codex, Claude Code or Cursor enabled, and no agent reported as agent_unprotected or hook_contract_unverified. With Claude Code enabled, it also needs an administrator's attestation that Claude Code runs DefenseClaw's managed hooks on this computer:

  1. Install. security_complete is false at this point.

  2. Confirm that Claude Code runs DefenseClaw's hooks. In an enrolled user's own session, start that user's Claude Code and have it make one tool call, for example listing the current folder. Then, from an elevated prompt, check that the gateway recorded the call:

    & $Cli audit export --connector claudecode -o "$Stage\audit-claudecode.jsonl"

    $Stage is the administrator-only folder from Write the config; the export can hold prompt and tool content.

    enterprise policy verify --live is not available on Windows; see Inspect machine policy.

  3. Record the attestation from an elevated PowerShell 7 session:

    & $Cli enterprise windows repair --profile standalone --attest-claude-effective-policy --json

    The Setup form is /repair ATTESTCLAUDEEFFECTIVEPOLICY=1 JSON=1.

DefenseClaw records the attestation as you give it; step 3 does not run Claude Code. The record is bound to the SHA-256 of the installed Claude Code policy file and of the hook binary, not to the computer. Every DefenseClaw upgrade replaces the hook binary, and a change to the Claude Code hook contract the policy is rendered from changes the policy, so either makes the record stale: security_complete returns to false until you repeat steps 2 and 3. Computers that run the same release and Claude Code contract have the same binding, so an MDM can check one reference computer and push the Setup form to the others; the attestation then stands for each of those computers.

The guardian writes a user's hook registrations only while that user has an active (connected) session. It retries until the session is active again.

What Windows shows after an install

The four services run under Automatic start, Add/Remove Programs lists Cisco DefenseClaw Enterprise, and the DefenseClaw event log (Event Viewer > Applications and Services Logs > DefenseClaw) holds one entry per lifecycle run. Captured on a standalone install, from an elevated prompt:

Elevated PowerShell
Get-Service DefenseClaw* | Format-Table Name, Status, StartType
Get-WinEvent -LogName DefenseClaw -MaxEvents 3 | Format-Table TimeCreated, Id, LevelDisplayName, ProviderName
Output
Name                      Status  StartType
----                      ------  ---------
DefenseClawGateway        Running Automatic
DefenseClawHookEnumerator Running Automatic
DefenseClawHookGuardian   Running Automatic
DefenseClawSensorHelper   Running Automatic

TimeCreated           Id LevelDisplayName ProviderName
-----------           -- ---------------- ------------
10/3/2026 4:03:07 AM 102 Information      DefenseClaw Lifecycle
10/3/2026 3:58:30 AM 150 Error            DefenseClaw Lifecycle
10/3/2026 3:58:30 AM 150 Error            DefenseClaw Lifecycle

Event 102 is a repair or reconcile, and 150 a refused run (here, a status with an invalid --profile); see Logs and events for every ID. Each message names the action and result and ends with its record, for example DefenseClaw enterprise repair (standalone) ok=true exit=0 version=1.0.29 installed=1.0.29 record 452e0e82c58af2aaf46a795939e582d7.

Each elevated lifecycle run appends its result to the lifecycle log. Every run except a healthy status or verify also writes an event (IDs 100 to 150) to the DefenseClaw event log and a legacy copy of it to the Application log. The marker key and the Add/Remove Programs entry change only after a successful run, and they are for detection only: verify never trusts them. See Detection for the detection rules, Logs and events for the event IDs, and Status and verify for monitoring.

Only LocalSystem and Administrators can write the DefenseClaw log (source DefenseClaw Lifecycle), and the accounts that can read the Application log can read it. Each run that writes an event registers the log and resets its access. A successful uninstall unregisters it, so the uninstall event (110) goes only to the Application log; forward the DefenseClaw log to your SIEM if you need its entries after uninstall. Unregistering does not delete the entries: Windows keeps %WINDIR%\System32\winevt\Logs\DefenseClaw.evtx (the Event Log service holds it open until it restarts), and a later install that registers the log again shows the old entries with the new ones.

Any account can write Application-log entries under any source name, including DefenseClaw Enterprise, so the Application-log copies are legacy, and a later release stops writing them. Point MDM detection rules and SIEM forwarding at the DefenseClaw log (Get-WinEvent -LogName DefenseClaw) instead of the Application log's DefenseClaw Enterprise source.

To check that the event-log entries are genuine, run events from any prompt. It exits 1 and names each entry that fails:

Check the DefenseClaw event-log entries
& 'C:\Program Files\Cisco\DefenseClaw\bin\defenseclaw.exe' enterprise windows events
& 'C:\Program Files\Cisco\DefenseClaw\bin\defenseclaw.exe' enterprise windows events --json
# The legacy Application-log copies:
& 'C:\Program Files\Cisco\DefenseClaw\bin\defenseclaw.exe' enterprise windows events --application

status and verify also name every agent the enumerator found installed but could not enroll (hook_contract_unverified, agent_unprotected); see Enrollment. Each is one account's agent, so both print it as a warning <code>: <message> line and --json lists it under warnings: security_complete is false, but verify, and so MDM detection, still passes. enterprise policy show lists them as well. Cursor's machine hooks file is published only while a user is enrolled for Cursor; see Machine policy. include_groups and exclude_groups apply on Windows as described there.

Review the audit log

The gateway service owns the local audit database under C:\ProgramData\Cisco\DefenseClaw\runtime. Export it from an elevated Administrator prompt, or as LocalSystem from an MDM script:

Elevated Administrator prompt
$Stage = 'C:\ProgramData\DefenseClaw-Staging'   # administrator-only, from Write the config
& 'C:\Program Files\Cisco\DefenseClaw\bin\defenseclaw.exe' audit export --connector claudecode -o "$Stage\audit-claudecode.jsonl"

On a standalone host, audit export run this way reads the managed deployment's configuration and audit database read-only beside the running gateway; it needs no environment variables. Standard accounts cannot read the managed audit log, and the command tells them to use an elevated prompt. Omit --connector to export every row. The output file must not exist yet; it takes the permissions of its folder, so write it to a folder only administrators can read. Treat it as sensitive: it can hold prompt and tool content.

Review AI Discovery

With ai_discovery.enabled: true in the deployment config, the gateway service scans each user profile for AI agents and apps, skills, MCP servers, plugins and running AI processes, and sends what it finds to your observability destinations. To read the inventory on the computer, run the read-only discovery view from an elevated Administrator prompt, or as LocalSystem from an MDM script:

Elevated Administrator prompt
& 'C:\Program Files\Cisco\DefenseClaw\bin\defenseclaw.exe' enterprise windows discovery
& 'C:\Program Files\Cisco\DefenseClaw\bin\defenseclaw.exe' enterprise windows discovery --user <account> --json

It lists each account's signals by category (--user lists one account's signals; it takes the account name or SID), then the runtime discovery planes (ai_discovery.runtime) with their state, last poll and findings. Standard accounts cannot run it.

Skills and MCP servers are inventoried, not scanned: a managed deployment does not run the skill or MCP scanners. The discovery view names each skill and MCP server per user. Your observability destinations get the ai_component.discovered, changed and removed records with the user (user.id, defenseclaw.user.name) but without the skill or MCP server name: the per-entry ai_component.observed records stay in the local inventory, so read the names with discovery --user <account> --json. See AI Discovery for the folders the service may read in each profile.

Inspect machine policy

Run the policy commands from an elevated Administrator prompt, or as LocalSystem from an MDM script. Like audit export, they read the managed deployment's configuration and need no environment variables:

Elevated Administrator prompt
& 'C:\Program Files\Cisco\DefenseClaw\bin\defenseclaw.exe' enterprise policy show
& 'C:\Program Files\Cisco\DefenseClaw\bin\defenseclaw.exe' enterprise policy verify

show lists each connector's route, lock and coverage; verify exits 1 while coverage is incomplete. With managed_hooks_only: enforce (the default) the Claude Code drop-in C:\Program Files\ClaudeCode\managed-settings.d\90-defenseclaw.json sets allowManagedHooksOnly: true, so user and project Claude Code hooks do not run. Claude Code applies the files in managed-settings.d in name order, so a file that sorts after 90-defenseclaw.json and sets allowManagedHooksOnly to false turns the lock off; enterprise policy verify and enterprise windows verify report that file. Standard accounts are told to use an elevated prompt.

enterprise policy verify --live is not available on Windows: Windows cannot start the client as another account, and a standard account cannot read the managed configuration. Use the static verify above, and to see the hooks run, make a tool call in the client from the user's own session, then read its record from the elevated prompt with audit export, as in Review the audit log.

Recover a pending transaction

A lifecycle that fails normally rolls back. If the rollback itself cannot finish, the transaction stays pending: the result reports transaction_pending: true, the DefenseClaw services stay stopped, and vendor machine policy the transaction had already published can still point at the stopped gateway. status shows the state; verify refuses until the transaction is recovered. The failed result names the command to run next.

The rollback never deletes content in an account's %USERPROFILE%\.defenseclaw that it cannot prove DefenseClaw wrote: a file or folder it did not create, a file other than a DefenseClaw hook file whose owner or permissions changed, or a hard link. A DefenseClaw hook file whose permissions changed is removed. The rollback does not stay pending for the rest either, and the same holds when the account changed the owner or permissions of the folder itself or replaced it: it renames the folder to %USERPROFILE%\.defenseclaw.rollback-<random>, with that content inside, and finishes. Review that folder and delete it. A file or folder another program holds open still makes the rollback wait, because a retry can finish once the program closes it.

The rollback of a failed first install also puts back each account's agent configuration and removes the machine policy the install published. It acts as each account, which needs LocalSystem. For a signed-out account it uses a service-for-user (S4U) logon: a local account always, a domain account when a domain controller answers. Set DEFENSECLAW_WINDOWS_ROLLBACK_SIGNED_OUT_ACCOUNTS=0 to skip signed-out accounts. No guardian is left to clean an account later, so the result lists each item it could not remove as a rollback_leftover warning, by account and connector, with the command that removes it.

Setup run from an elevated administrator prompt is not LocalSystem, so its rollback cannot act as any account. The guardian, a LocalSystem service, may already have registered DefenseClaw for the signed-in accounts (for example Copilot's %USERPROFILE%\.copilot\hooks\defenseclaw-vscode.json); those registrations stay and point at the removed hook binary, and each account is named with "because Setup did not run as LocalSystem". Only the failed run's result lists them, because a later /status finds no deployment, so keep that result. Fix the cause of the failure, then run /ensure and /uninstall as LocalSystem while the accounts have an active (connected) session (a signed-in account whose session is disconnected counts as signed out), as in Run Setup as LocalSystem. An empty C:\Program Files\ClaudeCode\managed-settings.d can also stay; see Remove.

Recover by running DefenseClaw Setup as LocalSystem (Intune install behavior System, or another MDM's system context). /ensure recovers the pending transaction and then installs or upgrades; /uninstall recovers it and removes the deployment:

As LocalSystem
DefenseClawSetup-Enterprise-Standalone-x64.exe /ensure CONFIG=C:\ProgramData\DefenseClaw-Staging\config.yaml JSON=1
DefenseClawSetup-Enterprise-Standalone-x64.exe /uninstall JSON=1

/repair also recovers the transaction; after a failed first install it then stops with "run Install", so /ensure is the one-step command. Outside an MDM, a one-time scheduled task that runs as SYSTEM gives the same context (see Run Setup as LocalSystem). From a payload folder (see Run the lifecycle CLI from a payload folder), "$Payload\defenseclaw.exe" enterprise windows ensure (or repair, uninstall) with the same --profile, trust and --config options, run as LocalSystem, works the same way.

If recovery cannot finish with the gateway the pending transaction staged, it can fall back to the gateway in the running Setup's payload, and it reports what it did in the result (recovery_gateway_fallback, recovery_gateway_not_used or recovery_activation_deferred). Do not edit DefenseClaw files or permissions by hand to recover.

Run Setup as LocalSystem

Without an MDM, an administrator gets LocalSystem from a one-time scheduled task. Run Setup from the administrator-only staging folder, never from a folder a standard user can write, because the task runs whatever file is at that path as SYSTEM. From an elevated PowerShell session, with $Stage as in Write the config:

Elevated PowerShell
Copy-Item .\DefenseClawSetup-Enterprise-Standalone-x64.exe $Stage
$Setup  = "$Stage\DefenseClawSetup-Enterprise-Standalone-x64.exe"
$Result = "$Stage\setup-as-system.json"
$Task   = 'DefenseClaw Setup as SYSTEM'
$Action = New-ScheduledTaskAction -Execute "$env:SystemRoot\System32\cmd.exe" `
    -Argument "/d /c `"`"$Setup`" /ensure CONFIG=$Stage\config.yaml JSON=1 > `"$Result`"`""
Register-ScheduledTask -TaskName $Task -Action $Action -User 'NT AUTHORITY\SYSTEM' -RunLevel Highest -Force | Out-Null
Start-ScheduledTask -TaskName $Task
do { Start-Sleep -Seconds 5 } while ((Get-ScheduledTask -TaskName $Task).State -in 'Queued', 'Running')
(Get-ScheduledTaskInfo -TaskName $Task).LastTaskResult
Unregister-ScheduledTask -TaskName $Task -Confirm:$false
Get-Content $Result

LastTaskResult is Setup's exit code. For /uninstall, replace /ensure CONFIG=$Stage\config.yaml with /uninstall.

Per-user installs

On a computer with the standalone deployment, the per-user product refuses to run:

Per-user actionWhat happens
install.ps1Refuses when the marker key exists, or when DisableSelfUpdate under HKLM\SOFTWARE\Policies\Cisco\DefenseClaw is nonzero
defenseclaw upgrade, defenseclaw rollbackRefuse when the marker key exists
Per-user gatewayRefuses to start on a managed computer

Nothing migrates a per-user install automatically. Before you deploy, have each user remove their per-user install with defenseclaw uninstall --all --binaries --yes. Setup needs --all: it does not adopt a %USERPROFILE%\.defenseclaw folder that a per-user install left, and refuses that profile until the folder is gone (move it aside to keep its data). A per-user gateway that still runs holds the gateway API port, and Setup names it in its api_port_held error. See Uninstall and preserved state.

Remove

With Setup:

& .\DefenseClawSetup-Enterprise-Standalone-x64.exe /uninstall JSON=1

Or with the installed CLI:

& 'C:\Program Files\Cisco\DefenseClaw\bin\defenseclaw.exe' enterprise windows uninstall --profile standalone --json

Uninstall removes DefenseClaw's hook registrations and machine-policy entries, the four services, the binaries, and the machine state under C:\ProgramData\Cisco\DefenseClaw (config, secrets, data and service logs). Each user keeps %USERPROFILE%\.defenseclaw and the per-user binaries. To remove those too, add PURGE=1 to Setup or --purge to the CLI. After a successful uninstall, the marker key, the Add/Remove Programs entry and a DisableSelfUpdate value that the lifecycle wrote are gone, and so are their parent keys and C:\Program Files\Cisco when nothing else is left in them. The lifecycle log in %WINDIR%\Logs\DefenseClaw stays. On a computer without DefenseClaw, uninstall succeeds and changes nothing.

Run the CLI uninstall with defenseclaw.exe. The other installed binaries, such as defenseclaw-gateway.exe, refuse it (exit 1639) without changing anything, because a running binary keeps its own folder in use. If an uninstall reports that it committed but could not finish, run the same defenseclaw.exe uninstall (or the MDM uninstall.ps1) again: it finishes the cleanup.

Per-user registrations at uninstall

Uninstall revokes every per-user enrollment first. Once it has committed, it removes DefenseClaw's own hook registrations and plugins (Amp, Antigravity, Devin, Hermes, Kiro, OpenCode, and a DefenseClaw Copilot user hook file) from the agent configuration of every signed-in user, running as that user. Only DefenseClaw's entries are removed; the user's own hooks and settings stay. Cleanups the guardian still owed to revoked users are included.

Acting as a user needs that user's session token, which only LocalSystem can obtain. An MDM uninstall runs as LocalSystem (Intune install behavior System). An uninstall run from an elevated administrator prompt, or from Add/Remove Programs, cannot act as other users, so it removes no per-user registrations. Users who are signed out during the uninstall keep theirs as well: no guardian is left to clean them at their next sign-in. The uninstall result names what stays: the user_registrations_pending warning lists each account and its connectors it could not act as, and user_registrations_failed lists removals that failed, including a registration that a connector's removal left in the user's agent configuration (the message names the file). An uninstall that did not run as LocalSystem attempts no removal, so it reports only user_registrations_pending. To clean every user, run the uninstall as LocalSystem while they are signed in (see Run Setup as LocalSystem).

PURGE=1 also removes each enrolled account's %USERPROFILE%\.defenseclaw folder, including that account's per-user hook tokens, whether or not the account is signed in. Some of its subfolders grant only the account and SYSTEM, not Administrators, so this also needs the uninstall to run as LocalSystem. As on Linux and macOS, the whole folder goes: the hook scripts, and the account's own hooks that the foreign-hook policy moved aside (foreign-hooks-backup; copy it first if the account wants them back). A %USERPROFILE%\.defenseclaw.rollback-<random> copy that a rolled-back enrollment kept aside goes too. The purge also removes the allow-only defenseclaw-hook.ps1 placeholder and its lock file, which the default uninstall keeps in C:\ProgramData\Cursor for Cursor windows that are still open, and the DefenseClaw launchers, binaries, the uv the per-user installer added (when unchanged) and its bookkeeping from %USERPROFILE%\.local\bin. When that leaves the folder empty, the folder goes, and so does its entry in the account's user Path; a folder other tools still use keeps its entry. A signed-out account's registry hive is not loaded, so its Path entry stays and the result says so. The result names each account whose data the purge removed. The per_user_state_remaining warning names each folder the purge could not remove and why: the uninstall did not run as LocalSystem, a file in it could not be removed, or the account's roaming or container profile is not on the computer while it is signed out. Remove what it names as LocalSystem. A purge that did not run as LocalSystem removes the machine deployment but none of these folders, so it fails (non-zero exit) and names each account: run Setup /ensure and then /uninstall PURGE=1, both as LocalSystem while the accounts have an active (connected) session.

The agents' shared machine folders stay while they hold anything else, because another product can use them. Setup removes its own files from them. A purge also removes C:\Program Files\ClaudeCode\managed-settings.d, and then C:\Program Files\ClaudeCode, when nothing else is left in them. It also removes the folders an interrupted elevated DefenseClaw command left: C:\ProgramData\DefenseClaw-PowerShell-<32 hex>, C:\ProgramData\DefenseClaw-Installer-<32 hex> and C:\Windows\Temp\DefenseClaw-Bootstrap-<32 hex>; every uninstall does this, not only a purge. The machine_state_remaining warning names any of these folders it could not remove, and why.

What stays is inert. Uninstall has already revoked every enrollment. The OpenCode and Amp plugins stop enforcing once uninstall removes C:\ProgramData\Cisco\DefenseClaw-HookRuntime and the install marker. The Devin, Hermes, Antigravity and Kiro hooks point at the removed defenseclaw-hook.exe, so each hook call fails to start. None of these agents blocks on that: Devin blocks only on exit code 2 (a missing command exits 127), and Hermes and Antigravity do not enforce a nonzero hook exit. A DefenseClaw Copilot user hook that stays points at the removed hook binary, so Copilot cannot start it and does not block on it. (This is a hook that cannot start at all, unlike a running hook a user stops; see Hook process control.)

Payload trust

The lifecycle refuses to run any payload file it cannot trust. There are two trust modes:

ModeHow a file is trusted
authenticodeEvery binary and script carries an Authenticode signature that Windows reports as Valid. An allowed-signer list narrows the accepted signer certificates.
hash_pinnedEvery file that is not validly signed must match a SHA-256 digest in an administrator-owned payload manifest. The CLI checks the installer script and module against it before PowerShell starts.

The default depends on how you start the lifecycle:

Entry pointTrust usedHow to change it
Standalone SetupChosen by the build. An unsigned Setup uses hash_pinned with a payload manifest (payload-trust.json) that Setup writes itself from its embedded, verified manifest. A signed Setup uses authenticode.ALLOWEDSIGNERS= pins the signer of a signed build. You never supply payload-trust.json.
defenseclaw.exe enterprise windowsauthenticode--trust-mode hash_pinned --payload-manifest <file>. --allowed-signer <sha256> (repeatable) pins signers.
MDM wrapper (Invoke-DefenseClawEnterprise.ps1)HashPinned: it checks the Setup file against -Sha256 before running it-TrustMode Authenticode -AllowedSigners <sha256>. See Install with an MDM.

Releases are Authenticode-signed only when the release pipeline has a code-signing certificate. Check the Setup you downloaded:

$sig = Get-AuthenticodeSignature -LiteralPath .\DefenseClawSetup-Enterprise-Standalone-x64.exe
$sig.Status
if ($sig.SignerCertificate) {
  $sha = [Security.Cryptography.SHA256]::Create()
  [BitConverter]::ToString($sha.ComputeHash($sig.SignerCertificate.RawData)).Replace('-', '').ToLowerInvariant()
}

Valid means the Setup is signed, and the last line prints the signer's SHA-256 thumbprint for ALLOWEDSIGNERS=. NotSigned means a hash-pinned build: trust comes from the Setup hash you checked against checksums.txt.

enterprise.trust in the config can only narrow what the entry point accepts. mode: authenticode refuses a hash-pinned run, including the unsigned Setup, with 1639, and also refuses a run over a deployment that was installed hash-pinned, because that deployment keeps admitting its payload by its recorded pins. Leave the mode unset or set hash_pinned while you deploy unsigned builds; a signed Setup is still verified by its signature. enterprise.trust.allowed_signers works like --allowed-signer; when both are given they must list the same thumbprints. See Payload trust.

The deployment marker's TrustMode records how the installed deployment was trusted. The MDM detect.ps1 and uninstall.ps1 scripts check the installed CLI's Authenticode signature only when it is authenticode.

Hash-pinned files have no publisher, so they do not satisfy WDAC or AppLocker rules that require one. Sign or re-sign the payload where those rules apply.

Advanced: run the lifecycle CLI from a payload folder

The lifecycle CLI can run from a folder that holds the seven payload files: defenseclaw.exe, defenseclaw-gateway.exe, defenseclaw-hook.exe, defenseclaw-acp.exe, defenseclaw-sensor-helper.exe, install-enterprise.ps1 and DefenseClawEnterprise.psm1. The CLI uses ..\libexec\install-enterprise.ps1 if that file exists, otherwise the installer script next to itself. ensure takes the binaries from the installer script's folder.

Releases ship these files only inside Setup, and Setup has no extract action. Use this path only when your own build or re-signing pipeline produces the files. Otherwise use Setup.

$Payload = 'C:\ProgramData\DefenseClaw-Staging\payload'
& "$Payload\defenseclaw.exe" enterprise windows ensure `
  --profile standalone `
  --config 'C:\ProgramData\DefenseClaw-Staging\config.yaml' `
  --json

For unsigned files, add --trust-mode hash_pinned --payload-manifest <file>. The manifest is JSON in the form {"schema_version":1,"files":{"<file name>":"<sha256>"}}. It must pin install-enterprise.ps1, DefenseClawEnterprise.psm1 and every other unsigned file. The ...payload-manifest.json release asset uses a different format and cannot be passed here. Later repair, verify and uninstall runs re-trust the installed files from the digests the deployment recorded, so they need no manifest.

Agent sessions in WSL

An agent that runs inside a WSL 2 distribution is outside every policy DefenseClaw publishes on Windows. The distribution has its own /etc/claude-code and ~/.codex, the user can open it as root (wsl -u root), and Windows endpoint sensors do not see the WSL VM. The standalone profile keeps these sessions off where a vendor documents a control, and enterprise policy show and verify report the rest in a wsl row. Set the behavior under enterprise.machine_policy.windows_wsl (see Configuration).

SurfaceWhat DefenseClaw doesVendor source
Claude Desktop WSL sessionsThe guardian adds disableWslSessions (REG_SZ true) to HKLM\SOFTWARE\Policies\Claude when the key already holds machine policy. It never changes an administrator's value: an administrator false or 0 turns WSL sessions on and fails verify unless agent_sessions: allow is set.Claude Code admin setup, Claude Desktop MDM
wslInheritsWindowsSettingsDetected, never written, in HKLM or HKCU SOFTWARE\Policies\ClaudeCode\Settings and the Program Files managed settings. While WSL sessions are allowed it fails verify: a WSL session would load DefenseClaw's Windows hook command, which cannot start inside Linux.Claude Code admin setup
Codex IDE extensionEvery guardian pass, as each enrolled user, the guardian resets chatgpt.runCodexInWindowsSubsystemForLinux: true to false in VS Code, VS Code Insiders and Cursor user settings, profiles included, keeping every other byte. After 3 repairs for one account within an hour it only reports. chatgpt.cliExecutable is reported, not changed.Codex IDE settings
Codex appReported only. The agent environment (Windows native or WSL) is an in-app setting with no documented managed control or storage.Codex app on Windows
WSL itselfWith platform: disable, the guardian sets HKLM\SOFTWARE\Policies\WSL\AllowWSL=0, which turns WSL off for every account. It never replaces an administrator value.WSL settings for enterprise

Claude Desktop's hive rule decides where the gate may go. Any REG_SZ, REG_EXPAND_SZ or REG_DWORD value directly under HKLM\SOFTWARE\Policies\Claude makes Desktop ignore HKCU\SOFTWARE\Policies\Claude entirely, and a managed key other than Desktop's app-behavior keys makes Desktop ignore local third-party configuration in %LOCALAPPDATA%\Claude-3p\configLibrary. So by default DefenseClaw only joins machine policy that is already there. With an empty key, Claude Desktop's own default applies: it keeps WSL sessions off on devices it treats as organization-managed. The wsl row stays covered and shows a pending line with the step that makes the gate explicit: add the output of enterprise policy export --connector wsl (reg, json or intune) to the Claude Desktop policy you already deploy, or set claude_desktop_key: create. With create DefenseClaw writes the value to an empty key, but still not while a signed-in account has HKCU Claude Desktop policy or any account has local third-party configuration; then verify fails, because the requested gate is missing. It never writes the gate when the key grants write access to anyone other than Administrators, SYSTEM and TrustedInstaller, and verify fails, because a standard account could turn WSL sessions on. Uninstall removes only the values DefenseClaw wrote that are still unchanged.

Limits:

  • Whether REG_SZ true forces Claude Desktop's WSL gate off is not documented; the vendor documents only false and 0, which turn WSL sessions on. Desktop also turns WSL sessions off by default on devices it treats as managed. Check Desktop's main.log for [wslPolicyGate] lines after you deploy.
  • A Claude Desktop WSL session that is already running continues. Desktop checks the value at each WSL session start.
  • A user can turn the Codex extension setting back on. The window lasts until the next guardian pass. The setting is window-scoped, so a trusted workspace's .vscode/settings.json or .code-workspace file can also turn it on; workspace settings and VS Code Remote - WSL windows are not checked.
  • Agent CLIs that a user runs inside the distribution, and editor or SSH sessions into it, are not covered. Only platform: disable (AllowWSL=0) closes WSL as a whole.
  • A Linux standalone install inside the distribution is refused. See Linux requirements.

Connectors on Windows

ConnectorRoute on WindowsNotes
CodexMachine policyCodex requirements file. DefenseClaw always sets allow_managed_hooks_only = true, and an administrator value of false makes the run fail.
Claude CodeMachine policyManaged-settings drop-in with DefenseClaw's hooks and, under the default managed_hooks_only: enforce, the allowManagedHooksOnly vendor lock. preserve leaves the lock out and turns the foreign-hook guard on for Claude Code. Windows refuses a non-empty HKLM\SOFTWARE\Policies\ClaudeCode\Settings.
CursorMachine policyCursor enterprise hooks
GitHub CopilotMachine policy%ProgramData%\GitHub\Copilot\policy.d, plus a per-user hook runtime
OpenCodeMachine policy%ProgramData%\opencode loads the managed plugin, plus a per-user hook runtime. Falls back to the per-user plugin while the managed plugin is not in force
Antigravity, Devin, HermesPer userThe guardian registers defenseclaw-hook.exe in each user's agent config
AmpPer userThe guardian registers an in-agent plugin that calls the gateway after the listener proves it can derive the user's credential
KiroPer userThe guardian writes defenseclaw-hook.exe into each user's global %USERPROFILE%\.kiro\hooks\defenseclaw.json (Kiro IDE 1.0.182 and later, kiro-cli --v3) and the CLI 2.x defenseclaw agent, pinned to a reviewed Windows hook contract (kiro-cli 2.24.1 and later, Kiro IDE 1.0.182 and later). A kiro-cli that has never run is enrolled at 2.24.1 until its first run names its version. See Kiro. The ACP guard stays available
OpenHands, OmniGent, OpenClaw, ZeptoClawNot managedThe enumerator writes no targets for them, so they are not protected. A target manifest row that names one is refused with a reason.

Windows handles machine policy differently from Linux and macOS. See Machine policy and Foreign-hook guard.

Upgrades and downgrades

Run /ensure with the newer Setup. It upgrades in place and keeps the config and state. /ensure refuses to install an older version (downgrade_refused). See Upgrade and Roll back. For failed runs, see Lifecycle error codes.