Skip to content

Humanize policy (3-layer model)

Human-like interaction (cursor movement, typing cadence, scroll bursts) is the single biggest anti-detection lever after the fingerprint itself. Ghostvault exposes a 3-layer model for deciding whether a given gv_fill_input / gv_click_element call is humanized, so you can tune it from "let the agent decide" all the way up to "force it on everywhere, agent cannot disable".

The three layers

Layer Where it lives Granularity Example
Layer 1 — per-call The humanize arg on each tool One call gv_fill_input(..., humanize=True)
Layer 2 — per-account The account's humanize_policy advanced key One account gv_update_account_config(..., reset_keys=["humanize_policy"])
Layer 3 — global GHOSTVAULT_HUMANIZE_POLICY env var Whole server .env: GHOSTVAULT_HUMANIZE_POLICY=always

Layer 1 — the agent decides (per-call)

Every interactive tool (gv_fill_input, gv_click_element, gv_scroll) takes a humanize argument. The tool's own docstring contains a Decision Guide that tells the agent when to turn it on — for example, the gv_fill_input guide says:

  • Google / SSO login forms (email, password) → ALWAYS
  • Captcha-protected form fields → ALWAYS
  • Banking / payment forms → ALWAYS
  • 2FA / OTP code fields → optional
  • Search boxes on trusted sites → optional

This is the default mode (GHOSTVAULT_HUMANIZE_POLICY=off) and preserves backward compatibility — the agent is fully in charge of every call.

Layer 2 — per-account policy

Set an account's humanize_policy advanced key to lock down behavior for that account regardless of what the agent passes:

await gv.update_account_config(
    account_id,
    # "off" | "recommended" | "always"
    device_config=None,  # not used here
    reset_keys=None,
    # ... the trick: humanize_policy lives in the GHOSTVAULT_LAYER_KEYS advanced dict,
    # so it's set via the advanced flags path, not device_config.
)

In practice humanize_policy is an advanced key (it lives in GHOSTVAULT_LAYER_KEYS, not the raw Camoufox schema), so it's set via the standard advanced-flags path on gv_update_account_config — pass it the same way you'd pass humanize or locale.

Per-account defaults

Two related advanced keys work the same way and give you per-account control without a policy: - humanize_typing — default humanize flag for gv_fill_input - humanize_clicks — default humanize flag for gv_click_element - default_typing_wpm — default typing speed (40–150) - default_mistake_rate — default typo rate (0–0.05)

Layer 3 — global default

Set GHOSTVAULT_HUMANIZE_POLICY in .env (or the env block of your MCP client config) to change the server-wide default. Per-account humanize_policy (Layer 2) always wins over this.

Resolution order

The policy is resolved per call by _resolve_humanize_policy() in src/ghostvault/tools.py:

Precedence Source How to set
1 (highest) Per-account humanize_policy gv_update_account_config
2 Global GHOSTVAULT_HUMANIZE_POLICY .env
3 (fallback) "off" (built-in default)

The effective policy is one of "off" | "recommended" | "always". Once the policy is known, the per-call humanize argument is resolved by _enforce_humanize():

Policy humanize arg not passed humanize=True humanize=False
always True (forced) True (forced) True (forced — agent cannot disable)
recommended True (default on) True False (agent can turn off)
off per-account default (humanize_typing / humanize_clicks), else False True False

In short:

  • always = the safety position. Humanize is forced on; the agent literally cannot disable it. Use this for your most sensitive accounts.
  • recommended = the "secure by default" position. Humanize is on unless the agent explicitly opts out — the inverse of Layer 1.
  • off = the agent decides, with per-account defaults as a fallback.

Enforcement semantics

The enforced humanize flag is echoed in every gv_fill_input / gv_click_element response so you can audit what actually happened:

{
  "clicked": "Next",
  "humanize": true,
  "title": "Welcome",
  "url": "https://accounts.google.com/..."
}

Both the gv_fill_input and gv_click_element docstrings explicitly warn the agent:

If the account's humanize_policy is "always", humanize is forced on regardless of what you pass here.

This means even a model that tries to pass humanize=False on a login form (whether by mistake or because it's optimizing for speed) cannot disable humanization when the policy is always.

Examples

.env:

GHOSTVAULT_HUMANIZE_POLICY=recommended

A trusted internal dashboard's search box — agent opts out for speed:

{ "target": "Search", "value": "Q3 report", "humanize": false }

Result: humanize is false (the agent's explicit false wins under recommended).

A Google login form — agent leaves the default:

{ "target": "Email", "value": "user@gmail.com" }

Result: humanize is true (default-on under recommended).

Example 2 — per-account "always", agent tries to disable

await gv.update_account_config(bank_account_id, humanize_policy="always")

Agent later calls:

{ "target": "Password", "value": "hunter2", "humanize": false }

Result: humanize is true — the policy forces it on, the agent's false is ignored.

Example 3 — global "off" (default), per-account defaults do the work

.env:

GHOSTVAULT_HUMANIZE_POLICY=off

Per-account config:

await gv.update_account_config(
    account_id,
    # These are advanced (GHOSTVAULT_LAYER) keys:
    humanize_typing=True,    # but how? see note below
)

Setting GHOSTVAULT_LAYER_KEYS

humanize_typing, humanize_clicks, default_typing_wpm, default_mistake_rate, and humanize_policy are all members of GHOSTVAULT_LAYER_KEYS. They're set through the same advanced-flags surface as locale / humanize on gv_update_account_config — there's no separate argument. The Programmatic SDK update_account_config accepts them as keyword args.

With the policy at off, the agent's per-call value (or the per-account default if the agent doesn't pass one) decides — the original backward-compatible behavior.

Where to set what

You want… Set
The agent to decide every call GHOSTVAULT_HUMANIZE_POLICY=off (default)
Humanize on by default everywhere, agent can opt out GHOSTVAULT_HUMANIZE_POLICY=recommended
Humanize forced on everywhere, agent cannot disable GHOSTVAULT_HUMANIZE_POLICY=always
One specific account to force humanize gv_update_account_config(..., humanize_policy="always")
A default typing speed for one account gv_update_account_config(..., default_typing_wpm=65)