From 3d5dccf0cabe4a5f46017067322d41d8df31460f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francesco=20Borz=C3=AC?= Date: Tue, 4 Aug 2026 09:25:52 +0200 Subject: [PATCH] feat(Agents): structure agents docs with progressive disclosure (#26946) --- .agents/README.md | 7 +-- .agents/docs/README.md | 20 ++++++++ .agents/docs/build.md | 14 ++++++ .agents/docs/cpp-guidelines.md | 28 +++++++++++ .agents/docs/cpp-scripts.md | 14 ++++++ .agents/docs/sql-guidelines.md | 15 ++++++ .github/agents/README.md | 13 ++--- .github/agents/pr-reviewer.md | 3 +- .gitignore | 5 ++ AGENTS.md | 92 +++++++--------------------------- 10 files changed, 127 insertions(+), 84 deletions(-) create mode 100644 .agents/docs/README.md create mode 100644 .agents/docs/build.md create mode 100644 .agents/docs/cpp-guidelines.md create mode 100644 .agents/docs/cpp-scripts.md create mode 100644 .agents/docs/sql-guidelines.md diff --git a/.agents/README.md b/.agents/README.md index 395f65b177..fe90911090 100644 --- a/.agents/README.md +++ b/.agents/README.md @@ -1,16 +1,17 @@ # .agents -Source of truth for this repo's agent skills and rules: +Source of truth for this repo's agent skills, rules, and docs: - `skills//SKILL.md` - `rules/.md` +- `docs/` — task-scoped agent docs; taxonomy and placement policy in `docs/README.md` -Agent-specific directories expose each via a relative symlink — for Claude Code: +Agent-specific directories expose skills and rules via a relative symlink — for Claude Code: .claude/skills/ -> ../../.agents/skills/ .claude/rules/.md -> ../../.agents/rules/.md -To add a skill or rule: create it here, then symlink it. +To add a skill or rule: create it here, then symlink it. Docs need no symlinks — AGENTS.md references them by path. The skills in this repository often build on those from [agent-toolkit](https://github.com/eai-org/agent-toolkit/), invoking them when available. diff --git a/.agents/docs/README.md b/.agents/docs/README.md new file mode 100644 index 0000000000..b97ac21013 --- /dev/null +++ b/.agents/docs/README.md @@ -0,0 +1,20 @@ +# .agents/docs + +Task-scoped agent guidance, routed from AGENTS.md's "Mandatory reading per task". Keep every doc +compact and agent-agnostic. + +## Taxonomy + +- Root — task-type docs (`build.md`, `cpp-guidelines.md`, `sql-guidelines.md`, …), kebab-case. + `-.md` is reserved for language-scoped specializations (e.g. `cpp-scripts.md`). +- `systems/` — cross-language subsystem docs, plain kebab-case subsystem names + (e.g. `battleground.md`). + +## Placing new guidance + +- The most specific applicable doc wins. +- Generic language lesson → the language doc (e.g. generic C++ → `cpp-guidelines.md`). +- Subsystem-specific lesson → `systems/.md`; create it if missing. +- Extend an existing doc before creating a new one. +- A new doc REQUIRES adding its routing bullet to AGENTS.md's "Mandatory reading per task" in the + same change. diff --git a/.agents/docs/build.md b/.agents/docs/build.md new file mode 100644 index 0000000000..b23e308009 --- /dev/null +++ b/.agents/docs/build.md @@ -0,0 +1,14 @@ +# Build & tests + +Out-of-source build is required (in-source is blocked). + +```bash +mkdir -p build && cd build +cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/azeroth-server -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DSCRIPTS=static -DMODULES=static +make -j$(nproc) && make install +``` + +C++20 required (`CMAKE_CXX_STANDARD 20`). Useful flags: `BUILD_TESTING=ON` (Google Test), `NOPCH=1` (disable precompiled headers). Full set in `conf/dist/config.cmake`. `compile_commands.json` is exported automatically. + +Tests (Google Test, in `src/test/`): configure `-DBUILD_TESTING=ON`, then `ctest` or `./src/test/unit_tests` from the build dir. diff --git a/.agents/docs/cpp-guidelines.md b/.agents/docs/cpp-guidelines.md new file mode 100644 index 0000000000..5fa7be0a78 --- /dev/null +++ b/.agents/docs/cpp-guidelines.md @@ -0,0 +1,28 @@ +# C++ guidelines + +Run the linter before claiming a change is done: `python apps/codestyle/codestyle-cpp.py` + +## Code style + +Hard rules (also enforced by CI with `-Werror`, plus `cppcheck`): + +- Allman braces. No braces around single-line statements. `if (x)` — never `if(x)` or `if ( x )`. +- `auto const&` (not `const auto&`); `Type const*` (not `const Type*`). +- Use `{}` format specifiers (`fmt`-style), not `%u`/`%s`. +- Use the typed helpers, not raw flag access: + - `IsPlayer()`, `IsCreature()`, `IsItem()`, … instead of `GetTypeId() == TYPEID_*`. + - `GetNpcFlags()`, `HasNpcFlag()`, `SetNpcFlag()`, `RemoveNpcFlag()`, `ReplaceAllNpcFlags()` instead of `*Flag(UNIT_NPC_FLAGS, …)`. + - `IsRefundable()`, `IsBOPTradable()`, `IsWrapped()` instead of `HasFlag(ITEM_FIELD_FLAGS, …)`. + - `HasFlag(ItemFlag)` / `HasFlag2(ItemFlag2)` / `HasFlagCu(ItemFlagsCustom)` instead of bitwise `Flags & ITEM_FLAG…`. + - `ObjectGuid::ToString().c_str()` instead of `ObjectGuid::GetCounter()`. + +## Project conventions + +- **Logging**: `LOG_INFO("category.sub", "msg with {}", arg)` (also `LOG_WARN`/`ERROR`/`DEBUG`/`TRACE`). Categories are hierarchical, dot-separated (`server.loading`, `entities.player`, `sql.dev`). No `printf`-style, no `sLog->`, no `TC_LOG_*`. Macro in `src/common/Logging/Log.h`. +- **Random**: use helpers in `src/common/Utilities/Random.h` — `urand`, `irand`, `frand`, `rand32`, `rand_chance`, `roll_chance_f`, `roll_chance_i`. Not `std::rand` or ``. +- **Strings**: `Acore::StringFormat(fmt, args...)` (`{}` placeholders) — `src/common/Utilities/StringFormat.h`. +- **Config**: `sConfigMgr->GetOption("Name", default)`. +- **Namespace**: project-wide `Acore::` (no `Trinity::` remnants — rename when porting from upstream forks). +- **Long-lived references**: don't store a raw `Player*` / `Creature*` / `Unit*` past the current call/tick — the object can be removed (logout, despawn, instance unload) and the pointer dangles. Store the `ObjectGuid` and resolve at use time via `ObjectAccessor::FindPlayer(guid)`, `Map::GetCreature(guid)`, etc. +- **DB queries**: use `PreparedStatement` (via `WorldDatabase` / `CharacterDatabase` / `LoginDatabase` and the prepared-statement enums), not raw query strings. Non-blocking reads go async: `_queryProcessor.AddCallback(db.AsyncQuery(stmt).WithPreparedCallback(...))` (or `WithCallback`). Multi-statement writes wrap in `SQLTransaction` + `Execute` / `AppendPreparedStatement`. +- **Timed actions in AI**: use `EventMap` (event id → delay; simple) or `TaskScheduler` (lambdas, repeats, cancellation), both members of `CreatureAI` — don't roll your own tick counters. See any boss script under `src/server/scripts/`. diff --git a/.agents/docs/cpp-scripts.md b/.agents/docs/cpp-scripts.md new file mode 100644 index 0000000000..dfa91e39bb --- /dev/null +++ b/.agents/docs/cpp-scripts.md @@ -0,0 +1,14 @@ +# C++ scripts + +Scripts inherit from a `ScriptObject` subclass (`SpellScript`, `AuraScript`, `CreatureScript`, `InstanceMapScript`, `GameObjectScript`, `CommandScript`, …). Two registration styles coexist: + +- **Spell / aura scripts**: `RegisterSpellScript(ClassName)` (or `RegisterSpellAndAuraScriptPair(...)`) inside `AddSC_()`. +- **Creature scripts**: prefer `RegisterCreatureAI(ClassName)` for new code; legacy zones still use `new ClassName();`. Match the surrounding pattern. + +Then declare and call `AddSC_()` from the regional loader (`Spells/spells_script_loader.cpp`, `EasternKingdoms/eastern_kingdoms_script_loader.cpp`, …). + +**SmartAI** (data-driven creature behaviour) lives in the world DB's `smart_scripts` table, not C++ (engine: `src/server/game/AI/SmartScripts/`). For new creature behaviour prefer SmartAI (via the SQL update workflow); reach for `CreatureScript` only when SmartAI's event/action vocabulary isn't enough. + +**Module hooks** (e.g. `OnPlayerLogin`, `OnWorldUpdate`, `OnSpellCast`) are declared in `src/server/game/Scripting/ScriptDefines/*.h`. Implement by inheriting the matching base (`PlayerScript`, `WorldScript`, …) and registering with `new MyClass();` (or its `RegisterXxxScript` macro) inside `AddSC_()`. Full list: https://www.azerothcore.org/wiki/hooks-script. + +Custom (non-upstream) scripts go in `src/server/scripts/Custom/` (gitignored). diff --git a/.agents/docs/sql-guidelines.md b/.agents/docs/sql-guidelines.md new file mode 100644 index 0000000000..d40002c8ad --- /dev/null +++ b/.agents/docs/sql-guidelines.md @@ -0,0 +1,15 @@ +# SQL guidelines + +## Adding SQL updates + +1. `cd data/sql/updates/pending_db_world/` (or `pending_db_auth` / `pending_db_characters`). +2. `./create_sql.sh` generates an empty `rev_.sql` to write into. +3. Conventions (linted): every `INSERT` preceded by a matching `DELETE` (idempotency); no double semicolons; no multiple blank lines; InnoDB engine. + +Run the linter before claiming a change is done: `python apps/codestyle/codestyle-sql.py` (compares to origin/master). + +## The three databases + +- `acore_auth` — accounts, realm list, IP/account bans, session keys. Shared across all realms. +- `acore_characters` — per-character state: characters, inventory, in-progress quests, mail, guilds, arena teams, achievements. One per realm. +- `acore_world` — static game content: creature/gameobject/item/quest templates, spawn lists, loot tables, SmartAI scripts, gossip, conditions. Read-mostly; rebuilt from SQL. diff --git a/.github/agents/README.md b/.github/agents/README.md index 2e7e7d58c8..6bbc0b16c0 100644 --- a/.github/agents/README.md +++ b/.github/agents/README.md @@ -19,18 +19,19 @@ The PR Reviewer agent is configured to review pull requests with deep understand - Testing and validation requirements - Security and quality standards -**Key Feature**: This agent always references `/AGENTS.md`, the C++ Code Standards wiki, and the SQL Standards wiki before reviewing any PR. +**Key Feature**: This agent always references `/AGENTS.md`, the matching `.agents/docs/*.md` task guides, the C++ Code Standards wiki, and the SQL Standards wiki before reviewing any PR. ## How It Works When an AI tool reviews a PR in this repository: 1. The tool reads the appropriate agent configuration from this directory -2. The agent configuration instructs it to read `/AGENTS.md` for full project context -3. For C++ changes, the agent also references the [C++ Code Standards wiki](https://github.com/azerothcore/wiki/blob/master/docs/cpp-code-standards.md) -4. For SQL changes, the agent also references the [SQL Standards wiki](https://github.com/azerothcore/wiki/blob/master/docs/sql-standards.md) -5. The agent applies project-specific rules during review -6. Feedback is provided following the project's conventions and standards +2. The agent configuration instructs it to read `/AGENTS.md` for project context and per-task routing +3. Per AGENTS.md's "Mandatory reading per task", it reads the `.agents/docs/*.md` guides matching what the PR touches +4. For C++ changes, the agent also references the [C++ Code Standards wiki](https://github.com/azerothcore/wiki/blob/master/docs/cpp-code-standards.md) +5. For SQL changes, the agent also references the [SQL Standards wiki](https://github.com/azerothcore/wiki/blob/master/docs/sql-standards.md) +6. The agent applies project-specific rules during review +7. Feedback is provided following the project's conventions and standards ## For Contributors diff --git a/.github/agents/pr-reviewer.md b/.github/agents/pr-reviewer.md index 878f6aa972..75e6659ccd 100644 --- a/.github/agents/pr-reviewer.md +++ b/.github/agents/pr-reviewer.md @@ -5,7 +5,8 @@ You are an expert code reviewer for the AzerothCore project. When reviewing pull ## Required Reading Before reviewing any PR, you MUST read and follow the instructions in: -- `/AGENTS.md` - Contains comprehensive project architecture, coding standards, build instructions, and PR requirements +- `/AGENTS.md` - Slim index of agent rules, repository layout, and per-task routing to `.agents/docs/` +- The `.agents/docs/*.md` guides matching what the PR's diff touches, per AGENTS.md's "Mandatory reading per task" - [C++ Code Standards](https://github.com/azerothcore/wiki/blob/master/docs/cpp-code-standards.md) - Detailed C++ coding conventions and style guide - [SQL Standards](https://github.com/azerothcore/wiki/blob/master/docs/sql-standards.md) - SQL query formatting and database standards diff --git a/.gitignore b/.gitignore index 156a417530..dea151f5b2 100644 --- a/.gitignore +++ b/.gitignore @@ -54,6 +54,11 @@ CMakeLists.txt.user *.BASE.* *.LOCAL.* +# +# Agents +# +.agents/plans/** + # # Claude # diff --git a/AGENTS.md b/AGENTS.md index 02c62b97a9..63084f8dae 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -5,22 +5,20 @@ AzerothCore is a C++ MMORPG server emulator for World of Warcraft 3.3.5a (WotLK) ## Agent rules - **Do not configure or build unless explicitly asked.** Builds are slow and rarely needed for code changes. -- **Never edit SQL files outside `data/sql/updates/pending_db_*/` unless explicitly requested. ** `data/sql/base/`, `data/sql/archive/`, and `data/sql/updates/db_*/` are immutable. +- **Never edit SQL files outside `data/sql/updates/pending_db_*/` unless explicitly requested.** `data/sql/base/`, `data/sql/archive/`, and `data/sql/updates/db_*/` are immutable. +- Formatting follows `.editorconfig`: UTF-8, LF, max 120 cols, trailing newline, no trailing whitespace; 4-space indent for C++ (tabs forbidden), 2-space for JSON/YAML/sh/ts/js. -## Build +## Mandatory reading per task -Out-of-source build is required (in-source is blocked). +Read the matching doc(s) BEFORE starting the task: -```bash -mkdir -p build && cd build -cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/azeroth-server -DCMAKE_BUILD_TYPE=RelWithDebInfo \ - -DSCRIPTS=static -DMODULES=static -make -j$(nproc) && make install -``` - -C++20 required (`CMAKE_CXX_STANDARD 20`). Useful flags: `BUILD_TESTING=ON` (Google Test), `NOPCH=1` (disable precompiled headers). Full set in `conf/dist/config.cmake`. `compile_commands.json` is exported automatically. - -Tests (Google Test, in `src/test/`): configure `-DBUILD_TESTING=ON`, then `ctest` or `./src/test/unit_tests` from the build dir. +- Compiling, configuring, or running tests → `.agents/docs/build.md` +- Writing or modifying C++ → `.agents/docs/cpp-guidelines.md` + - Script work (under `src/server/scripts/`) → also `.agents/docs/cpp-scripts.md` +- Creating or modifying SQL → `.agents/docs/sql-guidelines.md` + - SmartAI work (`smart_scripts` data) → also `.agents/docs/cpp-scripts.md` +- Touching a subsystem that has a doc in `.agents/docs/systems/` → read that doc too +- Capturing a lesson or adding/updating agent docs → `.agents/docs/README.md` ## Repository layout @@ -30,71 +28,17 @@ Tests (Google Test, in `src/test/`): configure `-DBUILD_TESTING=ON`, then `ctest - `src/server/database/` — DB abstraction and schema updater. - `src/server/shared/` — code shared by auth and world servers. - `src/server/apps/{authserver,worldserver}/` — entry points (ports 3724 and 8085). -- `src/test/` — Google Test unit tests + mocks. -- `data/sql/` — `base/` (historical schema), `updates/db_*/` (merged), `updates/pending_db_*/` (in-flight, **edit here**), `custom/` (gitignored). -- `modules/` — external modules (each a subdir with its own `CMakeLists.txt`). Disable with `-DDISABLED_AC_MODULES="mod1;mod2"`. See `modules/how_to_make_a_module.md`. +- `src/test/` — unit tests + mocks. +- `data/sql/` — `base/` (historical schema), `updates/db_*/` (merged), `updates/pending_db_*/` (in-flight), `custom/` (gitignored). +- `modules/` — external modules (see below). - `apps/` — helper scripts; `apps/codestyle/` holds the lint scripts. - `conf/dist/` — distributed config templates; `conf/*.conf` is gitignored. - `deps/` — vendored third-party dependencies. -## Adding SQL updates +## Modules -1. `cd data/sql/updates/pending_db_world/` (or `pending_db_auth` / `pending_db_characters`). -2. `./create_sql.sh` generates an empty `rev_.sql` to write into. -3. Conventions enforced by `apps/codestyle/codestyle-sql.py`: every `INSERT` preceded by a matching `DELETE` (idempotency); no double semicolons; no multiple blank lines; InnoDB engine. +External modules live in `modules/`, each a subdir with its own `CMakeLists.txt`. Disable with `-DDISABLED_AC_MODULES="mod1;mod2"`. See `modules/how_to_make_a_module.md`. -The three databases: +## Persisting lessons -- `acore_auth` — accounts, realm list, IP/account bans, session keys. Shared across all realms. -- `acore_characters` — per-character state: characters, inventory, in-progress quests, mail, guilds, arena teams, achievements. One per realm. -- `acore_world` — static game content: creature/gameobject/item/quest templates, spawn lists, loot tables, SmartAI scripts, gossip, conditions. Read-mostly; rebuilt from SQL. - -## Code style - -Formatting (charset, indent width, line length, final newline, trailing whitespace) follows `.editorconfig`. - -Run the linters before claiming a change is done: - -```bash -python apps/codestyle/codestyle-cpp.py # C++ -python apps/codestyle/codestyle-sql.py # SQL (compares to origin/master) -``` - -Hard rules (also enforced by CI with `-Werror`, plus `cppcheck`): - -- 4-space indent for C++ (tabs forbidden); 2-space for JSON/YAML/sh/ts/js. UTF-8, LF, max 120 cols, trailing newline. -- Allman braces. No braces around single-line statements. `if (x)` — never `if(x)` or `if ( x )`. -- `auto const&` (not `const auto&`); `Type const*` (not `const Type*`). -- Use `{}` format specifiers (`fmt`-style), not `%u`/`%s`. -- Use the typed helpers, not raw flag access: - - `IsPlayer()`, `IsCreature()`, `IsItem()`, … instead of `GetTypeId() == TYPEID_*`. - - `GetNpcFlags()`, `HasNpcFlag()`, `SetNpcFlag()`, `RemoveNpcFlag()`, `ReplaceAllNpcFlags()` instead of `*Flag(UNIT_NPC_FLAGS, …)`. - - `IsRefundable()`, `IsBOPTradable()`, `IsWrapped()` instead of `HasFlag(ITEM_FIELD_FLAGS, …)`. - - `HasFlag(ItemFlag)` / `HasFlag2(ItemFlag2)` / `HasFlagCu(ItemFlagsCustom)` instead of bitwise `Flags & ITEM_FLAG…`. - - `ObjectGuid::ToString().c_str()` instead of `ObjectGuid::GetCounter()`. - -## Project conventions - -- **Logging**: `LOG_INFO("category.sub", "msg with {}", arg)` (also `LOG_WARN`/`ERROR`/`DEBUG`/`TRACE`). Categories are hierarchical, dot-separated (`server.loading`, `entities.player`, `sql.dev`). No `printf`-style, no `sLog->`, no `TC_LOG_*`. Macro in `src/common/Logging/Log.h`. -- **Random**: use helpers in `src/common/Utilities/Random.h` — `urand`, `irand`, `frand`, `rand32`, `rand_chance`, `roll_chance_f`, `roll_chance_i`. Not `std::rand` or ``. -- **Strings**: `Acore::StringFormat(fmt, args...)` (`{}` placeholders) — `src/common/Utilities/StringFormat.h`. -- **Config**: `sConfigMgr->GetOption("Name", default)`. -- **Namespace**: project-wide `Acore::` (no `Trinity::` remnants — rename when porting from upstream forks). -- **Long-lived references**: don't store a raw `Player*` / `Creature*` / `Unit*` past the current call/tick — the object can be removed (logout, despawn, instance unload) and the pointer dangles. Store the `ObjectGuid` and resolve at use time via `ObjectAccessor::FindPlayer(guid)`, `Map::GetCreature(guid)`, etc. -- **DB queries**: use `PreparedStatement` (via `WorldDatabase` / `CharacterDatabase` / `LoginDatabase` and the prepared-statement enums), not raw query strings. Non-blocking reads go async: `_queryProcessor.AddCallback(db.AsyncQuery(stmt).WithPreparedCallback(...))` (or `WithCallback`). Multi-statement writes wrap in `SQLTransaction` + `Execute` / `AppendPreparedStatement`. -- **Timed actions in AI**: use `EventMap` (event id → delay; simple) or `TaskScheduler` (lambdas, repeats, cancellation), both members of `CreatureAI` — don't roll your own tick counters. See any boss script under `src/server/scripts/`. - -## Scripting registration - -Scripts inherit from a `ScriptObject` subclass (`SpellScript`, `AuraScript`, `CreatureScript`, `InstanceMapScript`, `GameObjectScript`, `CommandScript`, …). Two registration styles coexist: - -- **Spell / aura scripts**: `RegisterSpellScript(ClassName)` (or `RegisterSpellAndAuraScriptPair(...)`) inside `AddSC_()`. -- **Creature scripts**: prefer `RegisterCreatureAI(ClassName)` for new code; legacy zones still use `new ClassName();`. Match the surrounding pattern. - -Then declare and call `AddSC_()` from the regional loader (`Spells/spells_script_loader.cpp`, `EasternKingdoms/eastern_kingdoms_script_loader.cpp`, …). - -**SmartAI** (data-driven creature behaviour) lives in the world DB's `smart_scripts` table, not C++ (engine: `src/server/game/AI/SmartScripts/`). For new creature behaviour prefer SmartAI (via the SQL update workflow); reach for `CreatureScript` only when SmartAI's event/action vocabulary isn't enough. - -**Module hooks** (e.g. `OnPlayerLogin`, `OnWorldUpdate`, `OnSpellCast`) are declared in `src/server/game/Scripting/ScriptDefines/*.h`. Implement by inheriting the matching base (`PlayerScript`, `WorldScript`, …) and registering with `new MyClass();` (or its `RegisterXxxScript` macro) inside `AddSC_()`. Full list: https://www.azerothcore.org/wiki/hooks-script. - -Custom (non-upstream) scripts go in `src/server/scripts/Custom/` (gitignored). +When a user correction reveals a lesson that generalizes, offer to persist it into these docs (placement per `.agents/docs/README.md`): use the `/self-improve` skill if installed, otherwise suggest the user to install it and read this page: https://www.azerothcore.org/wiki/agentic-engineering