Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

Vigils is a local-first control plane for AI agents:

  • Action firewall (Firewall::evaluate) — fail-closed effect gating
  • Audit ledger (SHA-256 hash chain) — tamper-evident decision history
  • Privacy filter (hard-fingerprint rules + optional ONNX-backed PII detection)
  • MCP hub (Model Context Protocol server registry + descriptor pinning)
  • Approval queue (human-in-the-loop for risky effects)
  • Sandbox runner (Wasm + native, Linux Landlock LSM)

Vigils sits between AI agents and the effectful tools / APIs they touch, gating each action through redaction + policy + audit + approval — and everything stays on your machine.

Project status

DimensionState
Releases3-platform signed installers + auto-update (OTA) — latest release
Rust SDKvigil-sdk published to crates.io
SecurityComprehensive audit (OWASP + STRIDE + supply chain) — 9.9 / 10, 0 critical / high
MaturityCore safety claims proven-safe with code + test evidence; all sandbox / SDK / audit changes reviewed

Distribution

  • Desktop installers — Linux deb / rpm / AppImage + macOS dmg + Windows nsis / msi (Ed25519-signed, auto-update).
  • Rust SDKcargo add vigil-sdk (crates.io / docs.rs).
  • Browser extension — Chrome MV3 (redacts before paste / submit on AI sites).
  • CLI agent gatewayvigil-hub serve --stdio (Claude Code / Codex / Cursor / Zed).

License

Apache-2.0 © Vigils Project Contributors

Watch the demo (20 seconds)

One command — vigil-hub demo — shows the whole idea: your AI agent tries to leak a secret, and Vigils stops it. Everything below runs locally: the firewall, the redaction, and the tamper-evident audit are the real runtime code paths; only the external model/tool is simulated, and no LLM is contacted.

Player not loading? Download the recording and play it with asciinema play vigil-demo.cast, or just run it yourself after installing: vigil-hub demo.

What you just watched

  1. Default-deny. The agent puts a raw GitHub token into a tool call. The firewall refuses to forward a raw secret — DENY.
  2. The Vigils way. The agent instead passes a placeholder (secret://github_pat). The remote model only ever sees the placeholder; the real value is detokenized only at the local tool boundary; and when the tool’s result leaks a credential back, Vigils re-redacts it before the model sees anything.
  3. Tamper-evident audit. Every step lands in a SHA-256 hash-chained ledger — with no plaintext secrets stored. (vigil-hub demo --tamper alters one row and the chain verification fails, on purpose.)

The agent did useful work with a real secret — while the model, the logs, and the audit never received the real value. That is the whole product, in one command.

Next: install it and protect your own agents with vigil-hub setup --all.

Installation

Download the latest installers from the Releases page. Replace <version> below with the release you downloaded (e.g. 0.1.7).

Early releases aren’t OS-code-signed yet, so your OS may show a Gatekeeper / SmartScreen prompt on first run. Every artifact is still independently verifiable — see Verifying your download (中文) for gh attestation verify (build provenance) and checksums.

Desktop app (end users)

The installed program is Vigils (executable vigils / vigils.exe).

Linux

sudo dpkg -i Vigils_<version>_amd64.deb           # Debian / Ubuntu
sudo rpm -i  Vigils-<version>-1.x86_64.rpm         # Fedora / RHEL
chmod +x Vigils_<version>_amd64.AppImage && ./Vigils_<version>_amd64.AppImage   # portable

Windows

  • NSIS: double-click Vigils_<version>_x64-setup.exe (SmartScreen → More infoRun anyway).
  • MSI: msiexec /i Vigils_<version>_x64_en-US.msi

macOS (Apple Silicon)

Open Vigils_<version>_aarch64.dmg, drag Vigils to Applications, then clear the quarantine flag (unsigned build):

xattr -d com.apple.quarantine /Applications/Vigils.app

Auto-update

Installed apps check for updates over the Tauri auto-updater (Ed25519-signed). See Auto-Update.

Rust SDK (developers)

[dependencies]
vigil-sdk = "0.1"

Published on crates.io / docs.rs. See SDK Quickstart.

Browser extension (Chrome MV3)

Redacts secrets / PII before paste or submit on AI sites (ChatGPT / Claude / Gemini / Perplexity):

  1. chrome://extensions → enable Developer modeLoad unpacked → select extensions/chrome-mv3/.
  2. The extension talks to the desktop app’s native host (registered by the desktop installer / vigil-native-host install).

CLI agent gateway

For embedding Vigils as an MCP gateway in front of your agent (Claude Code / Codex / Cursor / Zed):

  • Prebuilt: download vigils-cli-<target>.tar.gz (or .zip on Windows) from the release — it contains vigil-hub and vigil-native-host.
  • From source: cargo install --path apps/vigil-hub-cli
vigil-hub serve --stdio    # MCP agent entry point

See the Agent Integration & Test guide for per-agent config (中文).

Verifying your download

🌐 中文版:验证你的下载

Vigils sits in front of your secrets, so you shouldn’t have to take our word that a download is genuine. Every release artifact is independently verifiable. This page shows how — and is honest about what each check does and doesn’t prove.

TL;DR

# The strongest check: proves the file was built by THIS repo's CI from THIS repo's
# source. Works for every artifact — CLI archives, desktop installers, extension zip.
gh attestation verify <downloaded-file> --repo duncatzat/vigils

A ✓ with a matching source repository and workflow means the binary is authentic; nothing else is strictly required. The sections below add complementary checks and explain the current absence of OS code-signing.

Every downloadable artifact ships with a SLSA build-provenance attestation, signed through GitHub’s Sigstore-backed infrastructure (no key for you to manage, nothing to trust besides GitHub and the public source):

  • CLI archives — vigils-cli-linux-x64.tar.gz, vigils-cli-macos-arm64.tar.gz, vigils-cli-windows-x64.zip
  • Desktop installers — .exe, .msi, .dmg, .deb, .rpm, .AppImage
  • Browser extension — vigils-chrome-extension.zip

Verify with the GitHub CLI:

gh attestation verify Vigils_0.1.7_amd64.deb --repo duncatzat/vigils

A pass proves the file was produced by this repository’s release workflow from a specific commit — i.e. it wasn’t swapped out, rebuilt by someone else, or altered after the build. This is a stronger statement about origin than a code-signing certificate alone, because it binds the binary to the exact public source commit and CI run you can go read.

Air-gapped? Download the artifact’s attestation bundle from the release and verify offline with gh attestation verify <file> --bundle <bundle.jsonl> --repo duncatzat/vigils.

2. Checksums — CLI archives

Each CLI archive is published next to a .sha256 file. The one-line installer checks it for you; to verify by hand:

# macOS / Linux — the .sha256 holds "<hash>  <filename>"
shasum -a 256 -c vigils-cli-linux-x64.tar.gz.sha256
# Windows — compare against the published hash in vigils-cli-windows-x64.zip.sha256
(Get-FileHash -Algorithm SHA256 vigils-cli-windows-x64.zip).Hash

A checksum only proves the bytes you got match the bytes the release published (it catches truncation / transport corruption). It is not a signature — use provenance (§1) for authenticity. Desktop installers rely on provenance rather than a separate .sha256.

3. The install script

The one-liner is a plain, readable shell/PowerShell script — read it before running. Note it verifies the archive checksum for you:

curl -fsSL https://vigils.ai/install.sh          # read it first
curl -fsSL https://vigils.ai/install.sh | sh     # then run
irm https://vigils.ai/install.ps1                # read it first
irm https://vigils.ai/install.ps1 | iex          # then run

4. About the “unsigned app” warning

Vigils installers are not yet OS-code-signed or notarized — that requires a paid, identity-verified certificate from Apple and a Windows CA, which isn’t in place yet. So on first run your OS will warn you:

  • macOS — Gatekeeper blocks the app. Verify provenance (§1) first, then clear the quarantine flag: xattr -d com.apple.quarantine /Applications/Vigils.app.
  • Windows — SmartScreen warns. Verify provenance (§1) first, then More info → Run anyway.

Until code-signing lands, build provenance is the verification path — and for proving a binary really came from this open source, it’s the stronger guarantee anyway.

5. Auto-updates are signed

Once installed, the desktop app’s auto-updater only accepts updates carrying a valid signature from the project’s minisign key (the .sig files in each release), so the update channel is authenticated end-to-end with no action from you. See Auto-Update.

SDK Quickstart

[dependencies]
vigil-sdk = "0.1"

Hello, redaction

Hard-fingerprint PII detection — zero model dependencies:

use vigil_sdk::prelude::*;

fn main() {
    let result: RedactionResult = scan_text(
        "API: ghp_0123456789abcdefghijklmnopqrstuvwxyz12"
    ).unwrap();
    for f in &result.findings {
        println!("{:?} @ {:?}", f.kind, f.span);
    }
    // Output: github_token @ (5, 45)
}

Firewall + approval

#![allow(unused)]
fn main() {
use vigil_sdk::prelude::*;

let firewall = Firewall::new(FirewallConfig::default());
match firewall.evaluate(&invocation, &decision) {
    Ok(FirewallOutcome::Allow) => proceed(),
    Ok(FirewallOutcome::ApprovalRequired(req)) => queue(req),
    Err(e) => return Err(e),  // FAIL CLOSED
}
}

Invariants

  1. Fail-closed — errors → DENY.
  2. No-plaintext audit.
  3. DecisionRecord mandatory.
  4. API stability — 0.x minor evolution allowed; v1.0 freezes the surface.

See Invariants.

Feature flags

FeatureDefaultDescription
ortoffONNX-Runtime PII scanner (3-engine ensemble)

Desktop Quickstart

First launch

The window opens on the Activity Feed (empty on first run). There are four tabs: Activity Feed, Approval Queue, Server Registry, and Session Replay.

Connect an AI agent

Claude Code (MCP stdio)

{ "mcpServers": { "vigil": { "command": "vigil-hub", "args": ["serve", "--stdio"] } } }

Cursor / Zed / Codex

The same vigil-hub serve --stdio MCP stdio entry point.

Browser extension

Chrome MV3 extension → native host → desktop app (stdio MCP).

Tabs at a glance

TabWhat it shows
Activity FeedRecent events, SQLite FTS5 search, hash-chain verification
Approval QueueRisky effects awaiting a decision — Approve / Reject / Delegate / Defer
Server RegistryActive / Pending / Removed servers, descriptor drift
Session ReplayThe full decision timeline for a chosen session_id

See Architecture.

Agent Integration & Test Guide

🌐 中文版:Agent 接入与测试指南

Put Vigils in front of your AI agent’s tools, so every tool call your agent makes is firewalled (default-deny), audited (tamper-evident hash chain), redacted (secrets / PII), and — when risky — sent to approval. Everything runs locally; nothing leaves your machine.

Works with any MCP-capable agent: Claude Code, Codex, Cursor, Zed, OpenCode, Continue, and more.

How it works

Vigils runs as an MCP gateway: your agent connects to vigil-hub over stdio, and vigil-hub proxies your real MCP tool servers (“upstreams”), gating every call.

┌──────────────────┐   stdio JSON-RPC   ┌────────────────────┐      ┌──────────────────┐
│  Your agent      │◄──────────────────►│  vigil-hub serve   │─────►│ Upstream MCP      │
│  Claude Code /   │                    │   --stdio          │      │ servers           │
│  Codex / Cursor /│                    │  ┌──────────────┐  │      │ (filesystem,      │
│  Zed / ...       │                    │  │ Firewall     │  │      │  github, db, ...) │
└──────────────────┘                    │  │ Audit ledger │  │      └──────────────────┘
                                        │  │ Redaction    │  │
                                        │  │ Approval     │  │
                                        │  └──────────────┘  │
                                        └────────────────────┘

Each upstream’s tools are namespaced with a __ (double-underscore) separator — <server>__<tool>, e.g. fs__read_file, github__create_issue — and aggregated into the tools/list your agent sees. When the agent calls one, Vigils evaluates it against the firewall before forwarding, records a decision in the audit ledger, and either allows it, denies it, or queues it for your approval.

Prerequisites

Install the CLI gateway, vigil-hub:

  • Prebuilt: download vigils-cli-<target>.tar.gz (.zip on Windows) from the latest release — it contains vigil-hub and vigil-native-host. Put vigil-hub on your PATH.
  • From source: cargo install --path apps/vigil-hub-cli

Verify: vigil-hub --help

Fastest path — Claude Code, one command (setup --all)

If you use Claude Code, you don’t need to hand-write configs at all. One command detects your setup and protects everything — your existing config is backed up and only Vigils’ own entries are added (fully reversible):

vigil-hub setup --all

setup --all wires up both layers:

  1. Native-tool input guard — a PreToolUse hook so every tool call (Bash, Edit, Write, Read, MCP tools, …) is checked before it runs; a real credential heading into a tool is blocked fail-closed and audited.
  2. MCP gateway — rewrites each of your stdio MCP servers to run through Vigils, so secrets in tool results are scrubbed before the model sees them and every call is audited. Defaults to monitor posture (your servers stay usable; raw-secret block, result redaction, and audit stay on). Add --enforce for default-deny gating.
vigil-hub setup --mcp --doctor    # pre-flight: will each wrapped MCP server actually start? (read-only PATH check)
vigil-hub inspect protection      # after using your agent: what Vigils caught (secrets blocked, leaks redacted, chain intact)
vigil-hub setup --all --uninstall # remove everything (config restored byte-for-byte)

Restart Claude Code and you’re protected. The rest of this guide is the manual path — use it for non-Claude agents (Codex / Cursor / Zed / …) or when you want explicit control over the serve gateway and its upstreams.json.

Step 1 — Smoke-test vigil-hub (30s, no agent needed)

Confirm the gateway speaks MCP before wiring any agent. Pipe an initialize + tools/list into it (MCP stdio is newline-delimited JSON-RPC):

printf '%s\n' \
 '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"smoke","version":"0"}}}' \
 '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
 | vigil-hub serve --stdio --ledger ./vigil.db

Expected stdout (two JSON-RPC responses):

{"id":1,"jsonrpc":"2.0","result":{"capabilities":{"tools":{"listChanged":false}},"protocolVersion":"2025-06-18","serverInfo":{"name":"vigil-hub","version":"0.1.7"}}}
{"id":2,"jsonrpc":"2.0","result":{"tools":[]}}

tools/list is empty because no upstreams are configured yet (next step). Startup banners go to stderr (stdout is reserved for the protocol).

Step 2 — Declare your tool servers (upstreams.json)

List the MCP servers you want Vigils to proxy. Bare commands resolve via PATH.

{
  "upstreams": [
    { "name": "fs",     "argv": ["npx", "-y", "@modelcontextprotocol/server-filesystem", "/data"] },
    { "name": "github", "argv": ["npx", "-y", "@modelcontextprotocol/server-github"] }
  ]
}

Pass it to serve:

vigil-hub serve --stdio --ledger ./vigil.db --upstream-config ./upstreams.json

For each entry Vigils registers the server, pins its launch command, and runs a gate-before-spawn check (argv + resolved-program drift) before starting the child process — then namespaces its tools (fs__…, github__…) into tools/list.

HTTP / remote MCP servers use OAuth onboarding instead: vigil-hub add-remote-mcp --url https://mcp.example.com/ --client-id <id> --scopes mcp:tools.read

Step 3 — Point your agent at vigil-hub

Use a shared ledger path so the desktop app and CLI see the same audit trail. The desktop app reads data_local_dir()/Vigil/ledger.sqlite3:

  • Windows: %LOCALAPPDATA%\Vigil\ledger.sqlite3
  • Linux: ~/.local/share/Vigil/ledger.sqlite3
  • macOS: ~/Library/Application Support/Vigil/ledger.sqlite3

The filename must be exactly ledger.sqlite3 (with the 3) and the directory must be data_local_dir() — a path mismatch means the desktop reads a different file and the Activity Feed stays empty. Easiest path: run vigil-hub setup --mcp / setup --all, which auto-targets this shared ledger. Do not omit --ledger on a manual serve --stdio — that uses an in-memory ledger the desktop can’t see. serve/wrap print the resolved ledger path on startup, so you can compare it with the desktop’s.

In the snippets below, replace the --ledger / --upstream-config paths and the vigil-hub path (use the absolute .exe path on Windows, e.g. C:\\Vigil\\vigil-hub.exe).

Claude Code

Project .mcp.json (or user-level ~/.claude.jsonmcpServers):

{
  "mcpServers": {
    "vigil": {
      "command": "vigil-hub",
      "args": ["serve", "--stdio", "--ledger", "~/.local/share/Vigil/ledger.sqlite3", "--upstream-config", "./upstreams.json"]
    }
  }
}

Run /mcp in Claude Code — vigil should show connected, with your upstream tools under it.

Codex (OpenAI Codex CLI)

~/.codex/config.toml (or project .codex/config.toml):

[mcp_servers.vigil]
command = "vigil-hub"
args = ["serve", "--stdio", "--ledger", "~/.local/share/Vigil/ledger.sqlite3", "--upstream-config", "./upstreams.json"]

Cursor

~/.cursor/mcp.json (or project .cursor/mcp.json):

{ "mcpServers": { "vigil": { "command": "vigil-hub", "args": ["serve", "--stdio", "--upstream-config", "./upstreams.json"] } } }

Zed

~/.config/zed/settings.json:

{ "context_servers": { "vigil": { "command": { "path": "vigil-hub", "args": ["serve", "--stdio", "--upstream-config", "./upstreams.json"] } } } }

OpenCode

Project opencode.json:

{ "mcp": { "vigil": { "type": "local", "command": ["vigil-hub", "serve", "--stdio", "--upstream-config", "./upstreams.json"], "enabled": true } } }

Continue (VS Code / JetBrains)

~/.continue/config.yaml:

mcpServers:
  - name: vigil
    command: vigil-hub
    args: ["serve", "--stdio", "--upstream-config", "./upstreams.json"]

Step 4 — Verify it’s actually gating

After your agent runs a tool call (or trigger one yourself), inspect the local ledger. inspect prints single-line JSON — pipe to jq:

vigil-hub inspect --db-path ./vigil.db protection            # at-a-glance: secrets blocked, leaks redacted, chain intact
vigil-hub inspect --db-path ./vigil.db activity --limit 20   # recent events / decisions
vigil-hub inspect --db-path ./vigil.db search "read_file"     # full-text search the trail
vigil-hub inspect --db-path ./vigil.db approvals list         # risky calls awaiting you
vigil-hub inspect --db-path ./vigil.db verify-chain           # tamper-evident chain check
# → {"kind":"ChainVerification","data":{"ok":true,"broken_at_event_id":null,"message":null}}

Or open the Vigils desktop app for a live view: Activity Feed, Approval Queue (approve / deny), Server Registry, Session Replay, and Privacy Findings.

What “gating” looks like: with the default firewall (deny-by-default), a risky tool call is either denied outright or surfaced in the Approval Queue — your agent’s call blocks until you approve. The decision is recorded in activity.

Optional — turn on the ML privacy filter

By default Vigils uses fast hard-fingerprint rules (no ML). To add the ONNX PII scanner, build the CLI with the ort feature and pass --enable-privacy-filter:

cargo install --path apps/vigil-hub-cli --features ort
vigil-hub serve --stdio --upstream-config ./upstreams.json --enable-privacy-filter

If the flag is set but the binary wasn’t built with --features ort, startup fails closed (it never silently runs without the filter you asked for).

Troubleshooting

  • command not found / agent can’t start vigil-hub — use the absolute path to vigil-hub (vigil-hub.exe on Windows) in the config; verify with vigil-hub --version.
  • Agent connects but no tools — you haven’t passed --upstream-config, or the file lists no upstreams. Add your upstreams.json.
  • An upstream fails to start — make sure its argv runs standalone and that npx/node (or whatever it needs) is on PATH.
  • Desktop app doesn’t show events — point --ledger at the same path the desktop app uses (Step 3), writable by the agent’s child process.
  • Garbled bytes in the agent log — nothing but JSON-RPC may go to stdout; vigil-hub keeps all banners on stderr.

References

Architecture Overview

Vigils is a 5-layer control plane (T0 → T4):

T4 — Desktop UI / Browser Extension / CLI
T3 — MCP Hub (server registry, descriptor pinning)
T2 — Action Firewall + Approval Queue + Policy + Audit Ledger
T1 — Privacy Filter + Sandbox Runner (Wasm + native)
T0 — Types + Schemas (vigil-types)

Crate layout

SDK boundary (publishable, 10 crates)

LayerCrate
T0vigil-types
T0vigil-redaction (hard rules + optional ORT)
T0vigil-runner-types
T2vigil-policy / vigil-audit / vigil-lease / vigil-firewall
T3vigil-ui-protocol / vigil-mcp
vigil-sdk (facade)

Internal (not published)

  • vigil-runner concrete (wasmtime + sandbox-linux + vigil-redaction deps)
  • vigil-sandbox-linux (Linux-only, target-gated)
  • vigil-http-auth / vigil-http-transport / vigil-browser
  • apps/desktop / apps/native-host / apps/vigil-hub-cli

Key invariants

  • Fail-closed errors → DENY
  • No-plaintext audit
  • DecisionRecord mandatory
  • inherit_env=false (native) + fuel/epoch dual limit (Wasm) + Landlock (Linux)
  • preopen allowlist only / per-run independent engine

See the ADR Index for the design rationale behind each layer.

Data flow (typical action)

1. AI agent → MCP request → vigil-hub stdio
2. vigil-hub::descriptor_lookup → drift check
3. vigil-firewall::evaluate → policy + scope + PII
4. (if approval needed) → ApprovalBroker → Desktop UI
5. (on approve) vigil-runner::spawn_native/wasm → sandbox
6. vigil-audit::append → SQLite ledger
7. result → AI agent

Every step is fail-closed: any error → DENY plus a ledger event.

Action Firewall

vigil-firewall::Firewall::evaluate(invocation, decision) → FirewallOutcome

A fail-closed effect-gating API with three outcomes:

  • Allow — policy, privacy, and scope checks all pass.
  • ApprovalRequired — a risky effect is queued for a human.
  • Deny — policy block, PII detected, or scope outside the allowlist.

Policy DSL

OAuth scope allowlists are enforced at the firewall layer (see ADR 0011): a request whose granted scopes fall outside the configured allowlist is denied by default.

PII scanner integration

Two layers of defense — hard fingerprint rules plus an optional ONNX ensemble. See Privacy Filter and ADR 0013.

Audit Ledger

vigil-audit — an append-only ledger protected by a SHA-256 hash chain:

event_n.hash = sha256(event_{n-1}.hash || serde_jcs(event_n) || timestamp_n)

serde_jcs (RFC 8785 canonical JSON) keeps the hash consistent across implementations.

Since the 2026-06 security audit the chain digest is versioned (v2) and additionally binds session_id, event_type, and redacted_text, so a local actor with database write access can no longer rewrite those columns undetected. Historical v1 events stay verifiable, and verify_chain enforces version monotonicity (a v2→v1 downgrade is rejected). See the ADR Index and the security advisory.

Storage

SQLite (WAL) + FTS5. Schema: vigil-audit/migrations/.

Invariants

  • Append-only (no UPDATE / DELETE).
  • No-plaintext (raw secrets are never stored).
  • SHA-256 chain (tamper-evident).
  • FTS5 search by event_type / session_id.

See ADR 0001 and ADR 0005.

Privacy Filter

vigil-redaction provides two layers of defense in depth.

Layer 1 — Hard fingerprints

Fixed-prefix and structured-credential rules with 100% precision, zero ML dependency, and instant startup:

KindPattern
github_tokenghp_ / gho_ / ghu_ / ghs_ / ghr_ + 36
slack_webhookhooks.slack.com/services/T...
stripe_secretsk_live_ / sk_test_
google_api_keyAIza + 35
gitlab_patglpat- + 20
aws_access_keyAKIA + 16 uppercase
database_url<scheme>://user:password@host/db
private_keyPEM block
13 kinds total

Layer 2 — ONNX ensemble (opt-in, --features ort)

A 3-engine ensemble (OpenAI Privacy Filter + xlmr-pii-v1 for multilingual text + yonigo-pii-v1) for natural-language PII. Typical latency: cold ~11 s, warm p95 ~419 ms.

A per-(language, label) threshold profile calibrates recall vs. false positives — for example tightening zh.account_number cut a noisy false-positive cluster while improving F1.

The two layers merge fail-closed (hard fingerprints win on overlap). See ADR 0013.

MCP Hub

vigil-mcp — a Model Context Protocol hub that sits in front of your tool servers.

  • Server registry — stdio servers and HTTP servers (OAuth / JWT; see ADR 0011).
  • Descriptor pinning — a SHA-256 of each server’s tool list + schemas, used for drift detection. A changed descriptor is treated as first-seen (approval-required), never auto-trusted.
  • Outbox — an append-only outbox table for reliable delivery.
  • Approval-queue integration — the embedded Hub shares cross-process SQLite persistence with the Approval Queue (see ADR 0014).

See ADR 0004, 0005, 0011, and 0014.

Approval Queue

Human-in-the-loop gating for risky effects (driven by FirewallOutcome::ApprovalRequired):

firewall::evaluate → ApprovalRequired(req)
  → ApprovalBroker (SQLite, persistent)
  → Desktop UI "Approval Queue" tab
  → user: Approve / Reject / Delegate / Defer
  → ledger event
  → vigil-runner spawn (only if approved)

ApprovalScope

Each request carries a scope (see ADR 0014):

  • server_id + tool_name
  • effect_kind (read / write / network / …)
  • resource_path
  • duration (once / session / forever)

Delegate hands the decision to a super-user or batch-approval flow.

See ADR 0003 and ADR 0014.

vigil-sdk Reference

crates.io docs.rs

A stable public facade that re-exports the vigil-types, vigil-firewall, vigil-redaction, and vigil-mcp surfaces.

Public surface

#![allow(unused)]
fn main() {
use vigil_sdk::prelude::*;

// vigil-types
pub use vigil_types::{DecisionRecord, AuditEvent, EffectVector,
    ApprovalRequest, ApprovalResolution, ApprovalScope, ApprovalStatus,
    ToolInvocation, EffectKind, DecisionKind};

// vigil-firewall
pub use vigil_firewall::{Firewall, FirewallConfig, FirewallError, FirewallOutcome,
    EngineStatusReport, PiiScanner, OAuthScopeContext};

// vigil-redaction
pub use vigil_redaction::{scan_text, RedactionResult, Finding, FindingKind, FindingSource};

// vigil-mcp
pub use vigil_mcp::descriptor_hash;
}

Out of scope (not exported)

  • Server runtime (Hub / oracle internals).
  • Backend implementations (NoopEngine / MockEngine / OrtEngine).
  • Ops infrastructure (bootstrap / model distribution).
  • The concrete vigil-runner (WasmRunner / spawn_native).

See Invariants and docs.rs/vigil-sdk.

SDK Invariants

The SDK boundary is defined by ADR 0015. Consumers can rely on these guarantees.

1. Fail-closed

#![allow(unused)]
fn main() {
match firewall.evaluate(..) {
    Ok(FirewallOutcome::Allow) => proceed(),
    Ok(_) => other_handling(),
    Err(e) => return Err(e),  // NEVER default to allow
}
}

2. No-plaintext audit

Raw text passed to the SDK is never persisted. Audit records go through DecisionRecord / AuditEvent (a hash plus a redacted body).

3. DecisionRecord mandatory

Every effect must first produce a DecisionRecord. No SDK API lets a consumer skip it.

4. API stability

  • 0.x: additive improvements are allowed (each behind review + an ADR).
  • After v1.0: additive only — no removals, no signature changes.
  • Adding a variant/field to a #[non_exhaustive] enum/struct is not a breaking change.

5. Reviewed surface changes

Every change to the SDK’s public surface is reviewed before release.

SDK Feature Flags

ort (default: off)

vigil-sdk = { version = "0.1", features = ["ort"] }

Enabled:

  • The ort crate + ONNX Runtime 1.24.4 (dynamic library).
  • A 3-engine ensemble (OpenAI Privacy Filter + xlmr-pii-v1 + yonigo-pii-v1).
  • An 8-class PrivacyLabel.

Disabled (default):

  • 13 hard fingerprint rules.
  • A NoopEngine placeholder.
  • No ONNX dependency; sub-second startup.

Choosing

ScenarioFeature
CLI tool wrapperdefault — hard rules cover the vast majority of leaks, instant
Long-running agentort — higher recall (~11 s cold + ~419 ms warm)
Browser extensiondefault — size- and cold-start-sensitive

Runtime environment (with ort)

export ORT_DYLIB_PATH=/path/to/onnxruntime-<platform>-1.24.4/lib/libonnxruntime.so.1.24.4
export VIGIL_PRIVACY_FILTER_MODEL_DIR=/path/to/models/openai-pf/v1

See ADR 0012, 0016, and 0017.

Auto-Update

Installed desktop apps update over the Tauri auto-updater, using Ed25519 (minisign) signatures.

Flow

client startup
  → Tauri updater plugin polls
    https://vigils.ai/desktop-updates/<target>-<arch>/<current_version>.json
  → server returns { version, url, signature, ... }
  → client compares server.version > local.version
  → downloads the bundle and verifies its .sig against the embedded public key
  → restarts on the new version

The update endpoint and signing key are operated by the project; release bundles are signed in CI.

Building a signed bundle

export TAURI_SIGNING_PRIVATE_KEY="$(cat <your-updater-key>)"
cargo tauri build --features gui --config '{"bundle":{"createUpdaterArtifacts":true}}'
# produces the platform bundle plus a matching .sig

For the full pipeline (CI signing → manifest generation → endpoint sync), see docs/ota-pipeline.md.

Multi-Platform Build

Three platforms; seven installer/bundle artifacts.

Linux

sudo apt install libwebkit2gtk-4.1-dev libsoup-3.0-dev libgtk-3-dev
cd apps/desktop
cargo tauri build --features gui --bundles deb,rpm,appimage

macOS

export CI=true  # skips the AppleScript Finder styling that needs a GUI session
cd apps/desktop
cargo tauri build --features gui --bundles app,dmg
# app target = updater artifact (.app.tar.gz + .sig)
# dmg target = user-facing installer

Windows

cd apps/desktop
cargo tauri build --features gui --bundles msi,nsis

Binary layout

apps/desktop/Cargo.toml declares a single binary — [[bin]] name = "vigils" path = "src/bin/vigils.rs" — aligned with the Tauri v2 bundle default (the bin name matches the path basename and mainBinaryName). The installed executable is vigils / vigils.exe (since v0.1.5; earlier builds shipped gui).

Architecture Decision Records

Every significant design decision is recorded as an ADR under docs/adr/. Each ADR and its implementation were reviewed before merge.

#Title
0001Action control plane
0002Audit ledger + hash chain (revised: v2)
0003Firewall + approval queue
0004MCP hub + outbox
0005Descriptor pinning + drift
0006Secret lease broker
0007Sandbox runner (Wasm + native + Landlock)
0008Desktop UI protocol
0009Browser extension + native host
0010HTTP MCP auth
0011HTTP transport + JWKS
0012Model distribution
0013Hard × model merge
0014Tauri-embedded Hub
0015SDK boundary
0016Performance gate
0017Model descriptor design
0018vigil-runner-types split
0019Audit advisories policy

Changelog & Releases

Vigils ships from a single public version line (0.1.x).

Recent highlights

VersionTheme
v0.1.7Security hardening — ports the first comprehensive audit’s fixes (hash-chain v2, descriptor-hash guard, …)
v0.1.6In-app branding consistency
v0.1.5Desktop binary renamed guivigils

The v0.1.7 audit summary is published as a security advisory.

验证你的下载

🌐 English: Verifying your download

Vigils 守在你的密钥前面,所以你不该仅凭我们一句话就相信某个下载是正版。每一个发布产物 都是可独立验证的。本页说明怎么验证——并诚实交代每种方法能证明什么、不能证明什么

速览

# 最强校验:证明该文件由「本仓库」的 CI 从「本仓库」的源码构建。
# 适用于全部产物——CLI 压缩包、桌面安装包、扩展 zip。
gh attestation verify <下载的文件> --repo duncatzat/vigils

输出 ✓ 且源仓库 / workflow 匹配,即说明二进制是正版;严格来说无需更多步骤。下面各节是 互补校验,并解释当前为何还没有操作系统级代码签名。

1. 构建溯源(Build provenance)——推荐,覆盖全部产物

每个可下载产物都附带一份 SLSA 构建溯源证明,由 GitHub 背后的 Sigstore 基础设施签发(你无需自管密钥,除 GitHub 与公开源码外无需信任其他方):

  • CLI 压缩包——vigils-cli-linux-x64.tar.gzvigils-cli-macos-arm64.tar.gzvigils-cli-windows-x64.zip
  • 桌面安装包——.exe.msi.dmg.deb.rpm.AppImage
  • 浏览器扩展——vigils-chrome-extension.zip

GitHub CLI 验证:

gh attestation verify Vigils_0.1.7_amd64.deb --repo duncatzat/vigils

通过即证明该文件由「本仓库」的发布流水线、从某个具体 commit 构建——也就是说它没有被 掉包、没有被第三方重新构建、构建后也没有被篡改。这对「来源」的证明强于单纯的代码签名 证书,因为它把二进制绑定到了你可以亲自去读的那个公开源码 commit 和 CI 运行。

离线 / 隔离网环境?从 release 下载该产物的 attestation bundle,离线验证: gh attestation verify <文件> --bundle <bundle.jsonl> --repo duncatzat/vigils

2. 校验和(Checksum)——CLI 压缩包

每个 CLI 压缩包旁边都发布了 .sha256 文件。一行安装器会自动校验; 手动验证:

# macOS / Linux —— .sha256 内容格式为 "<hash>  <文件名>"
shasum -a 256 -c vigils-cli-linux-x64.tar.gz.sha256
# Windows —— 与 vigils-cli-windows-x64.zip.sha256 中发布的 hash 比对
(Get-FileHash -Algorithm SHA256 vigils-cli-windows-x64.zip).Hash

校验和只能证明你下到的字节和 release 发布的字节一致(用于发现截断 / 传输损坏),它 不是签名——认证真伪请用溯源(§1)。桌面安装包依赖溯源,不另发 .sha256

3. 安装脚本

一行安装命令是一个朴素、可读的 shell / PowerShell 脚本——运行前先读它。注意它会替你 校验压缩包的校验和:

curl -fsSL https://vigils.ai/install.sh          # 先读
curl -fsSL https://vigils.ai/install.sh | sh     # 再运行
irm https://vigils.ai/install.ps1                # 先读
irm https://vigils.ai/install.ps1 | iex          # 再运行

4. 关于「未签名应用」警告

Vigils 安装包尚未做操作系统级代码签名 / 公证——那需要 Apple 与 Windows CA 颁发的、 付费且经身份核验的证书,目前还没有到位。因此首次运行时系统会警告:

  • macOS——Gatekeeper 会拦截。先验证溯源(§1),再清除隔离标记: xattr -d com.apple.quarantine /Applications/Vigils.app
  • Windows——SmartScreen 会提示。先验证溯源(§1),再点 More info → Run anyway

在代码签名落地之前,构建溯源就是验证路径——而对「证明二进制确实来自这份开源代码」 而言,它本就是更强的保证。

5. 自动更新是签名的

安装后,桌面应用的自动更新器只接受携带项目 minisign 密钥有效签名的更新(每个 release 里的 .sig 文件),因此更新通道无需你任何操作即端到端可信。见 自动更新

Agent 接入与测试指南

🌐 English: Agent Integration & Test Guide

Vigils 插在你的 AI agent 与它调用的工具之间,让 agent 的每一次工具调用都经过 防火墙(默认拒绝)、审计(防篡改哈希链)、脱敏(密钥 / PII),高危调用还会进入 人工审批。全部本地运行,数据不外传。

支持任何兼容 MCP 的 agent:Claude CodeCodexCursorZed、OpenCode、Continue 等。

工作原理

Vigils 作为 MCP 网关运行:你的 agent 通过 stdio 连接 vigil-hub,由 vigil-hub 代理你真正的 MCP 工具服务器(“upstream”),对每次调用进行管控。

┌──────────────────┐   stdio JSON-RPC   ┌────────────────────┐      ┌──────────────────┐
│  你的 agent      │◄──────────────────►│  vigil-hub serve   │─────►│ 上游 MCP server   │
│  Claude Code /   │                    │   --stdio          │      │ (filesystem、    │
│  Codex / Cursor /│                    │  ┌──────────────┐  │      │  github、db…)     │
│  Zed / ...       │                    │  │ 防火墙        │  │      └──────────────────┘
└──────────────────┘                    │  │ 审计账本      │  │
                                        │  │ 脱敏          │  │
                                        │  │ 审批          │  │
                                        │  └──────────────┘  │
                                        └────────────────────┘

每个 upstream 的工具会用 __(双下划线)分隔符做命名空间化 —— <server>__<tool>,例如 fs__read_filegithub__create_issue —— 聚合进 agent 看到的 tools/list。agent 调用某个工具时,Vigils 会在转发之前用防火墙评估它、在审计账本记一条决策, 然后放行、拒绝、或排进审批队列等你确认。

前置条件

安装 CLI 网关 vigil-hub

  • 预编译:从最新 release 下载 vigils-cli-<target>.tar.gz(Windows 为 .zip),内含 vigil-hubvigil-native-host。把 vigil-hub 放进 PATH
  • 从源码cargo install --path apps/vigil-hub-cli

验证:vigil-hub --help

最快路径 —— Claude Code,一条命令(setup --all

如果你用 Claude Code,完全不必手写配置。一条命令检测你的环境并全面保护 —— 既有配置会被备份,只新增 Vigils 自己的条目(完全可逆):

vigil-hub setup --all

setup --all 同时接入两层:

  1. 原生工具输入侧守门 —— PreToolUse hook,于是每次工具调用(Bash、Edit、Write、Read、MCP 工具……)执行前都先被检查:真实凭据流工具会被 fail-closed 拦截并审计。
  2. MCP 网关 —— 把你每个 stdio MCP server 改写为经 Vigils 路由,工具结果里的 secret 在模型看到 之前被脱敏,每次调用都被审计。默认 monitor 姿态(你的 server 保持可用;裸 secret 拦截、结果脱敏、 审计照常)。加 --enforce 升级 default-deny 硬拦。
vigil-hub setup --mcp --doctor    # 接入前预检:每个被包裹的 MCP server 真能启动吗?(只读 PATH 检查)
vigil-hub inspect protection      # 用过 agent 后:Vigils 拦了什么(裸 secret 拦截、泄漏脱敏、链完整)
vigil-hub setup --all --uninstall # 移除全部(配置逐字节还原)

重启 Claude Code 即受保护。本指南余下部分是手动路径 —— 用于非 Claude agent(Codex / Cursor / Zed / …)或你想显式控制 serve 网关及其 upstreams.json 时。

第 1 步 —— 冒烟测试 vigil-hub(30 秒,不用 agent)

接任何 agent 之前,先确认网关能说 MCP。给它喂一个 initialize + tools/list(MCP stdio 是逐行 JSON-RPC):

printf '%s\n' \
 '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"smoke","version":"0"}}}' \
 '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
 | vigil-hub serve --stdio --ledger ./vigil.db

预期 stdout(两条 JSON-RPC 响应):

{"id":1,"jsonrpc":"2.0","result":{"capabilities":{"tools":{"listChanged":false}},"protocolVersion":"2025-06-18","serverInfo":{"name":"vigil-hub","version":"0.1.7"}}}
{"id":2,"jsonrpc":"2.0","result":{"tools":[]}}

tools/list 为空是因为还没配 upstream(下一步配)。启动提示走 stderr(stdout 留给协议)。

第 2 步 —— 声明你的工具服务器(upstreams.json

列出你要 Vigils 代理的 MCP server。裸命令会自动经 PATH 解析。

{
  "upstreams": [
    { "name": "fs",     "argv": ["npx", "-y", "@modelcontextprotocol/server-filesystem", "/data"] },
    { "name": "github", "argv": ["npx", "-y", "@modelcontextprotocol/server-github"] }
  ]
}

传给 serve

vigil-hub serve --stdio --ledger ./vigil.db --upstream-config ./upstreams.json

对每个条目,Vigils 会注册该 server、固定其启动命令,并在启动子进程之前做一次 gate-before-spawn 校验(argv + resolved-program 双 drift),然后把它的工具命名空间化 (fs__…github__…)聚合进 tools/list

HTTP / 远程 MCP server 改走 OAuth onboarding: vigil-hub add-remote-mcp --url https://mcp.example.com/ --client-id <id> --scopes mcp:tools.read

第 3 步 —— 把 agent 指向 vigil-hub

同一个 ledger 路径,让桌面应用和 CLI 看到同一份审计。桌面应用读 data_local_dir()/Vigil/ledger.sqlite3

  • Windows:%LOCALAPPDATA%\Vigil\ledger.sqlite3
  • Linux:~/.local/share/Vigil/ledger.sqlite3
  • macOS:~/Library/Application Support/Vigil/ledger.sqlite3

文件名必须恰好是 ledger.sqlite3(带 3)、目录是 data_local_dir() —— 路径不一致桌面就读到 另一个文件,Activity Feed 一直空。最省心:跑 vigil-hub setup --mcp / setup --all,自动指向这个 共享账本。手动 serve --stdio 切勿省略 --ledger —— 省略 = 内存账本,桌面看不到。serve/wrap 启动时会打印解析后的账本路径,可与桌面读的路径比对。

下面的片段里,替换 --ledger / --upstream-config 路径和 vigil-hub 路径(Windows 用绝对 .exe 路径,如 C:\\Vigil\\vigil-hub.exe)。

Claude Code

项目根 .mcp.json(或用户级 ~/.claude.jsonmcpServers):

{
  "mcpServers": {
    "vigil": {
      "command": "vigil-hub",
      "args": ["serve", "--stdio", "--ledger", "~/.local/share/Vigil/ledger.sqlite3", "--upstream-config", "./upstreams.json"]
    }
  }
}

在 Claude Code 里运行 /mcp —— vigil 应显示已连接,其下挂着你的 upstream 工具。

Codex(OpenAI Codex CLI)

~/.codex/config.toml(或项目级 .codex/config.toml):

[mcp_servers.vigil]
command = "vigil-hub"
args = ["serve", "--stdio", "--ledger", "~/.local/share/Vigil/ledger.sqlite3", "--upstream-config", "./upstreams.json"]

Cursor

~/.cursor/mcp.json(或项目级 .cursor/mcp.json):

{ "mcpServers": { "vigil": { "command": "vigil-hub", "args": ["serve", "--stdio", "--upstream-config", "./upstreams.json"] } } }

Zed

~/.config/zed/settings.json

{ "context_servers": { "vigil": { "command": { "path": "vigil-hub", "args": ["serve", "--stdio", "--upstream-config", "./upstreams.json"] } } } }

OpenCode

项目根 opencode.json

{ "mcp": { "vigil": { "type": "local", "command": ["vigil-hub", "serve", "--stdio", "--upstream-config", "./upstreams.json"], "enabled": true } } }

Continue(VS Code / JetBrains)

~/.continue/config.yaml

mcpServers:
  - name: vigil
    command: vigil-hub
    args: ["serve", "--stdio", "--upstream-config", "./upstreams.json"]

第 4 步 —— 验证它真的在管控

等 agent 跑一次工具调用(或你自己触发一次)后,查本地账本。inspect 输出单行 JSON,可接 jq

vigil-hub inspect --db-path ./vigil.db protection            # 一眼看清:裸 secret 拦截、泄漏脱敏、链完整
vigil-hub inspect --db-path ./vigil.db activity --limit 20   # 最近事件 / 决策
vigil-hub inspect --db-path ./vigil.db search "read_file"     # 全文搜索审计链
vigil-hub inspect --db-path ./vigil.db approvals list         # 待你处理的高危调用
vigil-hub inspect --db-path ./vigil.db verify-chain           # 防篡改链校验
# → {"kind":"ChainVerification","data":{"ok":true,"broken_at_event_id":null,"message":null}}

或打开 Vigils 桌面应用实时看:Activity FeedApproval Queue(批准 / 拒绝)、 Server RegistrySession ReplayPrivacy Findings

“管控“长什么样:默认防火墙是 deny-by-default,一次高危工具调用要么被直接拒绝,要么进 Approval Queue —— 在你批准之前,agent 的这次调用一直阻塞。决策会记进 activity

可选 —— 开启 ML 隐私过滤

Vigils 默认用快速硬指纹规则(无 ML)。要加 ONNX PII 扫描器,用 ort feature 编译 CLI 并传 --enable-privacy-filter

cargo install --path apps/vigil-hub-cli --features ort
vigil-hub serve --stdio --upstream-config ./upstreams.json --enable-privacy-filter

如果传了 flag 但二进制没用 --features ort 编译,启动会 fail-closed(绝不静默地在你以为开了过滤 的情况下不开就跑)。

故障排查

  • command not found / agent 起不了 vigil-hub —— 配置里用 vigil-hub 的绝对路径(Windows 为 vigil-hub.exe);vigil-hub --version 验证可执行。
  • 连上了但没工具 —— 你没传 --upstream-config,或文件里没列 upstream。补上 upstreams.json
  • 某个 upstream 起不来 —— 确认它的 argv 能独立跑,且 npx/node(或它需要的东西)在 PATH
  • 桌面应用不显示事件 —— 把 --ledger 指向桌面应用用的同一路径(第 3 步),且 agent 子进程可写。
  • agent 日志里有乱字节 —— stdout 只能有 JSON-RPC;vigil-hub 所有 banner 都走 stderr。

参考