AGENTS.md
HarfBuzz is a low-level text shaping engine with stable public API and ABI expectations. Keep changes narrow, preserve behavior unless the task explicitly requires otherwise, and avoid style-only churn.
Read first
Before non-trivial work, read:
README.mdBUILD.mdTESTING.mdCONFIG.mdRELEASING.md
Core rules
- Prefer minimal diffs. Do not rename, reorder, or reformat unrelated code.
- Scope changes to one subsystem or concern when possible. Prefer incremental follow-up commits over large rewrites.
- Public API and ABI are hard constraints. Do not add new API unless explicitly asked. Do not change or remove existing API/ABI unless explicitly asked.
- Follow local conventions in the touched file.
- Preserve optional-feature behavior, reduced-feature builds, and compile-time feature guards.
- Keep out-of-memory behavior in mind. New code should fail safely and follow existing allocation and error-handling patterns.
- Prefer HarfBuzz's established
likely/unlikely and nil-object/null-pattern conventions where they fit the surrounding code. - Prefer HarfBuzz helpers from
hb-algs.hh such as hb_memcpy, hb_memcmp, and hb_memset over raw memcpy, memcmp, and memset where those helpers are available. - Do not introduce STL containers in library code. Follow HarfBuzz container and utility patterns instead.
- Leave unrelated user changes and untracked artifacts alone.
Repo map
src/: core library code.src/OT/: OpenType shaping/layout internals.src/graph/: subsetter graph helpers.src/rust/: HarfRust and fontations integration.util/: installed tools such as hb-shape, hb-view, hb-info, hb-subset, hb-vector, hb-raster.test/: API, shape, subset, vector, threads, and fuzzing tests.perf/: benchmarks.docs/: API/manual docs.
Build and verify
Default flow:
meson setup build --reconfigure
meson compile -C build
meson test -C build
If build/ does not exist yet, omit --reconfigure.
General expectations:
- Rebuild touched targets and make sure there are no new warnings.
- For shaping changes, run at least
meson test -C build --suite shape. - For subset changes, run at least
meson test -C build --suite subset. - For API changes, run at least
meson test -C build --suite api. - For
util/ changes, rebuild the relevant tool and exercise it on a small sample. - When fixing a bug or hardening a parser, add or update the nearest regression test, fuzz seed, fuzz target, or expected output when practical.
- Treat portability regressions as real bugs. HarfBuzz regularly fixes GCC, Clang, MSVC, 32/64-bit, and reduced-feature build issues.
Change-specific guidance
- Shaping work: check nearby tests under
test/shape/. - Subsetting work: check
test/subset/; src/graph/ is part of the subsetter. - Raster/vector/SVG work: prefer extracting helpers and splitting oversized files by responsibility instead of adding more branching to large translation units.
- Fuzzing/parser-hardening work: inspect
test/fuzzing/ and existing guardrail code first. Fuzzers run with failing-malloc enabled, so treat out-of-memory handling as part of the exercised surface. - Build-system work: keep Meson options, summaries, installed tools, tests, and dependent targets in sync. If packaging or cross-build behavior is affected, inspect CMake too.
- Generated data work: update the generator or makefile flow, then regenerate outputs. Do not hand-edit generated tables unless the task explicitly calls for it.
- Rust integration work: inspect
src/rust/meson.build and src/rust/Cargo.toml before changing build glue.
For API work:
- Public API lives in
src/hb-*.h, not .hh. - If new API is explicitly requested, document it in
NEWS, add XSince: REPLACEME in the public header docs, and update docs/harfbuzz-sections.txt and docs/harfbuzz-docs.xml when needed. - If functionality becomes user-visible through tools or libraries, update the relevant docs and install/build wiring in the same change when appropriate.
- Keep documentation placement consistent with local practice: public API docs may live in source files, while generated section indexes live in
docs/.
Avoid
- Do not make broad formatting passes.
- Do not silently change Meson defaults or feature defaults unless required.
- Do not assume generated outputs, local fonts, or untracked artifacts are disposable.
- Do not disable tests to get a green run without documenting why.
Working mindset
- Reproduce the issue before fixing it when practical.
- Understand root cause before writing code. If there is real ambiguity, ask instead of guessing.
- Validate simplifications carefully. This repo has many targeted reverts where a local cleanup broke broader behavior.
- If code looks unusually complex, it probably handles a real edge case. Check history before simplifying it.
- Centralize duplicated parsing, caching, or helper logic once duplication starts spreading.
Commit guidance
- Before any commit, run the entire test suite with
meson test -C build. - Exception: simple documentation-only or CI-only changes may be committed without running tests if they do not affect code, build logic, generated outputs, or test inputs.
- Use descriptive commit messages with consistent bracketed subsystem prefixes such as
[subset], [raster], [util], or [meson]. - Wrap commit message bodies to about 70 columns.
- For multi-line commit messages, write the message from a file or editor-backed input. Do not pass escaped
\n sequences via shell -m arguments. - Explain root cause, fix, and testing in the commit body when testing was actually performed or is relevant.
- When relevant, link issues or PRs with trailers such as
Fixes:. - Always include an
Assisted-by: trailer on commits you write through the agent.
Wisdom
- HarfBuzz sits at the bottom of the stack. Small changes can have very wide effects.
- If code looks unusually complex, assume it handles a real edge case until proven otherwise.
- Simplifications and optimizations are common sources of later reverts; validate them broadly.
- Prefer reproducible regressions over fix-only changes.
- When duplication starts to spread, extract the shared helper before it calcifies.