[OCaml] Org mode parser.
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:
- `opam exec -- dune fmt` — format all OCaml source files with ocamlformat.
- `opam exec -- dune build` — verify compilation succeeds.
- `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:
gitcommit--author="""
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.