# AGENTS.md – darktable
Instructions for AI coding agents working on darktable. It covers what agents
specifically get wrong; it is not an overview of the codebase.
**Read [`dev-doc/`](dev-doc/README.md) before changing a subsystem.** It is
darktable's in-tree developer documentation -- IOP module API, pixelpipe,
introspection, GUI helpers, shortcuts, the AI subsystem -- versioned with the
code, so it describes the checkout you have. Prefer it over the wiki wherever
the two disagree. Most bad agent patches come from inferring an API instead of
opening the page that documents it.
The [Developer's guide](https://github.com/darktable-org/darktable/wiki/Developer's-guide)
has the coding style, and [CONTRIBUTING.md](CONTRIBUTING.md) the social side.
## The one rule that matters most
**Every commit must compile on its own.**
`git bisect` is how darktable developers find regressions, and it is useless
across commits that do not build. A series where only the last commit compiles
is worse than one squashed commit, because it silently poisons the history for
everyone else.
If you produce a series, build at each step:
```bash
git rebase --exec 'cmake --build build'
```
If you cannot or will not do that, squash into a single commit that builds.
Do not commit a "checkpoint" or "work in progress" state. Do not split a change
so that the halves only work together.
## Boundaries
Go ahead without asking: read anything, build, run the test suites, run
`darktable-cli`, and edit the files the task is about.
Ask first: adding a dependency, changing a public API or the database schema,
touching a subsystem the task did not name, and anything CONTRIBUTING.md calls
substantial -- discuss those before writing them, not after.
Finish at a staged change, and a drafted commit message if one was asked for.
Committing, pushing and opening the PR are the human's steps, and they will
usually not be asked for at all. Stage only the files the task touched -- never
`git add -A` over a tree you have not looked at -- and keep build output,
editor files and scratch notes out of it.
Never reformat, rename or tidy code the task did not touch, and never fix an
unrelated bug you notice in passing: mention it instead. Do not add a comment,
file or abstraction that nobody requested.
## Commits
Subject on one line, under about 72 characters, no full stop. Prefix with the
area (`history:`, `exif:`, `bauhaus:`, `cmake:`, `ci:`) when the subject alone
would not say which part of darktable moved. Common here, not required.
Both a bare subject and a subject plus body are normal; roughly half of recent
commits carry a body. A subject alone is enough when the diff explains itself
-- data additions, translation updates, version bumps, typos. Anything
behavioural earns a body saying what was wrong before and what the change does
about it, wrapped at about 72 columns. If you cannot tell which applies, write
the body: an unnecessary paragraph costs far less than a behavioural change
nobody can account for later.
```text
cmake: link libwayland-client when GTK3 has the Wayland backend
gui/gtk.c calls into libwayland-client directly to detect server-side
decoration support, but gtk+-3.0.pc does not list wayland-client. The
symbols were only resolved by accident, via libgdk-3's own DT_NEEDED,
which breaks on distros linking with `-Wl,--no-undefined`.
Fixes #1234
```
Close issues with `Fixes #1234` or `Closes #1234` on its own line at the end,
or `Related: #1234` when the commit does not resolve the issue. In a series,
only the commit that completes the fix carries the closing keyword. A
reference never replaces the explanation: "fix #1234" alone is useless to
anyone reading `git blame` without a browser, and the history outlives the
issue tracker.
Describe the change, not the process that produced it. "address review
comments" and "second attempt" mean nothing to a later reader who cannot see
the thread.
Commit trailers are rare here. Disclose AI assistance in the pull request
description instead of inventing a trailer convention.
## Build
The README's Compile section has the commands, for the `build.sh` route and
for driving cmake by hand. What it does not say:
- `--enable-ai` and `-DUSE_AI=ON` are the same switch: `build.sh` uppercases
the feature name and prefixes `USE_`. The features are `ai`, `camera`,
`colord`, `gmic`, `graphicsmagick`, `imagemagick`, `jxl`, `kwallet`,
`libsecret`, `lua`, `mac_integration`, `map`, `mcp`, `opencl`, `opencv`,
`openexr`, `openmp`, `unity` and `webp`. Left alone, cmake enables what it
autodetects; a flag forces one feature either way
- to check that a change compiles you need neither prefix nor install: drop
`--install --sudo`, or stop after `cmake --build`
- on Windows, build in the MSYS2 UCRT64 shell, not a plain Windows prompt --
the toolchain and every dependency come from `mingw-w64-ucrt-x86_64-*`.
`build.sh` works there with `--build-generator Ninja` and no `--sudo`
- if `AGENTS.local.md` gives its own build or run commands, use those instead:
how a checkout is built is a local matter, not a project convention
Verify with a real build before proposing changes. A change that has only been
reasoned about is not finished. If you touch code behind an `#ifdef`, build
with that feature both on and off. The disabled path is where broken stubs
hide.
## Testing
Unit tests use cmocka and need `-DBUILD_TESTING=ON` plus `libcmocka-dev`.
Integration tests live in `src/tests/integration/` and check pixel output
against a reference within dE < 2, with OpenCL both off and on:
```bash
cd src/tests/integration && ./run 0001-exposure
```
They need ImageMagick's `compare` and python3 with `opencv`, `numpy` and
`colour-science`. **Run them if you touch the pixelpipe or any `src/iop/`
module.** They are the only thing that catches a change which builds, runs, and
quietly alters everyone's images.
`darktable-cli` runs the pipeline headless and is the fastest way to exercise a
change without the GUI:
```bash
darktable-cli [