Model a domain by dialogue
The gnd-model-from-text skill turns a conversation into an executable ontology. It
follows Halpin's Conceptual Schema Design Procedure (CSDP). Your agent asks for
concrete examples, verbalizes each elementary fact back to you, and then asks about
constraints one at a time, using your sample data. You answer in plain language; the
agent writes model.orm.yaml and a readable verbalization, then runs gnd validate.
Every constraint it writes records why it exists (provenance: the step, the turn,
your words) and how hard it is (modality: alethic or deontic). Its source is one
of explicit, sample, common-sense, llm-inferred or user-supplied, so you can
tell what you said from what the model guessed.
Ask for a model
Use gnd-model-from-text in Guided mode to model our movie catalog. Ask me for example
movies first, confirm each fact with me, then ask about uniqueness and mandatory roles.
Write model.orm.yaml and model.verbalization.txt and validate the model.
Modes: Guided walks every CSDP step in conversation, one confirmation at a time.
MVP-fast runs the same steps in batches, covers only the slice you are building now,
and ends with one compact review; it is the default for prototypes. One-shot drafts
the whole model from a rich description for you to review. Unattended is for a
pipeline with nobody to review: the model says so (source.mode: unattended), confirms
nothing, and cites a span of its source text for every claim (a common-sense constraint
cites its library entry and an induced one its induction evidence instead), which
gnd validate --document re-hashes for every document you supply.
Unattended mode covers Steps 3 to 7 too: the skill's references/unattended-growth.md says
what text licenses a uniqueness, mandatory, value or subtype proposal, how a pipeline grows the
model one document at a time (including how a round declares its new document and acts on a
shape match), and the reply shape a host asks its model for.
What the dialogue looks like
The skill ships a complete illustrative dialogue for a small movie catalog
(gnd-model-from-text/examples/movie_catalog.dialogue.md). An excerpt from step 1,
elementary facts:
Agent: Let me decompose into elementary facts and verbalize each. Please confirm, correct, or reject: "Movie #1 has title 'The Departed'." Is this an atomic fact?
User: All four are atomic. We treat title, director, release year, and rating as independent facts per movie.
From step 4, uniqueness:
Agent: Movie directed-by Director: each Movie has one Director in your sample. Always true, or are co-directors allowed?
User: We pick one director for co-directed films. So yes, one Director per Movie.
Each answer becomes a constraint that carries your words:
- id: movie_directed_by_director
reading: "{Movie} directed by {Director}"
constraints:
- type: uniqueness
roles: [movie]
source: explicit
status: confirmed
modality: alethic
provenance:
csdp_step: 4
dialogue_turn: 20
user_quote: "We pick one director for co-directed films. So yes, one Director per Movie."
Check the model the agent wrote
The finished model ships with the skill, so you can check it directly:
from importlib.resources import files
from shutil import copyfile
copyfile(str(files("gnd") / "skills" / "gnd-model-from-text" / "examples" / "movie_catalog.orm.yaml"),
"model.orm.yaml")
Every constraint carries its modality and provenance; the skill does not leave either implicit:
from ruamel.yaml import YAML
model = YAML(typ="safe").load(open("model.orm.yaml"))
constraints = [c for ft in model["fact_types"] for c in ft.get("constraints", [])]
constraints += model.get("constraints", [])
for c in constraints:
assert c["modality"] in {"alethic", "deontic"} and c["source"] and c.get("provenance") is not None
print(len(constraints), "constraints, each with a modality, a source and provenance")
Now the model checks the agent
Once you accept the model, it judges every later output. Write the sample catalog from the dialogue, plus a draft an agent might produce, with a second title for Parasite and a rating that does not exist:
import copy, json
facts = {
"movie_has_title": [{"movie": 1, "title": "The Departed"}, {"movie": 2, "title": "Inception"},
{"movie": 3, "title": "Parasite"}],
"movie_directed_by_director": [{"movie": 1, "director": "Martin Scorsese"},
{"movie": 2, "director": "Christopher Nolan"},
{"movie": 3, "director": "Bong Joon-ho"}],
"movie_released_in_year": [{"movie": 1, "year": 2006}, {"movie": 2, "year": 2010},
{"movie": 3, "year": 2019}],
"movie_has_rating": [{"movie": 1, "rating": "R"}, {"movie": 2, "rating": "PG-13"},
{"movie": 3, "rating": "R"}],
}
header = {"model": "model.orm.yaml", "source": "synthetic", "covers": list(facts)}
json.dump({"population": header, "facts": facts}, open("catalog.population.json", "w"), indent=1)
draft = copy.deepcopy(facts)
draft["movie_has_title"].append({"movie": 3, "title": "Gisaengchung"})
draft["movie_has_rating"][1] = {"movie": 2, "rating": "PG-14"}
json.dump({"population": header, "facts": draft}, open("agent-draft.population.json", "w"), indent=1)
The draft fails with two findings, each traceable to a sentence the user said:
BLOCKING (alethic)
[fail] fact_types[movie_has_title].constraints[0]: Each movie plays 'movie_has_title' with at most
one combination of the other roles — violated: movie '3' has 2 facts.
[fail] constraints[0]: Each rating value must be one of ['G', 'PG', 'PG-13', 'R', 'NC-17'] —
violated: 'PG-14'.
GND can also read any population back as sentences, which is useful for a reviewer or as context for the next agent turn:
Starting from something else
- An existing codebase:
gnd-model-from-coderuns a bounded static recovery pass and records evidence for every claimed element (evolution and recovery). - A GSD project:
gnd-adoptmaps every requirement into the recovered model (adopt a GSD project). - An existing ORM model in the RelationalAI ORM-skill dialect:
gnd import rai-orm MODEL --out DIRconverts it once and writes an alias map.
The format itself is documented in the gnd-orm-core reference library, and
ORM: the executable ontology explains the notation.
See it on an application: BookRec and Expense show the same skill prompt beside the rule it produces, read three ways, in BookRec chapter 7 and Expense chapter 4.