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
| Requirement | Detail |
|---|---|
| Windows | Native 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 7 | A 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 mode | PowerShell FullLanguage mode. Under a WDAC or AppLocker script policy, allow the DefenseClaw signer, or the run stops with powershell_constrained_language. |
| Privileges | An elevated administrator token, or SYSTEM (for example an MDM agent). |
| Disk space | Free 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 profiles | No 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.
| Item | Path |
|---|---|
| Binaries | C:\Program Files\Cisco\DefenseClaw\bin (defenseclaw.exe, defenseclaw-gateway.exe, defenseclaw-hook.exe, defenseclaw-acp.exe, defenseclaw-sensor-helper.exe) |
| Lifecycle scripts | C:\Program Files\Cisco\DefenseClaw\libexec (install-enterprise.ps1, DefenseClawEnterprise.psm1) |
| Config | C:\ProgramData\Cisco\DefenseClaw\etc\config.yaml |
| Secrets | C:\ProgramData\Cisco\DefenseClaw\secrets |
| Target manifest | C:\ProgramData\Cisco\DefenseClaw\hook-guardian\targets.yaml (the enumerator writes it) |
| Lifecycle state | C:\ProgramData\Cisco\DefenseClaw\install |
| Gateway data | C:\ProgramData\Cisco\DefenseClaw\runtime |
| Authorization ledger | C:\ProgramData\Cisco\DefenseClaw\hook-guardian-state |
| Service logs | C:\ProgramData\Cisco\DefenseClaw\logs |
| Hook runtime | C:\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:
| Registration | Value |
|---|---|
| Deployment marker | HKLM\SOFTWARE\Cisco\DefenseClaw\Enterprise, with Profile, ProductVersion, InstallRoot, StateRoot, TrustMode, UpdatedAt and DisableSelfUpdate |
| Add/Remove Programs | HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\CiscoDefenseClawEnterprise, shown as "Cisco DefenseClaw Enterprise" |
| Event log | The 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 policy | HKLM\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:
| Service | Identity | Role |
|---|---|---|
DefenseClawGateway | NT SERVICE\DefenseClawGateway, with SeChangeNotifyPrivilege only | Runs the policy engine and the hook API on 127.0.0.1:18970 |
DefenseClawSensorHelper | LocalSystem, with SeChangeNotifyPrivilege only | Answers the gateway's fixed AI Discovery requests |
DefenseClawHookGuardian | LocalSystem, with a fixed privilege list | Writes and repairs each enrolled user's hook registrations, using that user's token |
DefenseClawHookEnumerator | LocalSystem, with the same privilege list | Finds 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:
List view for small screens. Use the expand button to open the drawing.
TrustedZ0 · Admin and OS (SYSTEM)
- Service Control Managerknows the gateway's PID
- startsGatewayZ2
UntrustedZ4 · User session (the user)
- AI agentruns as the user
- runs per tool calldefenseclaw-hook.exe
- defenseclaw-hook.exechecks the listener
- asks over loopback TCPGatewayZ2
RestrictedZ2 · Gateway (virtual account)
- Gatewayallows or blocks
How the hooks stay in place:
List view for small screens. Use the expand button to open the drawing.
PrivilegedZ1 · Services (LocalSystem)
- Enumeratorlists the users
- writesTarget manifestZ3
- Guardianchecks every minute
- readsTarget manifestZ3
- repairs, as the userAgent configZ4
ProtectedZ3 · Admin-owned files
- Target manifesttargets.yaml
UntrustedZ4 · User session (the user)
- Agent configin the user's profile
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.txtandchecksums.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_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:
| Code | Meaning |
|---|---|
0 | Success, or nothing to do |
1603 | Failure. 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. |
1618 | Another lifecycle run holds the lock. Retry later. |
1639 | Invalid 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. |
3010 | Reserved. 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.
| Property | Meaning |
|---|---|
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=1 | With /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=1 | Print the result document on standard output |
NOSTART=1 | Install or update with the services stopped and disabled. A later /repair starts them. |
PURGE=1 | With /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:
enterprise:
profile: standalone
inspection:
ai_defense:
enabled: true
credential: ai-defense-api-keyThen 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 --jsonstatus 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:
| Field | Healthy value |
|---|---|
ok | true |
installed, installed_version | true and the version you deployed |
readiness | gateway, guardian, enumerator and sensor_helper all true |
coverage_complete | true: installed, the guardian is ready, and no transaction is pending |
security_complete | true: see below |
enrollment.targets | The number of entries (one per user and connector) in the target manifest. 0 means nobody is protected yet. |
errors | Empty |
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:
-
Install.
security_completeisfalseat this point. -
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"$Stageis the administrator-only folder from Write the config; the export can hold prompt and tool content.enterprise policy verify --liveis not available on Windows; see Inspect machine policy. -
Record the attestation from an elevated PowerShell 7 session:
& $Cli enterprise windows repair --profile standalone --attest-claude-effective-policy --jsonThe 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:
Get-Service DefenseClaw* | Format-Table Name, Status, StartType
Get-WinEvent -LogName DefenseClaw -MaxEvents 3 | Format-Table TimeCreated, Id, LevelDisplayName, ProviderNameName 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 LifecycleEvent 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:
& '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 --applicationstatus 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:
$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:
& 'C:\Program Files\Cisco\DefenseClaw\bin\defenseclaw.exe' enterprise windows discovery
& 'C:\Program Files\Cisco\DefenseClaw\bin\defenseclaw.exe' enterprise windows discovery --user <account> --jsonIt 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:
& 'C:\Program Files\Cisco\DefenseClaw\bin\defenseclaw.exe' enterprise policy show
& 'C:\Program Files\Cisco\DefenseClaw\bin\defenseclaw.exe' enterprise policy verifyshow 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:
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:
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 $ResultLastTaskResult 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 action | What happens |
|---|---|
install.ps1 | Refuses when the marker key exists, or when DisableSelfUpdate under HKLM\SOFTWARE\Policies\Cisco\DefenseClaw is nonzero |
defenseclaw upgrade, defenseclaw rollback | Refuse when the marker key exists |
| Per-user gateway | Refuses 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=1Or with the installed CLI:
& 'C:\Program Files\Cisco\DefenseClaw\bin\defenseclaw.exe' enterprise windows uninstall --profile standalone --jsonUninstall 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:
| Mode | How a file is trusted |
|---|---|
authenticode | Every binary and script carries an Authenticode signature that Windows reports as Valid. An allowed-signer list narrows the accepted signer certificates. |
hash_pinned | Every 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 point | Trust used | How to change it |
|---|---|---|
| Standalone Setup | Chosen 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 windows | authenticode | --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' `
--jsonFor 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).
| Surface | What DefenseClaw does | Vendor source |
|---|---|---|
| Claude Desktop WSL sessions | The 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 |
wslInheritsWindowsSettings | Detected, 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 extension | Every 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 app | Reported 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 itself | With 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
trueforces Claude Desktop's WSL gate off is not documented; the vendor documents onlyfalseand0, which turn WSL sessions on. Desktop also turns WSL sessions off by default on devices it treats as managed. Check Desktop'smain.logfor[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.jsonor.code-workspacefile 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
| Connector | Route on Windows | Notes |
|---|---|---|
| Codex | Machine policy | Codex requirements file. DefenseClaw always sets allow_managed_hooks_only = true, and an administrator value of false makes the run fail. |
| Claude Code | Machine policy | Managed-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. |
| Cursor | Machine policy | Cursor enterprise hooks |
| GitHub Copilot | Machine policy | %ProgramData%\GitHub\Copilot\policy.d, plus a per-user hook runtime |
| OpenCode | Machine 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, Hermes | Per user | The guardian registers defenseclaw-hook.exe in each user's agent config |
| Amp | Per user | The guardian registers an in-agent plugin that calls the gateway after the listener proves it can derive the user's credential |
| Kiro | Per user | The 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, ZeptoClaw | Not managed | The 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.
Enterprise threat model
Who DefenseClaw trusts, where each trust boundary sits on Windows, Linux and macOS, what a standard user can and cannot do, and which risks remain in the standalone enterprise profile.
Linux standalone deployment
Install the standalone DefenseClaw enterprise services on Linux from the deb or rpm package or the payload tarball, check the result, and remove them.