From 1b061a2814810e009d1f5bd1d365c71afb4be384 Mon Sep 17 00:00:00 2001 From: Gianluca Carucci Date: Mon, 6 Jul 2026 23:57:04 +0200 Subject: [PATCH 1/4] [#232] feat: shared lint/format config guideline + setup-gates provisioning KB guideline (shared-config-package pattern, per-type overrides, tools/* reference) + setup-gates provisioning step (configs + husky pre-commit/pre-push, D21/Q11 default, adoption-overridable, idempotent). Way-of-working hook-manager field + docs site pointers. --- .../shared-lint-format-config-guideline.md | 5 + .../docs/reference/guidelines-catalog.mdx | 2 +- .../content/docs/tutorials/team-setup.mdx | 2 + .../.pair/adoption/tech/way-of-working.md | 2 + .../code-design/quality-standards/README.md | 2 + .../shared-config-packages.md | 95 +++++++++++++++++++ .../.skills/capability/setup-gates/SKILL.md | 38 ++++++-- 7 files changed, 138 insertions(+), 8 deletions(-) create mode 100644 .changeset/shared-lint-format-config-guideline.md create mode 100644 packages/knowledge-hub/dataset/.pair/knowledge/guidelines/code-design/quality-standards/shared-config-packages.md diff --git a/.changeset/shared-lint-format-config-guideline.md b/.changeset/shared-lint-format-config-guideline.md new file mode 100644 index 00000000..c55a0e6e --- /dev/null +++ b/.changeset/shared-lint-format-config-guideline.md @@ -0,0 +1,5 @@ +--- +'@pair/knowledge-hub': minor +--- + +Add shared-config-packages guideline (per-type overrides, `tools/*` reference) and extend `/pair-capability-setup-gates` with a provisioning step for shared lint/format configs + husky pre-commit/pre-push hooks (KB default, adoption-overridable). diff --git a/apps/website/content/docs/reference/guidelines-catalog.mdx b/apps/website/content/docs/reference/guidelines-catalog.mdx index be042d52..7f233892 100644 --- a/apps/website/content/docs/reference/guidelines-catalog.mdx +++ b/apps/website/content/docs/reference/guidelines-catalog.mdx @@ -58,7 +58,7 @@ Code organization, principles, and quality standards. | **Design Principles** | SOLID, DRY, KISS, composition over inheritance, evidence-based do/don't design rules | | **Framework Patterns** | Framework-specific patterns and best practices | | **Package Management** | Dependency management, monorepo patterns | -| **Quality Standards** | Code metrics, complexity thresholds, maintainability | +| **Quality Standards** | Code metrics, complexity thresholds, maintainability, shared lint/format config packages | ### Collaboration diff --git a/apps/website/content/docs/tutorials/team-setup.mdx b/apps/website/content/docs/tutorials/team-setup.mdx index 829338ae..f32ae683 100644 --- a/apps/website/content/docs/tutorials/team-setup.mdx +++ b/apps/website/content/docs/tutorials/team-setup.mdx @@ -137,6 +137,8 @@ Edit `.pair/adoption/tech/way-of-working.md` to define your team's quality gate: Every developer and every AI assistant will run these checks before committing. +Prefer automation over hand-editing: `/pair-capability-setup-gates` provisions shared lint/format config packages (per-type overrides for backend/frontend/shared-lib workspaces) plus pre-commit + pre-push hooks, defaulting to husky. See the [shared config packages guideline](https://github.com/foomakers/pair/blob/main/packages/knowledge-hub/dataset/.pair/knowledge/guidelines/code-design/quality-standards/shared-config-packages.md) for the pattern — pair's own `tools/*` is the reference implementation. Override the hook manager by recording your choice in `way-of-working.md` before running the skill. + ### 7. Record key decisions For significant decisions that need rationale, create Architecture Decision Records (`/pair-next` may suggest this when decisions are pending): diff --git a/packages/knowledge-hub/dataset/.pair/adoption/tech/way-of-working.md b/packages/knowledge-hub/dataset/.pair/adoption/tech/way-of-working.md index b7df6a12..52d37c11 100644 --- a/packages/knowledge-hub/dataset/.pair/adoption/tech/way-of-working.md +++ b/packages/knowledge-hub/dataset/.pair/adoption/tech/way-of-working.md @@ -12,6 +12,8 @@ This document defines the **validated development practices and team workflows** - `pnpm quality-gate` is the adopted project-level quality gate command. - Quality gate includes: type checking (`ts:check`), testing (`test`), linting (`lint`), formatting (`prettier:fix`). +- **Hook manager**: `husky` (KB default, decision D21/Q11) — pre-commit runs fast local checks, pre-push runs lint. Override here if the project uses a different hook manager (e.g. `lefthook`, `simple-git-hooks`); `/pair-capability-setup-gates` reads this override before provisioning. +- **Shared config packages**: see [shared-config-packages.md](../../knowledge/guidelines/code-design/quality-standards/shared-config-packages.md) for the lint/format/type-config pattern and per-type override structure. ### Custom Gate Registry diff --git a/packages/knowledge-hub/dataset/.pair/knowledge/guidelines/code-design/quality-standards/README.md b/packages/knowledge-hub/dataset/.pair/knowledge/guidelines/code-design/quality-standards/README.md index 90fc6e6f..3c55ab32 100644 --- a/packages/knowledge-hub/dataset/.pair/knowledge/guidelines/code-design/quality-standards/README.md +++ b/packages/knowledge-hub/dataset/.pair/knowledge/guidelines/code-design/quality-standards/README.md @@ -22,6 +22,7 @@ Quality standards provide guidance on linting, formatting, code metrics, coverag - `linting-tools.md` (recommended linters and rules) - `eslint.md` (ESLint configuration and conventions) - `prettier-formatting.md` (formatting rules) +- `shared-config-packages.md` (shared-config-package pattern, per-type overrides, `tools/*` reference) - `code-metrics.md` (metrics & measurement) - `coverage.md` (coverage targets and strategies) - `technical-debt.md` (tracking and remediation) @@ -66,6 +67,7 @@ Guidelines for linting, formatting, code metrics, test coverage and automation t - `linting-tools.md` - `eslint.md` - `prettier-formatting.md` +- `shared-config-packages.md` - `code-metrics.md` - `coverage.md` - `technical-debt.md` diff --git a/packages/knowledge-hub/dataset/.pair/knowledge/guidelines/code-design/quality-standards/shared-config-packages.md b/packages/knowledge-hub/dataset/.pair/knowledge/guidelines/code-design/quality-standards/shared-config-packages.md new file mode 100644 index 00000000..4ac98681 --- /dev/null +++ b/packages/knowledge-hub/dataset/.pair/knowledge/guidelines/code-design/quality-standards/shared-config-packages.md @@ -0,0 +1,95 @@ +# Shared Config Packages + +## Overview + +Lint, format, type-check and markdown-lint rules duplicated across workspaces drift: each copy gets patched independently until "consistent tooling" is a fiction. The **shared-config-package pattern** fixes this by extracting each tool's configuration into its own workspace package, versioned like any other dependency, consumed via the tool's native extension mechanism (`extends`, `require`, or a `prettier`/similar field). One source of truth per concern; workspaces only carry local overrides. + +This guideline documents the pattern generically and then walks through pair's own `tools/*` packages as the reference implementation (R7.1). + +## The Pattern + +1. **One package per concern** — do not bundle lint + format + types into a single "tooling" package. Each tool gets its own package (`*-config`) so it can version and release independently. +2. **Consume via the tool's own mechanism** — don't invent a custom loader. Use `extends` for `tsconfig.json`, `require`/`extends` for ESLint flat config, a `"prettier"` field in `package.json`, and a config-discovery bin wrapper for tools that don't support a field (markdownlint). +3. **Package the enforcement, not just the rules** — ship bin wrappers (`lint`, `lint-fix`, `prettier-check`, `mdlint:check`, …) alongside the config so workspace `package.json` scripts stay one-liners instead of re-declaring flags/paths everywhere. +4. **Workspace configs carry only local overrides** — `paths`, `references`, `outDir`, package-specific `ignores`. Everything shared lives in the config package. +5. **Version like a dependency** — `@scope/*-config` is a `workspace:*` devDependency; bumping it (e.g. tightening a rule) is a normal dependency update, reviewed like one. + +## Per-Type Overrides + +Not every workspace needs the same ruleset. Split each config package into a **base** preset plus **type-specific** presets that extend it: + +| Type | What changes vs base | Typical need | +| --- | --- | --- | +| Backend / service (Node CLI, API, worker) | Node types, module resolution | `node.json`-style preset | +| Frontend (web app) | JSX, DOM types, React lint rules | `ui.json`-style preset + React lint overlay | +| Shared lib | Depends on what the lib *is* — a logic-only lib behaves like backend, a UI component lib behaves like frontend | Pick the matching preset, not a third one | + +Two rules keep this from becoming per-stack special-casing: + +- **Only split where the tool actually needs it.** TypeScript compiler options and lint rules diverge by runtime (Node vs browser) — split those. Formatting does not diverge by type — keep one Prettier config for everything. +- **The taxonomy is about the preset the package needs, not the package's category.** A "shared lib" is not a third preset; it picks whichever existing preset (`node`/`ui`) matches what it ships. + +## Reference Implementation: pair's `tools/*` + +pair's own monorepo is the canonical example. Four config packages, each consumed differently based on what the underlying tool supports: + +| Package | Presets / exports | Consumption | Bin wrappers | +| --- | --- | --- | --- | +| `tools/ts-config` (`@pair/ts-config`) | `base.json` → `node.json` / `ui.json` | `tsconfig.json`: `"extends": "@pair/ts-config/node.json"` | — (`tsc` runs directly) | +| `tools/eslint-config` (`@pair/eslint-config`) | `eslint.config.cjs` (base) → `eslint.config.react.cjs` (React overlay) | Base: bin wrappers apply it with no local file needed. Override: local `eslint.config.cjs` does `module.exports = require('@pair/eslint-config/eslint.config.react.cjs')` | `lint`, `lint-fix`, `eslint` | +| `tools/prettier-config` (`@pair/prettier-config`) | single `.prettierrc.json` (no per-type split — formatting doesn't diverge by type) | `package.json`: `"prettier": "@pair/prettier-config"` | `prettier-check`, `prettier-fix` | +| `tools/markdownlint-config` (`@pair/markdownlint-config`) | single `.markdownlint.jsonc` (+ ignore file) | discovered by the bin wrappers, no per-package config file | `markdownlint-check`, `markdownlint-fix` | + +Per-type mapping in practice — Node/service/lib workspaces (`apps/pair-cli`, `packages/knowledge-hub`, `packages/content-ops`) extend `@pair/ts-config/node.json` and take the ESLint base config as-is. Frontend and UI-lib workspaces (`apps/website`, `packages/brand`) extend `@pair/ts-config/ui.json` and override `eslint.config.cjs` to layer the React overlay: + +```jsonc +// apps/pair-cli/tsconfig.json (backend/CLI — node preset) +{ "extends": "@pair/ts-config/node.json", "compilerOptions": { /* local overrides only */ } } +``` + +```jsonc +// apps/website/tsconfig.json (frontend — ui preset) +{ "extends": "@pair/ts-config/ui.json", "compilerOptions": { "jsx": "preserve" /* local overrides only */ } } +``` + +```js +// packages/brand/eslint.config.cjs (shared UI lib — same override as frontend, because it ships JSX) +module.exports = require('@pair/eslint-config/eslint.config.react.cjs') +``` + +Every consuming workspace declares the config packages as ordinary `workspace:*` devDependencies (see any `apps/*/package.json` or `packages/*/package.json`) — they are dependencies, not magic. + +## Enforcement: Hooks + +Configs without enforcement get bypassed under deadline pressure. Wire two git hooks: + +- **Pre-commit** — fast local checks (type-check and/or lint on staged files). +- **Pre-push** — the full quality-gate command (lint + test + type-check), so nothing broken reaches CI. + +**Husky is the KB default hook manager** (D21 / Q11) — `.husky/pre-commit` and `.husky/pre-push` scripts, wired via `"prepare": "husky install"` in the root `package.json`. pair's own hooks are two one-liners: + +```sh +# .husky/pre-commit — fast local feedback +pnpm ts:check +``` + +```sh +# .husky/pre-push — full lint before code leaves the machine +pnpm quality-gate +``` + +A leaner project can put the actual lint/format commands on pre-commit instead (e.g. `lint-staged` running `eslint --fix` + `prettier --write` on staged files) and keep pre-push as the guard for anything pre-commit skipped. Either way, pre-push must run lint at minimum. + +Adoption can override the hook manager (e.g. `lefthook`, `simple-git-hooks`) by recording the choice in `way-of-working.md`; `/pair-capability-setup-gates` reads that override before provisioning. + +## Non-JS / Polyglot Projects + +The shared-config-package mechanism above (`extends`, `require`, package-manager fields) is JS/TS-tooling-specific. For other ecosystems, the *pattern* still applies — one versioned config artifact per concern, per-type presets, hook-enforced — but provisioning cannot generate it automatically. In that case `/pair-capability-setup-gates` documents the pattern and points to the ecosystem's equivalent (e.g. a shared `ruff`/`clippy`/`golangci-lint` config package) rather than generating JS config files. + +## Related + +- [linting-tools.md](linting-tools.md) — tool selection matrix +- [eslint.md](eslint.md), [prettier-formatting.md](prettier-formatting.md) — per-tool configuration detail +- [automation.md](automation.md) — pre-commit/CI automation patterns +- `/pair-capability-setup-gates` — provisions this pattern on a project (see SKILL.md provisioning step) +- ADR-006 (`.pair/adoption/tech/adr/adr-006-shared-tsconfig.md`, pair's own dogfooded adoption) — the decision record for `tools/ts-config` diff --git a/packages/knowledge-hub/dataset/.skills/capability/setup-gates/SKILL.md b/packages/knowledge-hub/dataset/.skills/capability/setup-gates/SKILL.md index 455c2b27..4ad1035c 100644 --- a/packages/knowledge-hub/dataset/.skills/capability/setup-gates/SKILL.md +++ b/packages/knowledge-hub/dataset/.skills/capability/setup-gates/SKILL.md @@ -1,6 +1,6 @@ --- name: setup-gates -description: "Configures CI/CD quality gates per quality-assurance guidelines, producing pipeline configuration for the adopted tech stack. Reads existing gate config from way-of-working. Idempotent: detects existing configuration, confirms rather than re-configuring." +description: "Configures CI/CD quality gates per quality-assurance guidelines, producing pipeline configuration for the adopted tech stack. Provisions shared lint/format config packages and husky pre-commit/pre-push hooks. Reads existing gate config from way-of-working. Idempotent: detects existing configuration, confirms rather than re-configuring." version: 0.4.1 author: Foomakers --- @@ -27,13 +27,16 @@ Configure CI/CD quality gates for the project. Reads quality assurance guideline 1. **Check**: Read [way-of-working.md](../../../.pair/adoption/tech/way-of-working.md) → look for Quality Gates section and Custom Gate Registry. 2. **Check**: Scan for existing CI/CD pipeline files (`.github/workflows/`, `.gitlab-ci.yml`, `Jenkinsfile`, etc.). -3. **Branch**: - - **Gates fully configured** (Quality Gates section + Custom Gate Registry + pipeline files exist) → present current config: +3. **Check**: Scan for existing shared lint/format config packages (e.g. `tools/*-config`, `packages/*-config`) and hook manager setup (`.husky/`, `lefthook.yml`, `.git/hooks/` via `simple-git-hooks`, etc.). +4. **Branch**: + - **Gates fully configured** (Quality Gates section + Custom Gate Registry + pipeline files + shared config/hooks exist) → present current config: > Quality gates already configured: > - Quality gate command: `[command]` > - Custom gates: [N gates listed] > - CI/CD pipeline: [file(s)] + > - Shared config packages: [package list | none found] + > - Hook manager: [husky | override | none found] > > Update configuration? (Only if developer explicitly requests.) @@ -47,6 +50,7 @@ Configure CI/CD quality gates for the project. Reads quality assurance guideline 1. **Act**: Read quality assurance guidelines: - [quality-assurance.md](../../../.pair/knowledge/guidelines/technical-standards/git-workflow/quality-assurance.md) — gate types and checklists - [quality-gates.md](../../../.pair/knowledge/guidelines/quality-assurance/quality-standards/quality-gates.md) — gate framework and registry format + - [shared-config-packages.md](../../../.pair/knowledge/guidelines/code-design/quality-standards/shared-config-packages.md) — shared-config-package pattern, per-type overrides, `tools/*` reference implementation 2. **Act**: Read adopted tech stack: - [tech-stack.md](../../../.pair/adoption/tech/tech-stack.md) — languages, test framework, linter, formatter - [way-of-working.md](../../../.pair/adoption/tech/way-of-working.md) — existing process @@ -96,12 +100,28 @@ Configure CI/CD quality gates for the project. Reads quality assurance guideline - Other → document commands for manual pipeline setup 3. **Verify**: Configuration files written. -### Step 5: Record Decision +### Step 5: Provision Shared Lint/Format Config + Hooks + +1. **Check**: For each config already detected in Step 1 that is not conflicting, skip provisioning it and note it as already present. +2. **Act**: Following [shared-config-packages.md](../../../.pair/knowledge/guidelines/code-design/quality-standards/shared-config-packages.md), provision one shared config package per lint/format concern the adopted tech stack uses (lint, format, types, and any project-specific linters). Split each into base + per-type presets (backend/frontend/shared-lib) only where the tool's rules actually diverge by runtime — pair's own `tools/*` is the reference implementation. +3. **Act**: Install the hook manager and wire the hooks: + - **Husky is the KB default** (decision D21/Q11). Use it unless [way-of-working.md](../../../.pair/adoption/tech/way-of-working.md) records a hook-manager override — if it does, use the overridden tool instead. + - `.husky/pre-commit` (or equivalent) — fast local checks (lint and/or type-check). + - `.husky/pre-push` (or equivalent) — pre-push lint (at minimum the adopted lint command; may be the full quality-gate command). + - Wire the install step (e.g. `"prepare": "husky install"`) into the root `package.json`. +4. **Verify**: Run the adopted lint command — it passes out of the box (AC3). Confirm the hook files are executable and fire on a trial commit/push. + +**Edge Cases:** + +- **Existing conflicting config** (a workspace already has its own lint/format config file that would be replaced): ask before overwriting — "Found existing `[file]`. Replace with the shared config, keep it, or merge?" Never overwrite silently. +- **Non-JS project**: the shared-config-package mechanism (`extends`/`require`/package-manager fields) is JS/TS-specific. Degrade to documenting the pattern generically (see shared-config-packages.md § Non-JS / Polyglot Projects) and pointing to the ecosystem's equivalent config package; skip file generation. + +### Step 6: Record Decision 1. **Act**: Compose `/record-decision`: - `$type: non-architectural` - `$topic: quality-gate-configuration` - - `$summary: "Quality gates configured: [gate list]. Command: [command]. CI: [pipeline type]."` + - `$summary: "Quality gates configured: [gate list]. Command: [command]. CI: [pipeline type]. Shared config packages: [list]. Hook manager: [husky | override]."` 2. **Verify**: Decision recorded. ## Output Format @@ -113,6 +133,8 @@ GATE CONFIGURATION COMPLETE: ├── CI: [N gates configured] ├── Pre-production: [N gates configured | N/A] ├── Pipeline: [file path | manual] +├── Shared configs: [package list | N/A — non-JS, documented pointer only] +├── Hooks: [husky pre-commit + pre-push | override: | N/A] ├── Adoption: [way-of-working.md — updated] ├── Record: [ADL path — created] └── Status: [Complete | Confirmed existing | Updated] @@ -135,10 +157,12 @@ When invoked **independently**: - If tech-stack.md is not found, ask developer for tooling choices to generate appropriate gate commands. - If `/record-decision` is not installed, warn and skip decision recording. - If no CI/CD platform is detectable, document gate commands for manual execution and skip pipeline file generation. +- If the project is not JS/TS, document the shared-config-package pattern generically (see [shared-config-packages.md](../../../.pair/knowledge/guidelines/code-design/quality-standards/shared-config-packages.md) § Non-JS / Polyglot Projects) and skip config-file generation — point to the ecosystem's equivalent shared config package. ## Notes -- This skill **modifies files** — it writes to way-of-working.md and creates/updates CI/CD pipeline configuration. -- **Idempotent**: re-invocation on an already-configured project confirms the existing configuration. Update only on explicit developer request. +- This skill **modifies files** — it writes to way-of-working.md, creates/updates CI/CD pipeline configuration, and provisions shared lint/format config packages + hook manager files (`.husky/` by default). +- **Idempotent**: re-invocation on an already-configured project confirms the existing configuration, including already-provisioned shared configs and hooks. Update only on explicit developer request. If a conflicting local config is found, ask before overwriting — never overwrite silently. - Gate commands must be executable in the project's development environment. Verify commands exist before writing. - Custom Gate Registry format follows the table schema from [quality-gates.md](../../../.pair/knowledge/guidelines/quality-assurance/quality-standards/quality-gates.md): Order, Gate, Command, Scope Key, Required, Description. +- **Hook manager default**: husky (decision D21/Q11). Adoption can override — record the override in [way-of-working.md](../../../.pair/adoption/tech/way-of-working.md) and this skill reads it before provisioning. From ae52e3b1b1cc85309853a9bbab44fd4275c83edc Mon Sep 17 00:00:00 2001 From: Gianluca Carucci Date: Tue, 7 Jul 2026 09:54:29 +0200 Subject: [PATCH 2/4] =?UTF-8?q?[#232]=20fix:=20gate=20hook-manager=20choic?= =?UTF-8?q?e=20on=20Step=201.3=20detection;=20correct=20mdlint=20bin=20nam?= =?UTF-8?q?ing;=20add=20eslint=E2=86=92shared-config-packages=20link?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Step 5.3 now defers to on-disk hook-manager detection before defaulting to husky, matching Step 5.1's skip-if-detected rule. shared-config-packages.md distinguishes the markdownlint-check bin from the mdlint:check root script alias. eslint.md links forward to shared-config-packages.md. --- .../guidelines/code-design/quality-standards/eslint.md | 2 +- .../code-design/quality-standards/shared-config-packages.md | 2 +- .../dataset/.skills/capability/setup-gates/SKILL.md | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/knowledge-hub/dataset/.pair/knowledge/guidelines/code-design/quality-standards/eslint.md b/packages/knowledge-hub/dataset/.pair/knowledge/guidelines/code-design/quality-standards/eslint.md index b14d419c..4ab96143 100644 --- a/packages/knowledge-hub/dataset/.pair/knowledge/guidelines/code-design/quality-standards/eslint.md +++ b/packages/knowledge-hub/dataset/.pair/knowledge/guidelines/code-design/quality-standards/eslint.md @@ -115,7 +115,7 @@ For existing codebases, introduce ESLint rules gradually: ### Team Configuration -**Shared Config Package**: Create a shared ESLint configuration package for consistency across projects. This centralizes rule decisions and makes updates easier. +**Shared Config Package**: Create a shared ESLint configuration package for consistency across projects. This centralizes rule decisions and makes updates easier. See [shared-config-packages.md](shared-config-packages.md) for the full pattern (per-type presets, bin wrappers, reference implementation). **Rule Documentation**: Document the reasoning behind custom rules, especially those that differ from community standards. This helps team members understand the rationale. diff --git a/packages/knowledge-hub/dataset/.pair/knowledge/guidelines/code-design/quality-standards/shared-config-packages.md b/packages/knowledge-hub/dataset/.pair/knowledge/guidelines/code-design/quality-standards/shared-config-packages.md index 4ac98681..4b528cdd 100644 --- a/packages/knowledge-hub/dataset/.pair/knowledge/guidelines/code-design/quality-standards/shared-config-packages.md +++ b/packages/knowledge-hub/dataset/.pair/knowledge/guidelines/code-design/quality-standards/shared-config-packages.md @@ -10,7 +10,7 @@ This guideline documents the pattern generically and then walks through pair's o 1. **One package per concern** — do not bundle lint + format + types into a single "tooling" package. Each tool gets its own package (`*-config`) so it can version and release independently. 2. **Consume via the tool's own mechanism** — don't invent a custom loader. Use `extends` for `tsconfig.json`, `require`/`extends` for ESLint flat config, a `"prettier"` field in `package.json`, and a config-discovery bin wrapper for tools that don't support a field (markdownlint). -3. **Package the enforcement, not just the rules** — ship bin wrappers (`lint`, `lint-fix`, `prettier-check`, `mdlint:check`, …) alongside the config so workspace `package.json` scripts stay one-liners instead of re-declaring flags/paths everywhere. +3. **Package the enforcement, not just the rules** — ship bin wrappers (`lint`, `lint-fix`, `prettier-check`, `markdownlint-check`, …) alongside the config so workspace `package.json` scripts stay one-liners instead of re-declaring flags/paths everywhere. (`mdlint:check` is the root script alias that calls the `markdownlint-check` bin — not a bin name itself.) 4. **Workspace configs carry only local overrides** — `paths`, `references`, `outDir`, package-specific `ignores`. Everything shared lives in the config package. 5. **Version like a dependency** — `@scope/*-config` is a `workspace:*` devDependency; bumping it (e.g. tightening a rule) is a normal dependency update, reviewed like one. diff --git a/packages/knowledge-hub/dataset/.skills/capability/setup-gates/SKILL.md b/packages/knowledge-hub/dataset/.skills/capability/setup-gates/SKILL.md index 4ad1035c..ff7a4549 100644 --- a/packages/knowledge-hub/dataset/.skills/capability/setup-gates/SKILL.md +++ b/packages/knowledge-hub/dataset/.skills/capability/setup-gates/SKILL.md @@ -105,7 +105,8 @@ Configure CI/CD quality gates for the project. Reads quality assurance guideline 1. **Check**: For each config already detected in Step 1 that is not conflicting, skip provisioning it and note it as already present. 2. **Act**: Following [shared-config-packages.md](../../../.pair/knowledge/guidelines/code-design/quality-standards/shared-config-packages.md), provision one shared config package per lint/format concern the adopted tech stack uses (lint, format, types, and any project-specific linters). Split each into base + per-type presets (backend/frontend/shared-lib) only where the tool's rules actually diverge by runtime — pair's own `tools/*` is the reference implementation. 3. **Act**: Install the hook manager and wire the hooks: - - **Husky is the KB default** (decision D21/Q11). Use it unless [way-of-working.md](../../../.pair/adoption/tech/way-of-working.md) records a hook-manager override — if it does, use the overridden tool instead. + - **Check Step 1.3 first**: if a hook manager was already detected on disk, it is the de facto override — use it, record it in [way-of-working.md](../../../.pair/adoption/tech/way-of-working.md) if not already recorded, and skip installing husky. + - **Otherwise, husky is the KB default** (decision D21/Q11). Use it unless [way-of-working.md](../../../.pair/adoption/tech/way-of-working.md) records a hook-manager override — if it does, use the overridden tool instead. - `.husky/pre-commit` (or equivalent) — fast local checks (lint and/or type-check). - `.husky/pre-push` (or equivalent) — pre-push lint (at minimum the adopted lint command; may be the full quality-gate command). - Wire the install step (e.g. `"prepare": "husky install"`) into the root `package.json`. From b2d1eee8ef08c9d911fc39e87201e542ad7712ae Mon Sep 17 00:00:00 2001 From: Gianluca Carucci Date: Tue, 7 Jul 2026 11:43:33 +0200 Subject: [PATCH 3/4] [#232] chore: remove changeset (deferred to release batch) --- .changeset/shared-lint-format-config-guideline.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .changeset/shared-lint-format-config-guideline.md diff --git a/.changeset/shared-lint-format-config-guideline.md b/.changeset/shared-lint-format-config-guideline.md deleted file mode 100644 index c55a0e6e..00000000 --- a/.changeset/shared-lint-format-config-guideline.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@pair/knowledge-hub': minor ---- - -Add shared-config-packages guideline (per-type overrides, `tools/*` reference) and extend `/pair-capability-setup-gates` with a provisioning step for shared lint/format configs + husky pre-commit/pre-push hooks (KB default, adoption-overridable). From 109fd2b737a5b6108444d8dfd0391d002f7f93a9 Mon Sep 17 00:00:00 2001 From: Gianluca Carucci Date: Wed, 8 Jul 2026 11:55:48 +0200 Subject: [PATCH 4/4] [#232] fix: sync installed setup-gates mirror, execute fixture-bootstrap QA, record D21/Q11 ADL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Sync .claude/skills/pair-capability-setup-gates/SKILL.md (installed mirror) with the dataset source: Step 1.3 detection, Step 5 provisioning (shared configs + husky hooks), edge cases, Output Format/Graceful Degradation/Notes updates, prefix-transformed (/pair-capability-record-decision, /pair-process-bootstrap, /pair-capability-setup-gates). - Execute the AC3 fixture-bootstrap QA (T-3): real fixture project, no prior config/hooks; provisioned @pair/eslint-config + @pair/prettier-config via the real bin-wrapper consumption mechanism; installed husky pre-commit/pre-push. Verified: pre-commit blocks a real lint violation, passes clean after fix; pre-push runs lint+prettier-check green. - Record decision-log/2026-07-08-husky-default-hook-manager.md (D21/Q11): the story's own AC/Business Rules cited "decision Q11" and "D21" with no backing record — closes the gap. Refs: #232 --- .../pair-capability-setup-gates/SKILL.md | 39 ++++++++++++++--- .../2026-07-08-husky-default-hook-manager.md | 43 +++++++++++++++++++ 2 files changed, 75 insertions(+), 7 deletions(-) create mode 100644 .pair/adoption/decision-log/2026-07-08-husky-default-hook-manager.md diff --git a/.claude/skills/pair-capability-setup-gates/SKILL.md b/.claude/skills/pair-capability-setup-gates/SKILL.md index 1b152180..436a265d 100644 --- a/.claude/skills/pair-capability-setup-gates/SKILL.md +++ b/.claude/skills/pair-capability-setup-gates/SKILL.md @@ -1,6 +1,6 @@ --- name: pair-capability-setup-gates -description: "Configures CI/CD quality gates per quality-assurance guidelines, producing pipeline configuration for the adopted tech stack. Reads existing gate config from way-of-working. Idempotent: detects existing configuration, confirms rather than re-configuring." +description: "Configures CI/CD quality gates per quality-assurance guidelines, producing pipeline configuration for the adopted tech stack. Provisions shared lint/format config packages and husky pre-commit/pre-push hooks. Reads existing gate config from way-of-working. Idempotent: detects existing configuration, confirms rather than re-configuring." version: 0.4.1 author: Foomakers --- @@ -27,13 +27,16 @@ Configure CI/CD quality gates for the project. Reads quality assurance guideline 1. **Check**: Read [way-of-working.md](../../../.pair/adoption/tech/way-of-working.md) → look for Quality Gates section and Custom Gate Registry. 2. **Check**: Scan for existing CI/CD pipeline files (`.github/workflows/`, `.gitlab-ci.yml`, `Jenkinsfile`, etc.). -3. **Branch**: - - **Gates fully configured** (Quality Gates section + Custom Gate Registry + pipeline files exist) → present current config: +3. **Check**: Scan for existing shared lint/format config packages (e.g. `tools/*-config`, `packages/*-config`) and hook manager setup (`.husky/`, `lefthook.yml`, `.git/hooks/` via `simple-git-hooks`, etc.). +4. **Branch**: + - **Gates fully configured** (Quality Gates section + Custom Gate Registry + pipeline files + shared config/hooks exist) → present current config: > Quality gates already configured: > - Quality gate command: `[command]` > - Custom gates: [N gates listed] > - CI/CD pipeline: [file(s)] + > - Shared config packages: [package list | none found] + > - Hook manager: [husky | override | none found] > > Update configuration? (Only if developer explicitly requests.) @@ -47,6 +50,7 @@ Configure CI/CD quality gates for the project. Reads quality assurance guideline 1. **Act**: Read quality assurance guidelines: - [quality-assurance.md](../../../.pair/knowledge/guidelines/technical-standards/git-workflow/quality-assurance.md) — gate types and checklists - [quality-gates.md](../../../.pair/knowledge/guidelines/quality-assurance/quality-standards/quality-gates.md) — gate framework and registry format + - [shared-config-packages.md](../../../.pair/knowledge/guidelines/code-design/quality-standards/shared-config-packages.md) — shared-config-package pattern, per-type overrides, `tools/*` reference implementation 2. **Act**: Read adopted tech stack: - [tech-stack.md](../../../.pair/adoption/tech/tech-stack.md) — languages, test framework, linter, formatter - [way-of-working.md](../../../.pair/adoption/tech/way-of-working.md) — existing process @@ -96,12 +100,29 @@ Configure CI/CD quality gates for the project. Reads quality assurance guideline - Other → document commands for manual pipeline setup 3. **Verify**: Configuration files written. -### Step 5: Record Decision +### Step 5: Provision Shared Lint/Format Config + Hooks + +1. **Check**: For each config already detected in Step 1 that is not conflicting, skip provisioning it and note it as already present. +2. **Act**: Following [shared-config-packages.md](../../../.pair/knowledge/guidelines/code-design/quality-standards/shared-config-packages.md), provision one shared config package per lint/format concern the adopted tech stack uses (lint, format, types, and any project-specific linters). Split each into base + per-type presets (backend/frontend/shared-lib) only where the tool's rules actually diverge by runtime — pair's own `tools/*` is the reference implementation. +3. **Act**: Install the hook manager and wire the hooks: + - **Check Step 1.3 first**: if a hook manager was already detected on disk, it is the de facto override — use it, record it in [way-of-working.md](../../../.pair/adoption/tech/way-of-working.md) if not already recorded, and skip installing husky. + - **Otherwise, husky is the KB default** (decision D21/Q11). Use it unless [way-of-working.md](../../../.pair/adoption/tech/way-of-working.md) records a hook-manager override — if it does, use the overridden tool instead. + - `.husky/pre-commit` (or equivalent) — fast local checks (lint and/or type-check). + - `.husky/pre-push` (or equivalent) — pre-push lint (at minimum the adopted lint command; may be the full quality-gate command). + - Wire the install step (e.g. `"prepare": "husky install"`) into the root `package.json`. +4. **Verify**: Run the adopted lint command — it passes out of the box (AC3). Confirm the hook files are executable and fire on a trial commit/push. + +**Edge Cases:** + +- **Existing conflicting config** (a workspace already has its own lint/format config file that would be replaced): ask before overwriting — "Found existing `[file]`. Replace with the shared config, keep it, or merge?" Never overwrite silently. +- **Non-JS project**: the shared-config-package mechanism (`extends`/`require`/package-manager fields) is JS/TS-specific. Degrade to documenting the pattern generically (see shared-config-packages.md § Non-JS / Polyglot Projects) and pointing to the ecosystem's equivalent config package; skip file generation. + +### Step 6: Record Decision 1. **Act**: Compose `/pair-capability-record-decision`: - `$type: non-architectural` - `$topic: quality-gate-configuration` - - `$summary: "Quality gates configured: [gate list]. Command: [command]. CI: [pipeline type]."` + - `$summary: "Quality gates configured: [gate list]. Command: [command]. CI: [pipeline type]. Shared config packages: [list]. Hook manager: [husky | override]."` 2. **Verify**: Decision recorded. ## Output Format @@ -113,6 +134,8 @@ GATE CONFIGURATION COMPLETE: ├── CI: [N gates configured] ├── Pre-production: [N gates configured | N/A] ├── Pipeline: [file path | manual] +├── Shared configs: [package list | N/A — non-JS, documented pointer only] +├── Hooks: [husky pre-commit + pre-push | override: | N/A] ├── Adoption: [way-of-working.md — updated] ├── Record: [ADL path — created] └── Status: [Complete | Confirmed existing | Updated] @@ -135,10 +158,12 @@ When invoked **independently**: - If tech-stack.md is not found, ask developer for tooling choices to generate appropriate gate commands. - If `/pair-capability-record-decision` is not installed, warn and skip decision recording. - If no CI/CD platform is detectable, document gate commands for manual execution and skip pipeline file generation. +- If the project is not JS/TS, document the shared-config-package pattern generically (see [shared-config-packages.md](../../../.pair/knowledge/guidelines/code-design/quality-standards/shared-config-packages.md) § Non-JS / Polyglot Projects) and skip config-file generation — point to the ecosystem's equivalent shared config package. ## Notes -- This skill **modifies files** — it writes to way-of-working.md and creates/updates CI/CD pipeline configuration. -- **Idempotent**: re-invocation on an already-configured project confirms the existing configuration. Update only on explicit developer request. +- This skill **modifies files** — it writes to way-of-working.md, creates/updates CI/CD pipeline configuration, and provisions shared lint/format config packages + hook manager files (`.husky/` by default). +- **Idempotent**: re-invocation on an already-configured project confirms the existing configuration, including already-provisioned shared configs and hooks. Update only on explicit developer request. If a conflicting local config is found, ask before overwriting — never overwrite silently. - Gate commands must be executable in the project's development environment. Verify commands exist before writing. - Custom Gate Registry format follows the table schema from [quality-gates.md](../../../.pair/knowledge/guidelines/quality-assurance/quality-standards/quality-gates.md): Order, Gate, Command, Scope Key, Required, Description. +- **Hook manager default**: husky (decision D21/Q11). Adoption can override — record the override in [way-of-working.md](../../../.pair/adoption/tech/way-of-working.md) and this skill reads it before provisioning. diff --git a/.pair/adoption/decision-log/2026-07-08-husky-default-hook-manager.md b/.pair/adoption/decision-log/2026-07-08-husky-default-hook-manager.md new file mode 100644 index 00000000..582bc333 --- /dev/null +++ b/.pair/adoption/decision-log/2026-07-08-husky-default-hook-manager.md @@ -0,0 +1,43 @@ +# Decision: Husky as Default Git Hook Manager + +## Date + +2026-07-08 + +## Status + +Active + +## Category + +Tooling Preference + +## Context + +Story #232 ("Shared lint/format config guideline + setup-gates provisioning") extends `pair-capability-setup-gates` to provision Git hooks (pre-commit lint/type-check, pre-push lint) alongside shared lint/format config packages. This requires a KB-wide default hook manager so `setup-gates` has a deterministic choice when a project has no hook manager on disk yet. + +During #232's refinement session this was resolved as an open question (**Q11**) and recorded only in the story body's "Refinement Session Insights" ("Q11 decided — husky default with adoption override") — never formalized as a decision record. The story's own Acceptance Criteria and Business Rules reference "decision Q11" and "D21" as if a durable record existed, creating a dangling citation. This ADL closes that gap. + +## Decision + +**Husky is the KB default Git hook manager.** `pair-capability-setup-gates` installs husky (`.husky/pre-commit`, `.husky/pre-push`, `"prepare": "husky install"`) when provisioning hooks on a project with no hook manager already detected on disk. + +This follows **D21** ("Adoption = solo delta" — convention over configuration): the default lives entirely in the KB, so a project that accepts husky writes nothing extra to its adoption files. A project may override the hook manager by recording the override in [way-of-working.md](../../../.pair/adoption/tech/way-of-working.md); `setup-gates` reads that override before defaulting to husky, and an already-detected on-disk hook manager (Step 1.3 of `SKILL.md`) takes precedence over both. + +## Alternatives Considered + +- **lefthook**: faster (Go binary, no Node dependency), but adds a non-JS toolchain requirement to every bootstrapped project — inconsistent with the KB's JS/TS-first reference implementation (`tools/*` shared config packages already assume a Node toolchain). +- **simple-git-hooks**: minimal footprint, but lacks husky's `prepare` lifecycle integration and is less commonly known, raising onboarding friction for contributors already familiar with husky from this monorepo's own tooling. +- **No default (always ask)**: rejected — contradicts D21's convention-over-configuration principle; would force every bootstrap to answer a question with an obvious, low-stakes default. + +## Consequences + +- `pair-capability-setup-gates` (both the dataset source and the installed mirror) provisions husky by default; no adoption file changes are required for projects that accept the default. +- Projects that already use a different hook manager, or that explicitly record an override in `way-of-working.md`, are unaffected — `setup-gates` defers to that choice. +- Non-JS projects degrade to a documentation pointer (see [shared-config-packages.md](../../../.pair/knowledge/guidelines/code-design/quality-standards/shared-config-packages.md) § Non-JS / Polyglot Projects) — husky provisioning is skipped, not forced. + +## Adoption Impact + +- No mandatory change to any project's adoption files — the husky default requires zero adoption footprint (D21). +- [way-of-working.md](../../../.pair/adoption/tech/way-of-working.md) gains an optional "Hook manager" override field, used only when a project deviates from husky. +- `pair-capability-setup-gates` `SKILL.md` (dataset + installed mirror) documents this decision inline (Notes section: "Hook manager default: husky (decision D21/Q11)").