Today each of us keeps a private, uncommitted CLAUDE.md (or equivalent) in our clones. Org-wide conventions are already shared through the xwiki-dev-llm plugin, but repo-specific knowledge isn’t shared at all. I’d like to brainstorm committing an AGENTS.md file in our repos, starting with xwiki-platform.
Why
Shared and reviewed: repo knowledge is improved through PRs instead of drifting in each dev’s private file.
Branch-accurate: it’s versioned with the code, so a stable branch carries the facts true for that branch (Java version, modules, test frameworks), which the plugin can’t do.
Tool-agnostic: AGENTS.md is read by Claude Code, Codex, Copilot, Cursor, Gemini, opencode, etc., and works for contributors who don’t have our plugin.
What to be careful about
Duplicating the plugin: if each repo restates the build commands, commit format or @since rules, we get 300+ copies that drift. Each fact must have one home.
Leaking private content: nothing from the private security plugin must end up in a public repo.
Stale facts: volatile data (current version, role holders, etc.) goes stale even when committed.
Personal content: local paths and personal preferences must not be committed.
Context cost: the file is loaded in every agent session, so it must stay small.
Claude Code reads AGENTS.md only when there’s no CLAUDE.md (nor CLAUDE.local.md) in the repo, so a dev’s existing personal CLAUDE.md would hide the shared file.
Proposed solutions
One classification rule: a fact true in any XWiki repo goes in the plugin; a security-sensitive fact goes in the security plugin; only a fact true solely in this repo goes in AGENTS.md. The plugin would tell agents to propose generic facts to the plugin instead.
A small template and a byte budget (a few KB), with a few allowed sections: module map, repo-specific build/test quirks, gotchas.
Commit a one-line CLAUDE.md containing @AGENTS.md, so Claude always loads it. Personal notes move to CLAUDE.local.md or ~/.claude/CLAUDE.md.
Duplicate check when the file is edited: when an agent edits AGENTS.md, the plugin warns if the edit copies plugin content, and the security plugin does the same locally for its own content (never in public CI). Edits made by hand are caught when the PR is prepared.
No boilerplate: only repos with something specific to say get an AGENTS.md.
WDYT? Is this something you’d want, and do you see other risks?
Good idea. To get a realistic example, I simulated the move (nothing committed): I went through the plugin for content that is only useful when working in xwiki-platform itself, i.e. not in commons, rendering or a contrib extension, and moved it to an xwiki-platform/AGENTS.md.
The result is ~3 KB:
xwiki-platform/AGENTS.md
# xwiki-platform
Org-wide XWiki conventions (build, commits, tests, `@since`, code style) are not repeated here: they are in the [xwiki-dev-llm](https://github.com/xwiki/xwiki-dev-llm) plugin. This file only holds what is true in this repository, on this branch.
## Layout
```
xwiki-platform/
├── xwiki-platform-tools/ Maven build plugins and tools
├── xwiki-platform-core/ 100+ feature modules — where development happens
│ ├── xwiki-platform-oldcore the legacy core (com.xpn.xwiki.*), the central engine
│ └── xwiki-platform-<feature> one per feature: rendering, security, livedata, …
└── xwiki-platform-distribution/ WAR packaging, the flavor, the jetty-hsqldb distribution
```
- Nearly every change lands in `xwiki-platform-core/`. A change under `tools/` changes the build of every module, and one under `distribution/` changes what ships: both reach further than their size.
- Modules worth knowing: `-oldcore`, `-rendering-*` (rendering pipeline), `-security-*` (authn, authz, crypto), `-extension-*` (Extension Manager), `-flamingo` (default skin), `-livedata`, `-ckeditor` and `-blocknote` (WYSIWYG editors).
- The OSGi manifest of every JAR comes from the bundle plugin configured once in `xwiki-platform-core/pom.xml`: a module never declares its own.
## Where new code goes
- **Never add to `xwiki-platform-oldcore`**: put the code in the feature module that owns the concern, or a new one. A new module may depend on oldcore, never the reverse; when oldcore turns out to need the new module, the oldcore code that uses it moves out instead.
## Build
- `xwiki-platform-distribution` is in the reactor only with `-Pdistribution`, or build it from its own pom: `mvn clean install -B -ntp -f xwiki-platform-distribution/pom.xml -Plegacy,integration-tests,snapshot`.
- After changing a template in `xwiki-platform-web-templates`, also rebuild `xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-war` (`-DskipTests`): Docker tests take the WAR from the local repository, so they don't see the template until then.
## Functional tests
- Each feature has its own `*-test-docker` module next to it (60+ in `xwiki-platform-core`). Add a feature's tests there, never to `xwiki-platform-flamingo-skin-test-docker`, which is already far too big. `xwiki-platform-distribution-flavor-test` only tests the flavor.
- `xwiki-platform-rest-test-docker` leaves its nested classes without `@UITest` on purpose: don't copy it.
## Frontend
- The JavaScript packages are an Nx monorepo over a pnpm workspace. Their sources are under `src/main/node` in the modules that ship them; `pnpm-workspace.yaml` is the list.
- Use `pnpm`, never `npm` (the lockfile is pnpm's): `pnpm install` once from the root, then `pnpm run build`, or `pnpm --filter <package> run build` for one package.
- `pnpm run build` is only the fast loop: the module's `mvn` build stays the reference, since it runs the linters and packages the WebJar.
Plus a one-line CLAUDE.md containing @AGENTS.md.
What I learnt doing it:
Almost nothing in it is new: it’s mostly content that sits in the plugin today (one OKF topic, parts of the build and Docker test skills, two gotchas) because there was nowhere else to put it. Moving it out removes ~6 KB from the plugin, and the knowledge then follows each branch and is reviewed by the people who work on that code.
It’s a lot less than one would think: knowledge about platform APIs (components, oldcore test APIs, the Docker test framework, Solr, rights, legacy modules) stays in the plugin, since contrib extensions use them too. Only facts about the platform repository move.
Facts kept away from the code go wrong: the simulation found one in the plugin that was already wrong (it said the distribution isn’t in the root reactor, but it is, under -Pdistribution). In the repo, the PR that changes the build would also update the fact.
The bigger win is outside the core repos: commons, rendering and platform are what the plugin’s knowledge base already documents, so their AGENTS.md stays small. A contrib extension (or any other repo) has its own architecture, build quirks and gotchas that the plugin will never hold, and today that knowledge lives nowhere shared. That’s where an AGENTS.md adds the most.
I’m not sure if there is a real advantage, and it increases the maintenance overhead as we now not only need to decide where it belongs in the plugin but also if it belongs in any of the core repositories. I also don’t agree regarding branches: I almost never start Claude Code on an LTS branch, but on master, LTS branches basically exclusively get backports, and re-reading the full AGENTS.md of every branch the backport should land on doesn’t sound useful, in particular if they are 90% identical. Personally, I maintain my own AGENTS.md in a git repository that sits on top of the three core repositories, so I have
xwiki/
├── xwiki-commons/
├── xwiki-rendering/
├── xwiki-platform/
├── AGENTS.md
└── CLAUDE.md (with includes for AGENTS.md and the plugin's main file)
That way, the agent can easily work in any (or several) of the three repositories and I have all of them available in my VS Code setup. This layout would also work with AGENTS.md inside the three repositories, in that case I would probably add includes to my main file.
Not having everyone run /init on every repo and maintain the result alone.
Content that is reviewed and improved over time by everyone, instead of each of us doing it in a private file.
I agree it’s smaller for commons, rendering and platform since the plugin already covers most of them, and bigger for contrib extensions and other repos.
That decision already exists today for everyone who keeps their own AGENTS.md/CLAUDE.md: it’s just made privately, by each of us. Committing the file means it’s made once, in a PR.
Agreed. We work on master and backport from a worktree, so what the session needs to know about a target branch has to be available from master. The per-branch file doesn’t help there, so it’s not an argument for the proposal.
I don’t use that layout and it works well for me, probably because the plugin already holds the cross-repo knowledge. But your AGENTS.md illustrates the problem: it sits outside any repo, so its content only benefits you. With the proposal, its generic parts would go into the plugin and its repo-specific parts into the repos’ AGENTS.md, so everyone gets them.