Content
# Sentinel
**A fully local verification layer for AI coding agents.** Sentinel plugs into any MCP-compatible agent (Claude Code, Cursor, Copilot, OpenCode, …) and lets it self-check its own work — does the diff actually do the task, does the code it references exist, did it leak a secret, does it match your codebase's style — before a human ever sees it. Everything runs on your machine: no cloud backend, no telemetry, no account.
[](LICENSE)
## Quickstart
```bash
# Requires Node.js 24+ (Sentinel uses Node's built-in SQLite — nothing to compile)
npm install -g sentinel-verify
cd your-project
sentinel init # creates the local .sentinel/ data folder
# Connect your agent — one command, no config editing:
sentinel connect claude-code # or: cursor, antigravity
```
That's it. Your agent now has four verification tools it can call after making changes. In agent mode Sentinel needs **no API key and no local model** — see the two modes below.
## Connecting an agent
**Recommended: `sentinel connect <agent>`** — run it from your project's root directory and it writes the correct MCP entry (absolute paths, project root pinned via `SENTINEL_PROJECT_ROOT`) into that agent's config, merging safely with any MCP servers already configured there. Malformed config files are never touched — you get an error instead.
| Agent | Command | Config it writes |
|---|---|---|
| Claude Code | `sentinel connect claude-code` | `<project>/.mcp.json` |
| Cursor | `sentinel connect cursor` | `<project>/.cursor/mcp.json` |
| Antigravity | `sentinel connect antigravity` | `~/.gemini/antigravity/mcp_config.json` (global — pinned to the project you ran it from) |
`sentinel connect --list` shows this table in the terminal. After connecting, restart/reload the agent so it picks up the new server. Re-run `connect` any time (e.g. after updating Node or Sentinel) — it refreshes the entry in place. Supporting a new agent is one entry in the `AGENTS` table in `src/cli/commands/connect.ts` — PRs welcome.
<details>
<summary><strong>Manual setup (fallback for agents not listed above)</strong></summary>
Any MCP client works — configure it to launch `sentinel mcp` as a stdio server. For clients configured via JSON:
```json
{
"mcpServers": {
"sentinel": {
"command": "sentinel",
"args": ["mcp"],
"env": { "SENTINEL_PROJECT_ROOT": "/absolute/path/to/your-project" }
}
}
}
```
If the agent launches servers without your shell's PATH, use the absolute path to the `sentinel` binary (find it with `which sentinel`) or `node /path/to/dist/cli/index.js` as the command. Claude Code users can equivalently run `claude mcp add sentinel -e SENTINEL_PROJECT_ROOT="$(pwd)" -- sentinel mcp`.
</details>
**How Sentinel finds your project:** some MCP clients launch servers from an unexpected working directory (even `/`), so Sentinel resolves the project root defensively, in this order: the `SENTINEL_PROJECT_ROOT` environment variable → a plausible launch directory → the workspace roots your MCP client declares (the protocol's `roots` capability). If none of those work, tool calls fail with a clear message instead of writing anywhere wrong. `sentinel connect` sets the env var for you, which is why it's the recommended path.
Optional extras:
```bash
sentinel install-hook # block bad commits at git pre-commit time
sentinel dashboard # local-only web UI over your verification history
```
## The four checks
| Tool | Question it answers |
|---|---|
| `verify_task_match` | Does the diff **functionally** accomplish the stated task — not just superficially? |
| `check_hallucination` | Do the packages, files, and symbols the diff references actually **exist**? (verified against `package.json`, `node_modules`, and the real filesystem) |
| `check_security` | Any leaked secrets (AWS/GitHub/Slack/Stripe/… keys, private keys, connection strings — detected and **masked**), `eval`, shell injection, disabled TLS, hardcoded credentials? |
| `check_style_consistency` | Does the diff write code the way **this** project already does? (indentation, quotes, semicolons, naming, module style — measured from your real files) |
Every check combines **deterministic evidence** (filesystem checks, pattern rules, style measurement — authoritative) with **model judgment** (for what rules can't prove). Every result is stored locally in `.sentinel/sentinel.db`.
## Two modes, one important idea
**Agent mode (MCP)** — when an AI agent calls Sentinel's tools, Sentinel does **not** run a model of its own. The calling agent is already a powerful, already-paid-for model; a second, weaker judge adds cost and noise. Instead each tool returns structured **evidence** — the deterministic findings, the measured style profile, your project rules — plus an instruction telling the agent how to judge. Requires nothing: no key, no Ollama.
**Standalone mode (CLI)** — running checks yourself in a terminal, there's no agent to judge, so Sentinel uses its own model layer: **free local Ollama by default** (recommended model: `ollama pull qwen2.5-coder`), or your own Anthropic API key if you set one.
```bash
git diff | sentinel test-security # standalone check, judged locally
git diff | sentinel test-hallucination
git diff | sentinel test-style
sentinel test-verify --task "Add rate limiting" --diff-file change.diff
```
All `test-*` commands exit non-zero on findings, so they compose into scripts.
| | Agent mode (MCP) | Standalone mode (CLI) |
|---|---|---|
| Who judges | The calling agent | Sentinel's configured model |
| Requirements | Nothing | Ollama running, **or** `ANTHROPIC_API_KEY` |
| Result | Evidence + judgment instruction | Final verdict (exit code) |
Standalone settings: `SENTINEL_PROVIDER` (`ollama`/`anthropic`; default auto — Anthropic if a key is set, else Ollama), `SENTINEL_MODEL` (model override), `OLLAMA_HOST`, `ANTHROPIC_API_KEY` (env or a git-ignored `.env` in your project root).
## The pre-commit hook
```bash
sentinel install-hook # sentinel uninstall-hook to remove
```
Every `git commit` checks the **staged** diff — `check_security` by default. Findings block the commit with a printed summary; bypass one commit with `git commit --no-verify`. **Fail-closed:** if the model layer is unavailable the commit is blocked with setup instructions — a broken setup never silently waves commits through. Install refuses to overwrite a hook Sentinel didn't create, and uninstall refuses to delete one.
## The local dashboard
```bash
sentinel dashboard # http://127.0.0.1:4747 (--port to change)
```
Totals, per-tool flag rates, and full history with click-to-expand details, served from one self-contained page bound to `127.0.0.1` — no external assets, no analytics. Secrets are masked before storage, so the dashboard can never display one.
## Configuration: `.sentinelrc` (optional)
Zero config is the default. An optional `.sentinelrc` (JSON, strictly validated — typos fail loudly) in your project root adds team standards:
```json
{
"context": "React + TypeScript SPA using GSAP for animations. Modern browsers only.",
"style": { "indent": 2, "quotes": "single", "semicolons": "always", "naming": "camelCase", "moduleStyle": "esm" },
"tools": { "check_style_consistency": false },
"rules": [
"Never suggest React class components — function components and hooks only.",
"No new npm dependencies without discussion."
],
"hook": { "tools": ["check_security", "check_hallucination"] }
}
```
| Field | Effect |
|---|---|
| `context` | Free-text project description fed to all model prompts (max 2000 chars). |
| `style` | Convention overrides that **replace** inference — enforced even in brand-new projects. `indent` is `"tabs"` or a number of spaces. |
| `tools` | Disable any tool: it leaves the MCP server and its CLI command prints a skip notice. |
| `rules` | Plain-language policies (max 20 × 500 chars) the model layer flags violations of. Short and concrete works best. |
| `hook.tools` | What the pre-commit hook runs (default `["check_security"]`; `verify_task_match` can't run in a hook). |
## Show you're covered
Integrated Sentinel in your project? Add the badge to your README:
```markdown
[](https://www.npmjs.com/package/sentinel-verify)
```
[](https://www.npmjs.com/package/sentinel-verify)
## Design principles
- **100% local** — no Sentinel-owned backend, no telemetry; nothing leaves your machine except your own optional API calls to your own provider.
- **Free by default** — agent mode needs no model at all; standalone mode runs on local Ollama.
- **Deterministic first** — filesystem checks, pattern rules, and measurements are authoritative; model judgment fills the gaps and never overrides them.
- **Agent-agnostic** — plain MCP; not locked to any vendor.
## Language coverage
The deterministic halves of `check_hallucination` and `check_style_consistency` cover JavaScript/TypeScript; `check_security`'s rules cover Node, Python, Go, and shell patterns. Other languages get the model-judgment half of every tool.
## Contributing
Issues and PRs welcome. The codebase is deliberately small and readable: `src/verify/` holds the four tools plus shared diff/combine logic, `src/providers/` the model layer (Ollama, Anthropic — an OpenAI provider is a welcome contribution), `src/mcp/` the server, `src/cli/` the commands, `src/dashboard/` the UI. Keep dependencies minimal (currently three), keep secrets masked, and keep everything local. Licensed MIT.