From e1013e7c1e929d9a1207a6cf8e87edcfc817f4e1 Mon Sep 17 00:00:00 2001 From: David de Hilster Date: Sun, 23 Aug 2026 19:18:05 -0400 Subject: [PATCH] docs(prompts): tell Prime Claude when the KB beats a dictionary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A session reaching for a .dict twice in one day to supply a fact that one rule needed. Loading a dictionary tags matching tokens in every pass for the whole run — a blast radius — and an attribute like s= goes further and changes tokenization, so plain _xALPHA rules stop matching those words. A knowledge base answers when asked, and that is what a single-rule fact wants. Adds the rule of thumb and the pattern that goes with it: match on shape, validate in code — the rule is permissive, the loop is strict. A pass picking US state codes matches a run of two-letter uppercase tokens separated by commas, then loops calling StateName() on each candidate; "multiple", "locations" and "in" each fail one of the three tests and drop out without the rule naming them. Co-Authored-By: Claude Opus 5 (1M context) --- Help/markdown/vscode/prompts/00-prime-claude.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Help/markdown/vscode/prompts/00-prime-claude.md b/Help/markdown/vscode/prompts/00-prime-claude.md index 75132ed..1b710cb 100644 --- a/Help/markdown/vscode/prompts/00-prime-claude.md +++ b/Help/markdown/vscode/prompts/00-prime-claude.md @@ -1,5 +1,5 @@ Prime Claude for NLP++ - + This is everything you need to know to help me work on NLP++ analyzers. NLP++ is a rule-based programming language for natural language processing, run by the NLP engine. Read this in full before we start — afterward I will ask you to build a new analyzer, extend an existing one, write dictionaries and knowledge bases, generate test inputs, or debug why a rule fires. Everything you need is already installed on this machine at the paths below: - NLP engine executable (run analyzers with this): {{engineExe}} @@ -30,6 +30,7 @@ Rules of thumb — build on the libraries, never on hand-typed word lists: - **Look in the libraries before you write a vocabulary.** {{languagesDir}} already ships, per language, dictionaries and matching knowledge bases for countries, nationalities/demonyms, languages, months and days, first names and surnames, professions, US states and street suffixes, numbers, prepositions, determiners, pronouns, conjunctions and stop words — plus a full lexicon (en-full.dict / en-full.kbb) carrying part of speech, root, and verb/noun features. {{miscDir}} adds currencies, ISO country codes, telephone country codes, timezones, emojis, roman numerals and URL domains. A pass built on the twenty words you typed by hand is brittle: it handles the test file and nothing else. The library file handles the whole vocabulary. - **Wire one in by copying the .dict and its matching .kbb into the analyzer's kb/user/.** The tokenizer auto-loads every .dict there and tags matching tokens. Keep the pair together — a .kbb with the same stem supplies the concept hierarchy and the ambiguity readings for its .dict. Files named `…full.dict` / `…full.kbb` lazy-load word by word, so even a large lexicon costs little at startup. For a heavy domain KB that only some inputs need, load it on demand with loaddict / loadkbb (a file name in kb/user, not a path), guarded by a global so it loads once. +- **A dictionary changes what every rule sees; a knowledge base answers when asked.** A .dict in kb/user tags matching tokens for the whole run, in every pass — that is a blast radius, and it is the right one when the analyzer is built on that vocabulary. When one rule needs one fact, the KB is the instrument instead. Match on *shape* and validate in code: the rule is permissive, the loop is strict. A pass that picks US state codes out of a list matches a run of two-letter uppercase tokens separated by commas, then loops calling a KB lookup (`StateName()`) on each candidate — two characters, uppercase, and known to the knowledge base. Words like "multiple", "locations" and "in" fail at least one of those three tests and drop out on their own, without the rule having to name them. Loading a .dict to buy that one lookup would tag those codes in every other pass too, and a dictionary attribute like `s=` even changes tokenization — dicttok builds a typed node for those words, so plain _xALPHA rules stop matching them. - **Match on the attributes, not on the words.** Dictionary attributes ride on the node, so `@PRE <1,1> var("nationality");` selects every entry in the file, and `N("country",1)`, `N("iso3",1)` read the data straight off the node — no dictfindword call needed. Rules written this way keep working as the library file grows. - **Match _phrase as well as _xALPHA.** Multi-word and hyphenated entries ("American Samoan", "Bissau-Guinean") arrive from the tokenizer as a single _phrase node carrying the same dictionary attributes. A rule that only matches _xALPHA silently misses every one of them. - **Join on a stable attribute, never on $text.** Key KB lookups on country=, iso3=, root= and the like — the surface form varies with plural, synonym and hyphenation, and $text on a hyphenated phrase comes back mangled ("bissau - guine").