CyberCLI

← All engines · AI

AiPolicyService

stable

v1.1.0 · last updated 2026-06-06 · source: cybercli.system.ai_policy.AiPolicyService

§1

What it does

Persists + audits which AI lane (local / byo_server / api / off) the install runs at, with two write paths — a hardware-driven probe for first install and an explicit operator override from the dashboard.

§2

Why you care

The AiPolicyService is the engine that makes 'which AI runs my SOC' a deliberate, recorded choice. The lane decision drives every downstream engine: the digest-pipeline reads it to pick a provider, the doctor reads it to benchmark the right model, the dashboard reads it to show the operator their current posture. Without it, the lane is a wire-once-and-forget setting; with it, the lane is auditable, reversible, and operator-controllable.

Other AI security products either lock you to their cloud (Charlotte AI, Dropzone, Prophet — your data goes to their model whether you want it to or not) or make you wire the model yourself with no engine support (Wazuh, OSSEC — bring your own everything). CyberCLI ships four lanes — local on-prem, BYO endpoint, managed API (paid only), or off — and the AiPolicyService is the engine that lets you pick + change + audit which one fires.

The service also stamps every lane change with a hardware probe. Switch to local lane and the engine records the GPU count + VRAM + CPU cores + RAM at the moment of the choice; the dashboard's hardware advisory then fires if the host can't realistically run local inference. The advisory is a UX feature, but the policy service is what makes it possible.

§3

How it works

AiPolicyService persists state to `ai_policy.json` in the data dir. The schema is a single AiPolicyRecord with the lane enum, the reason (operator-supplied or auto-resolved), the tier-at-probe, the api_available flag, the byo_endpoint URL, the hostname + gpu_count + total_vram_mib + free_vram_mib + ram_mb_total + cpu_cores at the probe moment, and the probed_at timestamp.

Two write paths exist. `probe_and_record()` runs at install-1 — it probes the hardware, asks the license service which tier the install is at, and picks the lane based on a deterministic rule: GPU + paid tier → api fallback to local; GPU + Free → local; no GPU + paid → api; no GPU + Free → safe_disabled. The result lands on the audit log as `ai_policy_recorded`.

`apply_operator_lane()` is the dashboard write path. The operator picks a lane explicitly on /settings → AI engine → Change lane; this method validates the choice against the license tier (api is paid-only), vaults the api key if the choice is api, and writes the record. The result lands on the audit log as `ai_policy_set` with the previous lane + the new lane + the operator id.

Reads are cheap and lock-free. Every engine that needs the current lane calls `service.current()` which reads the JSON file fresh — there is no in-memory cache. That deliberately trades a tiny per-call cost for the guarantee that a dashboard write is visible to the digest-pipeline on the next event with zero coordination.

§4

Configure & observe

CLI

$ cybercli setup wizard

Runs the hardware probe + tier check + records the initial lane choice. The wizard fires probe_and_record() under the hood.

$ cybercli doctor

Spot-checks the policy file exists, the lane is one of the known values, and the downstream digest-pipeline can construct a provider from it.

Dashboard surfaces

/settings (AI engine card)

The lane picker. Shows the current record + hardware specs + the hardware advisory if local lane is picked on a low-VRAM host. The 'Change lane' modal calls apply_operator_lane().

/audit (filter outcome=ai_policy_*)

Forensic replay of every lane change. Answers 'when did we move to API and who flipped it.'

Audit row shape

Outcomes emitted
ai_policy_recordedai_policy_setai_role_override_set
Parameters block

parameters.lane + parameters.previous_lane + parameters.tier_at_probe + parameters.gpu_count + parameters.total_vram_mib on every row. Operator-driven ai_policy_set rows additionally carry parameters.actor + parameters.byo_endpoint (when applicable).

§5

Status

Stable — the AiPolicyService has been on the v1 acceptance install since 2026-06-03 and has gated the lane through three operator-driven changes (local → byo_server pointing at hermes01 → byo_server with a different model). Every change carries the right audit row.

Shipped 2026-06-07 (complete): `cybercli doctor` runs check_ai_policy_hardware_drift on demand; the runtime now ALSO calls AiPolicyService.detect_hardware_drift() during build_runtime() and emits a WARN with the deltas at boot. The operator's lane choice stays the source of truth — the engine deliberately doesn't silently rewrite the record; the WARN nudges the operator to re-run `cybercli setup wizard` if the new hardware should change the lane.

Known limit: the policy file is single-tenant. Multi-tenant federation (v1.5) gets per-tenant policy records so a Marshal can run local on tenant A and BYO server on tenant B.

How this engine talks to the rest

Downstream · this engine feeds