mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-12 06:06:37 +03:00
hooks: two-tier design hook — immediate per-edit rules + full-set Stop deep pass
Eval evidence showed the per-edit PostToolUse stream fires overwhelmingly
on copy-level rules (em-dash-overuse ~97x/session) and measurably makes
models more conservative, while a full-detector pass at completion is what
actually fixes contrast/padding/glow. Split the hook accordingly:
- Per-edit (PostToolUse) now surfaces only IMMEDIATE_TIER_RULES: broken
output (broken-image, text-overflow, clipped-overflow-container,
body-text-viewport-edge), objective contrast/legibility failures
(low-contrast, gray-on-color, tiny-text), single-property mechanical
slop (gradient-text, dark-glow), and design-system drift (the four
design-system-* rules, which compound if left uncorrected). Everything
else defers. Override with hook.perEditRules: "all" in
.impeccable/config.json. Tiering is off for Cursor/Copilot harnesses,
which have no Stop pass wired, so nothing gets silently dropped there.
- Stop deep pass (runStopHook): runs the FULL rule set over every UI file
touched this session (tracked via the existing hook.cache.json session
state; deferred-only edits now mark the file touched), dedupes against
everything already surfaced per-edit, honors ignore-rule/file/value and
inline disables, reuses the [impeccable@1] envelope, and no-ops fast
when no UI files were touched. Emits hookSpecificOutput
{ hookEventName: "Stop", additionalContext } per the Claude Code SDK
Stop contract (conversation continues so the model can act on it).
Second Stop fire is silent - deep-pass findings are remembered.
- Wiring: Stop entries (timeout 30) in plugin/hooks/hooks.json, the
.claude settings + .codex hooks manifests (transformers + hook-admin
repair path). Claude Code and Codex both dispatch a native Stop event;
Cursor's stop hook is inconsistently dispatched (pre-write gate stays)
and Copilot's agentStop/sessionEnd don't inject model context, so
neither gets a Stop entry - documented in reference/hooks.md.
- Tests: tiering split/override/harness gating, Stop dedupe + silent
no-touched-files + ignore machinery + kill switches; existing per-edit
tests moved to immediate-tier rule ids. 181 tests green; smoke-tested
the built dist skill end to end (glow surfaced per-edit, em-dash only
at Stop, second Stop silent).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
8091f452d5
commit
c3aba1e343
@@ -23,6 +23,26 @@ export const IMPECCABLE_HOOK_COMMAND_MARKER = 'skills/impeccable/scripts/hook.mj
|
||||
|
||||
const TIMEOUT_SECONDS = 5;
|
||||
const STATUS_MESSAGE = 'Checking UI changes';
|
||||
// The Stop deep pass scans every UI file touched in the session with the
|
||||
// full rule set, so it gets a longer budget than the single-file per-edit
|
||||
// pass. Wired only for Claude Code and Codex, which both dispatch a native
|
||||
// `Stop` hook event; Cursor's stop hook is not consistently dispatched and
|
||||
// GitHub Copilot's stop-style events do not feed context back to the model.
|
||||
const STOP_TIMEOUT_SECONDS = 30;
|
||||
const STOP_STATUS_MESSAGE = 'Design deep pass';
|
||||
|
||||
function stopEntry(command) {
|
||||
return {
|
||||
hooks: [
|
||||
{
|
||||
type: 'command',
|
||||
command,
|
||||
timeout: STOP_TIMEOUT_SECONDS,
|
||||
statusMessage: STOP_STATUS_MESSAGE,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
const CLAUDE_PROJECT_HOOK = '${CLAUDE_PROJECT_DIR}/.claude/skills/impeccable/scripts/hook.mjs';
|
||||
const CLAUDE_PLUGIN_HOOK = '${CLAUDE_PLUGIN_ROOT}/skills/impeccable/scripts/hook.mjs';
|
||||
const CODEX_PLUGIN_HOOK = '${PLUGIN_ROOT}/skills/impeccable/scripts/hook.mjs';
|
||||
@@ -32,7 +52,7 @@ const GITHUB_PROJECT_HOOK = '$(git rev-parse --show-toplevel)/.github/skills/imp
|
||||
|
||||
export function buildClaudeSettingsManifest() {
|
||||
return {
|
||||
description: 'Impeccable design detector: runs after Edit/Write/MultiEdit on UI files and surfaces findings as system reminders.',
|
||||
description: 'Impeccable design detector: immediate-tier checks after Edit/Write/MultiEdit on UI files, full-rule deep pass on Stop.',
|
||||
hooks: {
|
||||
PostToolUse: [
|
||||
{
|
||||
@@ -47,6 +67,7 @@ export function buildClaudeSettingsManifest() {
|
||||
],
|
||||
},
|
||||
],
|
||||
Stop: [stopEntry(`node "${CLAUDE_PROJECT_HOOK}"`)],
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -73,6 +94,7 @@ export function buildClaudePluginHooksManifest() {
|
||||
],
|
||||
},
|
||||
],
|
||||
Stop: [stopEntry(`node "${CLAUDE_PLUGIN_HOOK}"`)],
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -96,6 +118,7 @@ export function buildCodexPluginHooksManifest() {
|
||||
],
|
||||
},
|
||||
],
|
||||
Stop: [stopEntry(`node "${CODEX_PLUGIN_HOOK}"`)],
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -116,6 +139,7 @@ export function buildCodexHooksManifest() {
|
||||
],
|
||||
},
|
||||
],
|
||||
Stop: [stopEntry(`node "${CODEX_PROJECT_HOOK}"`)],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user