@oni.bot/sentinel
npm install @oni.bot/sentinelRequires Node.js 18+ and an @oni.bot/core-compatible model adapter.
import { Sentinel } from "@oni.bot/sentinel";
import { anthropic } from "@oni.bot/core/models";
const sentinel = new Sentinel({
model: anthropic("claude-sonnet-4-6"),
fastModel: anthropic("claude-haiku-4-5"),
rootDir: process.cwd(),
});
// Scan changed files
const report = await sentinel.scan({
files: ["src/auth.ts", "src/payments.ts"],
});
console.log(report.summary);
// { high: 2, medium: 5, low: 8, filesScanned: 2 }
for (const finding of report.findings) {
console.log(`[${finding.severity}] ${finding.file}: ${finding.message}`);
}Sentinel is a multi-stage analysis pipeline:
1. Triage — Static analyzers score each file for risk before any LLM calls. Files are ranked and bucketed into tiers (critical / high / medium / low) so LLM budget is focused where it matters most.
2. Swarm review — A specialist agent swarm reviews the high-risk files. Topology (fan-out, pipeline, or debate) is selected automatically based on file count and complexity.
3. Debate verification — Findings from the swarm go through a structured multi-agent debate to reduce false positives and sharpen severity ratings.
4. Fix suggestions — Optional auto-fix mode generates targeted patches for flagged issues.
5. Reporting — Results emitted as console output, GitHub PR annotations, or SARIF (compatible with GitHub Code Scanning, VS Code, and most CI platforms).
Static analysis runs before any model calls — fast and zero-cost:
| Analyzer | What it catches |
|---|---|
| Security | Hardcoded secrets, injection patterns, unsafe eval, weak crypto |
| Complexity | Cyclomatic complexity, deeply nested logic, long functions |
| TypeScript | Unsafe any, missing types, unsafe assertions |
| Dependencies | Outdated packages, license issues, known vulnerability patterns |
| Diff | High churn, large deletions, rename detection |
| Pattern | Custom regex rules — bring your own |
const sentinel = new Sentinel({
model: anthropic("claude-sonnet-4-6"), // required — primary review model
fastModel: anthropic("claude-haiku-4-5"), // optional — triage / fast tasks
rootDir: process.cwd(), // project root for file resolution
config: "sentinel.jsonc", // optional config file path
});Scan a set of files for issues.
const report = await sentinel.scan({
files: string[], // file paths to analyze
maxFindings?: number, // cap total findings (default: 100)
});Review a pull request diff.
const report = await sentinel.reviewPR({
diff: string, // unified diff string
baseBranch?: string,
});import { CustomAnalyzer } from "@oni.bot/sentinel";
const myAnalyzer = new CustomAnalyzer({
name: "no-console",
patterns: [{ regex: /console\.(log|warn|error)/, severity: "low", message: "Remove console call" }],
});
const sentinel = new Sentinel({ model, analyzers: [myAnalyzer] });Create sentinel.jsonc in your project root:
- name: Sentinel Code Review
run: npx @oni.bot/sentinel --diff $(git diff origin/main...HEAD)
env:
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}- name: Sentinel Scan
run: npx @oni.bot/sentinel --sarif sentinel-results.sarif
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: sentinel-results.sarifPart of the ONI platform:
@oni.bot/core— graph execution engine and framework primitives@oni.bot/code— AI coding assistant CLI
MIT — AP3X Dev
{ // Which analyzers to enable (default: all) "analyzers": ["security", "complexity", "typescript"], // Risk thresholds for tier assignment "thresholds": { "critical": 90, "high": 70, "medium": 40 }, // Ignore patterns (glob) "ignore": ["**/node_modules/**", "**/*.test.ts"], // Output format: "console" | "github" | "sarif" "reporter": "console" }