{"id":50666949,"url":"https://github.com/williamsmithedward/arcaneedr","last_synced_at":"2026-06-11T20:00:17.059Z","repository":{"id":362909165,"uuid":"1261253866","full_name":"WilliamSmithEdward/ArcaneEDR","owner":"WilliamSmithEdward","description":"Arcane EDR is a lightweight Windows service for making unattended agent workstations safer while still allowing fast, bleeding-edge work.","archived":false,"fork":false,"pushed_at":"2026-06-08T05:46:24.000Z","size":936,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-08T07:26:54.696Z","etag":null,"topics":["agentic-ai","agentic-workflow","edr","security"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/WilliamSmithEdward.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-06-06T12:49:45.000Z","updated_at":"2026-06-08T05:46:27.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/WilliamSmithEdward/ArcaneEDR","commit_stats":null,"previous_names":["williamsmithedward/arcaneedr"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/WilliamSmithEdward/ArcaneEDR","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WilliamSmithEdward%2FArcaneEDR","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WilliamSmithEdward%2FArcaneEDR/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WilliamSmithEdward%2FArcaneEDR/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WilliamSmithEdward%2FArcaneEDR/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/WilliamSmithEdward","download_url":"https://codeload.github.com/WilliamSmithEdward/ArcaneEDR/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WilliamSmithEdward%2FArcaneEDR/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34215254,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-11T02:00:06.485Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agentic-ai","agentic-workflow","edr","security"],"created_at":"2026-06-08T07:05:34.004Z","updated_at":"2026-06-11T20:00:17.000Z","avatar_url":"https://github.com/WilliamSmithEdward.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Arcane EDR\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"src/Assets/square_logo.png\" alt=\"Arcane EDR logo\" width=\"280\"\u003e\n\u003c/p\u003e\n\nArcane EDR is a lightweight Windows service for making unattended agent\nworkstations safer while still allowing fast, bleeding-edge work. It is built\nfor sandbox hosts, AI-agent boxes, and small environments where autonomous tools\nneed broad local capability, but the owner still wants guardrails against\nsupply-chain compromise, RAT-like activity, persistence, suspicious egress, and\ncredential or remote-access abuse.\n\nIt watches TCP/UDP activity, enriches events with local process and host\ncontext, scores suspicious behavior, writes local evidence, and can send\nqualified alerts through modular notification paths. The goal is practical\nhost-level safety without needing to set up or pay for a full enterprise EDR,\nSIEM, MDM, or SOC deployment.\n\nThe service/CLI core intentionally uses .NET Framework and built-in Windows\ncomponents. The operator GUI is a self-contained .NET 10 / WinUI 3 application\nwith its runtime payload included in release builds.\n\nSee [docs/project-mission.md](docs/project-mission.md) for the project mission.\nSee [docs/release-deployment-policy.md](docs/release-deployment-policy.md) for\nthe source-vs-live deployment policy.\nSee [docs/gui-and-msi-install.md](docs/gui-and-msi-install.md) for the WinUI\nGUI and MSI install path.\nIf you are using an LLM or coding agent to operate the repo, see\n[AGENTS.md](AGENTS.md) for agent-specific workflow and tuning instructions.\n\n## What It Detects\n\n- New listening TCP/UDP ports.\n- New external outbound TCP connections.\n- External inbound TCP connections.\n- Connections to commonly abused remote ports.\n- Connection bursts by process.\n- Low-jitter repeated outbound connections that resemble beaconing.\n- Process path, command line, parent process, user, signer, and SHA256 context.\n- Sysmon process, network, DNS, and narrow high-risk file-create events when Sysmon is installed.\n- PowerShell operational log events, including script block, module, and lifecycle records.\n- Windows Security/System events for failed logons, RDP/network logons, privileged logons, service installs, scheduled task changes, and process-creation audit events when enabled.\n- Registry Run keys, Startup folders, automatic services, and scheduled-task inventory.\n- Executable/script drops into persistence-adjacent locations, suspicious sensitive-file writes, and high-risk file drop-then-execute patterns.\n- LOLBin and script-runtime external network activity.\n- Encoded or base64-obfuscated PowerShell/CLI commands.\n- Suspicious parent/child process chains.\n- Unsigned executables launched from user-writable paths.\n- First-seen executable and persistence reputation cache.\n- Local JSON custom rules in `config\\custom-rules.json`.\n- Known RMM/RAT process names.\n- Blocked domains, hashes, IPs, and CIDRs.\n- High-entropy DNS and dynamic DNS providers.\n- Optional DNS-over-HTTPS resolver detection.\n- Optional DNS resolver enforcement.\n- Untrusted process connections to internal lateral-movement ports.\n\nArcane EDR is not a packet sniffer or a full EDR platform. It is a focused\nWindows safety layer intended for unattended agent workstations, sandbox hosts,\nand small environments where local visibility and simple alerting are useful.\n\nSee [ROADMAP.md](ROADMAP.md) for the beta-to-`v1.0.0` roadmap.\nSee [docs/rule-family-reference.md](docs/rule-family-reference.md) for a\npractical guide to current rule families, telemetry requirements, tuning knobs,\nfalse positives, and safe tests.\n\n## Requirements\n\n- Windows with .NET Framework compiler available at\n  `%WINDIR%\\Microsoft.NET\\Framework64\\v4.0.30319\\csc.exe` or the 32-bit\n  Framework path.\n- PowerShell.\n- Administrator rights for service install, service removal, Sysmon install,\n  and some event-log validation checks.\n- Optional: Sysmon for richer process, network, DNS, and narrow file-create telemetry.\n- Optional: Brevo transactional email for external alert delivery.\n- Optional: AI provider API key for compact secondary log analysis.\n\n## Quick Start\n\nFor a release-MSI install with every step spelled out, start with\n[docs/step-by-step-install.md](docs/step-by-step-install.md).\n\nClone the repo and create local config files from the tracked templates:\n\n```powershell\ngit clone https://github.com/WilliamSmithEdward/ArcaneEDR.git\ncd ArcaneEDR\nCopy-Item .\\config\\ArcaneEDR.example.config .\\config\\ArcaneEDR.config\nCopy-Item .\\config\\Deployment.example.config .\\config\\Deployment.config\n```\n\nBuild the executable:\n\n```powershell\n.\\scripts\\build.ps1\n```\n\nRun in console mode:\n\n```powershell\n.\\bin\\ArcaneEDR.exe --console\n```\n\nValidate configuration and host prerequisites:\n\n```powershell\n.\\bin\\ArcaneEDR.exe --validate-config\n```\n\nValidate a specific config file while tuning a clone or staged deployment:\n\n```powershell\n.\\bin\\ArcaneEDR.exe --validate-config .\\config\\ArcaneEDR.config\n```\n\nPrint the executable version:\n\n```powershell\n.\\bin\\ArcaneEDR.exe --version\n```\n\n## Configuration\n\nTracked template files are safe defaults for GitHub:\n\n- `config\\ArcaneEDR.example.config`: runtime identity, log directory, alert\n  settings, event log names, thresholds, schedules, and detection tuning.\n- `config\\Deployment.example.config`: publish destination, application folder,\n  executable name, Sysmon executable name, and Sysmon config filename.\n\nLocal files are intentionally ignored by Git:\n\n- `config\\ArcaneEDR.config`\n- `config\\Deployment.config`\n- `config\\arcane-policy.json`\n\nKeep machine-specific values, recipient addresses, local paths, and environment\nvariable names in the ignored local files. The example runtime config disables\nexternal alerting and AI analysis by default.\n\n`config\\arcane-policy.json` is the unified allowlist, blocklist, response,\nremote endpoint, and alert-tuning policy file. Inspect loaded policy scopes and\ncounts with:\n\n```powershell\n.\\bin\\ArcaneEDR.exe --policy-inspect\n.\\bin\\ArcaneEDR.exe --policy-inspect --json\n```\n\n## Project Layout\n\n- `src\\Collection`: captures netstat, Sysmon, PowerShell, Windows Event Log, and persistence telemetry.\n- `src\\Enrichment`: adds process path, command line, parent, hash, signer, and user context.\n- `src\\Detection`: applies traffic, host, process, DNS, reputation, custom, baseline, and RAT-oriented rules.\n- `src\\Alerting`: handles alert cooldowns and provider-specific delivery sinks.\n- `src\\Policy`: unified policy models and scoped policy evaluation.\n- `src\\Presentation`: shared alert presentation models for email, reports, CLI, and future GUI surfaces.\n- `src\\ArcaneEDR.Gui`: self-contained .NET 10 / WinUI 3 operator console with a persistent tray icon for health, alerts, policy, reports, configuration, maintenance, and support workflows.\n- `src\\Response`: optional firewall block and process termination actions.\n- `src\\Runtime`: service polling, health, and integrity checks.\n- `src\\Configuration`: loads allowlists, thresholds, alert settings, and rule options.\n- `src\\Logging`: writes text logs and JSONL alert records with rotation.\n- `src\\Models`: shared alert, process, DNS, and network endpoint models.\n- `src\\Utils`: CIDR, IP, domain, filesystem, and port-range helpers.\n- `src\\Validation`: offline configuration and environment checks.\n- `scripts`: build, publish, service install, service removal, and Sysmon install helpers.\n\n## Build And Publish\n\nSource work is separate from live deployment. Ordinary source and documentation\nchanges should be built and validated from the source folder, but not published\nto the live application folder unless a tagged release is being deployed or the\noperator explicitly asks for a live update. See\n[docs/release-deployment-policy.md](docs/release-deployment-policy.md).\n\nBuild:\n\n```powershell\n.\\scripts\\build.ps1\n```\n\nRun the lightweight fixture suite used to guard core CLI seams:\n\n```powershell\n.\\scripts\\test-fixtures.cmd\n```\n\nBuild and publish the WinUI operator console:\n\n```powershell\n.\\scripts\\build-gui.cmd\n```\n\nBuild the WiX MSI installer:\n\n```powershell\n.\\scripts\\build-msi.cmd\n```\n\nFor operator installs and upgrades, prefer the MSI so the service, GUI, Start\nmenu shortcut, installer state, and uninstall path stay aligned.\n\nFor an older script-installed local service, migrate to MSI ownership from an\nelevated PowerShell session:\n\n```powershell\n.\\scripts\\build-msi.cmd\n.\\scripts\\install-msi-local.cmd -ReplaceExistingService\n```\n\nThe install helper installs product files under `C:\\Program Files\\Arcane EDR`,\nuses `%ProgramData%\\Arcane EDR` for first-install mutable logs/state, removes an\nexisting service registration only when `-ReplaceExistingService` is supplied,\nwrites installed first-run runtime/deployment config when missing, and then\nverifies the installed executable version, service path, config, and service\nstatus. After validation confirms the service points at\n`C:\\Program Files\\Arcane EDR\\bin\\ArcaneEDR.exe`, any old\n`C:\\Applications\\ArcaneEDR` folder may be deleted.\n\nFor source development or break-glass repair, publish to the destination\nconfigured in local `config\\Deployment.config`, or the example deployment\nconfig when no local config exists:\n\n```powershell\n.\\scripts\\publish.ps1\n```\n\nThe script-published folder contains the executable, config files, docs, Sysmon\nconfig, and install scripts. If a published `config\\ArcaneEDR.config` already\nexists, publish preserves it and writes the source config as\n`config\\ArcaneEDR.example.config`. Use `-OverwriteConfig` only when replacing a\nlive runtime config is intentional.\n\nExisting published `config\\Deployment.config` is also preserved by default. Use\n`-OverwriteDeploymentConfig` only when replacing the live deployment config is\nintentional.\n\nCreate a release ZIP from tracked templates, scripts, docs, and build output:\n\n```powershell\n.\\scripts\\package-release.ps1\n```\n\nThe release ZIP is written under `artifacts` with a SHA256 checksum file. Local\nmachine configs, runtime logs, and Sysmon binaries are not included. The ZIP\nincludes the WinUI GUI payload under `gui`.\n\nThe MSI is written under `artifacts` as `ArcaneEDR-\u003cversion\u003e.msi` with a\nSHA256 checksum. It installs the Windows service, WinUI GUI, Start menu\nshortcut, scripts, docs, assets, and config examples. Existing local\nconfiguration and JSONL evidence are preserved by default; the GUI\nConfiguration page provides a guarded reset-to-defaults flow with an explicit\nwarning checkbox and backup-before-reset behavior.\n\nThe standard MSI-owned product folder is `C:\\Program Files\\Arcane EDR`.\nThe standard first-install machine data folder is `%ProgramData%\\Arcane EDR`.\n\n## Install As A Windows Service\n\nMSI is the preferred operator path for installing and upgrading the service.\nUse the direct service scripts only for source development, diagnostics, or\nbreak-glass repair.\n\nFor a script-based development install, run PowerShell as Administrator from\nthe published application folder:\n\n```powershell\n.\\scripts\\install-service.ps1\n```\n\nThe service is installed using `ServiceName`, `ServiceDisplayName`, and\n`ServiceDescription` from `config\\ArcaneEDR.config`.\n\nUninstall:\n\n```powershell\n.\\scripts\\uninstall-service.ps1\n```\n\nThe installer configures Windows Service Control Manager recovery actions:\n\n- restart after 60 seconds on first failure\n- restart after 60 seconds on second failure\n- restart after 5 minutes on subsequent failure\n- reset the failure counter after 24 hours\n\n## Optional Constrained Admin Tasks\n\nIf you do not want to run the Codex desktop app as Administrator, you can create\non-demand scheduled tasks for specific elevated maintenance operations. This is\nmore constrained than giving a tool a general admin shell.\n\nThis is the preferred elevation strategy for source-driven Arcane EDR\nmaintenance from Codex. Once a machine is MSI-owned, prefer MSI repair/upgrade\nfor normal operator changes and keep admin tasks for diagnostics or\nbreak-glass repair. See `docs\\elevation-strategy.md` for the operating model.\n\nRun once from an elevated PowerShell session in the source repo:\n\n```powershell\ncd C:\\Development\\ArcaneEDR\n.\\scripts\\install-admin-tasks.cmd\n```\n\nThis registers these on-demand tasks under `\\ArcaneEDR\\`:\n\n- `PublishRestart`: stop service if installed, build from source, publish while\n  preserving live config, then restart the service.\n- `InstallService`: publish, install the Windows service, configure service\n  recovery, then start it.\n- `UninstallService`: stop and remove the Windows service.\n- `InstallSysmon`: install or update Sysmon from the published `tools` folder.\n- `ValidateAdmin`: run `ArcaneEDR.exe --validate-config` elevated.\n\nAfter setup, a normal shell can trigger an approved task:\n\n```powershell\n.\\scripts\\run-admin-task.cmd -TaskName PublishRestart\n.\\scripts\\run-admin-task.cmd -TaskName ValidateAdmin\n```\n\nThe `.cmd` wrappers use `powershell.exe -ExecutionPolicy Bypass -File` so the\nworkflow still works on machines where local `.ps1` execution is restricted.\n\nTask output is written to:\n\n```text\nC:\\Security\\AdminTasks\\\u003cTaskName\u003e.log\n```\n\nRemove the tasks from an elevated PowerShell session:\n\n```powershell\n.\\scripts\\uninstall-admin-tasks.cmd\n```\n\n## Optional Sysmon\n\nArcane EDR can read Sysmon when Sysmon is already installed on the machine. If\nthe `SysmonServiceName` from `config\\ArcaneEDR.config` is running, no Sysmon\nbinary is needed in the Arcane EDR folder.\n\nThe `tools` folder is only for installing or updating Sysmon from the published\napp folder. Sysmon is not bundled. To use that workflow, download Sysmon from\nMicrosoft Sysinternals, place the executable named by `SysmonExecutableName` in\n`tools`, then run:\n\n```powershell\n.\\scripts\\install-sysmon.cmd\n```\n\nThe included `config\\arcaneedr-sysmon.xml` enables process creation, network\nconnection, DNS query, SHA256 hash telemetry, and narrow FileCreate coverage for\nStartup folders, scheduled-task storage, browser extension paths, and\nsensitive-looking filenames. If Sysmon is not installed, Arcane EDR falls back\nto netstat-based collection and logs a warning once.\n\n## Test Commands\n\nTest alert delivery:\n\n```powershell\n.\\bin\\ArcaneEDR.exe --test-alert\n.\\bin\\ArcaneEDR.exe --test-alert --count 2\n```\n\nTest service-health notification delivery:\n\n```powershell\n.\\bin\\ArcaneEDR.exe --test-health\n```\n\nForce compact AI log analysis:\n\n```powershell\n.\\bin\\ArcaneEDR.exe --test-ai-analysis\n```\n\nGenerate and send a daily report on demand:\n\n```powershell\n.\\bin\\ArcaneEDR.exe --test-daily-report\n```\n\nPreview a daily report without sending an external notification or making an\nAI API call:\n\n```powershell\n.\\bin\\ArcaneEDR.exe --preview-daily-report\n.\\bin\\ArcaneEDR.exe --preview-daily-report --json\n.\\bin\\ArcaneEDR.exe --preview-daily-report --archive\n```\n\nUse `--validate-config \u003cconfig-path\u003e` to check a staged report configuration\nwithout copying it into the runtime `config` directory first.\n\nPreview the exact redacted payload that would be sent to the AI provider without\nmaking an API call:\n\n```powershell\n.\\bin\\ArcaneEDR.exe --preview-ai-payload\n```\n\nGenerate a privacy-first local support bundle:\n\n```powershell\n.\\bin\\ArcaneEDR.exe --support-bundle\n```\n\nThe bundle is written under `LogDirectory` and includes version, redacted\nconfig, service health state, collector/sink/runtime checks, recent alert\nsummaries, recent warning/error lines, recent incident summaries, and active\nexternal sink/AI provider metadata. It does not copy raw alert bodies, entities,\ncommand lines, script blocks, AI payloads, or secret values.\n\nPreview structured detection policy effects against recent alerts:\n\n```powershell\n.\\bin\\ArcaneEDR.exe --policy-preview --last 24h --limit 20\n```\n\nRun one monitor poll and exit without starting the Windows service or writing\nservice lifecycle health state:\n\n```powershell\n.\\bin\\ArcaneEDR.exe --poll-once\n```\n\nList safe detection simulations:\n\n```powershell\n.\\scripts\\simulate-detection.cmd -Scenario List\n```\n\nRun one representative simulation:\n\n```powershell\n.\\scripts\\simulate-detection.cmd -Scenario EncodedPowerShell\n.\\scripts\\simulate-detection.cmd -Scenario UnexpectedListener -DurationSeconds 120\n.\\scripts\\simulate-detection.cmd -Scenario ScheduledTaskPersistence\n.\\scripts\\simulate-detection.cmd -Scenario StartupFileDrop\n```\n\nRun a compact demo path that cleans prior simulation artifacts, generates\nharmless suspicious process telemetry, opens a localhost listener long enough\nfor the service or a second-shell poll, and prints the review commands:\n\n```powershell\n.\\scripts\\simulate-detection.cmd -Scenario Demo -DurationSeconds 120\n```\n\nClean up the scheduled-task simulation artifact:\n\n```powershell\n.\\scripts\\simulate-detection.cmd -Scenario Cleanup\n```\n\nThese simulations are harmless, but they can generate real local alerts and\nexternal notifications when the service is running. The unexpected-listener\nsimulation binds to localhost and should produce the lower-severity\n`NET-LISTEN-TCP-LOCALHOST-UNEXPECTED` shape in current builds.\n\n## Alerting\n\nAll alerts are always written locally under `LogDirectory`:\n\n```text\n\u003cLogDirectory\u003e\\ArcaneEDR.log\n\u003cLogDirectory\u003e\\ArcaneAlerts.jsonl\n```\n\nEvery alert carries structured `why` metadata that explains the rule-family\nconditions that caused it to fire. Alert records include UTC time plus the\nmachine's system-local time, Windows time zone, and UTC offset. Email, SMTP,\nWindows Event Log, local text logs, local JSONL, webhook, and generic HTTP/API\nsinks all receive the same explained, time-zone-aware alert object.\n\nSystem-local time is derived from the Windows time zone configured on the host.\nThis avoids hard-coding a project timezone while keeping alerts and reports\nreadable for the operator.\n\nAlerts also carry a rule `category`, derived from the rule ID. Current\ncategories include `Network`, `DNS`, `PowerShell`, `Persistence`, `Auth`,\n`File`, `Process`, `Agent`, `Response`, `RAT`, `AI`, `Health`, `Integrity`,\n`Baseline`, `Reputation`, `Custom`, `Test`, and `General`.\n\nArcane persists Windows, PowerShell, and Sysmon event-log watermarks under\n`LogDirectory` by default:\n\n```ini\nPersistEventLogWatermarks=true\nEventLogWatermarkFile=ArcaneEventLogWatermarks.tsv\n```\n\nCollector toggles are independent, and bounded collector, analysis-stage, or\nper-alert dispatch failures are logged without stopping the rest of the poll:\n\n```ini\nEnableNetstatCollector=true\nEnableSysmonIngestion=true\nEnablePowerShellLogIngestion=true\nEnableWindowsEventIngestion=true\nEnablePersistenceInventory=true\n```\n\nThis prevents service restarts, publish cycles, and recovery restarts from\nreprocessing the same recent event records into new local alerts and daily\nreport counts. If an event log appears to have reset or been cleared, Arcane\nallows newer low-record-ID events through instead of permanently trusting the\nolder watermark.\n\nRule policy tuning is controlled by config:\n\n```ini\nDisabledRuleIds=\nDisabledRuleCategories=\nRuleMinimumEmailScores=NET-DIRECT-IP-WEB-EGRESS=90,NET-EGRESS-UNUSUAL-PORT=90,NET-EGRESS-NEW-UNTRUSTED=80,NET-BEACON-TIMING-LOW-RISK=90,PS-SUSPICIOUS-COMMAND=90,BASELINE-NEW-PROCESS-DOMAIN=95,BASELINE-NEW-PROCESS-DESTINATION=95\nCategoryMinimumEmailScores=\n```\n\n`DisabledRuleIds` and `DisabledRuleCategories` suppress matching alerts before\nlocal alert logging, incident grouping, response handling, and external\ndelivery. `RuleMinimumEmailScores` and `CategoryMinimumEmailScores` affect\nexternal delivery only; local logging and incident grouping still use the\nnormal alert path. The example `RuleMinimumEmailScores` profile keeps weak\nstandalone discovery signals mostly local by default; use `--alert-volume\n--last 24h` and its baseline-off projection drivers to tune these thresholds\nfor the actual host.\n\nUnified policy is the preferred tuning surface for allow/block/trust decisions\nand machine-specific alert handling:\n\n```ini\nEnableDetectionPolicy=true\nPolicyFile=arcane-policy.example.json\n```\n\n`config\\arcane-policy.example.json` contains one JSON surface for network\nallowlists, domain/hash blocklists, trusted process and persistence context,\nresponse allow/block policy, ordered remote endpoint policy, and structured\nlocal alert tuning. Host-specific tuning should copy it to an ignored local\npolicy file and point `PolicyFile` there.\n\nDetection policy entries in `detection_policies` match fields such as\n`rule_id`, `category`, `process_name`, `parent_process`, `signer`,\n`path_prefix`, `command_terms`, `user`, `destination_domain`, `ip_cidr`,\n`port`, `hash`, and `text_contains`. Supported actions are `trusted_context`,\n`lower_score`, `suppress_external`, `raise_score`, `force_alert`, and\n`tag_only`.\n\n`suppress_external` keeps the local alert log, incident grouping, daily report\ncontext, and support-bundle summaries intact; it only prevents external\ndelivery for matching alerts. `lower_score` and `raise_score` adjust the local\nscore before logging, so the score change remains auditable in the alert body\nand `why` metadata.\n\nPreview policy effects against recent local alerts before relying on a rule:\n\n```powershell\n.\\bin\\ArcaneEDR.exe --policy-preview --last 24h --limit 20\n```\n\nPreview against a proposed sample alert before matching telemetry exists:\n\n```powershell\n.\\bin\\ArcaneEDR.exe --policy-preview --sample-rule NET-BEACON-TIMING-LOW-RISK --sample-process codex.exe --sample-score 55\n.\\bin\\ArcaneEDR.exe --policy-preview --sample-rule NET-EGRESS-PORT-MISUSE --sample-process ssh.exe --sample-ip 192.168.1.50 --sample-port 22 --sample-user operator\n.\\bin\\ArcaneEDR.exe --policy-preview --sample-rule PS-SUSPICIOUS-COMMAND --sample-process powershell.exe --sample-parent cmd.exe --sample-command \"powershell Invoke-WebRequest http://example.invalid/payload\"\n```\n\nYou can also preview against an alert JSON file:\n\n```powershell\n.\\bin\\ArcaneEDR.exe --policy-preview --sample-alert .\\sample-alert.json\n```\n\nSample context options include `--sample-process`, `--sample-parent`,\n`--sample-user`, `--sample-destination-domain`, `--sample-ip`,\n`--sample-port`, `--sample-path`, `--sample-signer`, `--sample-hash`, and\n`--sample-command`.\n\nNetwork port allowlists are in `allowlists.allowed_listening_ports`,\n`allowlists.allowed_outbound_ports`, and\n`allowlists.process_allowed_outbound_ports` inside `PolicyFile`.\nRemote country allowlisting is in `allowlists.allowed_remote_countries`.\n\nRemote endpoint enrichment adds DNS-derived names and remote owner/ASN/country\ncontext to network alerts. Country is best-effort registry/geolocation data,\nnot proof of physical origin. RDAP is enabled by default because the ordered\nendpoint policy uses owner, ASN, and country context to adjust review priority;\nthis discloses investigated remote IPs to the configured RDAP lookup service.\nOptional `ip-api.com` and `ipwhois.io`/`ipwho.is` hooks can fill geolocation\ncountry, owner, or ASN context when local country blocks and RDAP are\nincomplete. They are disabled in tracked config. Their free endpoints are for\nnon-commercial use only; commercial use requires the provider's paid/commercial\nplan.\n\n```ini\nEnableRemoteEndpointEnrichment=true\nEnableRemoteEndpointCountryBlockEnrichment=false\nRemoteEndpointCountryBlocksDirectory=country-ip-blocks\nEnableRemoteEndpointIpApiGeolocation=false\nRemoteEndpointIpApiUrlTemplate=http://ip-api.com/json/{ip}?fields=status,message,countryCode,org,isp,as,asname,query\nEnableRemoteEndpointIpWhoisGeolocation=false\nRemoteEndpointIpWhoisUrlTemplate=https://ipwho.is/{ip}?fields=success,message,country_code,org,isp,asn,ip\nRemoteEndpointGeoProviderMaxLookupsPerPoll=3\nEnableRemoteEndpointReverseDns=false\nEnableRemoteEndpointRdapEnrichment=true\nRemoteEndpointRdapUrlTemplate=https://rdap.org/ip/{ip}\nRemoteEndpointEnrichmentTimeoutSeconds=3\nRemoteEndpointEnrichmentCacheMinutes=1440\nRemoteEndpointRdapMaxLookupsPerPoll=3\nEnableRemoteEndpointPolicy=true\n```\n\nRemote allow, trust, block, and critical country/owner/domain/CIDR decisions\nbelong in `remote_endpoint_policies` inside `PolicyFile`. First enabled match\nwins. Keep two remote heuristics separate: `allowed_remote_countries` prevents\ncountry-only escalation, while `action: \"trust\"` with a known\n`remote_identity` is the deterministic score-dampening path for trusted\nproviders. The tracked default trusts Arcane EDR service self-traffic, trusts\nknown major provider identity such as Microsoft, Cloudflare, Amazon, GitHub,\nAnthropic, or Vercel only inside the allowed-country set, treats fully\nunresolved country/domain context after enabled local or provider geolocation\nenrichment as critical, observes ordinary country-unavailable outcomes as a\nscore enhancer, and treats countries outside\n`allowlists.allowed_remote_countries` as critical when no earlier trust rule\nmatched. Default allowed countries are `US`, `CA`, `GB`, `IE`, `DE`, `NL`,\n`FR`, `SE`, `CH`, `AU`, `NZ`, `JP`, and `SG`.\nCountry unavailable also becomes critical when paired with first-seen app/IP\ncontext or another stronger suspicious endpoint signal.\n\n`RemoteEndpointCountryBlocksDirectory` can point at an extracted\n`ipverse/country-ip-blocks` tree, for example a directory containing\n`country\\us\\ipv4-aggregated.txt` and `country\\us\\ipv6-aggregated.txt`. Arcane\nreads those files locally; it does not download country data at runtime.\n`RemoteEndpointGeoProviderMaxLookupsPerPoll` caps combined `ip-api` and\n`ipwhois` requests per poll so free/non-commercial endpoints are not hammered.\nArcane tries local country blocks first. If the resolved country is in\n`allowlists.allowed_remote_countries`, country alone does not escalate the\nalert. If no DNS/domain/company identity is available, Arcane can still use\nenabled RDAP, `ip-api`, or `ipwhois` lookups within configured caps so a known\nprovider `trust` rule can match. Otherwise it tries RDAP for registry owner/ASN\ncontext, then these optional providers only when country or useful owner/ASN\ncontext is still missing.\n\n```json\n{\n  \"id\": \"example-trust-expected-agent-cloudflare\",\n  \"enabled\": false,\n  \"action\": \"trust\",\n  \"reason\": \"Expected agent backend traffic.\",\n  \"match\": {\n    \"process_name\": \"codex.exe\",\n    \"country\": \"US\",\n    \"remote_identity\": \"Cloudflare\",\n    \"port\": 443\n  }\n}\n```\n\nPolicy text fields use case-insensitive contains matching by default. Prefix an\nentry with `regex:` or `re:`, or wrap it as `/pattern/`, for regex matching.\nUse JSON arrays for multiple values; strings are treated as one entry.\nSupported actions are `critical`, `block`, `trust`, `allow`, and `observe`.\n`critical` and `block` create high-score policy alerts. `trust` lowers only\nclean timing-only or direct-IP network noise from expected processes. `allow`\nskips generic external-remote analysis for the matching endpoint, so keep allow\nrules narrow and place more specific block/critical rules above broad allow\nrules.\nSee [docs/remote-endpoint-policy.md](docs/remote-endpoint-policy.md) for the\nfull match field list and examples.\n\nMaintenance context tuning labels expected admin/build/publish activity without\nmaking it disappear:\n\n```ini\nEnableMaintenanceContext=true\nMaintenanceContextExternalAlertMinimumScore=95\nMaintenanceContextTermGroups=icacls|/inheritance:r,powershell|-executionpolicy bypass|publish.ps1,ArcaneEDR.exe|--validate-config\nEnableMaintenanceSessionMarkers=true\nMaintenanceSessionMarkerFile=ArcaneMaintenanceSessions.jsonl\nMaintenanceSessionDefaultMinutes=60\nMaintenanceSessionMaximumMinutes=240\n```\n\nEach comma-separated group uses `|` for terms that must all appear in the alert\ntext. Matching alerts get `maintenance_context=true`, retain their local log and\nincident records, and only suppress external delivery when the score is below\n`MaintenanceContextExternalAlertMinimumScore`.\n\nFor expected work that does not fit a durable term group, start a bounded local\nmaintenance marker:\n\n```powershell\n.\\bin\\ArcaneEDR.exe --maintenance start --duration 1h --reason publish\n.\\bin\\ArcaneEDR.exe --maintenance list\n.\\bin\\ArcaneEDR.exe --maintenance clear --reason done\n```\n\nActive markers label alerts with maintenance context for their configured\nwindow. They do not suppress local evidence, change scores, or perform response\nactions.\n\nLow-value repeat dampening reduces external notification volume for the same\nstable behavior while preserving local evidence:\n\n```ini\nEnableExternalAlertGrouping=true\nExternalAlertGroupingMinimumCount=2\nExternalAlertGroupingMaximumScore=89\nExternalAlertGroupingMaxItems=8\nExternalAlertGroupingCategories=Network,DNS,Baseline,Reputation,Process\nEnableLowValueRepeatDampening=true\nLowValueRepeatDampeningMaximumScore=60\nLowValueRepeatDampeningWindowMinutes=60\nLowValueRepeatDampeningMaxExternalAlertsPerWindow=1\nLowValueRepeatDampeningCategories=Network,DNS,Baseline,Reputation,Process\n```\n\nWhen grouping is enabled, Arcane first records each alert locally, then combines\nsame-dispatch external notification candidates with the same rule/category and\nsource root into one external summary. The summary includes grouped counts and\nrepresentative rules, titles, processes, destinations, countries, and companies.\nAlerts above `ExternalAlertGroupingMaximumScore`, forced-policy alerts, service\nlifecycle notifications, daily reports, and distinct source roots still break\nthrough independently.\n\nRepeat dampening is the follow-on guardrail for matching low-score alerts that\nreappear later in the configured window. With the default value of\n`LowValueRepeatDampeningMaxExternalAlertsPerWindow=1`, Arcane allows one\nexternal notification for the repeat key, then suppresses additional external\ndelivery until the window expires. Local alert logs, incident grouping, response\nhandling, and high-score alerts are not affected. Leave\n`LowValueRepeatDampeningCategories` populated; an explicitly blank category list\ndisables repeat dampening matches.\n\nAuthentication special-privilege tuning keeps Windows `4672` events\ncorrelation-first:\n\n```ini\nAuthSpecialPrivilegeRepeatDampeningMinutes=60\nAuthSpecialPrivilegeRemoteCorrelationMinutes=15\n```\n\nStandalone `4672` events are low-severity local context and repeat-dampened per\nprincipal. If special privileges occur near recent remote logon activity for the\nsame account, Arcane raises stronger `AUTH-REMOTE-SPECIAL-PRIVILEGES` context.\nRemote-style logons with an unspecified source such as `0.0.0.0` are recorded\nas low-risk session context rather than ordinary remote source evidence.\n\nPersistence trust handling reduces noise from expected Windows/vendor service\nand scheduled-task activity without trusting names by themselves. A service or\ntask change is classified as trusted-location only when configured trusted\nname indicators match a trusted path or trusted signer, and suspicious command,\nuntrusted user-writable path, and RMM/RAT-like traits are absent. For\nscheduled-task create/update events, Arcane also inspects task action XML when\nWindows provides it.\n\nTrusted persistence name, path, and signer context lives in\n`allowlists.trusted_persistence_*` inside `PolicyFile`.\n\nHigh-signal file-create detection is Sysmon-backed and intentionally narrow:\n\n```ini\nEnableHighSignalFileDetection=true\nHighRiskFilePathIndicators=\\appdata\\roaming\\microsoft\\windows\\start menu\\programs\\startup\\,\\programdata\\microsoft\\windows\\start menu\\programs\\startup\\,\\windows\\system32\\tasks\\,\\appdata\\local\\google\\chrome\\user data\\default\\extensions\\,\\appdata\\local\\microsoft\\edge\\user data\\default\\extensions\\\nHighRiskFileExtensions=.exe,.dll,.scr,.com,.msi,.msp,.ps1,.psm1,.vbs,.vbe,.js,.jse,.hta,.bat,.cmd,.lnk,.url,.jar\nSensitiveFileNameIndicators=apikey,api_key,access_token,refresh_token,client_secret,private_key,id_rsa,id_ed25519,.pem,.pfx,.env,credentials,token.json\n```\n\nThese rules do not audit every file write. They depend on Sysmon FileCreate\nevents for high-risk targets, then alert on executable/script drops,\nsuspicious writers, agent writes outside approved roots, sensitive-looking\nfilenames, or recent high-risk drops followed by execution.\n\nArcane can also group alert records into local investigation incidents. This is\nlocal-only JSONL state, intended to make recent related alerts easier to scan:\n\n```ini\nEnableIncidentGrouping=true\nIncidentStoreFile=ArcaneIncidents.jsonl\nIncidentWindowMinutes=30\nIncidentMinimumScore=60\n```\n\nList recent incident summaries:\n\n```powershell\n.\\bin\\ArcaneEDR.exe --incidents --last 24h\n```\n\nShow the alert timeline for one incident:\n\n```powershell\n.\\bin\\ArcaneEDR.exe --timeline INC-...\n```\n\nSummarize recent local alert volume for tuning:\n\n```powershell\n.\\bin\\ArcaneEDR.exe --alert-volume --last 24h\n```\n\nSummarize the compact agent activity ledger:\n\n```powershell\n.\\bin\\ArcaneEDR.exe --agent-activity --last 24h\n```\n\nThe summary groups local alert records by severity, category, rule, and process,\nand estimates which records would qualify for external delivery before\nprovider, rate-limit, retry, or repeat-dampening behavior.\nIt also prints `BaselineOffExternalQualifiedBeforeRateLimits` and\n`baseline_off_external` bucket counts, plus baseline-off projection drivers by\nrule and process, so operators can estimate whether turning off\n`BaselineLearningMode` would create a notification flood before changing live\nconfig. When records would qualify for current or baseline-off external\ndelivery, the command also prints compact candidate examples with time, score,\nrule, process, maintenance context, and title only. It intentionally avoids raw\nentities, paths, command lines, IPs, users, and alert bodies. Service health,\ndaily report, and AI control notifications are counted as current external\ncandidates when they are present because those records use the direct\nnotification path rather than the normal detection threshold path.\nRun `--poll-once` first when you want a fresh one-poll sample without leaving\nthe monitor running.\nIf the published app uses a protected `LogDirectory` such as `C:\\Security`, run\n`--poll-once` elevated or collect the sample from a source build with a\nuser-writable log directory.\n\nExternal delivery is controlled by config:\n\n```ini\nExternalAlertProvider=Brevo\nRequireExternalAlerting=true\nMinimumEmailScore=60\nExternalAlertProviderMinimumScores=\nExternalAlertProviderMaxPerHour=\nExternalAlertMaxPerDispatch=3\nExternalAlertMaxPerHour=24\nEnableExternalAlertGrouping=true\nExternalAlertGroupingMinimumCount=2\nExternalAlertGroupingMaximumScore=89\nExternalAlertGroupingMaxItems=8\nExternalAlertGroupingCategories=Network,DNS,Baseline,Reputation,Process\nBrevoApiKeyEnvironmentVariable=\u003cconfigured env var\u003e\nBrevoSenderEmail=\u003cverified sender\u003e\nBrevoRecipientEmail=\u003crecipient\u003e\n```\n\n`ExternalAlertProvider` can be a single provider or a comma-separated list.\nSupported providers in the current source tree:\n\n- `Disabled`\n- `Brevo`\n- `Smtp`\n- `Webhook`\n- `GenericHttpApi`\n- `LocalJsonl`\n- `WindowsEventLog`\n\nExample fan-out to Brevo, a local external-alert JSONL file, and Windows Event\nLog:\n\n```ini\nExternalAlertProvider=Brevo,LocalJsonl,WindowsEventLog\nExternalAlertProviderMinimumScores=Brevo=90,LocalJsonl=60,WindowsEventLog=75\nExternalAlertProviderMaxPerHour=Brevo=6,WindowsEventLog=12\nLocalJsonlAlertSinkFile=ArcaneExternalAlerts.jsonl\nWindowsEventLogAlertSource=ArcaneEDR\nWindowsEventLogAlertLogName=Application\nWindowsEventLogAlertEventId=9100\n```\n\n`ExternalAlertProviderMinimumScores` adds provider-specific routing floors after\nthe global, rule, and category external thresholds. This is useful when one sink\nshould receive broader telemetry, while email or webhook destinations receive\nonly higher-confidence alerts. A skipped provider does not remove the local\nalert log, incident grouping, or daily report context.\n\n`ExternalAlertProviderMaxPerHour` adds optional per-provider hourly caps after\nglobal rate limits. Use it to keep a noisy provider quiet while still allowing\nanother configured sink to receive eligible alerts. Daily summary reports are\nnot counted against provider hourly caps. Service lifecycle notifications are\nalso exempt so crash recovery and restart notices are not hidden by alert\nbursts.\n`ExternalAlertMaxPerHour` is the shared runtime cap for normal detection\nalerts, AI notifications, and retry deliveries. Daily summary reports and\nservice lifecycle notifications bypass this cap so scheduled reports and\nrestart/recovery notices do not compete with alert bursts.\n\n`EnableExternalAlertGrouping` runs before per-dispatch and hourly external\ndelivery limits. A burst of matching same-root alerts therefore counts as one\nplanned external notification while every original alert remains in local logs,\nincidents, daily reports, and response evaluation.\n\nSMTP:\n\n```ini\nExternalAlertProvider=Smtp\nSmtpHost=smtp.example.com\nSmtpPort=587\nSmtpEnableSsl=true\nSmtpUsername=alerts@example.com\nSmtpPasswordEnvironmentVariable=SMTP_PASSWORD\nSmtpSenderEmail=alerts@example.com\nSmtpRecipientEmail=security@example.com\n```\n\nWebhook or generic HTTP/API JSON POST:\n\n```ini\nExternalAlertProvider=Webhook\nWebhookAlertUrl=https://example.com/arcane-alert\nWebhookSecretEnvironmentVariable=WEBHOOK_TOKEN\nWebhookSecretHeaderName=Authorization\nWebhookSecretPrefix=Bearer\n\nExternalAlertProvider=GenericHttpApi\nGenericHttpApiAlertUrl=https://example.com/api/security-alerts\nGenericHttpApiSecretEnvironmentVariable=API_TOKEN\nGenericHttpApiSecretHeaderName=Authorization\nGenericHttpApiSecretPrefix=Bearer\n```\n\nThe Brevo API key is read from Process, User, then Machine environment scope.\n`ExternalAlertSuppressionTermGroups` is a stronger external-only suppression\nescape hatch, not the preferred way to classify routine maintenance. It\nsuppresses external delivery only; local logging and incident grouping remain.\n\n## Health Notifications\n\nArcane EDR maintains local health state in:\n\n```text\n\u003cLogDirectory\u003e\\ArcaneServiceHealth.state\n```\n\nIt can send external notifications when:\n\n- the service starts\n- the service starts after a previous run did not record a clean stop\n- the daily summary interval elapses\n\nRelevant config:\n\n```ini\nNotifyOnServiceStart=true\nNotifyOnServiceStop=false\nNotifyOnCrashRecovery=true\nEnableDailySummary=true\nDailySummaryIntervalHours=24\nDailySummaryLocalTime=08:00\nDailySummaryTimeZoneId=\u003cconfigured Windows time zone ID\u003e\nDailySummaryScore=60\nEnableDailySummaryAIAnalysis=true\nDailyReportDestinations=ExternalAlertSinks,LocalArchive\nHealthHeartbeatSeconds=60\n```\n\nThe daily report uses a report-specific email layout, not the generic alert\ntemplate. It starts with a compact metadata header containing the high-level\ndetermination, compromise assessment, confidence, analyzed system-time window,\ngenerated system time, basis, and recommended next step, then uses compact\ntables for critical callouts, health, signal summary, false-positive context,\nhigh-signal details, automation activity, tuning notes, and optional AI\ndaily analysis. Critical and high-signal tables include process/source context\nwhen the source telemetry provides it. The top-level determination,\ncompromise assessment, recommended next step, and critical callouts are\ndeterministic local-telemetry sections; optional AI daily analysis is kept\ninside the labeled AI review section as a secondary opinion. The AI\ndaily prompt is tuned for customer-facing 24-hour review and explicitly treats\nalert volume, baseline learning, maintenance context, automation context, and\ntelemetry gaps as false-positive context rather than proof of compromise.\nDaily report structure and local archive output are configurable:\n\n```ini\nDailyReportDestinations=ExternalAlertSinks,LocalArchive\nDailyReportSections=QuickVerdict,CriticalCallouts,AtAGlance,SignalSummary,FalsePositiveContext,HighSignalDetails,AutomationActivity,AIReview,TuningNotes\nDailyReportCriticalCalloutRows=5\nDailyReportHighSignalRows=7\nDailyReportBucketRows=6\nDailyReportAgentBucketRows=3\nEnableDailyReportArchive=true\nDailyReportArchiveDirectory=reports\nDailyReportArchiveFormats=Markdown,Json\nDailyReportWebhookUrl=\nDailyReportWebhookSecretEnvironmentVariable=\nDailyReportWebhookSecretHeaderName=Authorization\nDailyReportWebhookSecretPrefix=Bearer\nDailyReportWebhookTimeoutSeconds=15\n```\n\n`DailyReportDestinations` separates daily reporting from normal alert routing.\n`ExternalAlertSinks` sends the daily report through the configured external\nalert sinks. `LocalArchive` writes the configured archive formats. `Webhook`\nposts the redacted JSON report payload to `DailyReportWebhookUrl`. Use\n`DailyReportDestinations=LocalArchive` for archive-only reporting while keeping\nreal-time alerts enabled, or `DailyReportDestinations=LocalArchive,Webhook` for\narchive plus report-specific webhook delivery.\nDaily reports delivered through `ExternalAlertSinks` bypass shared and\nprovider-specific hourly alert caps, but still require a configured external\nsink.\nSupported destination names are `ExternalAlertSinks`, `LocalArchive`, and\n`Webhook`.\n\nArchived reports are written under `LogDirectory` when\n`DailyReportArchiveDirectory` is relative. The Markdown archive mirrors the\ndelivered report body; the JSON archive stores redacted report metadata,\nmetrics, bucket summaries, high-signal summaries, and AI review metadata\nwithout raw alert bodies, entities, command lines, paths, users, IPs, URLs,\nemails, or secrets.\n\nExample report webhook destination:\n\n```ini\nDailyReportDestinations=LocalArchive,Webhook\nDailyReportWebhookUrl=https://example.com/arcane-daily-report\nDailyReportWebhookSecretEnvironmentVariable=ARCANE_REPORT_WEBHOOK_TOKEN\nDailyReportWebhookSecretHeaderName=Authorization\nDailyReportWebhookSecretPrefix=Bearer\n```\n\nUse `--preview-daily-report` while tuning `DailyReportSections` and row limits.\nThe preview command does not send external notifications and does not call\nthe AI provider; add `--archive` only when you want the preview written to the configured\narchive directory.\n\nFuture reporting work should keep moving these sections toward a configurable\nreporting engine with additional destinations, schedules, and audience-specific\ndetail levels.\n\n## AI Log Analysis\n\nArcane EDR can send a compact log sample to one or more AI analysis providers\nfor secondary analysis. `v0.4` supports concurrent provider fan-out for OpenAI,\nOpenAI-compatible Responses-style endpoints, and native Anthropic Claude\nMessages API endpoints. Each provider receives the same compact, redacted\npayload and returns the same Arcane result contract.\n\n```ini\nEnableAIAnalysis=true\nAIAnalysisIntervalMinutes=60\nAIAnalysisScoreThreshold=95\nAIAnalysisBaselineEmailMinimumScore=95\nAIAnalysisMinimumIncludedAlertScore=60\nAIAnalysisBaselineMinimumIncludedAlertScore=95\nAIAnalysisExcludedRuleIds=AI-LOG-ANALYSIS-ALERT,AI-LOG-ANALYSIS-TEST,SERVICE-STARTED,SERVICE-STOPPED,SERVICE-DAILY-SUMMARY,SERVICE-HEALTH-TEST,TEST-ALERT-DELIVERY\nAIAnalysisMaxLogLines=80\nAIAnalysisMaxAlertLines=80\nAIAnalysisMaxChars=12000\nAIAnalysisTimeoutSeconds=30\nEnableDailySummaryAIAnalysis=true\n```\n\nSingle-provider configuration:\n\n```ini\nAIAnalysisProviders=OpenAI\nAIAnalysisModel=\u003cconfigured model\u003e\nAIAnalysisApiKeyEnvironmentVariable=OpenAIAPIKey_ArcaneEDR\nAIAnalysisApiUrl=https://api.openai.com/v1/responses\n```\n\nProvider defaults fill common auth headers: OpenAI uses `Authorization` with a\n`Bearer ` prefix and defaults to `OpenAIAPIKey_ArcaneEDR`, and Claude uses\n`x-api-key` plus `anthropic-version`.\n\nMulti-provider configuration:\n\n```ini\nAIAnalysisProviders=OpenAI,Claude\nAIAnalysisProviderTypes=OpenAI=OpenAI,Claude=Anthropic\nAIAnalysisProviderModels=OpenAI=\u003cconfigured OpenAI model\u003e,Claude=\u003cconfigured Claude model\u003e\nAIAnalysisProviderApiKeyEnvironmentVariables=OpenAI=OpenAIAPIKey_ArcaneEDR,Claude=ANTHROPIC_API_KEY\nAIAnalysisProviderApiUrls=OpenAI=https://api.openai.com/v1/responses,Claude=https://api.anthropic.com/v1/messages\nAIAnalysisProviderAuthHeaderNames=OpenAI=Authorization,Claude=x-api-key\nAIAnalysisProviderAuthHeaderPrefixes=OpenAI=Bearer,Claude=\nAIAnalysisProviderVersionHeaderNames=Claude=anthropic-version\nAIAnalysisProviderVersionHeaderValues=Claude=2023-06-01\n```\n\nWhen multiple providers are enabled, Arcane runs them concurrently. A failed\nprovider is recorded in the provider breakdown without blocking a successful\nprovider. The aggregate AI review uses the strongest alertable provider result,\nor the highest-scored completed result when no provider flags the sample, and\nkeeps each provider's score, flag, and read visible in the daily report.\nUse the provider-specific maps for multi-provider setups; `--validate-config`\nwarns about unused map entries and single-provider fields that are ignored when\nmore than one `AIAnalysisProviders` entry is configured.\nSet `AIAnalysisAuthHeaderName=` only for a trusted no-auth local endpoint.\n\nThe payload is intentionally compact and redacted. It includes health counters,\nrecent event summaries, alert metadata, and sanitized aggregate context. The\naggregate context includes score buckets, category/rule counts, repeated-rule\nindicators, maintenance/agent-context counts, trend counters, and top sanitized\nreasons for score-60+ activity. Network alert summaries include bounded remote\nenrichment context such as process name, remote port, owner/ASN org, country,\ncountry lookup status, registrable/resolved domain labels, and remote policy id\nafter redaction; raw IPs, URLs, paths, and command lines remain omitted.\nDetailed alert summaries still honor `AIAnalysisMinimumIncludedAlertScore` or\n`AIAnalysisBaselineMinimumIncludedAlertScore`.\n\nArcane EDR does not send alert bodies, entities, command lines, script blocks,\ndecoded payload previews, usernames, file paths, IPs, URLs, emails, or\nconfigured secret values.\n\nResults are written to:\n\n```text\n\u003cLogDirectory\u003e\\ArcaneAIAnalysis.jsonl\n```\n\nHourly compact analysis records use `analysis_type=compact_log`; daily report\nanalysis records use `analysis_type=daily_report`.\n\nIf the configured AI provider returns `alertable=true` with a score at or above\n`AIAnalysisScoreThreshold`, Arcane EDR sends the model's summary and\nrecommended action through the configured external alert sinks.\n\n## Baseline Learning\n\nThe default deployment learns process/destination and process/domain pairs for\nthe first 24 hours:\n\n```ini\nBaselineEnabled=true\nBaselineLearningMode=true\nBaselineLearningEmailMinimumScore=90\nBaselineWarmupHours=24\n```\n\nAfter the baseline looks comfortable, set `BaselineLearningMode=false` to alert\non new process/domain and process/destination pairs. During baseline learning,\nlower-confidence alerts are still logged locally but not emailed unless they\nmeet `BaselineLearningEmailMinimumScore`.\n\n## Agent Profile\n\nArcane EDR can label existing alerts that involve known unattended agent\nprocesses. This helps separate ordinary workstation activity from activity that\nwas agent-launched or agent-adjacent.\n\nExample:\n\n```ini\nEnableAgentProfile=true\nAgentProcessNames=Codex.exe,codex.exe\nAgentChildProcessNames=powershell.exe,pwsh.exe,cmd.exe,git.exe,git-remote-https.exe,node.exe,npm.exe,npm.cmd,python.exe,pip.exe,curl.exe\nAgentWorkspaceRoots=C:\\Development\\\nAgentPublishRoots=\nAgentPackageManagerProcesses=git.exe,git-remote-https.exe,node.exe,npm.exe,npm.cmd,python.exe,pip.exe,curl.exe\nAgentApprovedAdminTaskNames=\\ArcaneEDR\\PublishRestart,\\ArcaneEDR\\InstallService,\\ArcaneEDR\\ValidateAdmin\nAgentSecretIndicatorTerms=apikey,api_key,access_token,refresh_token,client_secret,private_key,id_rsa,.pem,.pfx,.env\nEnableAgentAdminCommandGuardrails=true\nAgentAdminCommandMinimumScore=84\nAgentAdminCommandTerms=-verb runas,runas.exe,schtasks,start-scheduledtask,register-scheduledtask,new-scheduledtask,run-admin-task.cmd,run-admin-task.ps1,admin-task-runner.ps1,new-service,sc.exe create,sc create,set-service,netsh advfirewall,new-netfirewallrule,set-netfirewallrule,remove-netfirewallrule,icacls,takeown,set-acl,reg add,\\currentversion\\run,set-mppreference,add-mppreference,disableantispyware,disablerealtimemonitoring\nEnableAgentSecretReferenceGuardrails=true\nAgentSecretReferenceMinimumScore=78\nAgentSecretReferenceTerms=apikey,api_key,access_token,refresh_token,client_secret,private_key,id_rsa,id_ed25519,.pem,.pfx,.env,credentials,token.json,aws_access_key_id,azure_client_secret,gcloud,\\appdata\\local\\google\\chrome\\user data,\\appdata\\local\\microsoft\\edge\\user data,\\mozilla\\firefox\\profiles\nEnableAgentSupplyChainGuardrails=true\nAgentSupplyChainMinimumScore=74\nAgentSupplyChainTerms=npm install,npm ci,npm exec,npx,pnpm install,yarn install,pip install,pip3 install,python -m pip install,curl,curl.exe,invoke-webrequest,wget,downloadstring,downloadfile,git clone,invoke-restmethod,invoke-expression,install.ps1,install.sh,postinstall\nEnableAgentActivityLedger=true\nAgentActivityLedgerFile=ArcaneAgentActivity.jsonl\nAgentActivityLedgerMinimumScore=60\n```\n\nWhen an alert matches the profile, Arcane appends an `AgentContext` line, an\n`agent_context=` entity field, and an additional `why` explanation. This does\nnot raise the score, bypass cooldowns, trigger response actions, or send email\nby itself. It is correlation context for the local log, external alert sinks,\nand later review.\n\nWhen `EnableAgentActivityLedger=true`, Arcane also writes compact records for\nagent-involved alerts at or above `AgentActivityLedgerMinimumScore`. The ledger\nstores rule, score, process family, agent reason labels, command category,\nendpoint category, and file category; it does not store raw command lines,\npaths, IPs, users, URLs, or alert bodies.\n\nWhen `EnableAgentAdminCommandGuardrails=true`, Arcane raises\n`AGENT-ADMIN-COMMAND` when PowerShell, Windows process-creation audit, or\nSysmon process telemetry shows an agent-initiated elevation, service,\nscheduled-task, firewall, ACL, registry, persistence, or security-control\ncommand that is not one of the configured `AgentApprovedAdminTaskNames`. This\nis alert-only evidence; it does not change `ResponseMode` or perform\ncontainment.\n\nWhen `EnableAgentSecretReferenceGuardrails=true`, Arcane raises\n`AGENT-SECRET-REFERENCE` for agent-initiated commands or script blocks that\nreference configured token, key, certificate, SSH material, cloud credential,\nor browser credential-store indicators.\n\nWhen `EnableAgentSupplyChainGuardrails=true`, Arcane raises\n`AGENT-SUPPLY-CHAIN-COMMAND` for agent-initiated package installs, source\nclones, downloads, install scripts, or expression-execution indicators. These\nrules are review prompts for unattended agent work, not automatic containment\ntriggers.\n\n## Custom Rules\n\nCustom rules are compact JSON objects with `source`, `score`, `contains_any`,\noptional `process_names`, and a recommendation. They are loaded from\n`config\\custom-rules.json` and hot-reloaded when the file changes.\n\n## Response Mode\n\nThe default is alert-only:\n\n```ini\nResponseMode=AlertOnly\nResponseMinimumScore=95\nEnableFirewallBlockResponse=false\nEnableProcessTerminationResponse=false\nEnableResponsePolicy=true\nEnableResponseLedger=true\nResponseLedgerFile=ArcaneResponseLedger.jsonl\nEnableResponseFollowUpDetections=true\nResponseProcessRespawnWindowMinutes=10\nResponseProcessRespawnMinimumScore=94\nResponseFollowUpExternalAlertMinimumScore=95\n```\n\nDry-run modes are `DryRunBlockRemoteIp`, `DryRunTerminateProcess`, and\n`DryRunBlockAndTerminate`. They evaluate candidate response targets, write\ncompact local records to `ResponseLedgerFile`, and log what would have\nhappened, but they do not add firewall rules or kill processes. If response\npolicy would block the same alert in an active mode, the dry-run ledger records\nthat policy skip reason.\n\nActive modes are `BlockRemoteIp`, `TerminateProcess`, and\n`BlockAndTerminate`. These are intentionally opt-in because false positives can\ndisrupt legitimate tools. Keep `ResponseMinimumScore` high when testing active\nresponse. Firewall blocking requires `EnableFirewallBlockResponse=true`, and\nprocess termination requires `EnableProcessTerminationResponse=true` because it\ncannot be rolled back. Read `docs\\response-safety-and-rollback.md` before\nenabling active response.\n\nWhen `EnableResponsePolicy=true`, active response also requires an explicit\nallow entry in `response_policy.allowed_rule_ids` or\n`response_policy.allowed_categories` inside `PolicyFile`. The example policy\nleaves both allowlists empty, so active modes skip every action even if an\naction gate is enabled. Dry-run modes remain useful for discovering candidate\nrules before adding a narrow allow entry.\n\nFirewall block response rules are named `ArcaneEDR_BLOCK_\u003cresponse-id\u003e`, where\n`response-id` is a GUID recorded in `ResponseLedgerFile` with the triggering\nalert rule, score, target, and firewall rule name. List or remove Arcane-owned\nfirewall blocks with:\n\n```powershell\n.\\bin\\ArcaneEDR.exe --response-firewall list\n.\\bin\\ArcaneEDR.exe --response-firewall remove \u003cresponse-id-or-ArcaneEDR_BLOCK_guid\u003e\n.\\bin\\ArcaneEDR.exe --response-firewall remove-all\n```\n\nIf process termination is enabled and a same-named process relaunches within\n`ResponseProcessRespawnWindowMinutes`, Arcane raises\n`RESPONSE-PROCESS-RESPAWN` as escalatory local evidence. By default,\n`ResponseFollowUpExternalAlertMinimumScore=95` keeps these follow-up alerts\nfrom sending external notifications unless the score or local policy warrants\nit.\n\n## Hardening Notes\n\n- Run the service as a dedicated low-privilege user.\n- Grant that user read access to the app config and write access only to `LogDirectory`.\n- Keep Brevo, AI provider, SMTP, and webhook secrets out of config and expose them only through environment variables for the service account.\n- Keep allowlists narrow. Start in console mode, observe normal traffic, then tune config.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwilliamsmithedward%2Farcaneedr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwilliamsmithedward%2Farcaneedr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwilliamsmithedward%2Farcaneedr/lists"}