# Contributing to Hanfani Guard Thanks for your interest in improving Hanfani Guard! This project is a **deterministic** governance CLI — contributions should keep it fast, predictable, local-first, and AI-agnostic. ## Getting started Requirements: Node.js >= 20 and npm. ```bash git clone https://github.com/fruitizz/hanfani-guard.git cd hanfani-guard npm install npm run build # bundle to dist/ (ESM + type declarations) npm test # run the vitest suite npm run typecheck # tsc --noEmit ``` To try your local build as the real `hanfani` command: ```bash npm run build npm link hanfani --help # later: npm unlink -g @hanfani/guard ``` ## Project layout ``` src/ ├── cli.ts # CLI entry (commander) — thin wiring only ├── index.ts # public library API ├── commands/ # one file per command (init, check, commit, review, doctor, hook) ├── config/ # schema (zod), defaults, loader (jiti) ├── core/ # engine, context, reporter, commit-message, shared types ├── git/ # git wrapper + hook install/uninstall ├── policies/ # built-in policies (the "rules engine") └── utils/ # logger test/ # vitest suites ``` Keep the layers separated: CLI logic stays in `commands/`/`cli.ts`, and all governance logic stays in `core/` and `policies/` so it can be reused head-lessly via the library API. ## Adding a policy A policy is a small, isolated object implementing the `Policy` interface (`src/core/types.ts`). To add one: 1. Create it under `src/policies/` (group by category file, e.g. `code.ts`). 2. Give it a stable, kebab-case `id` (e.g. `code/no-focused-tests`). 3. Declare the `stages` it runs in and an `enabled(config)` predicate. 4. Read options from a namespaced config key; **do not hardcode behavior** that a user might reasonably want to tune. Extend the schema in `src/config/schema.ts` if you add options. 5. Return results via the `pass`, `skip`, or `fromIssues` helpers, with clear, actionable messages and a `hint` where possible. 6. Register it in `src/policies/index.ts`. 7. Add unit tests using the helpers in `test/helpers.ts`. Every policy must be independently disable-able (users can add its `id` to `disable: []`), deterministic, and covered by at least one test. ## Testing - Unit-test pure logic and policies with in-memory contexts (`test/helpers.ts`). - The `test/cli.test.ts` suite runs the built binary; it is skipped when `dist/` is missing, so run `npm run build` first if you want it to execute. - All tests must pass on Node 18, 20, and 22 (CI enforces this). ## Coding conventions - TypeScript, ESM, strict mode. Keep the runtime dependency footprint small. - Prefer deterministic heuristics over probabilistic behavior. - Comments should explain intent/trade-offs, not narrate the code. - No new runtime dependency on any specific AI provider — the core stays provider-agnostic. ## Commits & pull requests We dogfood our own rules: use **Conventional Commits**, keep commit **subjects** concise, and **do not** add commit bodies, `Co-authored-by:` trailers, or AI tool signatures. Running `hanfani commit` (or installing the hooks with `hanfani init`) will enforce this for you. Before opening a PR: ```bash npm run typecheck && npm run build && npm test ``` Please describe the motivation ("why") in the PR description, link any related issue, and include tests for new behavior. ## License By contributing, you agree that your contributions are licensed under the [MIT License](./LICENSE).