khwarizmi-hermes-plugin
May 31, 2026 ยท View on GitHub
Hermes Agent adapter for the Mizan reliability scale. A thin layer that maps mizan onto Hermes's pre_llm_call, pre_tool_call, and on_session_end hooks.
๐ธ๐ฆ ู ูุฎูุทููุท ุงูุทุจูุฉ ุจุงูุนุฑุจูุฉ ู ุน ู ุซุงู ุญูููู ู ูุชุฏุฑููุฌ ยท Arabic flow diagram + worked example:
docs/diagram-ar.md
v0.2 โ all four operations wired:
jabr(restore) +muqabalah(balance) run viamizan.preflight;qadiya(constraint-driven classification + dispatch) runs viamizan.ToolGate. Logic lives in the framework-agnosticmizanpackage; this repo is just the Hermes binding.
What it does today
| Hook | Action |
|---|---|
pre_llm_call | Runs mizan.preflight (jabr.restore โ muqabalah.balance) on the user message and injects the resolved/balanced trace as context. On contradiction, injects a hard "do not call any tool, ask one clarifying question" directive and stashes the conflict on the session. Carries the shared mizan receipt. |
pre_tool_call | Gates in order: (1) contradiction caught this turn โ block; (2) mizan.mcpscan tool-surface scan (multilingual/Unicode poisoning) โ audit/warn log only, block blocks on high severity (config mcpscan.mode, default off); (3) qadiya ToolGate โ block if the tool call matches no allowed case; (4) KHWARIZMI_BLOCK_TOOLS env list โ block. Otherwise audits. |
on_session_end | Flushes per-session state, writes a session_end audit record. |
Every event is appended to ~/.hermes/plugins/khwarizmi/audit.jsonl (JSONL, append-only).
What it does NOT do (yet)
- Tool gate is a tool-name allowlist today.
mizan.ToolGatesupports richer constraints (argument scope, target sensitivity) via a fullqadiyaCaseRegistry, butconfig.yamlcurrently only surfacestool_policy.allow_tools. Multi-constraint policies are open work. - No LLM-call saving on contradictions. Hermes's existing
pre_llm_callcan only append context. It cannot replace the user message, and it cannot short-circuit the turn. So contradictions still cost one LLM call per turn โ the strong injected directive steers most current models toward clarification, but the model is still consulted. Closing this gap requires the upstream extension proposed indocs/upstream_discussion.md. - Default contradiction predicates are minimal. English-only, eight pairs. Fine for smoke tests, not for production traffic. Override via
config.yaml.
Install
git clone https://github.com/Moshe-ship/khwarizmi-hermes-plugin
mkdir -p ~/.hermes/plugins
cp -r khwarizmi-hermes-plugin/khwarizmi ~/.hermes/plugins/
Hermes plugins are opt-in by default. Enable:
hermes plugins enable khwarizmi
That adds khwarizmi to plugins.enabled in ~/.hermes/config.yaml.
Install the packages the plugin imports (mizan plus the three primitives it wraps):
pip install git+https://github.com/Moshe-ship/jabr.git
pip install git+https://github.com/Moshe-ship/muqabalah.git
pip install git+https://github.com/Moshe-ship/qadiya.git
pip install git+https://github.com/Moshe-ship/mizan.git
Or, if you have the source checkouts at ~/Projects/{mizan,jabr,muqabalah,qadiya}/, the plugin auto-vendors them onto sys.path at import time โ no pip install needed for development.
Required core patch
Hermes commit fc8e4ebf calls get_pre_tool_call_block_message() at two sites in run_agent.py without forwarding session_id. Plugins that key state by session can't read it back. Apply patches/run_agent_session_id.patch:
cd ~/.hermes/hermes-agent
git apply /path/to/khwarizmi-hermes-plugin/patches/run_agent_session_id.patch
Or do the two-line edit by hand at lines ~7551 and ~7993:
# before
block_message = get_pre_tool_call_block_message(
function_name, function_args, task_id=effective_task_id or "",
)
# after
block_message = get_pre_tool_call_block_message(
function_name, function_args,
task_id=effective_task_id or "",
session_id=self.session_id or "",
)
Without that patch, the env blocklist still works, but the contradiction-triggered tool block silently no-ops because session_id arrives as "". The patch is also proposed upstream alongside the main pre_llm_call extension โ see docs/upstream_discussion.md.
Configure (optional)
~/.hermes/plugins/khwarizmi/config.yaml:
contradiction_predicates:
- ["yes", "no"]
- ["send", "cancel"]
- ["send", "do not send"]
- ["now", "later"]
- ["public", "private"]
- ["approve", "reject"]
- ["delete", "keep"]
# jabr: pronoun โ name resolution
referents:
# her: Alice
# him: Bob
# jabr: defaults for missing slots
defaults:
# recipient: Alice
# channel: "#general"
# qadiya tool gate (mizan.ToolGate): constraint-driven allowlist.
# When set, any tool NOT listed is escalated (blocked), never silently run.
# Omit this block to leave the gate inert.
tool_policy:
allow_tools:
- read_file
- search
- list_dir
audit_log: ~/.hermes/plugins/khwarizmi/audit.jsonl
Env knobs:
| Variable | Purpose |
|---|---|
KHWARIZMI_BLOCK_TOOLS | Comma-separated tool names to hard-block via {"action": "block"}. |
KHWARIZMI_AUDIT_OFF | Set to 1 to disable the audit log. |
Verify
tail -f ~/.hermes/plugins/khwarizmi/audit.jsonl
In a fresh Hermes session, expect:
- one
preflightrecord per turn (carrying the fullmizanreceipt: restore + balance stages) - one
tool_callrecord per tool the agent dispatches - a
contradiction_caughtrecord when the user input contains a configured contradiction predicate - a
tool_blocked_contradictionrecord if the model still attempts a tool after a contradiction was caught - a
tool_blocked_gaterecord whentool_policy.allow_toolsis set and the agent attempts a tool outside the allowlist - a
session_endrecord on session shutdown
Upstream proposal
The full proposal โ structured returns for pre_llm_call (allow / rewrite / early-exit) โ is in docs/upstream_discussion.md. This plugin is the reference implementation that motivates that discussion: every part of the pattern works on the existing hooks except the LLM-skip path on deterministically caught conditions.
Honest framing
The benchmark behind this work is intentionally a should-clarify set, not a should-call-a-tool set. Across 12 current OpenRouter models on 91 ambiguous cases, the four-step pattern (in its unrestricted reference form, not this hook-limited subset) raised mean safe-outcome accuracy from 95.1% to 98.4% and resolved 16.5% of cases before any LLM call. Local plugin behaviour will differ on different traffic distributions. Full reports: Moshe-ship/case-eval.
License
MIT. See LICENSE.