Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsCommunityBlog
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

Back to skills

Zhtw Rules

ASecurity

What the gates cannot tell you about adding or changing a zh-TW rule - why assets/ruleset.json is the only place a vocabulary rule lives, the false-friend problem and the four gates that answer it, the corpus thresholds a rule has to clear, why positions are byte offsets through NFC, and how a rule reaches the scanner, the fixer and the browser build. Use when adding or disabling a rule, when a rule fires on native zh-TW prose, when a fix lands at the wrong offset, or when touching src/engine...

482 stars
0 votes
0 copies
0 views
Added 9/20/2026
developmentpythongoawsgit

Works with

climcp

Security Analysis

A100/100

Scanned 9/20/2026

Install to Claude Code

$npx -y skills add sysprog21/zhtw-mcp --skill zhtw-rules --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Zhtw Rules?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Zhtw Rules
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/sysprog21-zhtw-rules/badge)](https://www.skillsdirectory.com/skills/sysprog21-zhtw-rules)

More formats (shields.io, HTML) on the badges page.

Download Zip
Files
SKILL.md
---
name: zhtw-rules
description: What the gates cannot tell you about adding or changing a zh-TW rule - why assets/ruleset.json is the only place a vocabulary rule lives, the false-friend problem and the four gates that answer it, the corpus thresholds a rule has to clear, why positions are byte offsets through NFC, and how a rule reaches the scanner, the fixer and the browser build. Use when adding or disabling a rule, when a rule fires on native zh-TW prose, when a fix lands at the wrong offset, or when touching src/engine/scan.
---

# Changing what zhtw-mcp flags

`assets/ruleset.json` is the source of truth. `build.rs` serializes it into the
binary with postcard, `scripts/check-ruleset.py` owns its dedup, sort and field
order, and `src/rules/schema.rs` is the type the two agree on through the
generated `scripts/schema-facts.json`. Hand formatting is rewritten and the
indent gate fails on it, so the loop is: edit, `python3
scripts/check-ruleset.py --lint`, `make indent`.

## The false friend is the whole problem

A `from` term that is also valid zh-TW with a different meaning is the failure
mode this project has to defend against, because it turns the linter into
something people switch off. 文件 is "file" in zh-CN and "document" in zh-TW.
字體 is a typeface here and a font file there. An ungated rule for either fires
on correct prose.

Four answers, in order of how much they cost the reader:

- `disabled: true` when the term cannot be judged from the sentence at all.
- `context_clues` and `negative_context_clues` when a nearby word settles it.
- `exceptions` when a fixed phrase is the only safe carve-out.
- `editorial_confidence` for the milder case, and `context_suggestions` when
  the correction itself differs by domain.

The two terms above took different answers, which is the point of having four.
文件 to 檔案 is `disabled`, because a sentence holding it reads correctly under
either meaning. 字體 to 字型 ships enabled behind `context_clues`, because the
typeface sense travels with words the rule can look for.

A rule that needs none of these is a rule where the zh-CN form has no zh-TW
reading, which is most of the vocabulary list and none of the hard cases.

## The corpus is the argument, not the opinion

The assertions in `tests/corpus-evaluation.rs` are what settles whether a rule
pays for itself. `make corpus` prints their table, but it does not gate: cargo
autodiscovers that target, so `make check` has already run every one of them.
There are ten, not the three the printed table draws the eye to:

- Aggregate precision at 90% or better.
- Two native zh-TW false-positive rates, per fixture and repeat-weighted, each
  at 5% or less, because each is blind to what the other catches.
- Three safe-fix rates: 85% on the AI-generated corpus, which is the figure
  `CLAUDE.md` records as the contract, and 99% on both the zh-CN conversion and
  the native corpora.
- Four per-corpus floors, added after the other six because recall was printed
  on every run and asserted nowhere, which let two commits rework AI detection
  unnoticed: AI-generated recall 94% and precision 91%, zh-CN conversion recall
  98% and precision 96%. Per corpus rather than aggregate, because zh-CN carries
  roughly twice the true positives and would mask an AI detector going quiet.

Three more assert each corpus is still big enough to mean anything. A rule that
drops a false-positive gate is a rule that fires on `native-zh-tw.json`, which
is exactly the prose it is supposed to leave alone.

`expected_issues` and `expected_fixed` in a corpus fixture are deliberately
independent: the scanner reports confusable and clue-gated rules that the
`lexical_safe` fixer will not touch, so an issue without a replacement is
correct and not an omission.

## Positions are byte offsets, and not the obvious ones

Every offset a rule produces is a byte offset into the original text, mapped
back through NFC normalization and, for markdown, through pulldown-cmark event
ranges. Computing one on the normalized string alone gives a number that is
right for ASCII, right for most CJK, and wrong the moment a composed character
or a markdown construct appears before it. `src/engine/normalize.rs` holds the
offset map and `src/engine/lineindex.rs` turns an offset into a line and
column, in UTF-16 code units by default because that is what LSP clients read.

## One rule, three consumers

A rule reaches the CLI, the MCP server and the browser extension. The last one
is the one that gets forgotten: the extension builds the library with
`browser-wasm` and no `native`, and anything touching `std::fs`, `dirs` or
`rayon` has to be behind `#[cfg(feature = "native")]` or that build breaks.
`make check` lints the two non-default feature shapes for exactly this reason.

The fixer is the second consumer worth naming. A scanner detection is not
automatically a fix: `src/fixer.rs` applies only what is safe to apply without
reading the sentence, and a rule whose correction depends on context belongs in
`context_suggestions` rather than in the safe fixer.

## Where the passes live

```text
src/engine/scan/spelling.rs      Vocabulary rules out of the ruleset
src/engine/scan/case_rule.rs     Casing of Latin technical terms
src/engine/scan/punctuation.rs   Half-width to full-width, context sensitive;
                                 emits the quote issues quotes.rs decided on
src/engine/scan/quotes.rs        Which quotation marks convert at all, the
                                 depth-based pairing fix, hierarchy validation
src/engine/scan/spacing.rs       CJK to Latin and CJK to digit spacing
src/engine/scan/ellipsis.rs      Non-standard ellipsis to the MoE …… form
src/engine/scan/repetition.rs    Consecutive duplicates, an ASR and paste tell
src/engine/scan/acronym.rs       Rejoins a spaced acronym, C P U to CPU
src/engine/scan/grammar.rs       A-not-A, bare 是, nominalization, prepositions
src/engine/scan/rule_ir.rs       The matcher spelling.rs drives; the 臺/台 family
                                 is variant rules behind variant_normalization
src/engine/scan/overlap.rs       Resolves detections that cover the same span
src/engine/s2t.rs                Simplified to traditional, from the OpenCC tables
```

`tests/unit/engine/scan/tests_generated.rs` is misnamed and is not generated: it
holds the hand-written scanner tests split out of `scan/mod.rs`. Add a scanner
test there or in the pass's own test file under `tests/unit/`, never in the pass
itself, and add the corpus fixture separately when the rule is meant to move a
metric. zhtw-verify has the `#[path]` declaration a module uses to reach its
tests.

Attribution

sysprog21sysprog21
View sourceMore from sysprog21 →
SSkills DirectorySkills Directory

Know which skills are safe — weekly.

Best new skills + every skill we flagged as malicious. From the team that scanned 103,619.

Join free

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Know which skills are safe — weekly.

Best new skills + every skill we flagged as malicious. From the team that scanned 103,619.

Join free

Related Skills

Browser Extension Developer

Use this skill when developing or maintaining browser extension code in the `browser/` directory, including Chrome/Firefox/Edge compatibility, content scripts, background scripts, or i18n updates.

281612 votes

Seo Optimizer

SEO optimization with keyword analysis, readability assessment, technical validation, content quality. Use for search rankings, blog posts, content audits, or encountering keyword density, readability scores, meta tags, schema markup errors.

2132 votes

Google Official Seo Guide

Official Google SEO guide covering search optimization, best practices, Search Console, crawling, indexing, and improving website search visibility based on official Google documentation

1862 votes

Tanstack Start

Build a full-stack TanStack Start app on Cloudflare Workers from scratch — SSR, file-based routing, server functions, D1+Drizzle, better-auth, Tailwind v4+shadcn/ui. Use whenever the user mentions TanStack Start, asks to scaffold a full-stack Cloudflare app with SSR, wants an SSR dashboard, or asks for a React 19 + Cloudflare Workers app with file-based routing and server functions — even if they don't name TanStack Start specifically. No template repo — Claude generates every file fresh per ...

9881 votes

Pentest

PTES-aligned adversarial security audit for backend, frontend, and mobile applications. Produces a CVSS-scored Hacker Report with verified PoCs and phased remediation.

5491 votes
View all in development →