Organizing our LLM configs for all our repos

Hi devs,

Now that we’ve started exploring/using LLMs, I feel the next step is deciding how to capitalize and share our setup between devs as much as possible.

Goals:

  • better consistency in LLM results
  • benefit from the work of other devs
  • simpler developer onboarding

Here’s an idea to get the conversation started.

The requirements I see:

  • Be able to have different setups for repos in the xwiki GH org and the xwiki-contrib GH org repos.
  • Be able to have a different setup for your own projects
  • Be able to have common setup
  • Ideally support different LLMs (however, the example below is mostly for Claude Code)

Claude Code natively walks up the directory tree loading every CLAUDE.md it finds. Organize repos by org on disk and you get context-switching for free.

Directory Layout on Developer Machine

  ~/dev/
  ├── xwiki/
  │   ├── CLAUDE.md           ← xwiki-org-wide config (symlink → xwiki-dev repo)
  │   ├── .claude/
  │   │   └── settings.json   ← xwiki-org MCP servers (symlink)
  │   ├── xwiki-commons/
  │   ├── xwiki-rendering/
  │   └── xwiki-platform/
  │       └── CLAUDE.md       ← repo-specific (checked in)
  ├── xwiki-contrib/
  │   ├── CLAUDE.md           ← contrib-wide config (symlink → xwiki-contrib-dev repo)
  │   ├── some-extension/
  │   └── another-extension/
  │       └── CLAUDE.md       ← repo-specific (checked in)
  └── personal/
      └── my-project/         ← no XWiki config loaded at all

Claude Code auto-composes: working in xwiki-platform loads ~/.claude/CLAUDE.md~/dev/xwiki/CLAUDE.mdxwiki-platform/CLAUDE.md. Personal projects get none of it.

Two Shared Repos

  │              Repo               │                                    Scope                                    │
  ├─────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────┤
  │ xwiki/xwiki-dev                 │ xwiki org conventions, core dev skills, strict standards                    │
  ├─────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────┤
  │ xwiki-contrib/xwiki-contrib-dev │ contrib conventions — inherits xwiki-dev where applicable, looser where not │
  └─────────────────────────────────┴─────────────────────────────────────────────────────────────────────────────┘

Note that xwiki-dev could actually be the existing xwiki-dev-tools (with a subdirectory for LLM configs). And we’d create a similar repo for xwiki-contrib.

xwiki-contrib-dev’s CLAUDE.md can simply @see xwiki-dev content and add/override.

What Symlinks to What:

~/dev/xwiki/CLAUDE.md~/dev/xwiki/xwiki-dev/claude/CLAUDE.md
~/dev/xwiki/.claude/~/dev/xwiki/xwiki-dev/claude/.claude/
~/dev/xwiki-contrib/CLAUDE.md~/dev/xwiki-contrib/xwiki-contrib-dev/claude/CLAUDE.md

setup.sh in each shared repo creates these symlinks. Developers run it once after cloning.

Layer Summary

  │  Layer   │             File              │           Source            │     Loaded when     │
  ├──────────┼───────────────────────────────┼─────────────────────────────┼─────────────────────┤
  │ Personal │ ~/.claude/CLAUDE.md           │ developer's own             │ always              │
  ├──────────┼───────────────────────────────┼─────────────────────────────┼─────────────────────┤
  │ Org-wide │ ~/dev/xwiki/CLAUDE.md         │ xwiki-dev repo (symlink)    │ all xwiki/* repos   │
  ├──────────┼───────────────────────────────┼─────────────────────────────┼─────────────────────┤
  │ Org-wide │ ~/dev/xwiki-contrib/CLAUDE.md │ xwiki-contrib-dev (symlink) │ all contrib/* repos │
  ├──────────┼───────────────────────────────┼─────────────────────────────┼─────────────────────┤
  │ Repo     │ <repo>/CLAUDE.md              │ checked in to repo          │ that repo only      │
  └──────────┴───────────────────────────────┴─────────────────────────────┴─────────────────────┘

MCP Servers — The Limitation

Claude Code only reads .claude/settings.json at the project root, not parent dirs. So for org-wide MCP:

  • Option A: setup.sh merges org MCP entries into ~/.claude/settings.json (simplest)
  • Option B: Each repo’s .claude/settings.json includes them (checked in, no secrets)
  • Avoid: Putting tokens in checked-in files — setup.sh handles secret injection into ~/.claude/settings.json

Skills

  • Use npx skills add <owner/repo> to add a skill (that uses the tool from vercel-labs/skills GH repo)
  • When you do so, it creates a skills-lock.json file to lock the skill used in a given version.
  • We share custom skills by putting them in our xwiki-dev (and xwiki-contrib-dev repos if need be)
  • Developers install the custom skills globally (or inside each repo, as they wish) using npx skills add ./path/to/the/skills/directory
  • We commit the skills-lock.json in our xwiki-dev repo (and xwiki-contrib-dev repo if need be)
  • Developers install the 3rd party skills by running npx skills experimental_install which will read the skills-lock.json file and install the skills defined in it.

New Developer Onboarding

  # One-time setup
  mkdir -p ~/dev/xwiki ~/dev/xwiki-contrib
  cd ~/dev/xwiki && git clone https://github.com/xwiki/xwiki-dev
  ./xwiki-dev/setup.sh   # creates symlinks, prompts for API keys

  cd ~/dev/xwiki-contrib && git clone https://github.com/xwiki-contrib/xwiki-contrib-dev
  ./xwiki-contrib-dev/setup.sh

After that, cloning any repo under the right directory “just works” — correct CLAUDE.md and MCP context auto-loads.

WDYT?

Open questions

  • Do you see some simpler structure/process? We could use git submodules but I find it more complex to use.
  • Could we use a xwiki claude plugin to distribute everything (and a xwiki-contrib plugin too)? I haven’t researched this.
  • We need to be careful to commit the minimum to the claude.md files, skill files, etc. And review them from time to time.
  • For those using LLMs other than Claude code, could it work with what’s defined above?

If we agree, then the next step is to propose some claude.md file for the different levels, and start with that, as it’s the most important.

I’ve asked claude to review my proposal and it got some interesting idea (the plugin marketplace being the best one IMO):


Following up on my own proposal — I dug into the Claude Code internals a bit more and want to refine the design. A few things turn out simpler than I first thought.

  1. The MCP “limitation” mostly isn’t one. MCP servers aren’t configured in .claude/settings.json — they live in .mcp.json at the repo root (project scope, checked in, shareable), or in user scope. And
    .mcp.json supports ${ENV_VAR} expansion, so secrets never need to be committed and we don’t need a setup.sh to inject them. We’re already doing exactly this in xwiki-platform (discourse + sonarqube, with ${SONARQUBE_TOKEN}). So the real question isn’t “how do we inject secrets,” it’s just “how do we avoid copy-pasting the same .mcp.json into every repo” — which the next point solves.

  2. Plugins + a marketplace can replace the symlinks entirely. A Claude Code plugin bundles skills, slash commands, subagents, hooks and MCP servers as one versioned unit, and a marketplace is just a git repo listing plugins. So instead of symlinks + setup.sh + a strict ~/dev/xwiki/ layout, onboarding becomes:

    /plugin marketplace add xwiki/xwiki-dev-tools
    /plugin install xwiki-core # + xwiki-contrib for contrib devs

    This removes the dependency on cloning into a specific directory, is versioned/updatable, works across machines, and carries the org-wide MCP servers with it. We’d keep the personal→org→repo CLAUDE.md
    layering for org-wide prose, but push tooling into the plugin. This is the answer to my own open question about an “xwiki claude plugin.”

  3. For non-Claude tools, lean on AGENTS.md. Several of us already run other tools (I use opencode alongside Claude Code). AGENTS.md is the cross-tool standard; CLAUDE.md is Claude-only. So I’d put the tool-agnostic content in AGENTS.md and make CLAUDE.md thin — basically @AGENTS.md plus Claude-specific bits. One source of truth, every tool benefits.

  4. Two corrections to my original post: the import syntax is @path (not @see), and a relative cross-repo import like @../xwiki/xwiki-dev/… only resolves if both repos are cloned side by side — fragile, and another reason to prefer the plugin’s dependency model over file paths.

  5. Governance. Since shared CLAUDE.md/skills/hooks are effectively executable agent instructions (a prompt-injection / supply-chain surface), I’d add a CODEOWNERS on the config repo and a short “what may go in shared configs” policy (no secrets, no auto-approved destructive actions). We already pin third-party skills via skills-lock.json, which is the right instinct.

Revised shape: keep the layered CLAUDE.md model, but (a) distribute skills/commands/agents/MCP via an xwiki-dev-tools marketplace + xwiki-core plugin, (b) put shared prose in AGENTS.md imported by CLAUDE.md, (c) rely on .mcp.json + ${ENV} (already in use) instead of setup.sh, (d) add CODEOWNERS + a short policy. That drops the symlinks, the setup.sh, and the directory-layout requirement, and makes it multi-LLM by construction.

If that sounds right, I’ll prototype a minimal xwiki-dev-tools marketplace with one xwiki-core plugin (one skill + our MCP servers) so we can try it before rolling it out. WDYT?


Update: I built a small working prototype so we can get a concrete feel for the plugin/marketplace approach rather than just discussing it in the abstract.

PR: [llm] Add Claude Code plugin + marketplace prototype (xwiki-core) by vmassol · Pull Request #19 · xwiki/xwiki-dev-tools · GitHub

It turns xwiki-dev-tools into a Claude Code marketplace with one xwiki-core plugin. Install is two commands, no symlinks and no setup.sh:

/plugin marketplace add https://github.com/xwiki/xwiki-dev-tools
/plugin install xwiki-core@xwiki-dev-tools

A few things the prototype demonstrates / clarifies vs. my original post:

  • Org-wide instructions auto-load every session. A CLAUDE.md bundled in a plugin is not loaded by Claude Code, so the shared conventions are injected via a SessionStart hook (instructions/xwiki-org.md). This is our “CLAUDE.md for all repos”.
  • Scoping is by git remote, not directory layout. The hook only fires in xwiki/* and xwiki-contrib/* repos — personal projects get nothing, and there’s no required ~/dev/xwiki/ structure.
  • It’s cross-platform. The hook is written in Node (which ships with Claude Code), so it works for Windows devs too — no bash/jq.
  • No committed secrets. The bundled MCP servers (discourse, sonarqube) use ${ENV} expansion.
  • It also ships one demo skill (xwiki-build) just to show how shared skills ride along.

It’s deliberately minimal — instructions/xwiki-org.md only has a handful of conventions and there’s just one skill. The point is the shape, not the content. If we like the direction, next steps would be a sibling xwiki-contrib plugin (looser standards), fleshing out the conventions, and adding CODEOWNERS for the shared config. WDYT?

PS: I haven’t tested it yet.

I didn’t receive any answer so I’ll go ahead and start experimenting by creating a new repo in the XWiki GH org: xwiki-dev-llm. We could decide to merge it with xwiki-dev-tools in the future or not.

Thanks