From harness-engineering
TypeScript/JavaScript harness configuration guidance. Covers Biome (format), Oxlint (lint), tsc (type check), dependency-cruiser or @softarc/sheriff (architecture boundaries), and Knip (dead code). Use when setting up TS harness, troubleshooting TS lint hook failures, choosing between ESLint and Oxlint, or enforcing layer boundaries in TS monorepos. Do NOT use for Go or Proto — see go-stack / proto-stack.
npx claudepluginhub toru-oizumi/claude-harness-engineering --plugin harness-engineeringThis skill uses the workspace's default tool permissions.
The TS side of the harness. Fast, Rust-based tooling so PostToolUse hooks finish in under a second.
Generates design tokens/docs from CSS/Tailwind/styled-components codebases, audits visual consistency across 10 dimensions, detects AI slop in UI.
Records polished WebM UI demo videos of web apps using Playwright with cursor overlay, natural pacing, and three-phase scripting. Activates for demo, walkthrough, screen recording, or tutorial requests.
Delivers idiomatic Kotlin patterns for null safety, immutability, sealed classes, coroutines, Flows, extensions, DSL builders, and Gradle DSL. Use when writing, reviewing, refactoring, or designing Kotlin code.
The TS side of the harness. Fast, Rust-based tooling so PostToolUse hooks finish in under a second.
| Role | Tool | Why |
|---|---|---|
| Format | Biome | Rust, ~50x faster than Prettier, same config for JS/TS/JSON/JSX |
| Lint | Oxlint | Rust, 50–100x faster than ESLint, covers ~400 common ESLint rules |
| Type check | tsc --noEmit | Still the only source of truth for types |
| Architecture | dependency-cruiser or @softarc/sheriff | Layer boundary enforcement |
| Dead code | Knip | Finds unused exports/files/deps (Vercel deleted 300k LOC with it) |
ESLint is fine but Node-based — PostToolUse hooks need to finish in <1s to feel responsive. Oxlint covers the common rules. If you need rules Oxlint doesn't have, run ESLint in CI, not in the hook.
Pick one. Don't run both.
Use ${CLAUDE_PLUGIN_ROOT}/templates/biome.json as the starting point. It has:
noExplicitAny as error in strict modeClean architecture boundaries for a typical Node.js backend:
src/
├── domain/ # No imports from anything below
├── application/ # May import domain
├── infrastructure/ # May import domain + application
└── interfaces/ # May import everything below
dependency-cruiser config enforcing this:
// .dependency-cruiser.js (NOTE: protected by pre-config-protect hook)
module.exports = {
forbidden: [
{
name: 'domain-no-outside',
severity: 'error',
from: { path: '^src/domain' },
to: { path: '^src/(application|infrastructure|interfaces)' },
},
{
name: 'application-no-infrastructure',
severity: 'error',
from: { path: '^src/application' },
to: { path: '^src/infrastructure' },
},
],
};
When you Write/Edit a .ts/.tsx file, post-edit-lint.js runs:
biome format --write <file> (silent auto-fix)oxlint --fix <file> (silent auto-fix)oxlint <file> (collect remaining violations)additionalContexttsc is NOT run in the hook (too slow for per-file). It's in lefthook pre-commit and CI.
tsconfig.json has trailing commas, Biome will format them out. Usually fine — tsc accepts both..eslintrc: configure via .oxlintrc.json or biome.json (Biome's lint side is compatible).edit-lint-feedback-loop — how PostToolUse hooks work end-to-endarchitecture-enforcement — dependency-cruiser deep diveharness-setup — bootstrap workflowSee gotchas.md.