diff --git a/.claude/hooks/prompt-context.sh b/.claude/hooks/prompt-context.sh index 6d504a7..df55f07 100755 --- a/.claude/hooks/prompt-context.sh +++ b/.claude/hooks/prompt-context.sh @@ -37,6 +37,9 @@ fi if echo "$prompt" | grep -qE 'coverage|uncovered|lcov|mutation|stryker|coverage band'; then inject+=('Coverage: ADR-020 + docs/guides/coverage.md (cookbook). 4 layers — L0 vitest thresholds, L1 pnpm coverage:diff (cover-the-diff), L2 coverage/summary.json (committed trend), L3 pnpm mutate (Stryker on entities + use-cases). Manifest-driven: feature.manifest.ts coverage.bands is the single source of truth.') fi +if echo "$prompt" | grep -qE 'commit|message|changelog|conventional'; then + inject+=('Conventional Commits (non-negotiable): (): (≤72 chars). Types: feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert. Use `!` for breaking changes. Body explains WHY if non-obvious. Examples: feat(auth): hash password before persisting; refactor(docs)!: consolidate scaffolding into guides. See CLAUDE.md Key Conventions.') +fi if [ ${#inject[@]} -gt 0 ]; then echo "=== context-relevant pointers (from .claude/hooks/prompt-context.sh) ===" diff --git a/.claude/hooks/session-start.sh b/.claude/hooks/session-start.sh index 39af0f2..8687249 100755 --- a/.claude/hooks/session-start.sh +++ b/.claude/hooks/session-start.sh @@ -9,6 +9,7 @@ Architecture: AGENTS.md, docs/architecture/overview.md, docs/architecture/agent- Workflow: pnpm work status | pnpm work next | pnpm work dispatch (ADR-019) Generator-first: pnpm turbo gen beats hand-rolled scaffolding (non-negotiable) Conformance: pnpm conformance + pnpm fallow (5-gate drift detection) +Conventional Commits (non-negotiable): (): — see CLAUDE.md Key Conventions Skills: to-prd, grill-with-docs, grill-me, handoff (.claude/skills/) EOF diff --git a/AGENTS.md b/AGENTS.md index 1a81bfc..b59e685 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,6 +4,8 @@ This is a **Turborepo + pnpm monorepo** organized by vertical features. Each fea > **Vocabulary:** Every cross-cutting term used in this repo (feature, use case, manifest, slice, conformance, dispatch, etc.) is defined in [`docs/glossary.md`](./docs/glossary.md). When in doubt about what a term means **here**, check the glossary first — it's the single source for shared vocabulary between humans and agents. +> **Commits:** Every commit message follows [Conventional Commits](https://www.conventionalcommits.org/): `(): ` (≤72 chars). Types: `feat | fix | docs | style | refactor | test | chore | perf | ci | build | revert`. Use `!` for breaking changes. The sandcastle implementer + reviewer prompts enforce this; agents authoring autonomously MUST honor it. + ## Agent-driven development This template assumes agents (Claude, Codex, etc.) will author most feature work. The orchestration substrate is [Sandcastle](https://github.com/mattpocock/sandcastle) — see [ADR-019](./docs/decisions/adr-019-sandcastle-for-agent-orchestration.md). Day-to-day entry points: diff --git a/CLAUDE.md b/CLAUDE.md index 2eb5e71..8370ebe 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -90,6 +90,7 @@ See `docs/guides/coverage.md` for the cookbook and ADR-020 for the full rational ## Key Conventions +- **Conventional Commits (non-negotiable)** — Every commit message MUST follow the [Conventional Commits](https://www.conventionalcommits.org/) spec: `(): ` (≤72 chars). Types: `feat | fix | docs | style | refactor | test | chore | perf | ci | build | revert`. Use `!` after type/scope for breaking changes. Body explains WHY if non-obvious. Examples: `feat(auth): hash password before persisting`, `test(blog): assert article not found error`, `refactor(docs)!: consolidate scaffolding into guides`. The sandcastle implementer + reviewer prompts both enforce this; agents authoring commits autonomously MUST honor it. - **Relative imports in `src/`** — Source files use relative paths (`../repositories/...`), not `@/` alias - **`@/` alias in tests** — Test files (`*.test.ts`) use `@/` to import from `src/` - **`vitest.config.ts`** — Every package must define `resolve.alias: { "@": path.resolve(__dirname, "./src") }`