Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

brand-vet

A local-first Python CLI that screens candidate brand names before you commit to one — running each name through six local shallow filters and an optional deep-vet stage that checks trademarks, domains, and social handles against live external APIs, then emitting a scored, schema-versioned JSON report alongside a human-readable table.

Not legal advice. Output is a surface-level signal to triage obvious problems early — not a clearance opinion.

Status: all six build epics implemented, ~312 tests passing, CI green on Python 3.11 + 3.12. Alpha — deep vet is opt-in, and the X/Instagram handle probes are best-effort against anti-bot measures (see caveats).

What it does

Given names (via --name, --stdin, or --input), brand-vet runs a two-stage pipeline.

Shallow filters — local, no network, no keys, fast:

Filter Checks
dictionary every token is a plain English word
common_name collisions with common personal names
generic_descriptive purely descriptive terms
profanity whole-word match across 5 languages (en, es, zh-pinyin, ar, hi)
brand_collision exact + fuzzy (Levenshtein ≤ 1) match against known brands
linguistic_sanity length, mixed-script, IDN/punycode issues

Names that fail a fail-threshold filter are marked shallow_fail and skip the expensive deep stage.

Deep vet — survivors are checked against external services, concurrently:

Provider Checks API key
uspto_tsdr USPTO trademark DB — closest marks, similarity, Nice classes required
rdap domain availability via RDAP (.com / .io / .ai / .co …) none
handles (github / x / instagram) username availability github: none
domainr fallback for RDAP-unsupported TLDs required

Architecture

The deep-vet stage is the interesting part. Providers implement a common DeepVetProvider protocol, and an async orchestrator dispatches them concurrently behind per-provider asyncio semaphores, a circuit breaker, retry-with-backoff, and a per-provider SQLite cache (WAL mode, concurrent-process-safe, per-provider TTLs with error-TTL clamping). Adding a provider means implementing the protocol and registering it — no orchestrator changes.

Config resolves through a precedence chain: package defaults → user config → project config → --config → env vars → CLI flags. Secrets load only from BRAND_VET_* env vars or a chmod 600 ~/.config/brand-vet/secrets.toml, and never appear in logs, config hashes, or reports.

Install

uv pip install -e .   # or: pip install -e .
brand-vet --version

Quickstart

brand-vet check --name "Lumenflux" --name "Sparkle"
echo -e "Lumenflux\nSparkle" | brand-vet check --stdin
brand-vet check --input names.txt --output report.json --json

# cache + corpora management
brand-vet cache stats
brand-vet corpora list

Deep vet is off by default; enable it in config and supply keys (e.g. BRAND_VET_USPTO_API_KEY) for the providers that need them.

Exit codes

See src/brand_vet/exit_codes.py. Common ones:

Code Meaning
0 Run completed
1 Internal error
2 Invalid configuration
64 Usage error
65 Input parse error
70 Required shallow corpus unavailable
130 SIGINT

Testing

pytest -q          # ~312 tests: unit, integration, baseline-gate, chaos
pytest -m perf     # performance tests

CI runs ruff + mypy + pytest on Python 3.11 and 3.12.

Caveats

  • The X and Instagram handle probes are unauthenticated HEAD requests and may be blocked by anti-bot measures in production.
  • domainr (RDAP fallback) reports not_configured and is skipped without an API key.

Reference

License

MIT — see LICENSE.

About

A local-first Python CLI that screens candidate brand names — shallow text filters plus concurrent deep-vet checks against trademark, domain, and social-handle APIs, with caching and scored JSON reports.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages