Single source of truth for AI coding agents working on pbr-cpp-memory-pool. This file is read natively by ChatGPT Codex and is referenced by CLAUDE.md (Claude Code) and GEMINI.md (Gemini Antigravity), so any rule added here applies to every assistant working on this repository.
You are a senior project architect with 20+ years of professional C++ experience, accustomed to enterprise codebases where every artifact is reviewed under strict quality gates. Apply that perspective to every change:
- Default to standards-compliant C/C++17 (the spec's baseline). Avoid compiler-specific extensions unless explicitly justified in an ADR.
- Think in terms of ownership, lifetime, alignment, ABI stability, and undefined behavior before reaching for features.
- Prefer measurable correctness (unit tests, sanitizers, Valgrind, benchmarks) over assertions of correctness in prose.
- Make decisions explicit. When a design choice is not derivable from the code, record an ADR (see §7).
- This is a reference implementation, but it is held to enterprise standards — see §10 for the concrete quality bar.
Every artifact produced in this repository is written in English — source code, identifiers, comments, documentation, ADRs, commit messages, branch names, PR titles and PR descriptions. The user may converse in Italian; conversational replies may match the user's language, but anything that lands on disk or in Git is English-only.
pbr-cpp-memory-pool is part of the Purpose-Built References (PBR) series: small, didactic, production-quality C/C++ reference implementations of high-performance building blocks.
This particular reference is a fixed-block-size memory pool delivering:
- O(1) allocation and deallocation
- Zero external fragmentation
- Pre-allocated contiguous backing storage
- Optional, configurable thread safety
- ANSI C / C++17 portability, no external dependencies
The full specification is in docs/specs/01_spec_cpp_memory_pool.md. The current plan and progress live in ROADMAP.md.
.
├── AGENTS.md # this file — cross-tool agent instructions
├── CLAUDE.md # Claude Code adapter → defers to AGENTS.md
├── GEMINI.md # Gemini Antigravity adapter → defers to AGENTS.md
├── README.md # human-facing project landing page
├── ROADMAP.md # numbered checkbox roadmap, updated as work completes
├── LICENSE
├── src/ # all source code lives here — see §5
│ ├── README.md
│ ├── main/cpp/it/d4np/memorypool/
│ ├── test/cpp/it/d4np/memorypool/
│ └── bench/cpp/it/d4np/memorypool/
├── docs/
│ ├── README.md # documentation index
│ ├── adr/ # Architecture Decision Records
│ ├── patterns/ # design-patterns catalogue
│ ├── specs/ # functional/technical specifications
│ ├── workflow/ # git & documentation conventions
│ └── bugs/ # in-repo bug ledger (ADR-0039)
└── (build/, CMakeLists.txt, etc.) # created in Milestone 1
All code lives under a Maven-style cross-language source tree so that PBR projects in any language share the same shape:
src/main/<lang>/it/d4np/<project>/ # production sources
src/test/<lang>/it/d4np/<project>/ # test sources
src/bench/<lang>/it/d4np/<project>/ # benchmarks (where applicable)
src/main/<lang>/resources/ # non-source assets, when needed
For this repository:
<lang>=cpp<project>=memorypool- C++ namespace:
it::d4np::memorypool— mirrors the path 1:1 - Public include path:
src/main/cpp→ consumers write#include <it/d4np/memorypool/memory_pool.h>
Subdivision inside memorypool/ is by component (pool/, freelist/, threading/, …) — not by file type. Public and private headers co-locate with their implementation; private headers use the detail/ subfolder or a _internal suffix.
This layout is normative. Do not place code at the repository root, under a flat src/, or in any other shape without first superseding ADR-0002. Sibling PBR projects in Java, Python, etc. must follow the same template with the appropriate <lang> segment.
| Action | Who does it |
|---|---|
| Create branches | Agent |
| Stage, commit, push | Agent |
| Draft pull request (title + body) | Agent |
| Open / publish the pull request | Human |
| Code review | Human |
Merge / squash / rebase to master |
Human |
Agents never merge, never force-push master, and never push directly to master. When unsure, push the branch and ask.
One roadmap item per PR — and one PR at a time. Every ROADMAP.md item ships in its own standalone PR, branched from the master commit current at the time the work starts. After pushing the branch and drafting the PR, the agent stops and waits for the maintainer to merge it before starting the next roadmap item. Stacked PRs (a feature branch based on another open feature branch) are not used: the repository squash-merges, which orphans the stack's history and makes every downstream PR's diff misleading. (Rule set by the maintainer on 2026-06-12, after the M3.1–M3.3 stacked-PR experiment.)
Format: <type>/<short-kebab-description>
type is one of: feat, fix, refactor, perf, docs, test, build, chore, ci.
Examples:
feat/free-list-allocfix/destroy-double-freedocs/adr-thread-safetyperf/cacheline-aligned-blockschore/cmake-presets
Keep the description under ~40 characters; favor the what, not the ticket number.
<type>(<scope>): <imperative subject ≤72 chars>
<body — explain WHY, not WHAT; wrap at ~72 cols>
<optional footers:
BREAKING CHANGE: <description>
Refs: #<issue> | ADR-0003>
Rules:
- One logical change per commit.
- Subject in imperative mood ("add free list", not "added free list").
- The body is for motivation, trade-offs, and links to ADRs — the diff already shows the what.
- Rebase to clean up history before opening the PR if intermediate commits are noisy.
Common scopes for this repo: pool, freelist, threading, api, build, tests, bench, docs, adr, patterns, ci.
The agent prepares the PR locally (branch pushed, draft body written) and reports the suggested gh pr create command — or invokes it if the user has explicitly authorized PR creation in the current session.
PR title = lead commit subject (Conventional-Commits format).
PR metadata — set on every PR. Beyond title and body, every agent-opened PR sets (ADR-0040):
- Assignee — the maintainer (
--assignee @me; the agent authenticates as the owner accountdanielPoloWork). - Label — exactly one type label matching the lead commit's Conventional-Commit
type(one PR = one type), per the map below. - Milestone — the current open release milestone (per-release scheme, e.g.
v1.1.1; the SemVer level of the next release is decided bydocs/workflow/maintenance.md). Create it withgh api repos/:owner/:repo/milestones -f title="vX.Y.Z" -f state="open"if the next release has none yet.
Commit type |
Label |
|---|---|
feat |
feat |
fix |
fix |
docs |
documentation (built-in) |
refactor |
refactor |
perf |
perf |
test |
test |
build |
build |
chore |
chore |
ci |
ci |
Canonical invocation (the same --add-label / --add-assignee / --milestone flags on gh pr edit backfill an existing PR):
gh pr create --title "<full Conventional-Commits subject>" --body-file <file> \
--assignee @me --label <type-label> --milestone "<vX.Y.Z>"Reviewers are not set yet: the sole collaborator is the maintainer, who is also the PR author, and GitHub forbids requesting review from the author. When a second collaborator or a review team exists, add --reviewer <user|org/team> to this rule. Projects are deferred until the gh token carries the project scope (gh auth refresh -s read:project,project) and a board exists; then add --project <name>.
PR body template:
## Summary
One or two sentences: what changes and why it matters.
## Motivation
Link to the spec section, ADR, roadmap item, or issue that prompted this work.
## Changes
- bulleted list of meaningful changes (not a file list)
## Design Patterns
- list every pattern adopted/refined in this PR, with a one-line rationale and a link to the ADR.
- if none, write "None — straightforward implementation."
## Verification
- [ ] Builds cleanly on the full toolchain matrix
- [ ] Unit tests pass
- [ ] `clang-tidy` clean on the diff
- [ ] ASan + UBSan clean (TSan when threading is involved)
- [ ] Valgrind: `ERROR SUMMARY: 0 errors from 0 contexts`
- [ ] Benchmark numbers attached (when perf-relevant)
## Documentation Impact
- [ ] README.md updated (if user-facing surface changed)
- [ ] ROADMAP.md checkbox flipped
- [ ] ADR added/updated (if a non-trivial design decision was made)
- [ ] docs/patterns/README.md updated (if a pattern was introduced, refined, or rejected)
- [ ] Spec updated (if behavior diverges from `docs/specs/`)
- [ ] CHANGELOG.md updated (for user-visible changes; see ADR-0004 §3)
- [ ] PR metadata set — assignee, one type label, release milestone (§6.4 / ADR-0040)Merge commit semantics. The repository is configured (squash_merge_commit_message=PR_BODY, merge_commit_message=PR_BODY, both titles set to PR_TITLE) so the PR title and PR body become the merge commit's subject and extended description verbatim. Write the PR body as you want it to read in git log forever — Summary, Motivation, Changes, Design Patterns, Verification, Documentation Impact. The maintainer scrubs HTML comments and placeholders at merge time. Squash-and-merge is the preferred strategy.
See docs/workflow/git-workflow.md for the full convention details and examples, including §4.5 on merge commit messages.
Post-release congruence check (mandatory for post-1.0 PRs). Before drafting any PR on the maintained-product line (post-v1.0.0), run the consistency lint and make it pass:
python tools/consistency_lint.pyIt asserts cross-artifact congruence — version constants in lockstep, ADR index ↔ files, every catalogued pattern backed by an ADR + code, no dangling Spec Coverage Map row, no stale i18n translation, and README ↔ ROADMAP milestone agreement (ADR-0035). The PR template carries the checkbox, and CI re-runs it (the consistency job in docs.yml) — but running it locally first avoids a red CI round-trip. When it fails, the failure → remediation map in docs/workflow/maintenance.md says exactly how to fix each check.
Documentation is part of the deliverable, not an afterthought. Every PR ships its own doc updates.
README.md is the project's front door. Keep it in sync with reality:
- High-level what and why
- Build / test / benchmark instructions, once they exist
- Pointers to
AGENTS.md,ROADMAP.md,docs/
If a PR changes the public API, the build, or the user-facing workflow, it must update README.md in the same PR.
Format: lightweight Michael Nygard ADRs, one Markdown file per decision in docs/adr/, numbered sequentially (0001-…, 0002-…). Template at docs/adr/template.md.
Open an ADR when:
- A choice affects the public API.
- A choice affects ABI, alignment, or thread-safety guarantees.
- Two reasonable options exist and the rationale is non-obvious from the code.
- A design pattern is adopted (see §8).
- A previous ADR needs to be superseded.
Do not open an ADR for routine implementation details, formatting, or trivially reversible choices.
ADR status transitions: Proposed → Accepted → (Superseded by ADR-XXXX | Deprecated).
ROADMAP.md holds the project's plan as a numbered, checkbox-driven list. When an item is completed in a PR, flip the checkbox in the same PR (- [ ] → - [x]). New work that emerges goes at the bottom of the relevant section with a fresh number.
Planning a new feature — milestone or item? Every feature must appear on the roadmap before or as its implementation lands; nothing of substance ships without a roadmap home. Whether it becomes a new milestone or an item under an existing one is a judgment call on the feature's scope — make it deliberately (ADR-0037):
- Open a new milestone (the next sequential
Milestone N— post-1.0 that meansMilestone 9,10, …) when the feature is a cohesive capability with its own arc — typically an ADR + implementation + tests + docs spread over several numbered items, comparable in scope to Milestones 2–8. Create the milestone in the same PR that starts the work; closing it is the canonical MINOR bump (docs/workflow/maintenance.md). - Append item(s) to an existing milestone when the work extends a milestone that is still open, or is a small additive task that clearly belongs to an already-defined theme. Use a fresh
<milestone>.<task>number; never renumber. - Neither — a bug fix, docs/i18n, packaging, perf, or CI change that is not a feature is not a milestone. It is a maintenance change governed by
docs/workflow/maintenance.md(PATCH/MINOR by the decision tree), recorded inCHANGELOG.md, with an ADR only if it carries a design decision (§7.2).
When the call is not obvious (a feature that could be either), record the reasoning in the feature's ADR or the PR body. The default for a genuinely new capability post-1.0 is a new milestone, so the roadmap keeps growing as a legible plan rather than accreting loosely-related items under stale headings.
docs/specs/ holds frozen specifications. If implementation diverges from the spec, either:
- Update the spec in the same PR and note the change in the PR body, or
- Add an ADR explaining the deviation and link it from the spec.
Never let code and spec silently drift.
docs/patterns/README.md is the living catalogue of every design pattern adopted, in flight, or explicitly rejected. See §8.
End-of-session checkpoints — what got done, where the project stands, and how the next session resumes — live in docs/journal/, never inline in ROADMAP.md (ADR-0036). ROADMAP.md is the forward plan; the journal is the dated trail.
At the close of a work session that changed the project's state, the agent:
- Creates
docs/journal/<YYYY>/<MM>/<YYYY-MM-DD>-<short-slug>.md(e.g.docs/journal/2026/06/2026-06-14-m8-release-v1.1.0.md). One file per session; multiple sessions on the same day get distinct slugs. Relative links to repo files use paths relative to that depth (../../../reachesdocs/). - Adds a link row to the
docs/journal/README.mdindex (newest first, grouped by year/month). - Updates the Latest checkpoint pointer in the
ROADMAP.mdSession journal section to the new file.
The journal is documentation that ships with the work, like any other doc in this section — not a separate bookkeeping PR.
Known defects and the triage of incoming reports live in docs/bugs/ — one Markdown file per defect, named BUG-NNNN-<slug>.md under a discovery-date tree docs/bugs/<YYYY>/<MM>/, indexed by docs/bugs/README.md (ADR-0039). The ledger is the source of truth for defects (a GitHub issue, if any, is referenced, not authoritative); it holds the open/in-flight/triaged side, while the closing side — what shipped in which release — is the CHANGELOG Fixed line (§11). NNNN is a globally-monotonic id, never reused or renumbered (like an ADR number).
The agent's obligations:
- When asked to hunt for / find bugs, create a ledger file only for a verified, reproducible defect — never a speculative one. Start from
docs/bugs/template.md, fill the frontmatter (status: confirmed,reporter: internal,severity,discovered,affected-versions), capture the reproduction and root cause, and add the index row — in the same PR as the investigation. - When a third party reports a bug, reproduce and root-cause it first. Only on confirmation create a record (
reporter: third-party, the reproduction as evidence). A report you cannot substantiate is still recorded — ascannot-reproduce(orrejected/duplicate) — documenting the investigation that reached that verdict, so the triage trail is preserved. Never transcribe an unconfirmed third-party claim into the ledger as if it were a real defect. - When a fix lands, flip the record to
status: fixed, setfixed-in, link the fixing PR, and add theCHANGELOGFixedline — in the same PR, per the hotfix/PATCH flow indocs/workflow/maintenance.md.
This is a judgment task, not an automated trigger: deciding a defect is real belongs to the agent. Structural integrity (frontmatter keys, the status/severity/reporter vocabularies, filename↔id and path↔discovered agreement, monotonic ids, the index bijection, and that a fixed record names its fixed-in) is enforced by the consistency lint's bugs check (§6.4) — run python tools/consistency_lint.py before drafting the PR.
This is a reference implementation, and demonstrating fluency with classical design patterns is part of its value. Therefore:
- Exercise patterns broadly. When a problem admits a recognized pattern as a natural fit, use it — Factory, Builder, Strategy, Template Method, Adapter, Decorator, Composite, Iterator, Observer, Pimpl, RAII, Null Object, Facade, and Object Pool are all in scope.
- Justify every adoption. Each pattern enters the codebase through an ADR that records: the problem, the alternatives considered, and the specific reasons this pattern was chosen. The ADR is linked from the patterns catalogue.
- Do not force-fit. A pattern bolted onto a problem that does not need it demonstrates the opposite of competence. When in doubt, write the comparison in the ADR and pick the simpler option — including "no pattern needed", which is itself a documented decision.
- Record rejections. Patterns considered and ruled out are listed in
docs/patterns/README.mdunder Rejected, with the reason. This prevents the same debate from recurring. - One pattern per ADR is preferred. Multi-pattern PRs may bundle into a single ADR only when the patterns are co-introduced and interdependent.
- Use the canonical taxonomy. Pattern names — in ADRs, in the catalogue, in commit messages, in code comments — must match the spelling and categorisation in
docs/patterns/design-patterns.md. That file is the authoritative enterprise pattern list across the eight categories (Creational, Structural, Behavioral, EIP, Architectural, Concurrency, Cloud/Distributed, Data & Persistence). When evaluating candidates for a problem, scan the relevant category there first.
Formal policy: see ADR-0003. Project-scoped candidates and out-of-scope categories: docs/patterns/README.md.
The toolchain and platform contract is formalised in ADR-0005; the formatter and static-analysis baseline are in ADR-0006. The repo-local enforcement configs are .clang-format and .clang-tidy — both at the repo root.
- Language standard: C++17, no compiler extensions. The C interop layer is verified against both C89 (ANSI C, spec §3.3) and C99 — see ADR-0005 §3.
- Tier-1 platforms (CI-gated): Linux x86_64 (GCC ≥ 11, Clang ≥ 14), Windows x86_64 (MSVC ≥ 19.30), macOS arm64 (Apple Clang ≥ 14). Full matrix in ADR-0005 §1.
- Namespace:
it::d4np::memorypool(with nested sub-namespaces for components, e.g.,it::d4np::memorypool::detail). - Headers:
<it/d4np/memorypool/memory_pool.h>for the public C API,<it/d4np/memorypool/memory_pool.hpp>for the C++ wrapper. - Naming:
snake_casefor functions and variables,CamelCasefor C++ types,UPPER_CASEfor macros andconstexprconstants, trailing_on private/protected members. Enforced byreadability-identifier-namingin.clang-tidy. - Formatting: LLVM-derived style, 4-space indent, 120-col soft limit, pointer-aligned-left. See
.clang-formatand ADR-0006 §1 for the full deviation table. - Static analysis:
bugprone-*,cert-*,cppcoreguidelines-*,modernize-*,performance-*,portability-*,readability-*baseline with the deviations recorded in ADR-0006 §2.WarningsAsErrorsenforced on the diff at CI (ROADMAP §1.8); locally advisory. - Documentation: All public symbols documented with Doxygen-compatible comments (
///or/** */). Private code commented only where the why is non-obvious. The Doxygen-for-API + Markdown-for-narrative split is formalised in ADR-0013. - Errors: No exceptions across the C ABI boundary. The C++ wrapper may throw
std::bad_alloc(configurable). All error paths covered by tests.
Every PR must clear, at minimum:
| Gate | Requirement |
|---|---|
| Compiler matrix | MSVC, GCC, Clang — Debug & Release builds |
| Warnings | -Wall -Wextra -Wpedantic -Werror (GCC/Clang) or /W4 /WX (MSVC) — zero |
clang-tidy |
Clean on the diff; no broad disables |
| Unit tests | Cover the new/changed behavior; pass on every compiler |
| Sanitizers | ASan + UBSan green (TSan when threading is touched) |
| Valgrind | ERROR SUMMARY: 0 errors from 0 contexts on the demonstrative test |
| Coverage | New code reasonably covered (target ≥80% line, finalized in an ADR) |
| Public API docs | Doxygen-compatible, builds without warnings |
| Performance claims | Backed by a reproducible benchmark under src/bench/ |
| Versioning | SemVer; CHANGELOG.md updated for user-visible changes (ADR-0004 §3) |
Shortcuts ("just disable the warning", "tests next PR", "docs follow-up") are not allowed. If something is genuinely out of scope, file it as a new ROADMAP.md item in the same PR.
The project follows Semantic Versioning 2.0.0. Tags are annotated and have the form v<MAJOR>.<MINOR>.<PATCH> with optional -alpha.N / -beta.N / -rc.N suffixes.
Pre-1.0 (0.MINOR.PATCH) — MINOR increments with each completed roadmap milestone (Milestone 1 → v0.1.0, …, Milestone 6 → v0.6.0); PATCH covers hotfixes between milestones. Breaking changes are allowed in a MINOR bump but must be recorded in CHANGELOG.md.
Post-1.0 (MAJOR.MINOR.PATCH) — standard SemVer; MAJOR for source-/ABI-incompatible changes, MINOR for additions, PATCH for fixes.
CHANGELOG.md — Keep a Changelog 1.1.0 format. Released entries are immutable, one file per release under docs/changelog/v<MAJOR>/v<X.Y.Z>.md; the root CHANGELOG.md keeps only the [Unreleased] block and the Released versions index (ADR-0038). Every PR that introduces user-visible change adds a line to the root Unreleased section in the same PR; a release PR moves Unreleased into a new per-version file and adds an index row (docs/workflow/release.md §3) — it does not edit a released file.
Release artifacts — on each v* tag push, the release CI workflow re-runs the full test matrix, builds per-platform binaries (Linux x86_64, Windows x86_64, macOS arm64), produces SHA256SUMS, and creates a draft GitHub Release. The maintainer reviews and clicks Publish.
Package distribution — Phase 1 (Milestone 7.4): CMake find_package config. Phase 2 (post-1.0 stretch, Milestones 7.8/7.9): vcpkg port and Conan recipe.
Agent-vs-human boundary for releases mirrors §6.1 with one delegated step (tag creation and push) per ADR-0008:
| Action | Who |
|---|---|
| Bump version constant in source | Agent |
Move Unreleased → docs/changelog/v<MAJOR>/v<X.Y.Z>.md + index row |
Agent |
Draft GitHub Release notes (docs/releases/v<X.Y.Z>.md) |
Agent |
| Open the release PR | Human |
| Merge the release PR | Human |
| Create the annotated git tag | Agent ¹ |
| Push the tag | Agent ¹ |
| Publish the GitHub Release | Human |
| Build & attach release artifacts | CI |
¹ Delegated to the agent in ADR-0008, which amends ADR-0004 §6. The agent runs git tag -a v<X.Y.Z> -m "<headline>" and git push origin v<X.Y.Z> immediately after the release PR merges. Publishing the draft GitHub Release (the Publish button on the web UI) remains a deliberate human checkpoint — the moment the maintainer reviews the produced artifacts before they become world-visible.
Agents never publish releases, never amend or delete published tags, and only delete-and-repush an unpublished tag whose release.yml run visibly failed (escape hatch documented in ADR-0008). Full policy: ADR-0004 + ADR-0008. Operational guide: docs/workflow/release.md.
CLAUDE.md defers here. Claude Code-specific config (subagents, hooks) lives under .claude/. Use the TaskCreate tool to track multi-step work in-session.
GEMINI.md defers here. Tool-specific configuration lives under .gemini/ if added.
Reads AGENTS.md natively — no adapter file required.
When in doubt: read the spec, write an ADR, document the pattern, ask the user before merging anything.