This seems to be what all the tools are standardizing on, except claude (https://github.com/anthropics/claude-code/issues/6235) so add a symlink from CLAUDE.md to AGENTS.md for now until they support it as well. I also had claude extend the instructions a bit. Co-developed-by: Claude <claude@anthropic.com>
7.7 KiB
AGENTS.md
This file provides guidance to AI coding agents when working with code in this repository.
Project Overview
systemd is a system and service manager for Linux, written in C (GNU17 with extensions). The project is built with Meson and consists of ~140 components including PID 1, journald, udevd, networkd, and many other system daemons.
Key Documentation
Always consult these files as needed:
docs/ARCHITECTURE.md— code organization and component relationshipsdocs/HACKING.md— development workflow with mkosidocs/CODING_STYLE.md— full style guide (must-read before writing code)docs/CONTRIBUTING.md— contribution guidelines and PR workflow
Build and Test Commands
CRITICAL: Read and follow these instructions exactly.
- NEVER compile individual files or targets. ALWAYS run
mkosi -f box -- meson compile -C buildto build the entire project. Meson handles incremental compilation automatically. - NEVER run
meson compilefollowed bymeson testas separate steps. ALWAYS runmkosi -f box -- meson test -C build -v <TEST-NAME>directly. Meson will automatically rebuild any required targets before running tests. - NEVER invent your own build commands or try to optimize the build process.
- NEVER use
head,tail, or pipe (|) the output of build or test commands. Always let the full output display. This is critical for diagnosing build and test failures.
# Initial setup (one-time)
mkosi -f genkey
mkosi -f box -- meson setup build
# Build everything
mkosi -f box -- meson compile -C build
# Run a specific unit test (also rebuilds as needed)
mkosi -f box -- meson test -C build -v <TEST-NAME>
# Run all unit tests
mkosi -f box -- meson test -C build --print-errorlogs -q
# Build and boot an OS image for integration testing
mkosi -f box -- meson compile -C build mkosi
mkosi boot # nspawn
mkosi vm # qemu
- CORRECT:
mkosi -f box -- meson test -C build -v <TEST-NAME> - WRONG: Separate compile then test steps
- WRONG:
mkosi -f box -- meson compile -C build src/core/systemd(individual target) - WRONG:
mkosi -f box -- meson test -C build -v <TEST-NAME> 2>&1 | tail -100(piped output)
Code Architecture
Shared Code Dependency Hierarchy (strict layering)
src/fundamental/ → no dependencies (used in EFI + userspace)
↑
src/basic/ → depends only on fundamental (userspace only)
↑
src/libsystemd/ → depends on basic + fundamental (public libsystemd.so)
↑
src/shared/ → depends on all above (libsystemd-shared-<nnn>.so)
↑
src/<component>/ → individual daemons and tools
Code should be linked as few times as possible. Place shared code at the lowest possible layer.
Key Components
src/core/— PID 1 service manager (system and user instances). Usessystemd-executorfor process spawning viaposix_spawn()to avoid fork+exec pitfalls.src/udev/— udev daemon and udevadm toolsrc/journal/— journald logging daemonsrc/network/— networkd network managersrc/resolve/— resolved DNS resolversrc/login/— logind session managersrc/boot/— systemd-boot EFI bootloadersrc/systemctl/,src/journalctl/,src/analyze/— CLI tools
Unit Settings Implementation
Adding a new unit setting requires changes in various places:
src/core/load-fragment-gperf.gperf.in+src/core/load-fragment.c— unit file parsingsrc/core/dbus-*.c— D-Bus interfacesrc/core/varlink-*.c— Varlink interfacesrc/shared/bus-unit-util.c— client-side parsing for systemctl/systemd-runtest/fuzz/fuzz-unit-file/— add to fuzz corpus
Tests
- Unit tests:
src/test/— match source files (e.g.,src/test/test-path-util.ctestssrc/basic/path-util.c). Use assertion macros fromtests.h(ASSERT_GE(),ASSERT_OK(),ASSERT_OK_ERRNO()for glibc calls). - Fuzzers:
src/fuzz/for basic/shared code; next to component code otherwise. Input samples intest/fuzz/. - Integration tests:
test/TEST-*directories, run via systemd-nspawn or qemu.
Coding Style (Essential Rules)
The full style guide is in docs/CODING_STYLE.md. Key rules:
Formatting
- 8-space indent (no tabs) for C; 4-space for shell scripts; 2-space for man pages (XML)
- ~109 character line limit
- Opening brace on same line:
void foo() { - Function parameters with double indent (16 spaces) when broken across lines
- Single-line
ifblocks without braces /* comments */for committed code;//reserved for temporary debug comments- Pointer in return types:
const char* foo()(star with type) - Pointer in parameters:
const char *input(star with name) - Casts:
(const char*) s(space befores, not after*)
Naming and Structure
- Structs:
PascalCase; variables/functions:snake_case - Return parameters prefixed
ret_(success) orreterr_(failure) - Command-line globals prefixed
arg_ - Enum flags: use
1 << Nexpressions, aligned vertically - Non-flag enums: include
_FOO_MAXand_FOO_INVALID = -EINVALsentinels - Commit messages: prefix with component name (e.g.,
journal:,nspawn:)
Error Handling
- Return negative errno values:
return -EINVAL - Use
RET_NERRNO()to convert libc-style returns - Combined log+return:
return log_error_errno(r, "Failed to ...: %m") - Use
SYNTHETIC_ERRNO()for errors not from a called function - Cast ignored errors to void:
(void) unlink("/foo/bar") - Always check OOM; use
log_oom()in program code
Header Files
- Keep headers lean — prefer implementations in
.cfiles - Include the appropriate forward declaration header (
basic-forward.h,sd-forward.h,shared-forward.h) instead of pulling in full headers - Order: external headers (
<>), thensd-*headers, then internal headers, alphabetically within each group - No circular header dependencies
Memory and Types
- Use
_cleanup_free_and friends for automatic cleanup - Use
alloca_safe(),strdupa_safe()instead of rawalloca(),strdupa() - Never use
off_t; useuint64_tinstead - Use
unsignednotunsigned int;uint8_tfor bytes, notchar
Functions to Avoid
memset→ usememzero()orzero()strcmp/strncmp→ usestreq()/strneq()strtol/atoi→ usesafe_atoli(),safe_atou32(), etc.basename/dirname→ usepath_extract_filename()/path_extract_directory()fgets→ useread_line()exit()→ usereturnfrom main or_exit()in forked childrendup()→ usefcntl(fd, F_DUPFD_CLOEXEC, 3)htonl/htons→ usehtobe32()/htobe16()
File Descriptors
- Always use
O_CLOEXEC/SOCK_CLOEXEC/MSG_CMSG_CLOEXEC/ ...
Logging
- Library code (
src/basic/,src/shared/): never log (exceptLOG_DEBUG) - "Logging" functions log errors themselves; "non-logging" functions expect callers to log
- Non-fatal warnings: suffix with
, ignoring: %m"or similar
Integration Tests
- Never use
grep -qin pipelines; usegrep >/dev/nullinstead (avoidsSIGPIPE)
Pull Request Review Instructions
- Focus on coding style compliance from
docs/CODING_STYLE.md - Only leave comments for logic issues if you are very confident in your deduction
- Frame comments as questions
- Always consider you may be wrong
- Do not argue with contributors; assume they are right unless you are very confident
- Be extremely thorough — every single coding style violation should be reported
AI Contribution Disclosure
Per project policy: if you use AI code generation tools, you must disclose this in commit messages by adding e.g. Co-developed-by: Claude <claude@anthropic.com>. All AI-generated output requires thorough human review before submission.