Ihor Orlovskyi 99f784578d Make dashfix language-aware and give both writing-style skills an enforcement hook (#28)
* Add the skills.sh badge and consolidate the install commands in README

* Make dashfix language-aware and give both writing-style skills an enforcement hook

Answers the first field feedback on dashfix 1.0.0.

- dashfix 1.1.0: "Language scope" binds the ban per file. English keeps the full
  ban; in Ukrainian, Russian, Polish and German the em dash is orthography, so the
  skill checks its form and a correct dash earns a fifth `justified` category.
- Both skills scan commit messages via `git log`, catalog them separately by hash
  and keep them out of the score, since history needs a rewrite to change.
- Both ship `scripts/commit-msg`: dashfix rejects a banned dash, negafix warns
  only, because its patterns overmatch by design. dashfix also documents a
  `PreToolUse` snippet, and both state that write mode dies with a compaction.
- Both scores are normalized by project size (`100 - spread - depth`) so five
  dirty files no longer force a 0 in a 2000-file repository.
- Scan exclusions become a rule, and dashfix drops the `grep -rnP` fallback that
  BSD grep on macOS cannot run.

* Fix the review findings on the history scan, the hooks and the score edges

- `git log --grep` now does the matching in both skills, so every hit prints with
  its hash even from a commit body, and merge commits stay in scope
- the dashfix hook skips a message written in Cyrillic instead of rejecting a
  correct Ukrainian or Russian dash, and its header names German among the
  languages that keep the hook uninstalled
- the `PreToolUse` snippet drops `jq`: without it the pipeline ended on a
  successful perl and passed the commit through in silence
- negafix looks for `not a ... but a` in its inventory regex and its hook, which
  its own pattern list had documented all along
- the score states what to report when no file is in scope, and the perl fallback
  uses `git ls-files -z | xargs -0` so a filename with a space survives

* Make the history scan a per-match catalog and harden the perl fallback

- `git log --grep` now only selects the commits; an inner `rg` pass over
  `git show -s --format=%B` prints one line per match as `<hash>:<line>:<snippet>`,
  so the history table catalogs every match instead of one row per commit.
  Verified on 09b2413, which carries five dashes in its body and produced five rows.
- the perl fallback passes `--` before the filenames, since perl otherwise reads a
  path such as `-weird.md` as its own switches and dies
- the Cyrillic heuristic states both of its limits in SKILL.md and in the hook
  header: an English message mentioning a Cyrillic name is skipped too, and
  Latin-script Polish and German cannot be detected at all. The audit is what
  catches what the hook misses.

* Count occurrences, not matching lines, in both audits

`rg -n` prints a line once however many matches it holds, so the line-oriented
inventory understates the total the catalog and the score depend on. On this
repository the gap is real: dashfix sees 80 lines against 89 occurrences, negafix
39 against 57.

- both skills add a `--count-matches` pass, and the reported total comes from it
- Step 2 says one row per matching line, a row states how many occurrences its
  line carries, and a line whose occurrences disagree on the verdict splits into a
  row each; both catalogs gain an example row
- Verification asks the catalog to account for every occurrence in that total

* Guard the shared negafix pattern and key split rows by occurrence

- negafix sets `PATTERN` once at the head of Step 1, and the working-tree,
  history and counting blocks each open with `: "${PATTERN:?...}"`. Run alone, a
  block previously handed `rg` an empty pattern, which matches every line and
  reported a total unrelated to the project; it now aborts with the message.
- a line whose occurrences carry different verdicts splits into rows keyed
  `<location>#<n>` in reading order, so no two catalog rows share a key. Both
  skills document the form and show an example pair.

* Anchor the working-tree scans at . and align the perl fallback with rg

- both working-tree passes name `.`: given a piped stdin and no path, `rg` reads
  the pipe instead of the tree and reports zero matches on a project that has 93
- the perl fallback repeats the scan exclusions as `:(exclude)` pathspecs, so it
  no longer scores a wider file set than the primary command
- the same fallback closes `ARGV` at each `eof`. Without it `$.` ran on across the
  whole file list, so every line number after the first file was wrong: the run on
  this repository pointed at CHANGELOG.md:381 where rg reports :101. With the fix
  both passes return byte-identical location lists (82 lines).

* Make the perl fallback scan the same file set as rg

On a fixture with a tracked, an untracked, a gitignored, a nested lock, a hidden
and a binary file, rg read two files and the fallback read one. Now both read the
same two.

- `--others --exclude-standard` picks up untracked files while still honoring
  `.gitignore`; plain `git ls-files` saw only tracked ones
- the exclusion pathspecs gain `**/`, so a nested `package-lock.json` drops out
  the way an rg glob without a slash already dropped it
- `':!:.*' ':!:**/.*'` skip hidden paths as rg does by default, with the text
  naming `--hidden` as the way to audit them on both sides
- binary files stay the one difference, stated in the text rather than left to
  surprise the reader

On this repository both passes now return byte-identical location lists.

* Exclude root lock files and binary files from the perl fallback

A git pathspec is not a gitignore pattern: `**/package-lock.json` reached the
nested copies and left the one in the root, so the fixture kept package-lock.json,
a.min.js and a.map that rg had dropped. Every exclusion is now listed twice, bare
and `**/`-anchored.

The fallback also skips a file holding a NUL byte, which is the rule rg uses to
call a file binary; the fixture's binary.dat no longer reaches the catalog. Perl's
own `-B` test was tried first and let that file through, since a few NUL bytes in
mostly ASCII stay under its 30% threshold.

Slurping with `-0777` and counting lines per file replaces `close ARGV if eof` and
keeps the numbering right.

Verified: on the fixture rg and the fallback agree except for a file with invalid
UTF-8 and no NUL, which the text now names as the best-effort limit; on this
repository both passes return byte-identical location lists.

* Name the force-added gitignored file as the second fallback limit

Reproduced on a fixture: a file that .gitignore covers but that `git add -f` put
in the index is skipped by rg, which goes by the ignore rules alone, and kept by
`--exclude-standard`, which sees it in the index.

Filtering those paths would need another `git check-ignore` stage in what is
already a long one-liner, so the text names the case instead, next to the invalid
UTF-8 one, and gives the command that lists them:
`git ls-files --cached --ignored --exclude-standard`. Rows from either kind get
dropped before scoring and the report says so.

* Skip symlinks in the perl fallback

rg follows a link only under --follow, so a fixture with real.md and a link.md
pointing at it gave rg one row and the fallback two, counting the same text twice.
`next if -l $ARGV` costs one token and closes the gap: both passes now return
real.md alone on that fixture, and byte-identical location lists on this
repository.

* Name the rg flag that pairs with dropping the symlink test

* Finalize v1.11.0 release details
2026-08-11 03:14:17 +03:00
2026-07-05 21:21:01 +03:00

Agent Skills

skills.sh

A collection of agent skills for Claude Code, Codex and other AI coding agents.

Skills

Skill Skill Version Release Description
scope-triage 1.0.3 v1.10.0 Classify request scope before design work, then route to direct implementation, a light spec, or a full design cycle.
plan-crafting 1.1.2 v1.10.0 Turn an approved design or settled requirements into a bite-sized, TDD-oriented implementation plan.
vitest 1.2.1 v1.10.0 Configure, write, debug, run, migrate, and audit Vitest tests for JavaScript/TypeScript projects.
typescript 1.3.2 v1.10.0 Configure tsconfig, diagnose compiler behavior, and audit or migrate TypeScript projects.
web-debug 1.3.2 v1.10.0 Debug and verify local web apps via Playwright.
echarts 1.1.2 v1.10.0 Build, audit, style, debug, and optimize Apache ECharts visualizations in vanilla JS, React, or Vue.
dashfix 1.1.0 v1.11.0 Ban typographic dashes in English text, check their form where a language's orthography requires them, audit a project, and score it 0-100.
negafix 1.1.0 v1.11.0 Ban negative parallelism ("it's not just X, it's Y"), audit prose for it, and score it 0-100.

Install

# All at once

npx skills add sentimony/skills -a codex claude-code -y

# Or each separately

npx skills add sentimony/skills -s scope-triage -a codex claude-code -y
npx skills add sentimony/skills -s plan-crafting -a codex claude-code -y
npx skills add sentimony/skills -s vitest -a codex claude-code -y
npx skills add sentimony/skills -s typescript -a codex claude-code -y
npx skills add sentimony/skills -s web-debug -a codex claude-code -y
npx skills add sentimony/skills -s echarts -a codex claude-code -y
npx skills add sentimony/skills -s dashfix -a codex claude-code -y
npx skills add sentimony/skills -s negafix -a codex claude-code -y

Have fun ;)

S
Description
echarts: You MUST use this when building, styling, debugging, or optimizing Apache ECharts charts in JavaScript, React, or Vue - setup, lifecycle, responsive resizing,…; web-debug: You MUST use this when interacting with or testing local web applications with Playwright - verifying frontend functionality, debugging UI behavior, capturing…; typescript: You MUST use this when configuring tsconfig, resolving compiler errors, debugging slow type-checking, fixing module resolution or ESM/CJS issues,…
Readme 1.1 MiB
Languages
Python 98.2%
Shell 0.6%
TypeScript 0.5%
HTML 0.4%
Vue 0.3%