Compromise 14
Compromise 14.19.x NLP code without pre-14 APIs or invented ones, with explicit selection scope, shared-state ownership, checked patterns and tags, bounded parsing work and package-manager-owned dependencies; any runtime or app shape. Rule IDs CMP-V/C/E/P/A/T/W; NEED TO blocks.
Set this profile
ccpp cpo profile set compromise-14Inside Claude Code, prefix the command with ! to run it in the session. Downloading a profile needs a Builder or Team plan; listing them does not.
Policies
62 policies, grouped by what they guard.
Untrusted input 3
Requests, downloads and tool output are validated before they reach SQL, a shell, eval or a deserializer.
cmp-c14-dynamic-patternsCMP-C14 · Values are not interpolated into match syntax (template strings, concatenation): literal words go through .lookup() or validated tokens
cmp-c16-html-page-sinkCMP-C16 · In HTML pages that load compromise, its output (.text(), .out(), .html(), .wrap()) is not assigned to innerHTML/outerHTML or document.write
cmp-c16-html-sinkCMP-C16 · compromise output (.text(), .out(), .html(), .wrap()) reaches HTML only through a text sink or verified escaping
Weakened checks 1
Suppressions, disabled lint or CI steps and relaxed strictness need a reason or the user's approval.
cmp-a06-type-suppressionsCMP-A06 · Type checks on compromise calls are not switched off (@ts-ignore, @ts-expect-error, @ts-nocheck, as any) to hide a wrong API assumption
Error handling 1
Failures are propagated or handled, never swallowed or turned into fake success.
cmp-a06-swallowed-failuresCMP-A06 · Failures around compromise calls are not swallowed (empty catch, catch returning [] / '' / null) to hide a wrong API assumption
Async & concurrency 1
Owned tasks, awaited promises, preserved cancellation and no blocking on event loops.
cmp-p09-promise-allCMP-P09 · Promise.all around synchronous compromise parsing adds no parallelism; bounded workers do, when measured
Performance & resource bounds 7
Timeouts, bounded retries and fan-out, reused clients, closed resources, no N+1 queries.
cmp-p01-reparseCMP-P01 · One function parses the same input once and reuses the document (clone it when an independent copy is needed)
cmp-p02-result-shapeCMP-P02 · Ask only for the result needed: .has() for booleans, .matchOne() for the first match, .out('array') for strings
cmp-p03-patterns-in-loopsCMP-P03 · Constant multi-token patterns used inside loops are compiled once with nlp.parseMatch() (compromise re-parses pattern strings on every call)
cmp-p04-literal-alternativesCMP-P04 · Long plain-word alternatives (a|b|c|…) become one reusable trie lookup when the profile sets maxLiteralAlternatives
cmp-p11-speed-entrypointsCMP-P11 · Browser code takes only browser-safe compromise-speed helpers (keyPress, lazy): no streamFile/workerPool from compromise-speed/browser or in browserPaths
cmp-p12-gpuCMP-P12 · No invented GPU/WebGL/WASM acceleration for compromise: no gpu options, backends, packages or methods (14.19 has no GPU backend)
cmp-p14-tagger-internalsCMP-P14 · Size and speed come from supported tiers, not from deleting or replacing tagger internals (world compute, hooks, two.* models)
Architecture & boundaries 6
Declared layers and dependency directions, no import cycles, small modules, explicit dependencies.
cmp-a02-cross-file-patternsCMP-A02 · A new multi-token match pattern that another compromise module already writes gets one named owner (bounded project scan)
cmp-a02-duplicate-patternsCMP-A02 · A match pattern repeated in a file gets one named owner (a constant or a parseMatch)
cmp-e01-lexicon-per-callCMP-E01 · A caller-supplied lexicon is not passed to nlp(text, lexicon): it is added to the shared global lexicon of every later parse
cmp-e02-registration-in-loopsCMP-E02/E05 · Plugins, words, tags and model changes are registered once before processing, not per item or per call
cmp-e03-tag-aliasesCMP-E03 · Custom tag aliases are valid, unique and not shadowed: no spaces or symbols, no alias used twice or taken by a built-in alias, no alias equal to a tag
cmp-e03-tag-graphCMP-E03 · Custom tags extend real parents: isA/notA name a tag of compromise 14.19, a tag defined in the file or a customTags entry
Language idioms 8
The conventions of the language that keep code predictable for its readers.
cmp-c02-selection-scopeCMP-C02 · The output of a transform is read from the document (doc.text()), not from the returned selection, unless the selection is the contract
cmp-c04-view-truthinessCMP-C04 · Existence is tested with .has(), .found or .length: a View (even empty) and an output array are always truthy
cmp-c05-word-countsCMP-C05/C10 · Words are counted and listed from compromise terms, not by splitting its text on spaces
cmp-c06-pattern-syntaxCMP-C06 · Match patterns are compromise term syntax: no nested groups, no character-regex outside /…/ tokens, balanced brackets, real @term methods
cmp-c08-capture-groupsCMP-C08 · A pattern with [capture] brackets is read through .groups(name) or the group argument, not as if brackets narrowed the match
cmp-p05-sweep-resultCMP-P05 · .sweep(net) returns { view, found }: its result is destructured or read through .view, never chained as a View
cmp-v12-manual-moneyCMP-V12/V14/A03 · Numbers and money are not re-parsed from compromise text (parseFloat, Number, x100 '%'): use .get(), .add(), .toPercentage()…
Caching 1
Cache scopes, lifetimes and invalidation stated explicitly.
cmp-p06-cache-mutationCMP-P06 · A document frozen with .cache() is .uncache()d before it is transformed (cached matches go stale)
Versions & deprecated APIs 9
Code matches the installed version, without removed, renamed or deprecated APIs.
cmp-v01-installed-versionCMP-V01/V02/W07 · At session start, Claude learns the resolved compromise version and plugins, whether this 14.19 profile applies, and where the version-matched docs are
cmp-v02-unknown-staticsCMP-V02 · nlp.* calls exist in compromise 14.19 or a loaded plugin (no invented statics such as nlp.normalize, nlp.parse, nlp.sentences)
cmp-v03-import-pathsCMP-V03/V01 · compromise is imported through its package exports: no src/builds/types internals, no type-only subpaths at run time, no v12/v13 plugins
cmp-v04-build-tierCMP-V04 · Code uses only what its compromise tier provides: no named selections on compromise/two, no tags or tagger methods on compromise/one or nlp.tokenize()
cmp-v05-compat-helpersCMP-V05/V08/V15 · Current spellings over retained compatibility helpers: .eq(n) over View .get(n), .json()[n] over .json(n), .json() over .data(), .compute('tagger'), .numbers(), DateOptions
cmp-v06-number-arraysCMP-V06 · .get() on numbers/money/percentages returns an array: it is not used as a number (arithmetic, comparison, toFixed)
cmp-v07-removed-apisCMP-V07 · No APIs removed by compromise 14: .parent(s), .lists(), .segment(), .export(), nlp.clone/load, function plugins, array patterns, toParticiple/toPossessive/hasPlural
cmp-v10-compute-namesCMP-V10 · .compute(name) names a computation the installed compromise or an official plugin registers (unknown names only log 'no compute')
cmp-v15-plugin-methodsCMP-V04/V15 · Plugin methods (.dates(), .ngrams(), .syllables(), .paragraphs(), payloads, nlp.keyPress…) are used only with the plugin installed
Logging & observability 1
Structured logs, bounded metric labels, no debug prints left in production code.
cmp-v11-debug-outputCMP-V11 · Tracing is targeted and switched off: no .debug(object), no .debug()/nlp.verbose() left in non-test code
Dependencies & toolchain 17
Packages change through the package manager, lockfiles stay consistent and the project's tools are used.
cmp-v01-install-specsCMP-V01/W03 · Installing compromise at a version outside this profile's release (another major, an older 14 minor, the stale `next` tag) is refused
cmp-v01-legacy-pluginsCMP-V01/V07 · No v12/v13-era compromise plugins (compromise-numbers, -sentences, -adjectives, -export, -html, -ngrams, -syllables…) are installed
cmp-v01-resolved-versionCMP-V01 · After an install that named compromise, the resolved compromise is still on this profile's release
cmp-w01-init-over-projectCMP-W01 · No package-manager initializer (npm/pnpm/yarn/bun init, npm create) runs in a directory that already has a package.json
cmp-w01-package-managerCMP-W01 · Dependencies are installed with the project's package manager (packageManager field, lockfile)
cmp-w01-second-lockfileCMP-W01 · No second lockfile next to another package manager's lockfile
cmp-w02-hand-written-manifestCMP-W02 · A new package.json without dependencies is initialized with the package manager
cmp-w02-new-manifestCMP-W02/W03 · A new package.json comes from the package-manager initializer (or a generator), and gets its dependencies from the package manager
cmp-w03-manual-dependency-editCMP-W03 · Dependencies change through the package manager (add/remove/update), never by editing package.json by hand
cmp-w03-package-manager-callRecords the tool calls that run a package manager (they may rewrite package.json and lockfiles; CMP-V01/W03/W04)
cmp-w03-version-lookupsCMP-W03 · Registry version lookups are not a step before installing
cmp-w03-version-pinsCMP-W03 · Packages are installed by name: no guessed exact version, no @latest, no --save-exact without a reason
cmp-w04-hand-edited-lockfileCMP-W04 · Lockfiles are written by the package manager only (no hand edit, no script rewriting them)
cmp-w04-stale-lockfileCMP-W04 · A turn that changes package.json dependencies also updates the lockfile next to it (once per stop)
cmp-w05-vendored-buildsCMP-W05 · compromise builds are not downloaded or copied into the project by hand (curl/wget from a CDN, cp from node_modules): the package manager provides them
cmp-w06-invented-cliCMP-W06 · No compromise CLI is invoked: the package declares no bin (npx/bunx/pnpm dlx compromise, a `compromise` command)
cmp-w06-manifest-cliCMP-W06 · package.json scripts do not call a compromise binary (compromise declares no bin)
Tests 4
Tests assert behavior, stay deterministic and are not removed or skipped silently.
cmp-c15-exact-tag-arraysCMP-C15 · Tests and code compare tag membership (has('#Tag'), tags.includes), not exact incidental tag arrays that change with the hierarchy
cmp-t01-mocked-compromiseCMP-T01 · Tests exercise compromise itself: no jest/vi/bun module mocks or stubs replacing compromise or its plugins
cmp-t03-fromspec-defaultsCMP-T03 · nlp.fromSpec() results are not used as validation: .failures needs a failures option, tag checks need tags: 'use' (defaults ignore both)
cmp-t04-testspec-resultCMP-T04 · testSpec() success is read from .failures (or throwError), never from the truthiness, .found, .length or text of the returned View
Completion evidence 3
A turn ends with its checks run and passing; claims of success need proof after the last edit.
cmp-p15-measurement-ledgerRecords that the turn ran a measurement (benchmark, profiler, timing script) for CMP-P15
cmp-p15-performance-claimsCMP-P15 · A turn that changed compromise code does not claim a speed, memory or accuracy gain without a measurement in the turn (once per stop)
cmp-turn-baselineRecords the work tree when a prompt starts: the baseline of the compromise end-of-turn checks (CMP-W04, P15)