Repository navigation
Agent Integration
This page is for people who wire this tool into an LLM coding agent (DeepSeek Harness, Claude Code, Cursor, a home-grown harness), and for the agents themselves. It covers the two things that decide whether the rule actually holds: where the rule lives and which implementation to call on which platform.
Everything here was measured on v3.0.0 (2026-10-09) against this repository.
| Where | What goes there | Why |
|---|---|---|
A skill — skills/clean-bom-crlf/SKILL.md
|
the full procedure: install, per-platform entry point, the decision table, exceptions, byte-level verification, exit codes | a skill loads when the task touches files, so the long text costs nothing until it is needed |
The agent's always-loaded rules (system prompt, AGENTS.md, CLAUDE.md…) |
one pointer sentence naming the skill | an always-present line is what makes the agent think to load the skill |
A skill alone is unreliable — nothing reminds the agent it exists. A rule alone is expensive and gets duplicated. Together they work like a loader plus a check.
Pointer sentence to paste into the rules file:
Any task that touches code or text files (create, edit, generate, patch, package:
.php .js .css .html .xml .sh .py .yaml .json .ps1 .md .txt…) — load and follow theclean-bom-crlfskill before delivering the result.
A ready-made prompt for a foreign agent (it creates the skill, adds the pointer, verifies both
are visible, and reports four concrete facts) lives in
docs/PROMPT-OTHER-HARNESS.md.
Copy the directory (a skill is a directory containing SKILL.md):
$DSH_HOME/skills/clean-bom-crlf/SKILL.md # DeepSeek Harness
~/.claude/skills/clean-bom-crlf/SKILL.md # Claude Code and compatible agents
<repo>/.agent/skills/clean-bom-crlf/SKILL.md # project-local, travels with the repo
An agent with no skill mechanism at all can take the body of SKILL.md as a section of its
rules file — the content does not depend on a loader.
Every file that stays behind: created, edited, generated, patched or packaged, and left in
a repository or shipped in a build, ends at BOM=False, CRLF=False — except the deliberate
exceptions below.
Two failure modes look exactly like success:
- running the tool with no arguments — it then walks the current directory and can rewrite files unrelated to the task;
- running it against a directory while files use an extension outside the default set
(
php css js txt xml htm html) — they are skipped silently while the report still says "done".
| Platform | Command | Notes |
|---|---|---|
| Linux, macOS, WSL, Git Bash | bash clean-bom-senior.sh --quiet <files…> |
POSIX shell, GNU and BSD userland, no extra runtime |
| Windows | pwsh -NoLogo -NoProfile -File clean-bom-senior.ps1 --quiet <files…> |
requires PowerShell 7.0+ (Core); pure .NET byte I/O, no Git Bash needed |
| Any host with Node ≥ 18 | node bin/bom.js --quiet <files…> |
fallback for Windows without PowerShell 7 |
| Any, without writing | --check |
exit 10 = needs cleaning, 0 = clean |
Parity is asserted, not assumed: sh↔node over 8 fixtures, sh↔ps1 over 77 scenarios.
The repository is public, so an agent can fetch a pinned revision and verify it. Pin a
commit, not main, or the instruction silently ages:
PIN=c799d11635a22e6abccd903e534dd84a409117a2
curl -fsSL -o clean-bom-senior.sh \
"https://raw.githubusercontent.com/paulmann/Clean_BOM_Senior/$PIN/clean-bom-senior.sh"
printf '%s %s\n' ec1634249bff874d10b0d2999760be603153b1f0fcccc06a5f6b0be667504693 clean-bom-senior.sh | sha256sum -c -
chmod +x clean-bom-senior.shWindows: fetch clean-bom-senior.ps1 and bin/bom.js the same way, and confirm PowerShell 7+
first — $PSVersionTable.PSVersion must print 7.x. On macOS use shasum -a 256 instead of
sha256sum. If the checksum does not match, do not run the file; if there is no network, say
so instead of imitating success.
| Situation | Result |
|---|---|
UTF-8 BOM + code (php js css html xml sh py yaml json) |
BOM removed, CRLF→LF |
| UTF-8 BOM + pure-ASCII content (any extension) | BOM removed |
BOM + non-ASCII in txt csv tsv ps1 psm1 psd1 and any unknown extension (incl. md)
|
BOM kept deliberately — Excel and PowerShell 5.1 need it; CRLF still normalised |
the same + --bom-policy=strip / --force
|
BOM removed |
| UTF-16/32 BOM, or NUL bytes anywhere |
never touched, even with --force
|
| invalid UTF-8 | untouched by default; --force = byte-level cleaning |
| file already clean | never rewritten — inode and mtime unchanged |
Exceptions — the expected result is inverted:
-
.bat,.cmd,.regmust keep CRLF (cmd.exe will not run an LF-only batch file). A plain call breaks them; if the BOM has to go, use--no-rn-normalize(measured: BOM removed, CRLF intact). - non-ASCII
txt/csv/ps1/mdkeep their BOM by policy. Remove it knowingly — a#!/usr/bin/env pwshscript that must also run on Unix has to be ASCII without a BOM, otherwise the kernel reads the BOM as magic and runs/bin/sh.
$b = [IO.File]::ReadAllBytes('<file>')
$bom = $b.Length -ge 3 -and $b[0] -eq 0xEF -and $b[1] -eq 0xBB -and $b[2] -eq 0xBF
$crlf = ([IO.File]::ReadAllText('<file>')) -match "`r`n"
"BOM=$bom CRLF=$crlf" # expected False False, except for the exceptions abovehead -c 3 '<file>' | od -An -tx1 | tr -d ' \n' # must not be efbbbf
tr -dc '\r' < '<file>' | wc -c # must be 0grep -c '\r' looks right and is wrong on GNU grep: \r is not a CR in a BRE, so the
pattern degenerates to the letter r and a clean file reports a non-zero count (measured 1
on GNU 3.11/Debian). Use tr -dc '\r' | wc -c, or grep -c "`$(printf '\r')" with a real
CR byte in the pattern.
Exit codes: 0 success · 1 per-file errors or --strict findings · 2 usage ·
3 environment · 4 internal · 10 --check found dirt · 11 update available.
Precedence: 2/3/4 > 1 > 10/11 > 0.
An agent claiming the rule is installed should return four facts: the path of the skill file
and of the rules file, that both are UTF-8 without BOM and LF-only, the first lines of the
rules section, and the output of --version. Without them, "the rule is installed" cannot be
checked — and that is exactly where such setups usually fail quietly.