Architecture Overview¶
High-Level Flow¶
flowchart TB
subgraph Cursor IDE
A[Developer Prompt] --> B[beforeSubmitPrompt]
B -->|allow| C[AI Agent]
B -->|block| D[Block Message]
C --> T[MCP Tool Call]
T --> U[beforeMCPExecution]
U -->|allow| V[Tool Execution]
U -->|block| W[Block Message]
V --> X[Tool Output]
X --> Y[postToolUse]
Y -->|violation| Z[Log + Warn]
C --> E[AI Response]
E --> G[Display Response]
G --> F[afterAgentResponse]
F -->|violation| H[Log + Warn]
F -->|clean| I2[No Action]
end
subgraph AIRS Hooks
B --> I[Config Loader]
I --> J[Scanner]
J --> K[AIRS Client]
K --> L[Circuit Breaker]
L --> M[Prisma AIRS API]
U --> I
Y --> I
F --> I
F --> N[Code Extractor]
N --> J
end
Cursor limitation
postToolUse and afterAgentResponse are observe-only. Cursor processes tool outputs and displays AI responses before these hooks fire — violations are logged and warnings emitted, but content cannot be blocked or retracted. See Cursor Limitation for details.
Module Map¶
| Module | Purpose |
|---|---|
src/config.ts |
Load and validate airs-config.json with env var resolution |
src/airs-client.ts |
SDK wrapper with circuit breaker integration |
src/scanner.ts |
Scan orchestration, DLP masking, UX block messages |
src/code-extractor.ts |
Extract code blocks from AI responses |
src/tool-name-parser.ts |
Parse MCP:server:tool format tool names |
src/content-limits.ts |
Configurable skip/truncate thresholds before scanning |
src/logger.ts |
Structured JSON Lines logging with rotation |
src/circuit-breaker.ts |
Failure tracking, cooldown bypass, automatic recovery |
src/dlp-masking.ts |
Per-service enforcement actions (block/mask/allow) |
src/log-rotation.ts |
Log file rotation at 10MB threshold |
src/types.ts |
TypeScript interfaces for config, Cursor API, AIRS |
src/hooks/before-submit-prompt.ts |
Cursor beforeSubmitPrompt entry point (can block) |
src/hooks/before-mcp-execution.ts |
Cursor beforeMCPExecution entry point (can block) |
src/hooks/post-tool-use.ts |
Cursor postToolUse entry point (observe-only) |
src/hooks/after-agent-response.ts |
Cursor afterAgentResponse entry point (observe-only) |
Request Lifecycle¶
Prompt Scan (beforeSubmitPrompt)¶
- Cursor pipes
{ prompt, user_email, ... }as JSON to stdin - Hook loads config, initializes logger
- Scanner sends prompt to AIRS via SDK (
promptcontent key) - Circuit breaker gates the request (bypass if open)
- AIRS returns verdict + detections
- If
enforcemode and verdict isblock: output{ "continue": false, "user_message": "..." } - If
observeor verdict isallow: output{ "continue": true }
MCP Tool Scan (beforeMCPExecution — can block)¶
- Cursor pipes
{ tool_name, tool_input, ... }as JSON to stdin - Hook loads config, initializes logger
- Content limits check: if input exceeds
max_scan_bytes, skip scan (fail-open) - Scanner sends tool input to AIRS via
tool_eventcontent key usingprofiles.tool - Circuit breaker gates the request (bypass if open)
- AIRS returns verdict + detections
- If
enforcemode and verdict isblock: output{ "continue": false, "user_message": "..." } - If
observeor verdict isallow: output{ "continue": true }
Tool Output Scan (postToolUse — observe-only)¶
- Cursor pipes
{ tool_name, tool_input, tool_output, ... }as JSON to stdin (after tool already executed) - Hook loads config, initializes logger, parses tool name
- Route by tool type:
MCP:*→ scan input+output astool_eventBash→ scan output asresponseWrite/Edit→ scan new content asprompt(DLP)- Skip list → no scan
- Content limits applied: truncate or skip oversized content
- If violation detected: log to audit trail + emit warning (cannot block — observe-only)
Response Scan (afterAgentResponse — observe-only)¶
- Cursor pipes
{ text, ... }as JSON to stdin (after the response is already displayed) - Hook loads config, initializes logger
- Code extractor splits response into natural language + code blocks
- Scanner sends both to AIRS (
response+code_responsecontent keys) code_responsetriggers WildFire/ATP malicious code detection- If violation detected: log to audit trail + emit warning (cannot block — observe-only)
- If clean: output
{ "permission": "allow" }
Build Modes¶
| Mode | Command | Hook Execution | Startup |
|---|---|---|---|
| Production | node dist/hooks/*.js |
Precompiled JS | ~800ms |
| Development | npx tsx src/hooks/*.ts |
JIT TypeScript | ~2.5s |
The install-hooks script points at compiled JS by default. See Contributing for the development workflow.