DEV Community

Cover image for Turn a Codebase into a Domain Model Your Team Signs Off On
MrOops
MrOops

Posted on Edited on

Turn a Codebase into a Domain Model Your Team Signs Off On

Updated September 2026 with what has shipped since this was published. The limits section at the end says what changed.

Every team I have worked on keeps two versions of the same product in its head.

One is the code. It is honest about what actually runs, but it speaks in class names and package paths. A PM cannot read it, and even an engineer new to the service cannot tell from it why a rule exists or who asked for it.

The other is the intent. It lives in PRDs, design docs, Notion, and an old Slack thread no one can find. It speaks the language of the business, but nobody keeps it in sync once the code lands. Before long no one trusts it, and everyone ends up back at an engineer's desk to confirm what is actually true.

These two drift apart every sprint, and the team ends up arguing about which one is right. Braid is my attempt to stop that argument by keeping a single model both sides can read. It is a framework. You bring the sources and pick an ontology, and it runs a loop where the AI drafts and asks, and people decide.

The Shape of the Idea

Braid reads your sources, and an AI drafts a domain model from them. The model is typed by an ontology, so it reads as a domain rather than a call graph. The default ontology is Domain-Driven Design, so a node is a bounded context, an aggregate, a command, or a rule, named in the ubiquitous language of the product.

A domain model is less an extraction than an agreement. The same code admits more than one honest reading, and the one that counts is the one the domain's owners will stand behind. Some of it is never in the source at all, like why a rule exists, and only a person can supply that, which is why the AI never has the final say here.

The result is one artifact an engineer, a PM, and a QA can all point at, traced back to the source it was drawn from.

A Real Run, from Code Alone

The strongest version of the claim is the hardest one. Give Braid a codebase with no docs at all, and see whether it produces something a person would recognize as their domain.

So in Studio I created a workspace, pointed it at conciergent, a service of mine that gives MCP tools a chat face on Slack, LINE, and Discord, and gave it no intent documents at all. Only the code.

Braid splits the codebase into business units first, models each one, then reconciles the overlaps into a single graph. The scan found eight units on this repo, and the reconciled model has 120 nodes and 159 edges across five bounded contexts, with no failed unit.

The conciergent model in Braid Studio, bounded contexts and aggregates

The full example is committed at examples/conciergent.

What Braid Actually Does

Each of these showed up in that run, and each is checkable in the committed example.

1. A Model in the Language of the Domain

The nodes are not classes. They are the concepts the product is about, described in plain language. Here is one aggregate from the run, its description quoted directly with the trailing state diagram left out:

Pending Approval. A sensitive action held back until the user says yes. When the assistant wants to use something the tool provider marked destructive, the action does not run. The work already in flight is set aside, and the user is shown a confirmation with Confirm and Cancel.

Rules that always hold:

  • At most one confirmation waits per conversation, and picking it up consumes it, so the same held work can never run twice.
  • The confirmation ages out on its own, and held work that can no longer be read counts as expired.
  • One answer decides every action held in that pause.

Nothing in there is Domain-Driven Design jargon, and nothing is a code identifier. It reads like a domain expert explaining the rule, because that register is exactly what the ontology asks the model to write in. A PM can read it, a QA engineer can turn each rule that always holds into a test, and an engineer can check it against the code.

2. The AI Drafts, a Person Decides

An AI-built model will not always match how each expert sees the domain. So Braid does not let the AI write to the model directly. Every change is a proposal, reviewed before it lands, and every disagreement is settled by a person rather than by the model's confidence.

Running extract over one issue in Braid Studio, then reading the evidence and the operations behind the proposal it produced, and applying it

Running extract over one source document, then opening the proposal it filed. Basis is the run's own accounting of which searches it ran and which nodes it cited. The operations list is every add and update the proposal would make. Nothing reaches the graph until Apply.

A question the run stopped on and a change it proposed arrive in the same queue, because what makes them one kind of thing is who has to act next. When the model runs into something genuinely ambiguous, it does not paper over it. It raises the question and waits, and the answer becomes part of the model.

3. Every Claim Points Back at Its Source

Each node carries a reference to the source it was drawn from, down to the file and line for a code source. A claim in the model can be traced back to the exact place it came from rather than taken on trust. When you disagree with a node, you can open the evidence and see what the AI was reading when it wrote it.

A node whose evidence has moved says so on its own face, rather than waiting for somebody to notice.

A View for a PM or QA, Projected from the Model

The model is the one artifact everything else derives from, and everything else is a read-only projection you regenerate rather than a second copy that drifts. You can read it as the graph itself, put a question to it and have a run answer over it, or write it out as a document. A document is the one to show here, written from material projected off the graph rather than kept in sync by hand. Here is how the one for the Conversation Turn Lifecycle context opens, unedited:

Conversation Turn Lifecycle

A person sends one message in a chat app and expects one useful answer back. Answering can detour through a sign-in, a confirmation the user has to tap, or a conversation so long the assistant can no longer hold all of it. This subsystem owns that single round trip, from an arriving message to a sent reply and an up-to-date conversation memory.

It goes on with a glossary of the terms the subsystem uses, the people it serves, each use case with the rules that always hold, and a lifecycle diagram. None of it is in code terms. It closes with the exact nodes it was drawn from:

Source nodes: ctx.conversationTurn, actor.chatUser, agg.turn, cmd.runTurn, evt.replySent, rule.oneReplyPerTurn, and twenty-five more.

Because the projection is a function of the graph, the same subject can be written more than one way for more than one reader, and each one knows when the graph has moved past it.

How It Compares

I did the homework so you do not have to. Braid sits next to three kinds of tool teams reach for today, each solving part of this problem.

Braid Team Docs AI Repo Wiki Self-Writing Wiki
A Typed Graph Model Yes, Nodes and Edges No, Pages Partly, Diagrams Partly, Linked Pages
Speaks the Domain Yes Yes No, Code-Facing Partly, Freeform
Keeps Pace With the Source Yes, Reacts to Source No, Drifts Yes, Regenerates Yes, Compounds
A PM or QA Can Read It Yes Yes Partly Yes
One Reviewed Source of Truth Yes, Human-Gated No, Hand-Maintained No, Auto-Generated No, Self-Written
Traceable to the Source Yes, Per Node No Partly, Links to Code Weak
Examples n/a Notion, Confluence DeepWiki llm-wiki

A reading guide for the table:

  • Team Docs in Notion or Confluence are the simplest option if you can live with prose that drifts.
  • AI Repo Wiki like DeepWiki gives the quickest read on an unfamiliar repo, but it documents the code rather than the business, and nobody reviews what it writes.
  • Self-Writing Wiki like llm-wiki maintains itself and resolves contradictions on its own. That is also the risk, since the AI has the final say and you are out of the loop.
  • Braid is for one reviewed, traceable model of the domain that engineers, PMs, and QA can all read and that keeps pace as the code moves.

What Is And Is Not There Yet

Braid is a young project, and I would rather be precise than oversell it. Everything above works today. Three things do not, in case one of them would block you.

  • Ontologies Beyond DDD: the ontology is a plugin and the framework does not assume DDD, but DDD is the only one shipped so far.
  • Agents Beyond a Coding Agent: the agent is a plugin axis too, and Claude Code is the only one shipped. Reading the model conversationally was on the roadmap when this was published and now ships as Ask.
  • Proof at Scale: the runs so far are modest repos like the one above. Whether the model stays coherent on a large, sprawling codebase is unproven, and it is genuinely hard to validate.

One more thing worth saying plainly. Extending Braid means putting files on disk, and there is no form for it. A plugin is registered where you start the server, so swapping an axis means owning the entry point rather than configuring the shipped binary. If one of these is what stands between you and trying it, an issue with the shape of your problem helps more than my guesses.

Closing

This is a personal side project, built to settle an argument I have watched teams have for years. If the drift between what shipped and what the team meant sounds like your problem, give it a run and open an issue with what is missing.

Top comments (0)