Skip to content

Commit baa80b0

Browse files
zeronelabsclaude
andcommitted
Initial commit — npx brandlint
Open source CLI that scans codebases for off-brand UI copy. Pick a voice, bring your own API key, get a score, share it. Co-Authored-By: Claude Opus 4.6 <[email protected]>
0 parents  commit baa80b0

File tree

16 files changed

+3244
-0
lines changed

16 files changed

+3244
-0
lines changed

.github/workflows/publish.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: Publish to npm
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
8+
jobs:
9+
publish:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
14+
- uses: pnpm/action-setup@v4
15+
with:
16+
version: 9
17+
18+
- uses: actions/setup-node@v4
19+
with:
20+
node-version: 20
21+
registry-url: https://registry.npmjs.org
22+
23+
- run: pnpm install --frozen-lockfile
24+
- run: pnpm build
25+
- run: npm publish --access public
26+
env:
27+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules/
2+
dist/
3+
*.tgz

LICENSE

Lines changed: 661 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
<p align="center">
2+
<img src="https://raw.githubusercontent.com/zeronelabs/brandlint-cli/main/logo.png" width="64" height="64" alt="Brandlint logo">
3+
</p>
4+
5+
<h1 align="center">Brandlint</h1>
6+
7+
<p align="center"><strong>Scan your codebase for off-brand UI copy. Get a score. Share it.</strong></p>
8+
9+
<p align="center">
10+
<a href="https://www.npmjs.com/package/brandlint"><img src="https://img.shields.io/npm/v/brandlint" alt="npm version"></a>
11+
<a href="LICENSE"><img src="https://img.shields.io/badge/License-AGPL--3.0-blue.svg" alt="License: AGPL-3.0"></a>
12+
<a href="https://nodejs.org"><img src="https://img.shields.io/badge/node-%3E%3D18-brightgreen" alt="Node.js >= 18"></a>
13+
</p>
14+
15+
<p align="center">
16+
<a href="https://brandlint.com"><strong>Website</strong></a> · <a href="https://brandlint.com/docs">Docs</a> · <a href="https://github.com/zeronelabs/brandlint-cli/issues/new">Feedback</a>
17+
</p>
18+
19+
&nbsp;
20+
21+
Like ESLint, but for your product voice. Brandlint scans your codebase for off-brand copy — inconsistent tone, vague messages, wrong casing — and tells you exactly where to fix it, with file and line number.
22+
23+
```
24+
npx brandlint
25+
```
26+
27+
You bring your own API key (Anthropic or OpenAI). Nothing is sent to Brandlint servers except the final score summary if you choose to share it.
28+
29+
&nbsp;
30+
31+
## How It Works
32+
33+
1. **Pick a voice** — Professional, Casual, or Technical
34+
2. **Scan** — Extracts user-facing strings from your codebase
35+
3. **Analyze** — AI checks each string against your brand voice guidelines
36+
4. **Report** — See your score, issues by file/line, and top problem categories
37+
5. **Share** — Generate a score card at `brandlint.com/score/<id>` with one keypress
38+
39+
<!-- TODO: Replace with actual terminal screenshot -->
40+
<img src="https://raw.githubusercontent.com/zeronelabs/brandlint-cli/main/screen.png" width="800" alt="Brandlint CLI">
41+
42+
&nbsp;
43+
44+
## Requirements
45+
46+
- Node.js 18+
47+
- An API key from [Anthropic](https://console.anthropic.com/) or [OpenAI](https://platform.openai.com/)
48+
49+
Set your key as an environment variable to skip the prompt on every run:
50+
51+
```bash
52+
export ANTHROPIC_API_KEY=sk-ant-...
53+
# or
54+
export OPENAI_API_KEY=sk-...
55+
```
56+
57+
&nbsp;
58+
59+
## Voice Templates
60+
61+
| Template | Style | Example guideline |
62+
|---|---|---|
63+
| **Professional** | Clear, confident, helpful | "Enter your email to continue" not "Fill in the required field" |
64+
| **Casual** | Friendly, warm, conversational | "Looks like something broke" not "Error 500: Internal failure" |
65+
| **Technical** | Precise, direct, informative | "Request timed out after 30s" not "Something went wrong!" |
66+
67+
&nbsp;
68+
69+
## What Gets Scanned
70+
71+
Brandlint extracts user-facing strings from:
72+
73+
| Category | File types |
74+
|---|---|
75+
| **JS / TS** | `.ts` `.tsx` `.js` `.jsx` `.mjs` `.cjs` |
76+
| **Frameworks** | `.vue` `.svelte` |
77+
| **Markup** | `.html` `.htm` |
78+
| **Templates** | `.ejs` `.hbs` `.pug` `.erb` `.slim` `.haml` `.twig` |
79+
| **Backend** | `.php` `.py` `.cshtml` `.razor` |
80+
| **Content** | `.json` `.yaml` `.yml` `.md` `.mdx` |
81+
82+
It finds strings in JSX text, UI attributes (`label`, `placeholder`, `title`, `error`, `description`), i18n functions (`t()`, `$t()`, `gettext()`), and template literals with user-facing content.
83+
84+
`node_modules`, `dist`, `build`, `.next`, `.git`, and similar directories are ignored automatically.
85+
86+
&nbsp;
87+
88+
## Score Card
89+
90+
After scanning, Brandlint offers to create a shareable score card at `brandlint.com/score/<id>`:
91+
92+
- Color-coded score with issue breakdown
93+
- Top problem categories (tone, clarity, casing, etc.)
94+
- Open Graph image that unfurls on X, Slack, and Discord
95+
- One-click share to X with pre-filled tweet
96+
97+
The only data sent is the summary (score, counts, categories, voice template). Your source code never leaves your machine.
98+
99+
&nbsp;
100+
101+
## Continuous Monitoring
102+
103+
The CLI gives you a one-time scan. For automated brand voice checks on every pull request, set up [Brandlint as a GitHub App](https://brandlint.com/signin) — it reviews PRs and comments inline with suggestions.
104+
105+
&nbsp;
106+
107+
## Development
108+
109+
```bash
110+
git clone https://github.com/zeronelabs/brandlint-cli.git
111+
cd brandlint-cli
112+
pnpm install
113+
pnpm build # Build to dist/cli.mjs
114+
pnpm dev # Build with watch mode
115+
```
116+
117+
&nbsp;
118+
119+
## Testing Locally
120+
121+
**Run from source:**
122+
123+
```bash
124+
pnpm build
125+
node dist/cli.mjs
126+
```
127+
128+
**Test as if installed via npx:**
129+
130+
```bash
131+
pnpm pack # Creates brandlint-0.1.0.tgz
132+
npx ./brandlint-0.1.0.tgz # Runs exactly like npx brandlint would
133+
```
134+
135+
**Test score card upload against local web app:**
136+
137+
```bash
138+
BRANDLINT_API_URL=http://localhost:3000/api/score-card node dist/cli.mjs
139+
```
140+
141+
&nbsp;
142+
143+
## Releasing
144+
145+
Releases are automated via GitHub Actions. When you push a version tag, the workflow builds and publishes to npm.
146+
147+
**One-time setup:**
148+
149+
1. Generate an npm access token at [npmjs.com](https://www.npmjs.com/) → Access Tokens → Classic → Automation
150+
2. Add it as `NPM_TOKEN` in repo Settings → Secrets → Actions
151+
152+
**To release:**
153+
154+
```bash
155+
npm version patch # 0.1.0 → 0.1.1 (or minor / major)
156+
git push && git push --tags # Triggers publish workflow
157+
```
158+
159+
After a few seconds, `npx brandlint` serves the new version globally.
160+
161+
**First publish** (before any tags exist):
162+
163+
```bash
164+
npm login
165+
pnpm build && npm publish
166+
```
167+
168+
&nbsp;
169+
170+
## License
171+
172+
[AGPL-3.0](LICENSE)

logo.png

8.66 KB
Loading

package.json

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
{
2+
"name": "brandlint",
3+
"version": "0.1.1",
4+
"description": "Scan your codebase for brand voice consistency",
5+
"license": "AGPL-3.0",
6+
"author": {
7+
"name": "Brandlint",
8+
"url": "https://brandlint.com"
9+
},
10+
"repository": {
11+
"type": "git",
12+
"url": "https://github.com/zeronelabs/brandlint-cli.git"
13+
},
14+
"homepage": "https://brandlint.com",
15+
"keywords": [
16+
"brand",
17+
"voice",
18+
"copy",
19+
"linter",
20+
"ux-writing",
21+
"microcopy",
22+
"brand-consistency",
23+
"cli"
24+
],
25+
"type": "module",
26+
"bin": {
27+
"brandlint": "./dist/cli.mjs"
28+
},
29+
"files": [
30+
"dist"
31+
],
32+
"scripts": {
33+
"build": "tsup",
34+
"dev": "tsup --watch"
35+
},
36+
"dependencies": {
37+
"@anthropic-ai/sdk": "^0.72.0",
38+
"@clack/prompts": "^0.9.1",
39+
"fast-glob": "^3.3.3",
40+
"open": "^10.1.0",
41+
"openai": "^4.96.0",
42+
"picocolors": "^1.1.1"
43+
},
44+
"devDependencies": {
45+
"@types/node": "^22.0.0",
46+
"tsup": "^8.4.0",
47+
"typescript": "^5.9.0"
48+
}
49+
}

0 commit comments

Comments
 (0)