content-grade 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +376 -0
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -96,8 +96,17 @@ npx content-grade headline "Why Most Startups Fail at Month 18"
|
|
|
96
96
|
| `grade "<text>"` | Alias for `headline` |
|
|
97
97
|
| `init` | First-run setup: verify Claude CLI, run smoke test |
|
|
98
98
|
| `start` | Launch the full web dashboard (6 tools) |
|
|
99
|
+
| `telemetry [on\|off]` | View or toggle anonymous usage tracking |
|
|
99
100
|
| `help` | Full usage and examples |
|
|
100
101
|
|
|
102
|
+
**Global flags:**
|
|
103
|
+
|
|
104
|
+
| Flag | Description |
|
|
105
|
+
|------|-------------|
|
|
106
|
+
| `--no-telemetry` | Skip usage tracking for this one invocation |
|
|
107
|
+
| `--version`, `-v`, `-V` | Show installed version |
|
|
108
|
+
| `--help`, `-h` | Show help |
|
|
109
|
+
|
|
101
110
|
---
|
|
102
111
|
|
|
103
112
|
## The 6 web dashboard tools
|
|
@@ -207,6 +216,26 @@ Use this when something isn't working — it tells you exactly what to fix.
|
|
|
207
216
|
|
|
208
217
|
---
|
|
209
218
|
|
|
219
|
+
### `telemetry`
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
content-grade telemetry # show current status
|
|
223
|
+
content-grade telemetry off # opt out — persisted permanently
|
|
224
|
+
content-grade telemetry on # opt back in
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Anonymous usage tracking (command name + score range, no file contents, no PII). Enabled by default; `telemetry off` writes a local flag file and is honoured by all future invocations.
|
|
228
|
+
|
|
229
|
+
**One-time opt-out per invocation:**
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
content-grade analyze ./post.md --no-telemetry
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Pass `--no-telemetry` to any command to skip tracking for that run only without changing the saved preference.
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
210
239
|
### `start` / `serve`
|
|
211
240
|
|
|
212
241
|
```bash
|
|
@@ -312,6 +341,353 @@ npm run test:coverage # coverage report
|
|
|
312
341
|
|
|
313
342
|
---
|
|
314
343
|
|
|
344
|
+
## Output format
|
|
345
|
+
|
|
346
|
+
When `content-grade analyze` runs, Claude returns structured JSON that is rendered to the terminal. The raw schema:
|
|
347
|
+
|
|
348
|
+
```json
|
|
349
|
+
{
|
|
350
|
+
"content_type": "blog | email | ad | social | landing",
|
|
351
|
+
"total_score": 72,
|
|
352
|
+
"grade": "B+",
|
|
353
|
+
"headline": {
|
|
354
|
+
"text": "Why Most Startups Fail",
|
|
355
|
+
"score": 61,
|
|
356
|
+
"feedback": "Too vague — the reader doesn't know if this applies to them."
|
|
357
|
+
},
|
|
358
|
+
"dimensions": {
|
|
359
|
+
"clarity": { "score": 80, "note": "Well-organized with clear section breaks." },
|
|
360
|
+
"engagement": { "score": 60, "note": "Opens with a statistic but drops momentum in paragraph 3." },
|
|
361
|
+
"structure": { "score": 72, "note": "Good use of subheadings but the conclusion is thin." },
|
|
362
|
+
"value_delivery": { "score": 65, "note": "Core advice is solid but needs a concrete takeaway." }
|
|
363
|
+
},
|
|
364
|
+
"one_line_verdict": "Strong structure undermined by a weak headline — fix that first.",
|
|
365
|
+
"strengths": [
|
|
366
|
+
"Well-organized with clear section breaks",
|
|
367
|
+
"Specific statistics in the opening hook"
|
|
368
|
+
],
|
|
369
|
+
"improvements": [
|
|
370
|
+
{
|
|
371
|
+
"issue": "Headline is too vague",
|
|
372
|
+
"priority": "high",
|
|
373
|
+
"fix": "Why 90% of SaaS Startups Fail at Month 18 (and How to Be the 10%)"
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
"issue": "Paragraph 2 makes claims without evidence",
|
|
377
|
+
"priority": "medium",
|
|
378
|
+
"fix": "Cite a specific study — 'CB Insights found...' beats 'many startups...'"
|
|
379
|
+
}
|
|
380
|
+
],
|
|
381
|
+
"headline_rewrites": [
|
|
382
|
+
"Why 90% of SaaS Startups Fail at Month 18 (and How to Be the 10%)",
|
|
383
|
+
"The Month 18 Startup Trap: What Kills Growth-Stage Companies"
|
|
384
|
+
]
|
|
385
|
+
}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
For `content-grade headline`, the schema:
|
|
389
|
+
|
|
390
|
+
```json
|
|
391
|
+
{
|
|
392
|
+
"score": 74,
|
|
393
|
+
"grade": "B",
|
|
394
|
+
"verdict": "Strong promise but lacks the proof element that separates a 74 from an 88.",
|
|
395
|
+
"scores": {
|
|
396
|
+
"rule_of_one": { "score": 22, "max": 30, "note": "Single idea present but promise is vague." },
|
|
397
|
+
"value_equation": { "score": 22, "max": 30, "note": "Dream outcome clear; likelihood undermined by '10x' without proof." },
|
|
398
|
+
"readability": { "score": 16, "max": 20, "note": "Short, no jargon — reads well." },
|
|
399
|
+
"proof_promise_plan": { "score": 14, "max": 20, "note": "Timeframe adds proof; missing the 'how'." }
|
|
400
|
+
},
|
|
401
|
+
"rewrites": [
|
|
402
|
+
"How I Doubled Conversions in 30 Days by Fixing One Headline",
|
|
403
|
+
"The 3 Headline Fixes That Grew My Conversions 10x (Backed by 847 A/B Tests)"
|
|
404
|
+
]
|
|
405
|
+
}
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
---
|
|
409
|
+
|
|
410
|
+
## Scoring methodology
|
|
411
|
+
|
|
412
|
+
ContentGrade uses Claude as a scoring engine with **calibrated anchor examples** that force use of the full 0–100 range. This prevents the common AI problem of all scores bunching in the 60–80 band.
|
|
413
|
+
|
|
414
|
+
**Score thresholds (for `analyze`):**
|
|
415
|
+
|
|
416
|
+
| Score | What it means |
|
|
417
|
+
|-------|--------------|
|
|
418
|
+
| 90–100 | Exceptional — data authority, curiosity gap, ultra-specific, publication-ready |
|
|
419
|
+
| 80–89 | Strong — clear value equation, good proof, specific promise |
|
|
420
|
+
| 65–79 | Good — readable, structured, some specificity gaps |
|
|
421
|
+
| 50–64 | Adequate — readable but vague, generic structure |
|
|
422
|
+
| 35–49 | Poor — clichés, no hook, commodity topic |
|
|
423
|
+
| 0–34 | Very weak — no structure, zero reader benefit, or content too short |
|
|
424
|
+
|
|
425
|
+
**Dimensions:**
|
|
426
|
+
|
|
427
|
+
- **Clarity** — Organization, section breaks, readability. Does the reader always know where they are?
|
|
428
|
+
- **Engagement** — Hook strength, momentum, reader retention. Would someone read to the end?
|
|
429
|
+
- **Structure** — Heading hierarchy, flow, conclusion strength. Is there a logical arc?
|
|
430
|
+
- **Value Delivery** — Concrete advice, takeaways, actionable insights. Does the reader leave with something useful?
|
|
431
|
+
|
|
432
|
+
**Content-type calibration:** The scoring prompt knows it's reading a blog post vs. an email vs. ad copy. A 200-word email doesn't get penalized for "thin structure" the way a blog post would.
|
|
433
|
+
|
|
434
|
+
**Headline framework calibration anchors:**
|
|
435
|
+
|
|
436
|
+
| Score range | What it takes |
|
|
437
|
+
|-------------|--------------|
|
|
438
|
+
| 95+ | Data authority + curiosity gap + ultra-specificity + clear reader identity |
|
|
439
|
+
| 88–92 | Strong proof + promise + plan, low jargon, 6–10 words |
|
|
440
|
+
| 75–84 | Clear value equation, objection handling, some specificity |
|
|
441
|
+
| 65–74 | Clear differentiator or positioning, but vague on proof |
|
|
442
|
+
| 50–64 | Decent structure but generic or lacking urgency |
|
|
443
|
+
| 35–49 | Standard cliché phrasing, no hook element |
|
|
444
|
+
| 0–34 | Commodity topic, passive voice, zero benefit stated |
|
|
445
|
+
|
|
446
|
+
---
|
|
447
|
+
|
|
448
|
+
## Programmatic use (REST API)
|
|
449
|
+
|
|
450
|
+
Start the server with `content-grade start`, then call any tool via HTTP:
|
|
451
|
+
|
|
452
|
+
### Grade a headline
|
|
453
|
+
|
|
454
|
+
```bash
|
|
455
|
+
curl -s -X POST http://localhost:4000/api/demos/headline-grader \
|
|
456
|
+
-H 'Content-Type: application/json' \
|
|
457
|
+
-d '{"headline": "Why Most Startups Fail at Month 18"}' | jq .
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
Response:
|
|
461
|
+
```json
|
|
462
|
+
{
|
|
463
|
+
"total_score": 74,
|
|
464
|
+
"grade": "B",
|
|
465
|
+
"diagnosis": "Strong promise but lacks the proof element that separates a 74 from an 88.",
|
|
466
|
+
"framework_scores": {
|
|
467
|
+
"rule_of_one": { "score": 22, "max": 30, "note": "..." },
|
|
468
|
+
"value_equation": { "score": 22, "max": 30, "note": "..." },
|
|
469
|
+
"readability": { "score": 16, "max": 20, "note": "..." },
|
|
470
|
+
"proof_promise_plan": { "score": 14, "max": 20, "note": "..." }
|
|
471
|
+
},
|
|
472
|
+
"rewrites": ["...", "..."],
|
|
473
|
+
"usage": { "remaining": 2, "limit": 3, "isPro": false }
|
|
474
|
+
}
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
### Compare two headlines (Pro)
|
|
478
|
+
|
|
479
|
+
```bash
|
|
480
|
+
curl -s -X POST http://localhost:4000/api/demos/headline-grader/compare \
|
|
481
|
+
-H 'Content-Type: application/json' \
|
|
482
|
+
-d '{
|
|
483
|
+
"headlineA": "Why Most Startups Fail",
|
|
484
|
+
"headlineB": "Why 90% of SaaS Startups Fail at Month 18",
|
|
485
|
+
"email": "you@example.com"
|
|
486
|
+
}' | jq .
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### Audit a landing page URL (Pro)
|
|
490
|
+
|
|
491
|
+
```bash
|
|
492
|
+
curl -s -X POST http://localhost:4000/api/demos/page-roast \
|
|
493
|
+
-H 'Content-Type: application/json' \
|
|
494
|
+
-d '{"url": "https://example.com", "email": "you@example.com"}' | jq .
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
### Score ad copy
|
|
498
|
+
|
|
499
|
+
```bash
|
|
500
|
+
curl -s -X POST http://localhost:4000/api/demos/ad-scorer \
|
|
501
|
+
-H 'Content-Type: application/json' \
|
|
502
|
+
-d '{
|
|
503
|
+
"adCopy": "Stop wasting money on ads that don'\''t convert.",
|
|
504
|
+
"platform": "facebook",
|
|
505
|
+
"email": "you@example.com"
|
|
506
|
+
}' | jq .
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
### Grade a Twitter thread
|
|
510
|
+
|
|
511
|
+
```bash
|
|
512
|
+
curl -s -X POST http://localhost:4000/api/demos/thread-grader \
|
|
513
|
+
-H 'Content-Type: application/json' \
|
|
514
|
+
-d '{
|
|
515
|
+
"threadText": "1/ Most people think productivity is about working more hours...\n\n2/ They'\''re wrong.",
|
|
516
|
+
"email": "you@example.com"
|
|
517
|
+
}' | jq .
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
### Generate an email
|
|
521
|
+
|
|
522
|
+
```bash
|
|
523
|
+
curl -s -X POST http://localhost:4000/api/demos/email-forge \
|
|
524
|
+
-H 'Content-Type: application/json' \
|
|
525
|
+
-d '{
|
|
526
|
+
"product": "A CLI tool that grades content quality",
|
|
527
|
+
"audience": "developers who write technical blog posts",
|
|
528
|
+
"goal": "cold_outreach",
|
|
529
|
+
"tone": "casual",
|
|
530
|
+
"email": "you@example.com"
|
|
531
|
+
}' | jq .
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
**Rate limit response** (when daily free limit is hit):
|
|
535
|
+
```json
|
|
536
|
+
{
|
|
537
|
+
"gated": true,
|
|
538
|
+
"isPro": false,
|
|
539
|
+
"remaining": 0,
|
|
540
|
+
"limit": 3,
|
|
541
|
+
"message": "Free daily limit reached (3/day). Get 100 analyses/day with Pro"
|
|
542
|
+
}
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
See [`docs/api.md`](./docs/api.md) for the full reference — every endpoint, complete request/response shapes, and more cURL examples.
|
|
546
|
+
|
|
547
|
+
---
|
|
548
|
+
|
|
549
|
+
## Workflows & integrations
|
|
550
|
+
|
|
551
|
+
### GitHub Actions — CI content quality gate
|
|
552
|
+
|
|
553
|
+
Fail the build if content quality drops below a threshold. Useful for content-heavy repos (marketing site, docs, blog).
|
|
554
|
+
|
|
555
|
+
```yaml
|
|
556
|
+
# .github/workflows/content-quality.yml
|
|
557
|
+
name: Content quality check
|
|
558
|
+
|
|
559
|
+
on:
|
|
560
|
+
pull_request:
|
|
561
|
+
paths:
|
|
562
|
+
- 'content/**'
|
|
563
|
+
- 'blog/**'
|
|
564
|
+
- '*.md'
|
|
565
|
+
|
|
566
|
+
jobs:
|
|
567
|
+
grade:
|
|
568
|
+
runs-on: ubuntu-latest
|
|
569
|
+
steps:
|
|
570
|
+
- uses: actions/checkout@v4
|
|
571
|
+
|
|
572
|
+
- name: Install Node.js
|
|
573
|
+
uses: actions/setup-node@v4
|
|
574
|
+
with:
|
|
575
|
+
node-version: '20'
|
|
576
|
+
|
|
577
|
+
- name: Install Claude CLI
|
|
578
|
+
run: npm install -g @anthropic-ai/claude-code
|
|
579
|
+
|
|
580
|
+
- name: Login to Claude (non-interactive)
|
|
581
|
+
run: echo "${{ secrets.ANTHROPIC_API_KEY }}" | claude login --api-key
|
|
582
|
+
# Note: Claude CLI requires authentication. Store your API key in GitHub secrets.
|
|
583
|
+
|
|
584
|
+
- name: Grade changed content
|
|
585
|
+
run: |
|
|
586
|
+
for f in $(git diff --name-only origin/main...HEAD | grep -E '\.(md|txt|mdx)$'); do
|
|
587
|
+
echo "=== Grading $f ==="
|
|
588
|
+
npx content-grade analyze "$f" --no-telemetry
|
|
589
|
+
done
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
> **Note:** Claude CLI must be authenticated. In CI, this requires an Anthropic API key. Set `ANTHROPIC_API_KEY` in your repository secrets and use it to log in.
|
|
593
|
+
|
|
594
|
+
---
|
|
595
|
+
|
|
596
|
+
### Pre-commit hook
|
|
597
|
+
|
|
598
|
+
Grade content before it enters the repo. Add this to `.git/hooks/pre-commit` (make it executable with `chmod +x .git/hooks/pre-commit`):
|
|
599
|
+
|
|
600
|
+
```bash
|
|
601
|
+
#!/bin/sh
|
|
602
|
+
# Content quality pre-commit hook
|
|
603
|
+
# Grades staged .md/.txt files and blocks commit if any score below threshold
|
|
604
|
+
|
|
605
|
+
THRESHOLD=40
|
|
606
|
+
|
|
607
|
+
staged=$(git diff --cached --name-only --diff-filter=ACMR | grep -E '\.(md|txt|mdx)$')
|
|
608
|
+
|
|
609
|
+
if [ -z "$staged" ]; then
|
|
610
|
+
exit 0
|
|
611
|
+
fi
|
|
612
|
+
|
|
613
|
+
echo "Running ContentGrade on staged files..."
|
|
614
|
+
|
|
615
|
+
for file in $staged; do
|
|
616
|
+
# Only check files over 100 characters (skip tiny files)
|
|
617
|
+
chars=$(wc -c < "$file" 2>/dev/null || echo 0)
|
|
618
|
+
if [ "$chars" -lt 100 ]; then
|
|
619
|
+
continue
|
|
620
|
+
fi
|
|
621
|
+
|
|
622
|
+
echo " Grading $file..."
|
|
623
|
+
npx content-grade analyze "$file" --no-telemetry
|
|
624
|
+
done
|
|
625
|
+
|
|
626
|
+
echo "✓ Content quality check complete."
|
|
627
|
+
exit 0
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
To block low-scoring commits, parse the score from output and compare against `$THRESHOLD`. The current output format prints `OVERALL SCORE 72/100` — grep for the number and exit 1 if below threshold.
|
|
631
|
+
|
|
632
|
+
---
|
|
633
|
+
|
|
634
|
+
### Batch processing a directory
|
|
635
|
+
|
|
636
|
+
Grade every content file in a directory and save results:
|
|
637
|
+
|
|
638
|
+
```bash
|
|
639
|
+
# Grade all markdown files and save output
|
|
640
|
+
find ./content -name '*.md' -not -name 'README.md' | while read f; do
|
|
641
|
+
echo "--- $f ---"
|
|
642
|
+
npx content-grade analyze "$f" --no-telemetry
|
|
643
|
+
echo ""
|
|
644
|
+
done > content-grades-$(date +%Y%m%d).txt
|
|
645
|
+
|
|
646
|
+
# Or use the built-in directory scan (picks the best candidate):
|
|
647
|
+
npx content-grade ./content
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
---
|
|
651
|
+
|
|
652
|
+
### Comparing scores over time
|
|
653
|
+
|
|
654
|
+
Track score progression across revisions:
|
|
655
|
+
|
|
656
|
+
```bash
|
|
657
|
+
# Score the current version of a post
|
|
658
|
+
npx content-grade analyze ./blog/my-post.md --no-telemetry > scores/my-post-$(date +%Y%m%d).txt
|
|
659
|
+
|
|
660
|
+
# Compare two versions side-by-side
|
|
661
|
+
diff scores/my-post-20240101.txt scores/my-post-20240201.txt
|
|
662
|
+
|
|
663
|
+
# Quick numeric comparison
|
|
664
|
+
grep "OVERALL SCORE" scores/my-post-*.txt
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
For structured tracking, use the REST API (run `content-grade start` first):
|
|
668
|
+
|
|
669
|
+
```bash
|
|
670
|
+
# Score via API, extract just the number
|
|
671
|
+
curl -s -X POST http://localhost:4000/api/demos/headline-grader \
|
|
672
|
+
-H 'Content-Type: application/json' \
|
|
673
|
+
-d '{"headline": "Your Post Title Here"}' \
|
|
674
|
+
| jq '.total_score'
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
Log to a CSV:
|
|
678
|
+
|
|
679
|
+
```bash
|
|
680
|
+
DATE=$(date +%Y-%m-%d)
|
|
681
|
+
HEADLINE="Your Post Title Here"
|
|
682
|
+
SCORE=$(curl -s -X POST http://localhost:4000/api/demos/headline-grader \
|
|
683
|
+
-H 'Content-Type: application/json' \
|
|
684
|
+
-d "{\"headline\": \"$HEADLINE\"}" | jq '.total_score')
|
|
685
|
+
|
|
686
|
+
echo "$DATE,$HEADLINE,$SCORE" >> headline-scores.csv
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
---
|
|
690
|
+
|
|
315
691
|
## Pricing
|
|
316
692
|
|
|
317
693
|
| | Free | Pro |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "content-grade",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "AI-powered content analysis CLI. Score any blog post, landing page, or ad copy in under 30 seconds — runs on Claude CLI, no API key needed.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -50,7 +50,12 @@
|
|
|
50
50
|
"test:watch": "vitest",
|
|
51
51
|
"test:coverage": "vitest run --coverage",
|
|
52
52
|
"stats": "node scripts/npm-stats.js",
|
|
53
|
-
"stats:week": "node scripts/npm-stats.js --week"
|
|
53
|
+
"stats:week": "node scripts/npm-stats.js --week",
|
|
54
|
+
"metrics": "node scripts/metrics.js",
|
|
55
|
+
"metrics:save": "node scripts/metrics.js --save",
|
|
56
|
+
"metrics:history": "node scripts/metrics.js --history",
|
|
57
|
+
"metrics:csv": "node scripts/metrics.js --csv",
|
|
58
|
+
"github-traffic": "node scripts/github-traffic.js"
|
|
54
59
|
},
|
|
55
60
|
"dependencies": {
|
|
56
61
|
"@fastify/cors": "^9.0.1",
|