vigiles API reference
    Preparing search index...

    Interface RunHookOptions

    interface RunHookOptions {
        cwd?: string;
        egress?: { allow: readonly string[] };
        env?: Record<string, string>;
        recordEgress?: boolean;
        sandbox?: SandboxMode;
        timeoutMs?: number;
        trusted?: boolean;
    }
    Index

    Properties

    cwd?: string

    Working directory for the hook process. Default: a value won't be set.

    egress?: { allow: readonly string[] }

    Allowlisted egress: let the hook actually reach the network, but ONLY the listed hosts, with the boundary at the packet layer (an nft allowlist inside the sandbox netns, fed by slirp4netns) — so a raw socket to an off-list host is dropped too, which a recordEgress/HTTP_PROXY allowlist cannot guarantee. Use it to test a hook/skill whose setup needs a real npm install from a registry you expect, and nothing else. Implies confinement (it needs the netns), and refuses if bubblewrap + slirp4netns

    • nft aren't available. The hosts are resolved to IPs at launch; results land in HookRunResult.egress (the allowlisted hosts that were reached, with allowed: true) and HookRunResult.egressDropped (how much off-list traffic was blocked). See docs/sandboxing.md.
    env?: Record<string, string>

    Extra env vars (merged over process.env). {cwd} in values is left as-is.

    recordEgress?: boolean

    Record the hook's network egress. Implies confinement (the recorder lives in the sandbox netns, so this forces a sandboxed run and refuses if no sandbox is available). A recording proxy on loopback captures every host:port a proxy-honoring tool (npm/pip/curl/fetch) tries to reach — surfaced as HookRunResult.egress — while the netns still blocks it (nothing actually leaves). Use it to test what a hook/skill phones home to, or which registry an install would hit. Raw-socket egress is blocked but not recorded (it never reaches the proxy) — the block is the boundary, the record is best-effort observability over it.

    sandbox?: SandboxMode

    Confine the hook under bubblewrap (Linux). When unset, the mode follows RunHookOptions.trusted: a trusted hook runs directly (false), an untrusted one is confined-or-refused ("auto"). Set it explicitly to override: "auto"/"strict" force confinement (a no-egress namespace with a cleared environment — your opts.env is added back — or a refusal if no bwrap is available), and false is the opt-out that runs even untrusted code unconfined. macOS/Windows have no bwrap, so "auto"/"strict" throw there — see src/sandbox.ts.

    timeoutMs?: number

    Per-run timeout ms. Default 10000.

    trusted?: boolean

    Provenance of the hook command. true (default) means YOU authored it — the usual case at this tier, a command written inline in the test — so it runs directly. false marks it foreign (a vendored third-party hook script), which makes confinement the DEFAULT: with no explicit sandbox, an untrusted hook behaves as sandbox: "auto" — confined under bubblewrap, or refused if none is available — so foreign code is never run unconfined by accident. This mirrors the harness tier, where trust follows plugin/pluginDir provenance (specTrusted in src/sandbox.ts); the unit tier takes a raw command string with no provenance signal, so you declare it here.

    Why this is opt-in (untrusted) and not always-on: the sandbox isn't always available (Linux + working userns only — forcing it would refuse a hook you wrote on macOS/hardened CI), it's deliberately hostile (no egress, --clearenv, empty HOME, read-only fs — a false failure for trusted code that needs the network or an env var), trust follows provenance (you already vouched for inline code), and direct exec is ms vs. the confined path's setup+spawn. See docs/sandboxing.md ("Why confinement is opt-in"). Use sandbox: "strict" to force confinement even on trusted code.