-
Notifications
You must be signed in to change notification settings - Fork 3
Hooks Reference
VCP registers 4 hooks. Dev Buddy hooks were removed in v0.5.0 (see Dev Buddy Hooks below). All hooks are TypeScript files executed by Bun.
Layer 1: Proactive context injection at session start.
| Property | Value |
|---|---|
| Event | SessionStart |
| Trigger | Every session start (new, resume, clear, compact) |
| Timeout | 15 seconds |
| Exit code | Always 0 (never blocks) |
| Command | bun ${CLAUDE_PLUGIN_ROOT}/hooks/security-context.ts |
- Reads
CLAUDE_PROJECT_DIRenvironment variable (falls back tocwd()) - Calls
generateContext(projectRoot)fromvcp-context-core.ts, which loads global config (~/.vcp/config.json) to resolve the standards URL and applies global defaults - Outputs formatted VCP rule summaries to stdout
- On any error (network failure, missing config), outputs a fallback message
If the manifest cannot be fetched or any error occurs:
VCP active but not fully initialized. Run /vcp-init to configure, then /vcp-audit before committing.
If no global config exists, outputs:
VCP active but not initialized. Run /vcp-init to configure.
Upstream Claude Code bugs may prevent the hook's output from being injected into the model context. See #10373, #11509, #12151. Use /vcp-context as a manual fallback.
Layer 3: Real-time blocking of dangerous code patterns.
| Property | Value |
|---|---|
| Event | PreToolUse |
| Trigger |
Write|Edit and Bash (two separate matchers) |
| Timeout | 10 seconds |
| Exit code | 0 = allow, 2 = block |
| Command | bun ${CLAUDE_PLUGIN_ROOT}/hooks/security-gate.ts |
Reads JSON from stdin with the structure:
{
"tool_name": "Write",
"tool_input": {
"file_path": "/path/to/file.ts",
"content": "..."
}
}For Edit: checks old_string and new_string fields.
For Bash: checks the command field. Bash-specific patterns (CWE-95 shell eval, CWE-116 obfuscation) only apply to Bash tool calls.
When blocking (exit 2): Writes to stderr (fed to Claude as error message):
VCP Security Gate — BLOCKED:
CWE-798: Hardcoded secret detected. Use environment variables or a secret manager.
When suppressing (exit 0): Outputs JSON to stdout (shown to user via systemMessage):
{"systemMessage":"VCP Security Gate — WARNING: Suppressed 1 finding(s) via .vcp/config.json ignore (CWE-798)."}Reads both ~/.vcp/config.json (global) and .vcp/config.json (project) from CLAUDE_PROJECT_DIR. Merges ignore arrays from both configs (union). Filters patterns by CWE entries in the merged ignore list. For example, "CWE-798" in either config's ignore list disables all hardcoded secret patterns. Suppressed findings emit a warning via stdout JSON so the user is aware.
The hook gracefully handles missing global config — if ~/.vcp/config.json doesn't exist, only project ignores are used.
See Security Gate Patterns for the complete reference of all 21 patterns.
Warns when AI-generated test code contains mock-abuse patterns.
| Property | Value |
|---|---|
| Event | PostToolUse |
| Trigger |
Write|Edit (test files only) |
| Timeout | 10 seconds |
| Exit code | Always 0 (never blocks — informational only) |
| Command | bun ${CLAUDE_PLUGIN_ROOT}/hooks/test-quality-warning.ts |
Reads JSON from stdin with the structure:
{
"tool_name": "Write",
"tool_input": {
"file_path": "/path/to/test_file.py",
"content": "..."
}
}Only processes Write and Edit tool calls where the file path matches test file patterns (*.test.*, *.spec.*, test_*.*, __tests__/, *_test.go, *Test.java, *_test.rb, *_spec.rb, *_test.rs). Non-test files are silently skipped.
The hook detects 3 mock-abuse patterns:
-
Excessive mocking — More than 3 mock/stub setup calls (
mock(),jest.fn(),vi.fn(),patch(),stub(),spyOn(),.mockReturnValue(),.mockResolvedValue(),.mockImplementation(),.return_value =,sinon.stub/mock/fake). Maps to core-testing Rule 4. -
Mock-only assertions — Test contains mock assertions (
.assert_called,.toHaveBeenCalled,.calledWith, etc.) but zero value assertions (.toEqual,.toBe,assert,assertEqual, etc.). Maps to core-testing Rule 5. -
Tautological mock assertions — Test asserts that a mock returns exactly what it was configured to return (e.g.,
.mockReturnValue(42)followed by.toEqual(42)). Maps to core-testing Rule 3.
Outputs warnings as JSON to stdout (shown to user via systemMessage):
{"systemMessage":"VCP Test Quality Warning — 2 issue(s) in tests/test_payments.py:\n - Excessive mocking: 7 mock setup calls detected. VCP standard core-testing Rule 4: \"Mock external services, not internal logic.\" Consider reducing mocks to external boundaries only.\n - Mock-only assertions: 3 mock assertion(s) found but no value assertions. VCP standard core-testing Rule 5: \"When you mock, verify the contract — not the call.\" Add assertions on return values or state changes."}- PostToolUse hooks signal issues via JSON stdout with
systemMessage— this is how Claude Code surfaces hook output to the user - Warnings are informational; the user can choose to address them or not
- The hook runs quickly (regex-based, no I/O beyond stdin)
Reminder to run VCP checks before committing.
| Property | Value |
|---|---|
| Event | Stop |
| Trigger | When the AI finishes a task |
| Timeout | None (fast, no I/O) |
| Exit code | Always 0 |
| Command | bun ${CLAUDE_PLUGIN_ROOT}/hooks/stop-reminder.ts |
Outputs JSON to stdout (shown to user via systemMessage):
{"systemMessage":"Reminder: Run /vcp-audit, /vcp-review-tests, or /vcp-pre-commit-review before committing."}As of v0.5.0, Dev Buddy's hooks.json is empty ({"hooks": {}}). The three hooks previously registered — ralph-stage-gate.ts, dispatch-gate.ts, and uat-completion-gate.ts — have been removed.
What replaced them:
-
Stage sequencing — Enforced by the ralph state machine (
ralph-state-machine.ts). ThecomputeNextAction()function returns the correct skill for the current status. Review-gated statuses (discover-review,requirements-review,decompose-review) emituser_checkpointactions that require user approval before advancing. -
Dispatch proof — No longer needed. Stage skills now call
stage-runner.tswhich handles executor dispatch as a subprocess pipeline, not prompt-level instructions. -
UAT completion — Enforced by
checkPreconditions()in the state machine, which verifies UAT results before allowing thedonetransition.
If migrating from v0.4.x, no action is needed — the hooks are simply gone. The state machine provides equivalent enforcement with fewer moving parts.
When debug is enabled in the global config (~/.vcp/config.json), all hooks write diagnostic entries to .vcp/vcp.log in the project root. This log records what each hook checked and decided, useful for verifying hooks are running and diagnosing issues. By default, debug is false and no log file is generated.
To enable: /vcp-config global set debug true or set "debug": true in ~/.vcp/config.json.
2026-02-16T10:30:45.123Z [SessionStart] security-context: info — Generated context (9876 chars)\n--- BEGIN CONTEXT ---\n## VCP Standards Context\n...\n--- END CONTEXT ---
2026-02-16T10:31:02.456Z [PreToolUse] security-gate: allow — No findings
2026-02-16T10:31:05.789Z [PreToolUse] security-gate: block — CWE-798
2026-02-16T10:31:10.012Z [PreToolUse] security-gate: warn — Suppressed 1 finding(s) (CWE-798)
2026-02-16T10:32:00.345Z [PostToolUse] test-quality-warning: warn — 2 issue(s) in /src/foo.test.ts
2026-02-16T10:35:00.890Z [Stop] stop-reminder: info — Reminder shown
Each line: ISO_TIMESTAMP [event] source: decision — details
-
.vcp/*.logshould be added to.gitignore(VCP's own.gitignorealready includes it) - Logging is best-effort — if the project root is unavailable or not an absolute path, logging is silently skipped
- The logger is shared by hooks and lib modules via
vcp-logger.ts
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [{ "type": "command", "command": "bun ${CLAUDE_PLUGIN_ROOT}/hooks/security-gate.ts", "timeout": 10 }]
},
{
"matcher": "Bash",
"hooks": [{ "type": "command", "command": "bun ${CLAUDE_PLUGIN_ROOT}/hooks/security-gate.ts", "timeout": 10 }]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [{ "type": "command", "command": "bun ${CLAUDE_PLUGIN_ROOT}/hooks/test-quality-warning.ts", "timeout": 10 }]
}
],
"SessionStart": [
{
"hooks": [{ "type": "command", "command": "bun ${CLAUDE_PLUGIN_ROOT}/hooks/security-context.ts", "timeout": 15 }]
}
],
"Stop": [
{
"hooks": [{ "type": "command", "command": "bun ${CLAUDE_PLUGIN_ROOT}/hooks/stop-reminder.ts" }]
}
]
}
}| Variable | Available To | Description |
|---|---|---|
CLAUDE_PLUGIN_ROOT |
hooks.json command templates | Resolves to the plugin directory at registration time |
CLAUDE_PROJECT_DIR |
Hook scripts at runtime | The user's project root directory |
Note: CLAUDE_PLUGIN_ROOT is a template variable expanded in hooks.json, not an environment variable available to scripts at runtime. Skills use pluginRoot from .vcp/config.json instead.
VCP Wiki
Guides
- First-Time Setup Guide
- How Configuration Works
- Configuration Recipes
- Web Portal Guide
- Daily VCP Workflow
- Troubleshooting
VCP Plugin
- Configuration
- Skills Reference
- Three‐Layer Enforcement Model
- Hooks Reference
- Security Gate Patterns
- Shared Modules
Dev Buddy Plugin
- Dev Buddy Quick Start
- Dev Buddy Configuration
- Stage Skills Guide
- AI Provider Presets
- System Prompts Reference
- Chatroom
MCP Doc Plugin
Standards
Project
VCP Wiki (中文)
指南
VCP 插件
Dev Buddy 插件
MCP Doc 插件
标准
项目