Creo applicazioni web moderne e strumenti digitali personalizzati per aiutare le attività a crescere attraverso l'innovazione tecnologica. La mia passione è unire informatica ed economia per generare valore reale.
La mia passione per l'informatica è nata tra i banchi dell'Istituto Tecnico Commerciale di Maglie, dove ho scoperto il potere della programmazione e il fascino di creare soluzioni digitali. Fin da subito, ho capito che l'informatica non era solo codice, ma uno strumento straordinario per trasformare idee in realtà.
Durante gli studi superiori in Sistemi Informativi Aziendali, ho iniziato a intrecciare informatica ed economia, comprendendo come la tecnologia possa essere il motore della crescita per qualsiasi attività. Questa visione mi ha accompagnato all'Università degli Studi di Bari, dove ho conseguito la Laurea in Informatica, approfondendo le mie competenze tecniche e la mia passione per lo sviluppo software.
Oggi metto questa esperienza al servizio di imprese, professionisti e startup, creando soluzioni digitali su misura che automatizzano processi, ottimizzano risorse e aprono nuove opportunità di business. Perché la vera innovazione inizia quando la tecnologia incontra le esigenze reali delle persone.
Le Mie Competenze
Analisi Dati & Modelli Previsionali
Trasformo i dati in insights strategici con analisi approfondite e modelli predittivi per decisioni informate
Automazione Processi
Creo strumenti personalizzati che automatizzano operazioni ripetitive e liberano tempo per attività a valore aggiunto
Sistemi Custom
Sviluppo sistemi software su misura, dalle integrazioni tra piattaforme alle dashboard personalizzate
Credo fermamente che l'informatica sia lo strumento più potente per trasformare le idee in realtà e migliorare la vita delle persone.
🚀
Democratizzare la Tecnologia
La mia missione è rendere l'informatica accessibile a tutti: dalle piccole imprese locali alle startup innovative, fino ai professionisti che vogliono digitalizzare la propria attività. Ogni realtà merita di sfruttare le potenzialità del digitale.
💡
Unire Informatica ed Economia
Non è solo questione di scrivere codice: è capire come la tecnologia possa generare valore reale. Intrecciando competenze informatiche e visione economica, aiuto le attività a crescere, ottimizzare processi e raggiungere nuovi traguardi di efficienza e redditività.
🎯
Creare Soluzioni su Misura
Ogni attività è unica, e così devono esserlo le soluzioni. Sviluppo strumenti personalizzati che rispondono alle esigenze specifiche di ciascun cliente, automatizzando processi ripetitivi e liberando tempo per ciò che conta davvero: far crescere il business.
Trasforma la Tua Attività con la Tecnologia
Che tu gestisca un negozio, uno studio professionale o un'azienda, posso aiutarti a sfruttare le potenzialità dell'informatica per lavorare meglio, più velocemente e in modo più intelligente.
Il mio percorso accademico e le tecnologie che padroneggio
Certificazioni Professionali
8 certificazioni conseguite
Nuovo
Visualizza
Reinvention With Agentic AI Learning Program
Anthropic
Dicembre 2024
Nuovo
Visualizza
Agentic AI Fluency
Anthropic
Dicembre 2024
Nuovo
Visualizza
AI Fluency for Students
Anthropic
Dicembre 2024
Nuovo
Visualizza
AI Fluency: Framework and Foundations
Anthropic
Dicembre 2024
Nuovo
Visualizza
Claude with the Anthropic API
Anthropic
Dicembre 2024
Visualizza
Master SQL
RoadMap.sh
Novembre 2024
Visualizza
Oracle Certified Foundations Associate
Oracle
Ottobre 2024
Visualizza
People Leadership Credential
Connect
Settembre 2024
💻 Linguaggi & Tecnologie
☕Java
🐍Python
📜JavaScript
🅰️Angular
⚛️React
🔷TypeScript
🗄️SQL
🐘PHP
🎨CSS/SCSS
🔧Node.js
🐳Docker
🌿Git
💼
12/2024 - Presente
Custom Software Engineering Analyst
Accenture
Bari, Puglia, Italia · Ibrida
Analisi e sviluppo di sistemi informatici attraverso l'utilizzo di Java e Quarkus in Health and Public Sector. Formazione continua su tecnologie moderne per la creazione di soluzioni software personalizzate ed efficienti e sugli agenti.
💼
06/2022 - 12/2024
Analista software e Back End Developer Associate Consultant
Links Management and Technology SpA
Esperienza nell'analisi di sistemi software as-is e flussi ETL utilizzando PowerCenter. Formazione completata su Spring Boot per lo sviluppo di applicazioni backend moderne e scalabili. Sviluppatore Backend specializzato in Spring Boot, con esperienza in progettazione di database, analisi, sviluppo e testing dei task assegnati.
💼
02/2021 - 10/2021
Programmatore software
Adesso.it (prima era WebScience srl)
Esperienza nell'analisi AS-IS e TO-BE, evoluzioni SEO ed evoluzioni website per migliorare le performance e l'engagement degli utenti.
🎓
2018 - 2025
Laurea in Informatica
Università degli Studi di Bari Aldo Moro
Bachelor's degree in Computer Science, focusing on software engineering, algorithms, and modern development practices.
📚
2013 - 2018
Diploma - Sistemi Informativi Aziendali
Istituto Tecnico Commerciale di Maglie
Technical diploma specializing in Business Information Systems, combining IT knowledge with business management.
Contattami
Hai un progetto in mente? Parliamone! Compila il form qui sotto e ti risponderò al più presto.
* Campi obbligatori. I tuoi dati saranno utilizzati solo per rispondere alla tua richiesta.
05 - Cursor Hooks: Automate Your Workflow with AI Guardrails
There is a fundamental tension in working with autonomous AI agents: you cannot monitor every single
action in real time, but you also cannot blindly trust what they do. An agent that writes code,
runs terminal commands, and modifies files in an automated sequence can be extraordinarily productive,
but also dangerously unpredictable without proper control mechanisms.
Cursor's answer to this problem is called Hooks. Introduced with Cursor 1.7 in
October 2025, the Hooks system lets you inject custom logic at precise points in the agent's lifecycle:
before it runs a shell command, after it modifies a file, before an MCP call, when it finishes its
work. They are, in essence, automated guardrails you configure once and that fire
every time the agent works in your codebase.
This article explores the Hooks system in depth: from basic configuration to advanced patterns for
auto-formatting, security validation, test automation, and documentation sync. By the end you will
know how to build a robust workflow where the AI agent is productive but always under your control.
What You Will Learn in This Article
What Cursor's Hooks system is and how it differs from simple shell scripts
Available hook types: beforeShellExecution, beforeMCPExecution, beforeReadFile, afterFileEdit, stop
How to configure global and project-level hooks with hooks.json
Building hooks that block dangerous actions using exit codes and JSON responses
Post-edit automation: auto-format with Prettier/ESLint via afterFileEdit
Stop hooks for final verification and task-completion notifications
Practical patterns: security auditing, automatic test runner, documentation sync
How hooks integrate with Agent Mode for a complete, safe workflow
Debugging hooks: the output channel, logging, common error troubleshooting
Best practices for idempotent, performant, and maintainable hooks
Series Navigation: Cursor IDE and AI-Native Development
#
Article
Level
1
Cursor IDE: Complete Guide for Developers
Beginner
2
Cursor Rules: Configure AI for Your Project
Intermediate
3
Agent Mode: Modify Your Codebase with One Command
Intermediate
4
Plan Mode and Background Agents
Advanced
5
Cursor Hooks: Automate Your Workflow (you are here)
Intermediate
6
MCP and Cursor: Connect Your IDE to Databases and APIs
Advanced
7
Debugging with Cursor AI: 3x Faster
Intermediate
8
Cursor vs Windsurf vs Copilot in 2026
Beginner
9
Professional Workflow: Angular Project with Cursor
Advanced
What Is a Hook in Cursor
A hook in Cursor is an external process that runs automatically in response to
specific events in the agent's lifecycle. When the agent is about to execute a shell command, Cursor
calls your hook, passing information about the action as JSON via stdin. Your hook can analyze that
data and respond with a directive: allow the action, block it, or ask for user confirmation.
It is critical to understand that hooks are not simple background scripts. They are
synchronous processes integrated into the agent loop: the agent pauses, waits for the hook's response,
then decides how to proceed based on that response. This makes them powerful tools for validation,
auditing, and automation.
The hooks available in Cursor 1.7+ cover these lifecycle events:
beforeShellExecution - Fires before every terminal command. Receives the exact
command the agent is about to run. Can block dangerous commands, log them, or modify them.
beforeMCPExecution - Fires before every MCP server call. Receives the tool
name and input parameters. Useful for auditing database or API operations.
beforeReadFile - Fires before the agent reads a file's contents. Allows you
to control which files the agent can access or mask sensitive information.
afterFileEdit - Fires after every file modification. Receives the file path
and the exact changes (old_string/new_string). Ideal for auto-formatting and linting.
stop - Fires when the agent completes its task. Useful for notifications,
automatic commits, documentation sync, and cleanup actions.
Beta Feature in Active Development
Cursor Hooks were introduced as a beta feature with Cursor 1.7 in October 2025. The documentation
and APIs may change in future releases. Before implementing hooks in a production environment,
check the official documentation at cursor.com/docs/agent/hooks for updates.
Configuration: Global and Project-Level hooks.json
Cursor hooks are configured via hooks.json files. There are two configuration
levels that work in a complementary way:
Global hooks (~/.cursor/hooks.json) - Apply to all projects
opened with Cursor on that machine. Ideal for personal security policies, notifications, or audit
tools you always want active.
Project hooks (.cursor/hooks.json in the repo root) - Apply only
to the current project and can be committed to the repository. This lets the whole team share the
same automations.
When both files exist, hooks are merged: global hooks run first, then project hooks for each event.
The file format is straightforward: a JSON object with a version field and a hooks
object that maps each event name to an array of commands.
Here is a complete example of hooks.json that configures hooks for all major events:
The command field accepts any executable: Node.js scripts, bash, Python, npm binaries.
Cursor runs the command as a separate process, pipes the event data as stdin in JSON
format, and reads the hook's response from stdout. Diagnostic logs and errors go
to stderr.
The base JSON structure Cursor sends via stdin to every hook includes these common fields:
// JSON structure sent via stdin to every hook
{
"conversation_id": "668320d2-2fd8-4888-b33c-2a466fec86e7",
"generation_id": "490b90b7-a2ce-4c2c-bb76-cb77b125df2f",
"hook_event_name": "beforeShellExecution", // event type
"workspace_roots": ["/path/to/project"], // workspace roots
// additional fields specific to each hook type...
}
Pre-Execution Hooks: Block Dangerous Actions
The before hooks are the most powerful because they can stop actions before they happen.
The most immediate use case is protecting critical files or directories from accidental agent
modifications, or blocking destructive shell commands.
For beforeShellExecution, the JSON received via stdin includes the command
field with the exact command the agent is about to run and the cwd field with the
current working directory:
The hook responds via stdout with a JSON indicating whether the action should be allowed or blocked.
The key field is permission with values "allow", "deny", or
"ask". Here is a Node.js hook that blocks potentially destructive commands:
// .cursor/hooks/security-check.js
// Hook: block dangerous shell commands
const readline = require('readline');
async function readStdin() {
return new Promise((resolve) => {
const rl = readline.createInterface({ input: process.stdin });
let data = '';
rl.on('line', (line) => { data += line; });
rl.on('close', () => resolve(data));
});
}
// Patterns of commands that must be blocked
const DANGEROUS_PATTERNS = [
/rm\s+-rf\s+\//, // rm -rf / (root filesystem)
/rm\s+-rf\s+~\//, // rm -rf ~/
/sudo\s+rm\s+-rf/, // sudo rm -rf anything
/DROP\s+DATABASE/i, // SQL DROP DATABASE
/git\s+push.*--force\s+origin\s+main/, // force push to main
];
// Files and directories the agent cannot touch
const PROTECTED_PATHS = [
'.env',
'.env.production',
'secrets/',
'firebase.json',
'.firebaserc',
];
async function main() {
const rawInput = await readStdin();
let input;
try {
input = JSON.parse(rawInput);
} catch (e) {
// If we cannot parse, fail-open to avoid blocking the agent
process.stdout.write(JSON.stringify({ permission: 'allow' }));
return;
}
const command = input.command || '';
// Check for dangerous commands
const isDangerous = DANGEROUS_PATTERNS.some((pattern) =>
pattern.test(command)
);
if (isDangerous) {
process.stderr.write(`[security-check] Blocked command:
#123;command}\n`);
process.stdout.write(
JSON.stringify({
permission: 'deny',
userMessage: `Command blocked by security policy: #123;command}`,
agentMessage:
'This command was blocked by the project security policy. ' +
'Do not run rm -rf on system paths or force push to protected branches.',
})
);
return;
}
// Check if command touches protected files
const touchesProtectedPath = PROTECTED_PATHS.some((protectedPath) =>
command.includes(protectedPath)
);
if (touchesProtectedPath) {
process.stdout.write(
JSON.stringify({
permission: 'ask',
userMessage: `About to run: #123;command} - Do you want to proceed?`,
})
);
return;
}
// Safe command: allow
process.stdout.write(JSON.stringify({ permission: 'allow' }));
}
main().catch((err) => {
process.stderr.write(`[security-check] Error: #123;err.message}\n`);
process.stdout.write(JSON.stringify({ permission: 'allow' })); // fail-open
});
With "permission": "ask", Cursor shows the user a confirmation dialog before proceeding,
displaying the message defined in userMessage. The user can approve or reject the action.
With "permission": "deny", the action is permanently blocked and the message is shown
to both the user and passed to the agent as context.
Protecting Specific Files with beforeReadFile
The beforeReadFile hook receives a file_path field in the stdin JSON.
Use it to prevent the agent from reading files containing credentials or secrets, or to mask
the content of sensitive files before it gets passed to the AI model.
afterFileEdit Hook: Auto-Format and Automatic Linting
The afterFileEdit hook is the most commonly used in day-to-day practice. It fires
every time the agent writes or modifies a file, and receives via stdin a JSON with the modified file's
path and an array of edits with original and new strings:
With this data you can automatically run your preferred formatter on the just-modified file. Here
is a complete Node.js hook that applies Prettier for TypeScript/JavaScript and ESLint for automatic
fixes, respecting the existing configuration files in the project:
Unlike before hooks, afterFileEdit is designed for side effects: formatting,
linting, updating indexes. It does not need to return a JSON response on stdout because the action
(the file edit) has already happened. The hook runs its work and exits; Cursor continues regardless
of the exit code.
Stop Hooks: Final Verification and Notifications
The stop hook fires when the agent considers its task complete. It does not receive
details about the specific actions taken, but has access to the conversation_id and
workspace_roots. This is the ideal moment for closing actions such as notifications,
automatic commits, documentation updates, or running the full test suite.
Here are two practical stop hook examples: the first sends a desktop notification on macOS/Linux,
the second produces a git summary of the work the agent produced:
// .cursor/hooks/notify-completion.sh
# Stop hook: desktop notification on task completion
#!/bin/bash
# Read JSON from stdin (not used here but good practice)
INPUT=$(cat)
# macOS notification
if [[ "$OSTYPE" == "darwin"* ]]; then
osascript -e 'display notification "Task completed!" with title "Cursor Agent" subtitle "Check the changes in your repository"'
fi
# Linux notification
if command -v notify-send &>/dev/null; then
notify-send "Cursor Agent" "Task completed! Review the changes."
fi
# Audit log
echo "$(date '+%Y-%m-%d %H:%M:%S') - Agent task completed" >> ~/.cursor/agent-log.txt
exit 0
// .cursor/hooks/git-status-check.js
// Stop hook: summarise git changes made by the agent
const readline = require('readline');
const { execSync } = require('child_process');
async function readStdin() {
return new Promise((resolve) => {
const rl = readline.createInterface({ input: process.stdin });
let data = '';
rl.on('line', (line) => { data += line; });
rl.on('close', () => resolve(data));
});
}
async function main() {
const rawInput = await readStdin();
const input = JSON.parse(rawInput);
const workspaceRoot = input.workspace_roots?.[0] || process.cwd();
try {
const status = execSync('git status --short', {
cwd: workspaceRoot,
encoding: 'utf8',
});
const modifiedFiles = status
.split('\n')
.filter((line) => line.trim().length > 0);
if (modifiedFiles.length > 0) {
process.stderr.write(
`[git-check] Agent modified #123;modifiedFiles.length} file(s):\n`
);
modifiedFiles.forEach((f) => process.stderr.write(` #123;f}\n`));
} else {
process.stderr.write('[git-check] No changes in working tree\n');
}
} catch (e) {
process.stderr.write(`[git-check] Git not available: #123;e.message}\n`);
}
}
main();
Practical Use Cases for Development Teams
Hooks become especially valuable when working in teams or on projects with rigorous quality
requirements. Here are the most effective patterns that emerged from the Cursor community in 2025.
Pattern 1: Security Audit Before MCP Operations
If you use MCP with databases or external APIs, the beforeMCPExecution hook lets you
log every operation before it runs. The stdin JSON includes the MCP tool name and the exact
parameters passed:
// .cursor/hooks/mcp-audit.js
// Audit log for every agent MCP call
const readline = require('readline');
const fs = require('fs');
const path = require('path');
async function readStdin() {
return new Promise((resolve) => {
const rl = readline.createInterface({ input: process.stdin });
let data = '';
rl.on('line', (line) => { data += line; });
rl.on('close', () => resolve(data));
});
}
const BLOCKED_MCP_TOOLS = [
'delete_database',
'drop_table',
'truncate_table',
'execute_raw_sql',
];
async function main() {
const rawInput = await readStdin();
const input = JSON.parse(rawInput);
const toolName = input.tool_name || 'unknown';
const toolInput = input.tool_input || '{}';
const workspaceRoot = input.workspace_roots?.[0] || '.';
// Log the MCP operation
const auditEntry = {
timestamp: new Date().toISOString(),
tool: toolName,
input: toolInput,
conversation_id: input.conversation_id,
};
const auditFile = path.join(workspaceRoot, '.cursor', 'mcp-audit.log');
fs.appendFileSync(auditFile, JSON.stringify(auditEntry) + '\n');
// Block destructive tools
if (BLOCKED_MCP_TOOLS.includes(toolName)) {
process.stdout.write(
JSON.stringify({
permission: 'deny',
userMessage: `MCP operation blocked: #123;toolName}`,
agentMessage:
`The MCP tool '#123;toolName}' is blocked by project policy. ` +
`Use more specific operations or ask for manual user confirmation.`,
})
);
return;
}
process.stdout.write(JSON.stringify({ permission: 'allow' }));
}
main();
Pattern 2: Automatic Test Runner After Test File Edits
Another very useful pattern is automatically running tests when the agent modifies spec or test files.
This ensures changes do not break the existing suite:
A useful pattern for technical documentation: when the agent modifies a TypeScript interface or
routing file, the stop hook can check whether the documentation needs updating:
The integration between Hooks and Agent Mode creates a feedback loop that makes the agent safer and
more reliable over time. When the agent works autonomously on complex tasks, hooks act as a safety
net that engages at every step of the execution cycle.
Consider a real-world scenario: you are using Agent Mode to refactor an Angular module. The agent
executes dozens of actions in sequence: reads files, modifies components, updates routing, runs npm
commands. With hooks configured correctly, every critical step is intercepted:
beforeShellExecution - Blocks any unapproved npm install commands
or pushes to protected branches
beforeReadFile - Prevents the agent from reading .env files
or configuration files containing secrets
afterFileEdit - Every modified file is automatically formatted with Prettier
and checked with ESLint before moving to the next step
stop - When the agent completes, you receive a notification and a git summary
of changes to review
The agentMessage field in hook responses is passed to the AI model as additional context.
This lets the agent adapt its behaviour based on defined policies: if a hook blocks
a certain action with an explanatory message, the agent can choose an alternative approach without
human intervention.
Architecture of a Complete Hooks Workflow
Phase
Hook
Action
Before shell commands
beforeShellExecution
Block destructive commands, require confirmation for git operations
Before MCP calls
beforeMCPExecution
Audit log, block dangerous DB operations
Before reading files
beforeReadFile
Protect .env files, mask secrets
After every edit
afterFileEdit
Prettier, ESLint --fix, update indexes
Task complete
stop
Desktop notification, git status, docs check
Debugging Hooks: Output Channel and Troubleshooting
One of the first things you discover when working with hooks is that silent errors are the most
common problem. A hook that does not start, a malformed JSON, an unhandled timeout: all scenarios
that can make the agent's behaviour unpredictable. Cursor provides a dedicated tool for diagnosing
these issues.
To access the Hooks Output Channel:
Open the Output panel in Cursor (View > Output or Ctrl+Shift+U)
Select "Hooks" from the dropdown in the panel toolbar
You will see logs for every hook execution: which script was called, the exit code, and
everything the script wrote to stderr
The most common issues and how to resolve them:
# Issue 1: Hook not found
# Error: "Cannot find command: node .cursor/hooks/auto-format.js"
# Cause: the path is relative to the workspace root, not to hooks.json location
# Fix: ensure the command path is relative to the project root
# Issue 2: Malformed JSON in response
# Error: "Malformed JSON response from hook, silently allowing"
# Cause: non-JSON output on stdout (debug prints, npm output, etc.)
# Fix: ALWAYS use process.stderr for logs, process.stdout ONLY for the JSON response
# Issue 3: Hook too slow (timeout)
# Cause: blocking operation (e.g. full test suite) without timeout
# Fix: always add timeout to execSync calls
try {
execSync(command, {
cwd: workspaceRoot,
timeout: 10000, // 10 second maximum
stdio: ['ignore', 'pipe', 'pipe'],
});
} catch (e) {
if (e.signal === 'SIGTERM') {
process.stderr.write('[hook] Timeout reached, skipping operation\n');
}
}
# Issue 4: Hook fails due to missing node_modules
# Cause: project dependencies not installed
# Fix: always check for binary existence before using it
const hasPrettier = fs.existsSync(
path.join(workspaceRoot, 'node_modules', '.bin', 'prettier')
);
if (!hasPrettier) return; // Skip silently if not available
A useful pattern for initial debugging is adding a logging hook that records every event to file,
giving you a complete audit trail of what the agent did and in what order:
Having covered configuration, examples, and debugging, here are the principles that guide building
professional-quality hooks.
Principle 1: Fail-Open or Fail-Safe, Never Fail-Silent
You must consciously decide how to behave on error. For security hooks (blocking commands, protecting
files), the correct behaviour is often fail-safe: on error, block the action for
safety. For automation hooks (formatting, linting), prefer fail-open: if the
formatter is not available, let the action through without blocking the agent's work. Never choose
fail-silent: always log the error to stderr.
Principle 2: Idempotency
Hooks can be called multiple times on the same file, especially afterFileEdit in Agent
Mode when the agent modifies the same file in successive steps. Your hooks must be idempotent:
running Prettier twice on the same file must give the same result as running it once. Avoid
operations that append data or create duplicates.
Principle 3: Performance and Timeouts
Hooks are synchronous in the agent loop: a slow hook slows down the entire workflow. Practical
guidelines:
For beforeShellExecution and beforeReadFile: respond within 2-3 seconds
For afterFileEdit: formatting and linting should complete within 10-15 seconds
For stop: you have more margin (30-60 seconds), but notifications and logs
should be fast
Always set a timeout on execSync calls to prevent indefinite blocking
Principle 4: Separation of Concerns
Prefer many small, focused hooks over a single hook that does everything. Each hook in
hooks.json is independent: you can add, remove, or debug each one without touching
the others. One hook for formatting, one for linting, one for tests: each script has a clear,
single responsibility.
Principle 5: Hook Security
Hooks execute arbitrary code: they are a potential attack vector if the project's hooks.json
is compromised. Never hardcode secrets in hook scripts. Use environment variables or configuration
files external to the repository. Always validate file paths received via stdin before using them
in shell commands to prevent path traversal attacks.
// Example: path validation to prevent path traversal
function isPathSafe(filePath, workspaceRoot) {
const resolvedPath = require('path').resolve(filePath);
const resolvedRoot = require('path').resolve(workspaceRoot);
// Ensure the file is inside the workspace root
return resolvedPath.startsWith(resolvedRoot + require('path').sep);
}
// Always validate before file operations
if (!isPathSafe(input.file_path, workspaceRoot)) {
process.stderr.write('[hook] Unsafe path, skipping operation\n');
return;
}
Hooks vs Cursor Rules: When to Use Which
Cursor Rules instruct the agent on how to write code (style, conventions,
patterns to follow). Hooks control what happens when the agent executes
actions (automatic formatting, security validation, notifications). They are complementary: use
Rules to guide code generation, Hooks to ensure the quality and safety of actions.
Conclusions
Cursor's Hooks system represents a qualitative leap in the control you have over the AI agent.
It is no longer about hoping the agent does the right thing: you can define precise policies,
reliable automations, and security guardrails that engage automatically, every session, for every
developer on the team.
The most effective patterns that emerged from the community in 2025 combine:
beforeShellExecution for strict security policies and git branch protection
afterFileEdit for automatic code quality (formatting + linting) without
relying on individual developer discipline
stop for feedback, notifications, and post-task verification
Project hooks (.cursor/hooks.json) committed to the repository to share the
same policies across the entire team
The natural next step after Hooks is MCP (Model Context Protocol): while Hooks let
you control agent actions, MCP lets you connect the agent to external data sources like databases,
REST APIs, and third-party tools. In the next article we will cover how to configure MCP servers
with Cursor to create workflows that directly integrate PostgreSQL databases, remote filesystems,
and external APIs.
Next Steps in the Series
Previous Article: Plan Mode and Background Agents - how to plan and execute
complex tasks in parallel
Next Article: MCP and Cursor: Connect Your IDE to Databases and APIs - integrate
databases and external services directly into the agent
Related:Introduction to MCP - the dedicated series on
Model Context Protocol
Related:Agent Mode - how to delegate complex tasks
to the agent before configuring hooks