A formal language that reads like English
FORML is precise enough for a machine to check and plain enough for a person to argue with. That combination is rarer than it sounds.
The usual trade
Every attempt to write down what a system means lands somewhere on a line with two bad ends. At one end sits formal logic: unambiguous, checkable, and unreadable by the person who actually knows whether the rule is right. At the other sits prose: readable by everyone, checkable by no one, and quietly wrong within a quarter.
Teams resolve this by producing both and maintaining neither. The formal artifact becomes the schema, which drifts toward whatever the code needed last sprint. The readable artifact becomes a Confluence page, which drifts toward fiction. Nothing connects them, so nothing detects the moment they start disagreeing.
FORML — the Formal Object-Role Modeling Language — refuses the trade by making one artifact render as the other. The constraints are structured data. The sentences are generated from that data. There is no second document to keep in sync, because the readable version is a projection of the checkable one and cannot say anything the model does not.
A sentence that a domain expert can reject and a validator can enforce is the same sentence. That is what makes it usable as context for an agent.
Formal, in the way that matters
FORML sentences look like English and are not written in it. Each is emitted from a specific constraint by a specific rule, which is why the vocabulary is so small and so repetitive — the repetition is the grammar.
| What the model holds | What it reads as |
|---|---|
| A fact type, no constraints | It is possible that some Person works for some Company. |
| Uniqueness on the first role | Each Person works for at most one Company. |
| Uniqueness + mandatory | Each Person works for exactly one Company. |
| Uniqueness spanning two roles | In each population of “Person has Skill”, each Person, Skill combination occurs at most once. |
| A value constraint | It is necessary that the possible values of GenderCode are {'M', 'F'}. |
| An exclusive, exhaustive subtype set | It is necessary that each Person is exactly one of: Employee or Contractor. |
| A subset constraint | It is necessary that if some Person drives some Car then some Person holds some Licence. |
| An objectified fact type | Each Enrolment objectifies exactly one “Student enrols in Course” fact. |
| The same rule, deontic | It is obligatory that each Employee has a Salary. |
Two details in that table carry more weight than the rest.
The first is the difference between rows two and three. At most one and exactly one differ by a single mandatory dot on a role. The distinction is invisible in a class definition, ambiguous in prose, and fully explicit here — and it is precisely the distinction an agent gets wrong when it guesses from a nullable column.
The second is the last row. It is necessary that marks an alethic rule: it cannot be otherwise, and the database will enforce it. It is obligatory that marks a deontic one: it should not be otherwise, but the system must be able to record the violation anyway. Most modelling languages have no way to say the second, so it gets modelled as the first, and six months later somebody is writing a workaround for the fact that a legitimate exception cannot be saved. An agent reading the model can tell which kind of rule it is looking at before it writes the migration.
Why this is the right format for an agent
Given a choice of context formats, the useful question is not which one is most expressive but which one an LLM parses with the fewest degrees of freedom. FORML scores unusually well, for four reasons that have nothing to do with it having been designed for machines — it was designed for business analysts in the 1990s.
- It is already the native modality. No diagram to interpret, no XML to walk, no notation legend to hold in working memory. Declarative sentences are what these models are best at, and the model was already stored as text.
- The vocabulary is closed. each, at most one, exactly one, it is necessary that, it is obligatory that, if…then, if and only if, no…both. A small, repeated set of quantifiers means the same rule reads the same way every time, so there is nothing to normalise and no house style to infer.
- Absence means something. Because every constraint verbalizes, a rule that is not in the text is a rule that is not in the model. That converts silence from ambiguity into information — the one thing prose documentation can never do.
- It round-trips. The sentence came from a constraint, so a claim about the sentence is a claim about the model, and it can be checked. An agent that quotes FORML back is quoting something falsifiable.
Grounded in examples, not just rules
A rule is easier to apply when you have seen it hold. ORM models carry sample populations — real example rows stored in the same file — and the verbalizer substitutes them back into the readings:
- Employee 101 works for Acme.
- Employee 102 works for Acme.
- Employee 103 works for Globex.
For an agent, that is few-shot grounding it did not have to be given, in the same vocabulary as the rules. For a domain expert it is the sanity check that catches invented fact types — a fact type nobody can populate with a real example is usually one that does not exist. And the validator checks the constraints against those same rows, so a uniqueness or value constraint contradicted by your own data is reported rather than believed.
The whole domain, in a prompt
Size is the quiet advantage. A domain that occupies forty tables and several thousand lines of DDL is a few hundred FORML sentences. That fits in a context window whole, which changes the shape of the problem: there is no retrieval step, no chunking, no risk of reasoning about one constraint while the interacting one sits unretrieved.
$ factum verbalize model/domain.orm.json | wc -w
1 842
The same command is how you put the domain in front of an agent that does not speak MCP: pipe it
into the prompt. With factum-mcp the agent calls verbalize_model itself,
along with read_population for the examples and validate_model to check
whatever it proposes.
Formal languages people will actually maintain
There have been many attempts at a business-rules language a machine can execute — SBVR, OCL, Schematron, a long tail of DSLs. Most are technically excellent and nearly unused, and the reason is consistent: the person who knows the rule cannot read the artifact, so the artifact is written by someone who does not know the rule, and it rots.
FORML avoids that trap by never asking anyone to write it. You draw a fact type and place a constraint; the sentence is generated. The formal artifact is a by-product of an act of modelling that a domain expert can watch and correct in real time — which is why it is still accurate a year later, and why it is worth handing to an agent at all.