git:20260803.915e4ed to git:20260914.e3ee679
109 added, 23 removed. Audit A to A.
---
id: zaebal
name: 'Z.A.E.B.A.L.: profanity-triggered self-audit for agents'
summary: >-
KISA's plugin: user frustration becomes an operational signal. Profanity at the agent
- fires an escalation protocol — stop, two independent auditors, an inventory of beliefs,
- and at level 3 an external auditor (a different CLI) reads the transcript from outside.
- Python stdlib only; Claude Code, Codex, Kimi CLI, OpenCode. RU/EN/ZH detection.
+ triggers a session-history audit with two independent internal auditors and an optional
+ external CLI auditor. Python 3.10+ stdlib only; RU/EN/ZH detection. Codex hook setup
+ supports native Windows and Linux; Linux adapters also cover Claude Code, Kimi and OpenCode.
type: skill
author: kisa
recommended: true
added: 2026-08-03
- tags: [self-audit, hooks, escalation, debugging, agent, protocol]
+ tags: [self-audit, hooks, escalation, debugging, agent, protocol, windows, linux, codex]
source: https://github.com/howdeploy/Z.A.E.B.A.L
description: >-
Use when the agent loops on the same mistake and the user is visibly frustrated.
Z.A.E.B.A.L. treats profanity as an audit signal: stop, disprove the wrong belief,
- escalate repeated failures to an external auditor. Installs as hooks in four agent hosts.
+ escalate repeated failures to an external auditor. Also use for requested hook setup
+ on Linux or Windows. Select the target process OS and install only the requested host.
reminder: >-
An agent that has already erred cannot trust its own self-check. The loop is almost
always one wrong belief treated as fact — find and disprove THAT, not the symptoms.
"Written ≠ took effect": verify the act of consumption, not the act of writing.
- triggers: [self-audit, agent keeps failing, user frustrated, zaebal]
+ triggers: [self-audit, agent keeps failing, user frustrated, zaebal, Windows hook setup, Linux hook setup]
license: MIT
---
# Z.A.E.B.A.L. — profanity-triggered self-audit
**Z**aebal? **A**udit. **E**rrors. **B**reak. **A**nalyze. **L**eave no assumption.
When a coding agent gets stuck, it repeats the same action with small variations — because
one underlying belief about the task or the codebase is wrong, and the agent treats that
belief as fact. Another self-check just reproduces the mistake. Z.A.E.B.A.L. plugs a
feedback loop into the user-message boundary: **profanity and direct complaints become an
audit signal**, repeated signals escalate, and at the top level an **external auditor**
(the same or a cross-vendor CLI) reads the transcript and repository evidence from outside.
Public: `howdeploy/Z.A.E.B.A.L`, MIT, Python standard library only.
+ The upstream [installation router](https://github.com/howdeploy/Z.A.E.B.A.L/blob/main/skills/zaebal/SKILL.md)
+ and [Windows/Linux change](https://github.com/howdeploy/Z.A.E.B.A.L/pull/2) are the
+ source for the platform instructions below. Fetch the skill and runtime from the same
+ repository revision; downloading just the skill folder does not install a working hook.
+
## Why it works
The named failure patterns (collected from real session postmortems):
- **The wrong belief is invisible to the agent.** It doesn't loop from inattention — it has
sincerely stopped understanding the problem. The protocol's goal is not "find the
mismatch" but **find and disprove the wrong belief**.
- **"Written ≠ took effect".** A classic: the agent wrote a config/hook/instruction file and
assumes it works because the file exists — while the harness reads it from a different
path. Verify the act of *consumption*, not the act of writing.
- **Sycophancy vs hallucinated correctness.** Agreeing under pressure and abandoning a
working solution — or defending broken code with invented facts. The cure for both:
**execution over intuition**. Defending code with verbal arguments is forbidden — only a
- micro-test, a run, logs. This kills ~90% of "lying" cases.
+ micro-test, a run, logs.
- **First plausible hypothesis.** A lone agent fixates on the first version. That's why
auditors get raw artifacts, not the agent's interpretation — and why there are two of
them: independent versions disprove each other's dead ends.
+ - **Missing session history.** Read the original request through the trigger, locate the
+ first divergence, and correlate it with diffs, commits and actual test/error output.
+ A transcript excerpt is orientation; read the full source when its path is available.
+ Mark causal conclusions unverified when missing history could change them.
## The escalation ladder
Detection covers Russian, English and Chinese profanity (including leetspeak), classifies
- intent (praise with profanity like "fucking great, it works" **closes** an incident instead
- of opening one), and tracks a per-session streak in a 30-minute window:
+ intent, and tracks a per-session streak in a 30-minute window. Praise with profanity
+ such as "fucking great, it works" is silent and adds no weight; it does **not** close an
+ active incident or acknowledge recovery.
| Level | Streak weight | What happens |
|---|---:|---|
- | **L1** | 1–1.5 | STOP. Two independent internal sub-agent auditors, belief inventory (every statement tagged FACT — confirmed by execution — or HYPOTHESIS), micro-plan, notify the human. |
- | **L2** | 2–3.5 | Remove unverified assumptions, compare the work verbatim against the original request. |
- | **L3** | 4+ | FULL STOP of all agents and background work. External auditor (Claude / Codex / Kimi / OpenCode CLI) delivers a verdict; work resumes only after explicit human acknowledgment. |
+ | **L1** | 0.5–1.5 | STOP. Read the session chronology, run two independent internal audits when policy permits, inventory beliefs and prepare a micro-plan. |
+ | **L2** | 2–3.5 | Repeat the independent audits, check the previous audit and compare the work against the original request. |
+ | **L3** | 4+ | Stop non-audit work; run internal audits and attempt the configured external audit. Resume only after explicit human acknowledgment. |
+ Directed complaints add `1.0`; ambiguous profanity adds `0.5`. If internal auditors
+ cannot be launched, state the degraded mode. An external verdict exists only inside
+ `<zaebal-verdict>` and remains a hypothesis to verify; internal sub-agents are not external.
+ For a false trigger, run the exact tokenized `--dismiss-trigger` command supplied by the
+ hook. This retracts only that trigger; replay is a no-op.
+
Recovery is explicit only: "continue", "продолжай", "по плану". A calm message — or even new
logs and evidence — does **not** lift the stop. The protocol is discipline-based: there is
no technical tool lock (a blocking mutation lock was researched for all four hosts and is
feasible, but deliberately not shipped yet — the human keeps final control).
> **The external auditor sees your context.** At L3 the auditor CLI receives a transcript
- > tail plus repository evidence — which may contain private code, tokens and secrets, and a
+ > source/excerpt plus repository evidence — which may contain private code, tokens and secrets, and a
> cross-vendor auditor sends that to **another provider**. The telemetry note
> (`incidents.jsonl` holds no message contents) does not cover the audit payload itself.
> The defaults are the safe end: same-vendor auditor, L3 only. If the code or the
> conversation is sensitive, keep it that way or set `"auditor": "none"` — and never point
> a cross-vendor audit at a repository you wouldn't paste into that vendor's chat.
Fail-open by design: a malformed payload, missing auditor or timeout never breaks the host
session. Telemetry (trigger, auditor, verdict — no message contents) lands in
`~/.zaebal/incidents.jsonl`.
## Install
- Requirements: `python3`, plus at least one supported agent CLI if external auditing is on.
+ Use an existing Python **3.10+** and the full repository. Reading this catalog entry or
+ using the audit protocol does not itself authorize installation. For a requested setup,
+ determine the OS of the **target agent process** once; a process inside WSL follows Linux
+ instructions, while a native Windows process follows Windows instructions.
```bash
git clone https://github.com/howdeploy/Z.A.E.B.A.L.git
cd Z.A.E.B.A.L
- chmod +x install.sh && ./install.sh
```
- The installer detects available hosts and updates only the relevant user config:
+ Read only the selected platform reference from that same checkout:
+ - [Native Windows](https://github.com/howdeploy/Z.A.E.B.A.L/blob/main/skills/zaebal/references/install-windows.md):
+ no WSL, Bash or Linux packages required.
+ - [Linux, including WSL](https://github.com/howdeploy/Z.A.E.B.A.L/blob/main/skills/zaebal/references/install-linux.md):
+ no Windows tools required.
+
+ For **Codex on native Windows**, run from the repository in PowerShell:
+
+ ```powershell
+ py -3 scripts/install_codex_hook.py --platform windows
+ ```
+
+ For **Codex on Linux**, run:
+
+ ```bash
+ python3 scripts/install_codex_hook.py --platform linux
+ ```
+
+ Use the discovered Python executable if its command differs. The helper honors
+ `CODEX_HOME` and saves an absolute interpreter/runtime command in `hooks.json`. It
+ preserves unrelated hooks, settings and incident history, prints a unique config backup,
+ and replaces its own entry on repeated setup. `--config` and `--dest` select custom paths.
+ Close editors changing `hooks.json` during setup; concurrent helper runs are serialized,
+ while external editors do not share that coordination.
+
+ Support boundaries and auditor defaults:
+
| Host | Integration | Default auditor |
|---|---|---|
- | Claude Code | `UserPromptSubmit` in `~/.claude/settings.json` | `claude -p`, read-only tools |
- | Codex CLI | `UserPromptSubmit` in `~/.codex/hooks.json` | `codex exec --sandbox read-only` |
- | Kimi CLI | hook in `~/.kimi-code/config.toml` | `kimi -p` |
- | OpenCode | plugin `~/.config/opencode/plugins/zaebal.ts` | `opencode run` |
+ | Codex | Native Windows/Linux helper; `UserPromptSubmit` in `CODEX_HOME/hooks.json`, default `~/.codex/hooks.json` | `codex exec --sandbox read-only` |
+ | Claude Code | Existing Linux adapter; `~/.claude/settings.json` | `claude -p`, read-only tools |
+ | Kimi CLI | Existing Linux adapter; `$KIMI_CODE_HOME/config.toml`, default `~/.kimi-code/config.toml` | Refused by default: no enforced read-only mode |
+ | OpenCode | Existing Linux adapter; `~/.config/opencode/plugins/zaebal.ts` | Refused by default: no enforced read-only mode |
- Settings live in `~/.zaebal/config.json`: pick the auditor (`"same"` or cross-vendor —
- Claude auditing Codex is a good pattern), which levels call it (`audit_levels`, default
- `[3]`), timeout, transcript tail size. Wordlists are plain text under `core/wordlists/`.
+ Native Windows integration for Claude, Kimi and OpenCode is **not established** by this
+ helper. For another Linux host, read only its adapter and the matching `install.sh`
+ section. The legacy `./install.sh` installs every detected host; use it only when all
+ those integrations were requested.
+
+ ## Verify, update and remove
+
+ Run the platform smoke suite from the checkout with the selected Python:
+
+ ```bash
+ python3 -X utf8 -m unittest discover -s tests -p test_cross_platform.py
+ ```
+
+ On native Windows use `py -3 -X utf8 -m unittest discover -s tests -p test_cross_platform.py`.
+ The suite uses temporary configuration/state, executes the registered command, and makes
+ no paid model calls. It covers Unicode paths, escalation, acknowledgment, concurrent state
+ writes, false-trigger rollback, custom auditor arguments and installer preservation.
+
+ Verify live host activation separately after setup: review/trust the hook if the host
+ requires it, start a fresh session, confirm a controlled complaint injects the protocol
+ and ordinary input stays silent. A passing standalone command does not prove host loading.
+ If this check is unavailable, report "command smoke passed; host activation unverified".
+
+ Update by repeating setup from one matching new checkout. Add `--remove` to the same
+ Codex setup command to unregister only that hook, repeating custom path arguments.
+ Runtime, settings and history remain. The legacy `./uninstall.sh` removes all integrations
+ and data; it is not the single-host removal path.
+
+ ## Configure the auditor
+
+ Settings live in `~/.zaebal/config.json` and take effect on the next trigger:
+
+ - `auditor`: `"same"` by default; choose a supported CLI or `"none"` to disable it.
+ - `audit_levels`: `[3]`; `auditor_timeout_sec`: `90`.
+ - `transcript_tail_chars`: `12000`; `agent_context_tail_chars`: `2500`. These are
+ orientation excerpts; the readable transcript source remains authoritative.
+ - `auditor_command`: a legacy POSIX command string or an argv array. Prefer an array for
+ Windows paths with spaces/backslashes; the prompt is appended as the final argument.
+ - `allow_unsafe_auditor`: `false`. Built-in Kimi/OpenCode auditors are refused because
+ they lack enforced read-only modes; use Claude/Codex or a sandboxed custom command.
+
+ The shared core uses native `msvcrt` locking on Windows and `fcntl` on Unix, atomic state
+ replacement and UTF-8 streams. Both platforms share the audit protocol, wordlists and
+ state format. Wordlists live under `core/wordlists/`.
## Why this is in deploychan
This is the missing fourth pillar of the `agent-harness` route: hooks control the loop,
prompts set the rules, memory holds state — and Z.A.E.B.A.L. catches the case where all
three are fine but the agent is confidently building on a wrong belief. It turns the user's
frustration (which would otherwise just be swearing into the void) into a structured audit
with an external pair of eyes.