Conflict marker detector
Leftover merge conflict markers caught instantly
After every file write or edit, checks the file on disk for leftover git conflict markers. Requires both an opening and a closing marker line to flag, which avoids false positives on markdown setext underlines. Non-blocking: feeds a warning back to the agent so it resolves the conflict before moving on.
What does the Conflict marker detector hook do?
Conflict marker detector is a Claude Code PostToolUse hook matching Write|Edit. It fires automatically at that lifecycle event — outside the model, so it can't be skipped or forgotten. Leftover merge conflict markers caught instantly.
As a PostToolUse hook it runs after the action, reacting to what just happened rather than blocking it. Because it is a deterministic Node.js script, it executes on every matching event without relying on the model to remember — the guarantee that makes agentic workflows safe to automate.
Use cases
- Catching half-resolved conflicts after an assisted merge or rebase
- Preventing conflict markers from reaching CI or production
- Flagging files pasted from a conflicted state
Tags
settings.json fragment
{
"hooks": {
"PostToolUse": [
{
"hooks": [
{
"command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/post-edit-conflict-marker-check.mjs",
"type": "command"
}
],
"matcher": "Write|Edit"
}
]
}
}Script · .claude/hooks/post-edit-conflict-marker-check.mjs
#!/usr/bin/env node
// @hookstack post-edit-conflict-marker-check
// Signale les marqueurs de conflit git oubliés après une écriture (PostToolUse Write|Edit)
import { existsSync, readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
const OPEN_MARKER = /^<{7} /m;
const CLOSE_MARKER = /^>{7} /m;
export function run(
input,
{ readFile = readFileSync, fileExists = existsSync } = {},
) {
const filePath = input.tool_input?.file_path ?? "";
if (!filePath || !fileExists(filePath)) return null;
let content;
try {
content = readFile(filePath, "utf8");
} catch {
return null;
}
// Les deux bornes sont requises : évite les faux positifs (ex. soulignés markdown)
if (!OPEN_MARKER.test(content) || !CLOSE_MARKER.test(content)) return null;
return {
message: `[conflict-marker] ${filePath} contains git conflict markers (<<<<<<< / >>>>>>>). Resolve the conflict and remove the markers before moving on.\n`,
};
}
/* v8 ignore next 5 */
if (process.argv[1] === fileURLToPath(import.meta.url)) {
const input = JSON.parse(readFileSync(0, "utf8"));
const result = run(input);
if (result?.message) process.stderr.write(result.message);
}