AGENTS.md

September 9, 2026 · View on GitHub

Guidance for AI coding agents (and humans) writing code with compromise, a rule-based English NLP library. This file is the map; the linked docs are the territory. Prefer them over guessing — the published docs at observablehq.com are interactive notebooks and do not render as readable text.

Read these first

FileWhat's in it
docs/concepts.mdthe document/View/Term model, mutability, build tiers — the mental model
docs/match-syntax.mdthe .match() mini-language (#Tag, [capture], (a|b), ~fuzzy~, {root}, …)
docs/tags.mdthe complete, valid part-of-speech tagset
docs/api.mdevery method, signature, and one-line description
docs/recipes.mdcopy-paste solutions to common tasks
llms-full.txtall of the above concatenated into one file
docs/SKILL.mdexample skill for using compromise in a coding agent

30-second mental model

import nlp from 'compromise'

let doc = nlp('she sells seashells by the seashore.')  // parse → a View of the whole document
doc.verbs().toPastTense()                               // select verbs, transform them (mutates doc)
doc.text()                                              // 'she sold seashells by the seashore.'
  • nlp(text) returns a View. Almost every method returns a View, so calls chain.
  • Find with .match(), .has(), .if(), or named selections like .people(), .numbers().
  • Transform with .toPastTense(), .replace(), .tag(), .normalize(), etc.
  • Output with .text(), .json(), .out('array'), .debug().

Rules that prevent most mistakes

  1. Transforms mutate the document in place. The View they return is the selection, not the whole doc. Read the final result from the original variable:

    let doc = nlp('I walk to work')
    doc.verbs().toPastTense()
    doc.text()                       // ✅ 'I walked to work'
    // ❌ nlp('I walk to work').verbs().toPastTense().text()  →  'walked work' (selection only)
    

    Use .clone() to transform a copy without touching the original.

  2. Only real tags work. A #Tag that isn't in docs/tags.md matches nothing, silently. Frequent inventions that are NOT tags: #Name, #Location, #Subject, #Object, #Adj, #Time (it's #Date/#Time… check the list). When in doubt, grep docs/tags.md.

  3. The match-syntax is not regex. It matches whole words/terms. + * ? . ^ $ mean term-level things; for character-level patterns use a /regex/ token. See docs/match-syntax.md.

  4. Sentences are the ceiling. Matches don't cross sentence boundaries. Use the paragraphs plugin for multi-sentence matching.

  5. compromise is the full build. Import compromise (or compromise/three) to get .people(), .numbers(), .verbs(), etc. compromise/two has tags but no named selections; compromise/tokenize (/one) has no tags at all.

Not supported (don't try)

  • Nested match groups: '(modern (major|minor))? general' — chain .match() calls instead.
  • A grammar/dependency parse tree — transforms are heuristic.
  • Slash-joined matching — nlp('eats/shoots/leaves') splits on the slash.

Plugins & extension

nlp.plugin({
  words: { kermit: 'FirstName' },         // add lexicon entries
  tags:  { Muppet: { isA: 'Person' } },   // extend the tagset graph
  api:   (View) => { View.prototype.myMethod = function () { return this } },
})

Or the lightweight forms: nlp(text, { kermit: 'FirstName' }) and nlp.addWords({...}). Official plugins live in plugins/ (dates, stats, syllables, wikipedia, paragraphs).

Debugging a wrong result

doc.debug()        // prints how every word was tagged — start here
doc.json()         // full structured data
nlp.verbose(true)  // log the tagger's decision-making

Repo / contributor notes

  • Source is layered src/1-onesrc/4-four (tokenize → tags → selections → sense). The default entry is src/three.js.
  • pnpm is used for repository development: pnpm install, pnpm test, pnpm build, and pnpm lint. The package scripts themselves avoid package-manager-specific commands, so npm, Yarn, and Bun remain usable too.
  • Regenerate the machine docs after changing types or the tagset: node ./scripts/docs.js (writes docs/tags.md, docs/api.md, llms-full.txt). The other docs are hand-written.