Configuration
A minimal config
Section titled “A minimal config”import { defineConfig } from 'fast-classifier/config'
export default defineConfig({ categories: [{ name: 'Dev', label: 'Inbox/Dev' }], rules: [{ kind: 'domain', domain: 'github.com', category: 'Dev' }], keepList: ['important@example.com'], sweep: { targetLabel: 'Promotion' }, needsAction: { label: 'Needs action', windowDays: 60 },})fast-classifier init writes a fuller starter config with a domains() helper for bulk domain rules.
Discovery order
Section titled “Discovery order”Explicit --config <path> → fast-classifier.config.ts → .mjs → .js → .json in the working directory → built-in defaults.
JSON works identically
Section titled “JSON works identically”JSON configs work identically to TypeScript ones — rule patterns are plain strings in every format (the schema compiles them to case-insensitive regexes), so nothing is lost in translation.
Fields
Section titled “Fields”| Field | What it configures |
|---|---|
provider |
mail transport: type: 'jmap' | 'mcp' plus an optional baseUrl endpoint override (testing / self-hosted JMAP) |
categories |
{ name, label, description? } — the category names rules reference, and the Fastmail label each files into (labels may be nested paths like 'Inbox/Finance') |
rules |
the classifier rules: { kind: 'sender', address } (exact address, wins first), { kind: 'domain', domain } (registrable root domain), or { kind: 'name', pattern, onlyForDomains? } (display-name regex, by default only consulted for relay domains) |
keepList |
exact sender addresses that must never be swept, even when their mail says “unsubscribe” — enforced twice, server-side and client-side |
sweep |
targetLabel (default 'Promotion'), textHeuristic (default 'unsubscribe'), optional after ISO date |
needsAction |
label, threshold (default 3), languages (built-in keyword packs, default ['en']), optional highKeywords / exclusionKeywords (arrays of { phrase, weight } — when present they replace the packs), unreadBonus, personalNeedsReplyBonus, windowDays (default 60) |
detection |
relay/account/personal-provider domain lists, the user’s own personalDomains, and the regex sources behind the human-sender detector — including brandNamePattern, which defaults to global household names only |
ops |
batching and pacing: batchSize (≤ 50), batchDelayMs, stallBackoffMs, stallLimit, progressEvery, optional maxItems — see Ops Conventions |
The config is validated with zod: rules must reference declared categories, duplicate category/domain/sender entries are rejected, and every regex source must compile — a bad pattern fails at load time with a pointed error, never as a raw SyntaxError mid-run.
Build your config from your inbox
Section titled “Build your config from your inbox”You do not have to write rules from scratch — the suggest engine drafts a first config from what is actually in your inbox. It scans read-only, skips domains your config already covers, and matches the rest against a built-in catalog of about 200 globally recognizable root domains grouped into 12 generic categories (Finance, Shopping, Travel, Development, Social, Jobs, News, Entertainment, Health, Telecom, Cloud, Accounts). Domains not in the catalog come back as unknown, sorted by volume, for you to decide on — the catalog never guesses.
Three ways to run it:
- CLI:
fast-classifier suggestprints the suggestions plus a paste-ready config fragment — see the CLI reference. - MCP: the
suggest_rulestool returns the same result asstructuredContentwith aconfigFragmentstring, so an agent can build your config for you. - Library:
suggestRules(analyzeReport.domains, compiled)andtoConfigFragment(result, accepted)fromfast-classifier.
The fragment includes any category definitions you are missing, in defineConfig style — paste it into your config, run plan to check coverage, then write rules for the unknown domains the report surfaced. Iterate until coverage is where you want it.
Needs-action language packs
Section titled “Needs-action language packs”The needs-action scorer ships two built-in keyword packs: en (the default) and de. High-signal phrases (“action required”, “deadline” / “Frist”, “Mahnung”) score +3; receipt/shipping/newsletter exclusions score −2.
needsAction: { languages: ['en', 'de'] } // opt into the German pack alongside EnglishExplicit highKeywords / exclusionKeywords arrays replace the enabled packs entirely — packs and custom lists never merge, so what you write is exactly what scores.
The brand-name pattern
Section titled “The brand-name pattern”detection.brandNamePattern feeds the human-sender detector: a sender whose address or display name contains a brand token is never treated as a human awaiting your reply. The built-in default covers global household names only (uber, amazon, paypal, github, …) so it holds for any user. Add your regional or niche brands by overriding it:
detection: { brandNamePattern: 'uber|amazon|paypal|github|my-regional-bank|my-local-delivery',}examples/fast-classifier.config.ts carries the origin session’s full 55-token list as exactly this kind of override.
Examples
Section titled “Examples”See examples/ in the repo for a full real-world config — the German-power-user setup that reached 87% coverage (14 categories, 81 domain rules, the bilingual languages: ['en', 'de'] packs, and the full brand-pattern override) — plus its JSON twin and minimal sweep-only / needs-action-only / MCP-transport variants.