Building a Schema With an AI Agent Without Naming a Single Column

· Updated

Ask an AI agent for a discussion-board schema and you’ll get one in about four seconds. Here is the part nobody mentions: you’ll also get is_deleted in this table and del_yn in the next one, because the model is pattern-matching against every schema on GitHub, and those schemas disagree with each other and with you.

The fix is not a better prompt. It is giving the agent the same thing you’d give a new hire — the list of words your team actually uses — and making it impossible to ignore.

I did that with a threaded discussion board. I never typed a column name. The whole run fits in three and a half minutes:

The setup, in one call

The agent starts by binding a new project to our team standard:

create_erd {
  name: "Threaded Discussion Board",
  workspaceId: "…",
  target: { server: true }
}

get_erd_overview
// → { glossaryLinked: true, dictionaryEntryCount: 28, domainCount: 15 }

Twenty-eight words and fifteen domains arrive with the project. That is the whole trick. From here the agent isn’t choosing names — it’s resolving them.

Describing the work

Then I talked to it the way I’d talk to a colleague: members post articles, a post can reply to another post, members comment on posts.

The agent called the tools with logical names — business terms, not column names:

upsert_entity    { logicalName: "Post" }              // → POST
upsert_attribute { logicalName: "Post Content",
                   domain: "Content" }                // → POST_CNTS
upsert_attribute { logicalName: "Delete Flag",
                   domain: "Flag" }                   // → DELETE_YN

ContentCNTS and FlagYN aren’t the model’s taste. They’re our word list’s abbreviations, applied exactly as they were applied in every table we’ve built before. The domain carries the type, so Content is varchar(1000) everywhere — nobody decides column widths per table anymore.

Notice what didn’t happen: I didn’t review a name and correct it. There was nothing to correct.

The part most tools get wrong

Then the board needed threading — a post that replies to another post. A self-referencing foreign key.

This is where diagram tools quietly fall over. The child column can’t reuse the parent’s name (POST_NO referencing POST_NO in the same table), so something has to give it a role. Most tools either refuse, or let you type whatever you want, which is how you end up with parent_id in one table and prnt_post_no in another.

Here the role prefix is itself a naming rule, resolved through the same word list as everything else:

`PARENT_POST_NO` varchar(20) COMMENT 'Parent Post Number'

Register ParentPRNT in the word list and it becomes PRNT_POST_NO instead — team-wide, in every self-referencing relationship anyone ever draws. The prefix is a decision made once, by the standard’s owner, not per-table by whoever is typing.

What happens when a word is missing

Real modelling hits words nobody registered. Ours didn’t have “Delete”, which is why DELETE_YN came out unabbreviated. The lint said so:

lint_erd
// → { code: "unknown-word", severity: "warning", objectName: "Delete Flag" }

The agent’s move here is the interesting one. It does not invent DEL. It files a proposal:

propose_dictionary_word {
  logicalWord: "Delete", physicalWord: "DELETE", abbreviation: "DEL",
  note: "Found while modelling the discussion board"
}
// → { status: "pending" }

A human approves it, and the abbreviation propagates to every connected project. The agent is a proposer, not an authority. That distinction is the entire difference between an assistant and a liability — and it’s the thing a chatbot with no shared state cannot do, no matter how good the model gets.

Checking work that already exists

The same computation runs backwards. Give it a name someone already wrote and it tells you what the standard would have produced:

check_naming { logicalName: "Customer Phone Number",
               physicalName: "CUSTOMER_PHONE_NUMBER" }
// → { generatedPhysicalName: "CUST_TEL_NO", compliant: false }

That runs in CI with no agent involved — npx sqemo-mcp lint schema.erd.json exits 1 on violations. Humans, agents, and pull requests all get held to the same computation.

The output

CREATE TABLE `POST` (
  `POST_NO`        varchar(20)   NOT NULL COMMENT 'Post Number',
  `POST_CNTS`      varchar(1000) NOT NULL COMMENT 'Post Content',
  `DELETE_YN`      char(1)       NOT NULL DEFAULT 'N' COMMENT 'Delete Flag',
  `PARENT_POST_NO` varchar(20)            COMMENT 'Parent Post Number',
  PRIMARY KEY (`POST_NO`)
);

The business terms survive as column comments, so the meaning reaches the database instead of dying in a diagram nobody opens.

What it doesn’t do

Being straight about the edges:

The point

Look at who decided what:

DecisionMade by
Which tables and relationships existMe, in business terms
Abbreviations, separators, caseThe team standard
Data typesDomains
New words entering the standardThe standard’s owner, by approval

The agent did the typing and none of the deciding. A naming convention in a wiki asks every person and every tool to remember it. This one is computable, which means it can be applied, checked, and enforced without anyone remembering anything.

The step-by-step version, with every call and its output, is in the walkthrough. If you want the argument before the tutorial, an ERD MCP server covers what these tools are and where they stop; database naming conventions covers what to put in the word list in the first place.

Try it in the app — no signup — or point your agent at npx sqemo-mcp.