Your style guide says "customers," but someone just merged a PR with "users" in 12 places. Your docs say "click," but your buttons say "tap," "press," and "select."
Brand consistency dies in pull requests. Code review catches bugs, not tone. And nobody has time to manually check every string.
Stringly-Typed is a GitHub Action that validates UI strings against your brand voice using AI.
- Runs on every PR β Catches issues before merge, not after deploy
- Uses your style guide β Define rules once in markdown, enforce everywhere
- 2-minute setup β One workflow file, one style guide, done
- Fast feedback β Analyzes only changed files in ~2-5 seconds
Add STYLE_GUIDE.md to your repo:
# Brand Voice
- Use active voice, not passive
- Say "customers" not "users"
- Keep sentences under 20 words
- Be friendly but professionalCreate .github/workflows/stringly-typed.yml:
name: Stringly-Typed
on: [push, pull_request]
jobs:
brand-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ddnetters/stringly-typed@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
with:
files: 'src/**/*.{js,ts,tsx}'
checker: 'brand_style'
style-guide-file: 'STYLE_GUIDE.md'
decider: 'threshold'
decider-options: '{"minValidRatio": 0.9}'That's it. Stringly-Typed now validates every string against your brand voice.
Stringly-Typed Results:
βββ src/components/Button.tsx
β βββ Line 12: "Click here to continue" β
β β βββ Use "Select" not "Click" (terminology)
β βββ Line 18: "Your order has been placed" β
OK
βββ src/utils/errors.ts
β βββ Line 5: "An error was encountered by the system" β
β βββ Use active voice: "Something went wrong" (tone)
βββ Summary: 4/6 strings valid (67%) - FAILED
Brand Voice Enforcement
Ensure every user-facing string matches your tone guidelines. Define voice rules in your style guide, and Stringly-Typed flags violations like passive voice, wrong terminology, or off-brand phrasing.
checker: 'brand_style'
style-guide-file: 'STYLE_GUIDE.md'Documentation Consistency
Validate markdown files for consistent terminology and style. Great for docs-as-code workflows where multiple contributors write documentation.
files: 'docs/**/*.md'
checker: 'brand_style'String Length Limits
Enforce character limits for UI stringsβuseful for buttons, tooltips, and mobile interfaces where space is constrained.
checker: 'char_count'
checker-options: '{"maxChars": 40}'Custom Validation Rules
Write your own JavaScript validation logic for specialized requirements like banned words, required patterns, or domain-specific rules.
checker: 'custom'
checker-options: '{"expression": "!content.toLowerCase().includes(\"todo\")"}'Stringly-Typed can automatically comment on pull requests with validation results.
| Value | Behavior |
|---|---|
on-failure |
Comment only when validation fails (default) |
always |
Comment on every PR run |
never |
Disable PR comments |
- uses: ddnetters/stringly-typed@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
comment: 'on-failure'| Checker | Use Case |
|---|---|
brand_style |
AI-powered voice & tone validation |
char_count |
Enforce max string length |
custom |
Your own JavaScript validation logic |
| Guide | Description |
|---|---|
| Installation | Setup, local dev, Docker, npm package |
| Configuration | All options in detail |
| Checkers | char_count, custom, brand_style |
| Deciders | threshold, noCritical, custom |
| LLM Providers | OpenAI, OpenRouter, Anthropic, Azure, AWS Bedrock, Groq, and more |
| Examples | Real-world usage scenarios |
| API Reference | TypeScript interfaces |
| Troubleshooting | Common issues |
How much does the AI cost?
You use your own API key. A typical PR check costs $0.01-0.05 depending on how many strings changed.
Is my code sent to the LLM?
Only the string literals you specify are analyzed. Your source code logic is never sent.
Can I use Claude or Gemini instead of OpenAI?
Yes! Stringly-Typed supports multiple LLM providers. See the Providers Guide for setup instructions.
What if it flags false positives?
Configure sensitivity in your style guide, or set the decider threshold lower. You can also use warn mode instead of blocking merges.
Does it work with my stack?
Works with any text filesβTypeScript, JavaScript, JSX, JSON, Markdown, YAML. Configure file patterns to match your project.
How do I ignore certain strings?
Use file patterns to exclude paths, or configure checker options to skip specific patterns. See Configuration for details.
Contributions welcome! See CONTRIBUTING.md for guidelines.
- Open an issue for bugs or feature requests
- Start a discussion for questions or ideas
- Read the docs for detailed guides
MIT - see LICENSE
