demonstration 1 of 11 · chat.html
Natural Language Understanding
The chat page runs the same engine as the command line, entirely in your browser. You type English. It answers from facts it can point at, and it says so when it cannot.
What it demonstrates
Open chat.html and you get a full chat surface with no server behind it. The page ships the engine as a JavaScript bundle and loads a starter memory of about 70,000 facts. Everything after that happens on your machine.
Three things are worth watching in a demonstration. The engine reads ordinary sentences, not a query language. A fact answer carries a citation showing where the fact came from. And a question it cannot ground gets a refusal instead of a plausible sentence.
That last one is the point of the whole project. The literature calls it abstention. tmct abstains because nothing in the store matched, not because a score fell under a threshold.
- Teach it something in a sentence and it repeats back the triple it stored.
- Ask a question and it answers, with a source chip beside the reply.
- Ask something it has no facts for and it declines, and tells you what shapes of question it does handle.
- Turn on the Wikipedia mode and it will go and read a Simple English Wikipedia article before answering.
Chat you can replay
Every exchange below is real. Each one is either asserted verbatim by a test in this repository or captured by running the command line in it. None of them are written by hand to look good.
Teach a fact, then ask a question that needs it plus something the corpus already knew. The answer cites both, and the via: clause names the fact it chained through.
tmct> Rover is a dog. noted — remembered 1 fact: rover rdfs:subClassOf dog (rover is a type of dog) tmct> Does Rover bark? yes — dog can bark (source: corpus:human /r/CapableOf) — via: rover is a kind of dog (source: ace:chat:<session-id>@<timestamp>)
Asserted in test-e2e/pages-chat-taught-capability-chain.test.mjs, which types this into the real page in a real browser. The same run is scripted in examples/rover-infer.mjs.
The same shape, run through the command line in this repository. Two taught facts, one chained answer.
tmct> A robin is a bird. noted — remembered 1 fact: robin rdfs:subClassOf bird (every robin is a bird) tmct> A bird can fly. noted — remembered 1 fact: bird mgx:capableOf fly tmct> Can a robin fly? yes — you told me: bird can fly (source: ace:chat:...@2026-08-02T17:13:26.750Z | corpus:human /r/CapableOf) — via: robin is a kind of bird (source: ace:chat:...@2026-08-02T17:13:26.539Z)
Captured by piping the lines into node bin/tmct.mjs. Session ids shortened for width; nothing else changed.
A two hop class chain. The answer walks poodle to dog to animal and cites each step.
tmct> A poodle is a dog. noted — remembered: poodle is a kind of dog tmct> A dog is an animal. noted — remembered 1 fact: dog rdfs:subClassOf animal (dog counts as an animal) tmct> Is a poodle an animal? yes — poodle is a kind of dog (source: teach:chat:...@...); dog is a kind of animal (source: ace:chat:...@... | corpus:human /r/IsA); so poodle is an animal
Captured from the command line. The same chain is a corpus row: test/corpus/inference.jsonl, key inference-mixed-source-isa-chain-cites-both-premises.
The honest miss. A question with nothing behind it gets a refusal and a hint, never a guess.
tmct> Does a teapot own a spaceship? I couldn't read that as a question I can answer. Try "what is a dog" for general vocabulary. Type /help for all query shapes. (this repo has no code graph — index it with `tmct index`, point me at a `.tmct/graph.json` with `--repo <path>`, or run `npm run example:mini`.)
Captured from the command line. The core wall wording, couldn't parse this as a graph question. Try:, is asserted by four rows in test/corpus/grammar.jsonl, including grammar/relaxation-unknown-verb-honest-miss.
A missing quantifier is also a miss. It says what it was never told, rather than counting something up.
tmct> redis is a cache tmct> how many redis are cache I don't know — I was never told a quantifier for that.
Corpus row grammar/recall-no-quantifier-honest-dont-know in test/corpus/grammar.jsonl, asserted as an exact body match.
What it looks like
The chat page mid-answer, with a source chip beside the reply and the memory panel docked on the right.
What it works out
The engine parses your sentence into a graph question, resolves the terms in it, walks the store, and renders an answer. Each of those four steps can decline, and a decline at any of them produces a refusal rather than a fallback.
What it retrieves. A question resolves to a subject and a relation, and the answer is whatever facts sit on that edge. There is no ranking model and no embedding search on this path. If the edge is empty, the answer is empty.
What it infers. Class membership chains through rdfs:subClassOf. Ask whether Rover barks and the engine finds no fact on Rover at all. It walks up to dog, finds dog mgx:capableOf bark, and answers yes, listing both the fact it used and the step it took to get there. That step is the via: clause.
Where trust comes from. Every fact carries a provenance tag. src/domain/memory/trust.mjs parses the tag into a source kind and gives it a prior: an operator statement scores 1.0, something you taught scores 0.95, a curated corpus row 0.7, a live Wikipedia read 0.5, an entailed fact 0.3. The page turns that into one of three chips beside the answer.
- rover rdfs:subClassOf dog (source: ace:chat:<session>@<timestamp>)
- dog mgx:capableOf bark (source: corpus:human /r/CapableOf)
How it carries a thread. The session keeps the last resolved subject as a focus. Ask about something, then ask “what calls it?”, and the pronoun binds to that focus. A pronoun with no focus behind it resolves to nothing and is reported as unresolved, not guessed.
Reasoning through class expressionsReasoning through class expressions
Beyond fact retrieval and class inheritance chains, two explicit reasoning commands close questions that need description logic (class unions, negations) or EL saturation through existential restrictions. The engine reasons over taught class axioms without materialising new facts into the store.
/classify. EL saturation: what follows from class membership facts? Use it when one class is described as an existential restriction and you want to ask about a composed restriction two hops away.
tmct> every heart has a valve noted — remembered 1 fact: heart rdfs:subClassOf [restriction: every heart has some valve] tmct> every valve is a flap noted — remembered 1 fact: valve rdfs:subClassOf flap /classify heart derived 1 entailed fact(s) classifying "heart": heart rdfs:subClassOf [restriction: every heart has some flap] tmct> does a heart have a flap yes — every heart has a valve (source: ace:chat:...@...) and a valve is a flap (source: ace:chat:...@...) — via: class expression ∃has.flap (source: entailed:elSubsumption)
EL entailment example from INF-7 in PLAN_SYLLOGIST_EL_DL.md, integrated into the chat ask lane through the auto-synthesis hook that runs /classify silently after a learn-on-miss load.
/prove. DL tableau refutation: what entails a specific fact in description logic? Use it for a question shape the ask lane cannot resolve alone — a disjunction (union), a negated class, or a class expression too composed to teach directly.
tmct> every pet is a cat or a dog noted — remembered: pet ⊔ [cat, dog] tmct> rex is a pet noted — remembered 1 fact: rex rdf:type pet tmct> rex is not a cat noted — remembered 1 fact: rex owl:disjointWith cat /prove is rex a dog yes — every pet is a cat or a dog (source: ace:chat:...@...) and rex is a pet (source: ace:chat:...@...) and rex is not a cat (source: ace:chat:...@...) — in every case, rex is a dog.
Disjunction elimination example from INF-3 (case analysis), integrated into /prove as an explicit command that branches on each disjunct and reports the case-analysis marker when a union premise is used.
How it is builtHow it is built
The page is generated by src/services/chat-page-viz.mjs. It has no server side. Three files do the work.
chat-browser.bundle.js, built fromsrc/surfaces/web/chat-browser-entry.mjs, wraps the real turn engine and puts it onglobalThis.tmct.chat-seed.json, built byscripts/build-chat-seed.mjs, carries the starter memory: a persona band, the SEON code ontology, a capped ConceptNet slice, three technology bands and a WordNet band.src/services/chat.mjsis the turn engine itself.runTurnroutes a line to a teach lane, an ask lane or a research lane, andsrc/domain/ask.mjsholds the graph question grammar.
The seed's URL carries a content hash. That is what lets the service worker read it cache first without ever handing you a stale copy: a rebuilt seed is asked for by a different URL.
Nothing on this page calls a model. The only language machinery is wink-nlp, served from the site's own vendor/wink.js, used for lemmas and parts of speech.
Related work
The behaviour this page shows has names in the literature. These are the works the repository already cites for it.
- Chow, “On optimum recognition error and reject tradeoff”, IEEE Transactions on Information Theory 16(1), 1970.The reject option: a classifier allowed to decline. The root of what tmct calls the honest miss.
- Reiter, “On Closed World Data Bases”, in Logic and Data Bases, Plenum, 1978, pp. 55–76.The open world assumption. Absence of a fact is not evidence against it, which is why tmct declines instead of denying.
- Ji et al., “Survey of Hallucination in Natural Language Generation”, ACM Computing Surveys 55(12), 2023.The failure mode this design is aimed at.
- Attempto Controlled English, ACE 6.7, 2013.The controlled English tradition tmct's teach grammar sits in.
- Kuhn, “A Survey and Classification of Controlled Natural Languages”, Computational Linguistics 40(1), 2014.The survey that places ACE and its neighbours.
- ConceptNet 5.7.0 relations.The relation vocabulary behind the
/r/IsAand/r/CapableOfcitations you see in the answers. - Damerau, CACM 7(3), 1964; Levenshtein, Soviet Physics Doklady 10(8), 1966.The edit distance work behind term matching on a typo.
Credits and further reading
Everything on this page is in the repository. The full bibliography lives in the README.
- README, whose “Standards and bibliography” section carries every citation above with its full reference.
- wink-nlp and wink-eng-lite-web-model, bundled first party as
vendor/wink.js. They supply lemmas and parts of speech, and nothing else. - ConceptNet 5.7.0, the source of the commonsense relation slice in the starter memory.
- The W3C recommendations the memory model follows: OWL 2, RDF 1.1 Semantics and PROV-O.