View raw

Table of Contents

---

inclusion: always

Git Conventions

This project uses Git for version control. Follow these conventions for all commits and branches.

Conventional Commits

All commit messages must follow the Conventional Commits specification (https://www.conventionalcommits.org/).

Format

<type>[optional scope]: <description>

[optional body]

[optional footer(s)]

Types

| Type | Purpose | |------------|---------------------------------------------------------| | `feat` | A new feature or capability | | `fix` | A bug fix | | `refactor` | Code change that neither fixes a bug nor adds a feature | | `test` | Adding or updating tests | | `docs` | Documentation changes | | `chore` | Build process, tooling, or auxiliary changes | | `ci` | CI/CD configuration changes | | `perf` | Performance improvement | | `style` | Code style changes (formatting, whitespace) |

Scopes

Use a scope to indicate the area affected. Common scopes for this project:

* `lexer` — lexer recognition changes * `parser` — Menhir grammar changes * `ast` — AST type definitions * `normalize` — normalization phase * `inline` — inline parsing * `prescan` — pre-scan configuration discovery * `diagnostic` — diagnostic reporting * `test` — test infrastructure (not individual test additions)

Omit the scope when the change is cross-cutting or does not fit a single module.

Rules

* Use the imperative mood in the description: "add heading parser", not "added heading parser". * Keep the first line under 72 characters. * Do not end the description with a period. * Use the body to explain *what* and *why*, not *how*. * Use `BREAKING CHANGE:` in the footer when a change breaks the public API. * A `!` after the type/scope indicates a breaking change: `feat(ast)!: restructure heading representation`.

Examples

feat(lexer): add keyword line classification

Recognize lines matching #+KEY: VALUE as Keyword tokens.
fix(normalize): attach affiliated keywords across blank lines

Previously affiliated keywords separated by a blank line from their
target element were left as standalone nodes. Now they correctly
remain unattached per the Org spec.
test: add malformed block recovery fixtures
refactor(parser): extract list item grouping into helper function

Conventional Branches

Branch naming format

<type>/<short-description>

Use kebab-case for the description. Keep it concise but descriptive.

Branch types

| Prefix | Purpose | |-------------|----------------------------------------------------| | `feat/` | Feature development | | `fix/` | Bug fixes | | `refactor/` | Refactoring without behavior change | | `test/` | Test additions or infrastructure | | `docs/` | Documentation work | | `chore/` | Tooling, build, or maintenance |

Rules

* Branch from `master` unless working on a dependent feature. * One logical change per branch. * Do not reuse branch names after merging. * Delete branches after they are merged.

Examples

feat/heading-parser
fix/list-indentation-edge-case
refactor/inline-lexer-modes
test/block-recovery-fixtures
docs/update-support-matrix
chore/upgrade-menhir

General Git practices

* Keep commits atomic: one logical change per commit. * Commit after each individual feature is implemented. * Do not mix formatting changes with behavioral changes in the same commit. * Prefer rebase workflows to keep linear history on `master`. * Squash fixup commits before merging to `master`. * Do not commit generated files (build artifacts, `.merlin`, etc.). * Do not commit editor-specific files unless shared tooling requires them. * Always amend the latest unpushed commit when the requested modifications concern files already modified in that commit. Otherwise, create a new commit.

Pre-commit checks

Before every commit, run the following in order:

  1. `opam exec -- dune fmt` — format all OCaml source files with ocamlformat.
  2. `opam exec -- dune build` — verify compilation succeeds.
  3. `opam exec -- dune runtest` — verify all tests pass.

Do not commit if any of these steps fail.

Authorship

When an AI agent produces code, authorship must be correctly attributed in the commit metadata.

* **Author**: the AI agent that produced the changes. Use the format:

  Agent-Name (effort-level) <noreply@company-domain>

Where `effort-level` reflects the reasoning or effort mode the agent was operating under when it produced the changes (e.g. `high`, `medium`, `standard`, or a model-specific indicator). The email domain identifies the company developing the agent.

Example: `Kiro (high) <noreply@kiro.dev>`

* **Committer**: always the human who reviewed and accepted the changes. Use the human's normal Git identity.

Set authorship with:

git commit --author="Kiro (high) <noreply@kiro.dev>" -m "..."

This ensures `git log` and `git blame` clearly distinguish AI-generated code from human-written code, while the committer field records who took responsibility for merging it.