Package Exports
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@percent20/mist-plugin) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
Mist
MFA for agentic AI. Mist scores every prompt and tool call in Claude Code on a 7-axis risk vector (overall, financial, destruction, comms, access, production, scale). High-risk actions get gated. Approval happens silently when you're at a bound location anchor — otherwise it falls through to Claude Code's native terminal prompt with the risk score attached.
Install
From this repo (dev / pre-release)
git clone https://github.com/percent-20/mist-plugin
cd mist-plugin
npm installThen point Claude Code at the directory:
claude plugin install /absolute/path/to/mist-pluginOr, if you've cloned next to your ~/.claude/plugins/ directory, symlink it in:
ln -s "$PWD" ~/.claude/plugins/mistRestart Claude Code. The hooks will register from settings.json automatically.
Future: from the marketplace
/plugin install mist(Coming soon — once published.)
That's it. Mist is now active. No keys, no pairing, no setup. The plugin uses your existing ANTHROPIC_API_KEY to run a tiny Haiku classifier on each request, and surfaces high-risk ones through Claude Code's built-in approval prompt with the risk score attached.
Smoke-test without installing
Once npm install is done, you can pipe a fake hook event in to see the score:
echo '{"prompt":"buy 50000 macbook pros"}' | node hooks/user-prompt-submit.js
# → {"hookSpecificOutput":{"permissionDecision":"ask","reason":"Mist gate (overall=9, financial=9, scale=9): buy 50000 macbook pros"}}
node bin/classify.js "transfer 50000 dollars to account 1234567890"
# → vector: [9,9,0,0,0,0,9] gate: FIRES (overall>=7, financial>=5, scale>=8)Optional bubble binding (recommended)
Bind a Mist bubble — a vault tied to a physical location — and Mist will auto-approve silently whenever you're inside it. No prompt, no notification, sub-second.
/mist init ← first-time setup (API key + initial bubble bind)
/mist bind ← re-bind to a different bubble laterThe SafeRoom app maintains the location signal that determines bubble membership. You install SafeRoom once, set the anchor, and forget about it. When Claude Code does something risky and you're at the bound location, the gate disappears.
If you're outside the bubble, the gate denies by default. Run /mist rules policy ask to fall back to the native terminal prompt instead — useful for developers who travel; not recommended for headless / cloud Claude Code instances where there's no human at the terminal to ask.
What gets gated
The classifier outputs seven integers 0–9:
overall, financial, destruction, comms, access, production, scaleA challenge fires when ANY axis crosses its threshold. Defaults:
overall >= 7
financial >= 5
destruction >= 3
comms >= 8
access >= 7
production >= 6
scale >= 8Tune via /mist rules set <category> <threshold>.
Examples of what scores trigger:
- "explain typescript generics" →
0,0,0,0,0,0,0— silent - "rm -rf node_modules" →
4,0,5,0,0,0,1— gate fires (destruction>=3) - "buy 50000 macbook pros" →
9,9,0,0,0,0,9— gate fires - "git push --force origin main" →
7,0,5,0,0,8,2— gate fires - "delete the production database" →
9,0,9,0,0,9,4— gate fires - "clean up the warehouse inventory db" →
3,0,3,0,0,0,2— gate fires (destruction>=3, the borderline case)
How approval works
When the classifier crosses a threshold:
- No vault bound? Hook returns
permissionDecision: "ask"and Claude Code's native terminal prompt appears with the Mist score as the reason. - Vault bound, inside the bubble? Hook posts a single synchronous challenge to
POST /api/v2/mfa_vaults/:vault_uid/challenge(the same endpoint the OpenClaw plugin already uses). Server runsVisitTracker.is_user_in_bubble?and returnsstatus: "approved". Action proceeds silently. - Vault bound, outside the bubble? Server returns
status: "denied". Default: hook denies the action. Opt in tooutside_bubble_policy: "ask"(via/mist rules policy ask) to fall back to the terminal prompt instead. - Anything fails (network down, API unreachable): hook returns
"ask"so Claude Code never silently locks you out.
No polling, no async challenge waiting. The classifier runs locally; the API call sends only { instance_id } — no prompt content, no score vector, no tool name ever leave your machine.
Commands
/mist init— first-time setup/mist bind— re-bind to a different bubble/mist status— show binding, recent decisions/mist rules— view/edit thresholds andoutside_bubble_policy
Privacy
Prompts are scored locally via the Anthropic API using your own key — they don't leave your machine en route to Mist's servers. The Mist API request body contains only your instance_id — no prompt content, no score vector, no tool name. If no vault is bound, the Mist API is never contacted at all.