In a previous post, I outlined a four-step AI adoption strategy for engineering teams. The first step — building a knowledge layer — is the one most teams skip, and the one that matters most.
This post is the practical follow-up. How do you actually build that knowledge layer when you have 50+ engineers, hundreds of Confluence pages, thousands of Jira tickets, and dozens of GitHub repos?
The problem: context fragmentation
In any mid-to-large engineering org, knowledge lives in at least three places:
- Confluence — architecture decisions, runbooks, domain models, onboarding docs
- Jira — what's being built, why, by whom, and what's blocked
- GitHub — the code itself, PRs, reviews, comments, API contracts
An engineer working on Service A needs to understand how Service B's API behaves, what the Confluence architecture doc says about the integration, and whether there's a Jira ticket in flight that changes the contract.
Without that cross-service context, AI generates code that compiles but breaks at integration. It's technically correct and practically useless.
The architecture
The setup has three layers:
1. Knowledge index (Onyx) — crawls and indexes your Confluence, Jira, and GitHub data into a searchable vector store.
2. Context bridge (MCP) — a lightweight server that lets Claude Code query the knowledge index on demand.
3. Local guardrails (CLAUDE.md) — per-repo configuration files that define conventions, patterns, and boundaries.
Engineer asks Claude Code to implement a feature
│
├──▶ MCP → Onyx: fetches Jira ticket details
├──▶ MCP → Onyx: searches Confluence for relevant docs
├──▶ MCP → Onyx: finds related code across all repos
├──▶ Local: reads current codebase directly
└──▶ Local: reads CLAUDE.md for conventions
│
▼
Code generated with full organisational context
Let's walk through each layer.
Layer 1: The knowledge index
You need something that crawls your tools, chunks the content, generates embeddings, and keeps everything in sync. You could build this yourself — the RAG pattern isn't complicated — but at scale, you want something purpose-built.
Onyx (formerly Danswer) is open source, self-hosted, and has pre-built connectors for Confluence, Jira, GitHub, Slack, and Google Drive. You deploy it with Docker, point it at your Atlassian and GitHub credentials, and it handles crawling, chunking, embedding, and incremental sync.
What matters here isn't the tool — it's the principle: centralise your organisation's knowledge into something AI can search. Whether that's Onyx, Glean, or something you build internally, the outcome is the same: a single retrieval layer over everything your team knows.
A few practical notes:
- Incremental sync is non-negotiable. You'll have thousands of documents. Full re-indexing on every change doesn't scale. The sync layer needs to track what's changed since the last run.
- Metadata matters as much as content. Every chunk needs to be tagged with its source, project, author, date, and type. This lets you filter queries — "only search Confluence" or "only this Jira project" — which dramatically improves relevance.
- Stale docs are a real problem. If your Confluence has outdated architecture pages, the AI will confidently use wrong context. Build in a relevance scoring layer, or flag pages that haven't been updated in 6+ months.
Layer 2: The context bridge
Once your knowledge is indexed, you need a way for Claude Code to query it. This is where the Model Context Protocol (MCP) comes in.
MCP is a standard that lets AI tools connect to external data sources through lightweight servers. You build a small MCP server that:
- Accepts search queries from Claude Code
- Hits your Onyx API
- Returns relevant chunks with metadata
The MCP server is configured in your Claude Code settings:
{
"mcpServers": {
"org-knowledge": {
"command": "node",
"args": ["mcp-onyx-bridge/index.js"],
"env": {
"ONYX_API_URL": "https://onyx.internal.yourcompany.com",
"ONYX_API_KEY": "..."
}
}
}
}
With this in place, when an engineer says "implement PROJ-456", Claude Code can:
- Fetch the Jira ticket details, acceptance criteria, and comments
- Search Confluence for related architecture docs and domain context
- Find how other services handle similar patterns across your GitHub org
- Then generate code grounded in all of that context
The bridge is intentionally thin. It's a translator between Claude Code and your knowledge index — not a place for business logic. Keep it simple.
Layer 3: Local guardrails
The knowledge index gives Claude what to know. The guardrails tell it how to behave.
Every repo gets a CLAUDE.md file at its root. This is a plain markdown file that Claude Code reads automatically. It defines:
What this service is and who owns it:
This is the payment-service, owned by the Payments squad.
It processes transactions via Stripe and publishes events to Kafka.
Key dependencies and integration points:
## Dependencies
- webhook-service: receives payment status callbacks (see PROJ-234 for contract)
- notification-service: triggered via Kafka events on payment.completed
- Stripe API: all payment processing goes through our Stripe wrapper in lib/stripe/
Conventions and patterns to follow:
## Conventions
- All API endpoints use the handler pattern in src/handlers/
- Errors must use the AppError class from lib/errors.ts
- Database queries go through the repository pattern, never raw SQL
- All new endpoints need integration tests, not just unit tests
What to never do:
## Guardrails
- Never commit API keys or secrets — use environment variables
- Never bypass the rate limiter middleware
- Never write directly to the payments database from outside this service
This is the centralised agent skills definition from the adoption strategy. When you standardise these files across your org, you get consistent AI behaviour everywhere — same patterns, same guardrails, same quality bar.
How it comes together: a real example
An engineer on the Payments squad picks up PROJ-456: "Add retry logic to payment webhook handler."
They open Claude Code in the payment-service repo and type: "Implement PROJ-456."
Here's what happens:
- Claude reads
CLAUDE.md— knows this is the payment-service, knows the handler pattern, knows the error conventions - Claude queries Onyx via MCP — fetches PROJ-456 from Jira, gets the description, acceptance criteria, and a comment from the tech lead saying "use exponential backoff, max 3 retries"
- Claude queries Onyx for "webhook retry" in Confluence — finds the architecture doc that specifies retry policy and SLA requirements
- Claude queries Onyx for related code across GitHub — finds that notification-service already implements retry logic with the same pattern, sees the exact backoff parameters
- Claude reads the local codebase — finds the existing webhook handler, the test patterns, the Kafka publisher
- Claude generates the implementation — with exponential backoff (not just simple retry), matching the existing notification-service pattern, following the handler convention, with integration tests
That's the difference between "AI that writes code" and "AI that writes code that belongs in your system."
Rollout
Don't try to set up all three layers at once. The sequence matters:
Week 1–2: Deploy Onyx. Connect Confluence, Jira, and GitHub. Let it index. Validate that search results are relevant. This is your foundation — if the knowledge layer is bad, everything built on top of it will be bad.
Week 3: Build the MCP bridge. A thin server that queries Onyx. Test it with Claude Code on one repo, with one senior engineer. Iterate on the query patterns — you'll learn what context Claude actually needs vs. what's noise.
Week 4–5: Write CLAUDE.md files for key repos. Start with 3–5 high-traffic repos. Have the senior engineers who own those repos write them. These files encode years of tribal knowledge into something AI can use.
Week 6+: Expand. More repos, more engineers, more refined guardrails. The senior engineers who piloted the setup become the advocates.
The unglamorous truth
None of this is technically hard. Docker, a small MCP server, and some markdown files. The hard part is organisational:
- Getting Confluence clean enough that AI doesn't hallucinate from outdated docs
- Getting engineers to write and maintain CLAUDE.md files
- Getting leadership to invest in the indexing infrastructure before they see results
But the teams that do this work end up with something genuinely powerful: AI that doesn't just write code — it writes code that understands why the code exists, how it fits into the system, and what constraints it needs to respect.
That's the context layer. And it's the difference between AI as a toy and AI as infrastructure.
This is the practical companion to A Practical AI Adoption Strategy for Engineering Teams. If you're building this for your org and want help with the setup, get in touch.