this shit broke prod again — what the hell is going on with this damn CI 🙄
Keep your repo
🤬 Potty Mouth
free.
A drop-in GitHub Action that scans issues, pull requests, and comments for profane content — then replaces it with the strategy of your choice. Built with .NET Native AOT for instant, dependency-free runs.
MIT licensed · No registration · Works with the built-in GITHUB_TOKEN
# .github/workflows/profanity-filter.yml
name: Profanity filter
on:
issues:
types: [opened, edited, reopened]
pull_request:
types: [opened, edited, reopened]
issue_comment:
types: [created, edited]
permissions:
issues: write
pull-requests: write
jobs:
apply-filter:
runs-on: ubuntu-latest
steps:
- name: Scan for profanity
if: github.actor != 'dependabot[bot]'
uses: IEvangelist/profanity-filter@main
with:
token: ${{ secrets.GITHUB_TOKEN }}
replacement-strategy: emoji Live filtering, every keystroke.
A typewriter pours a sentence into the input below — the same logic that runs in
the WebApi container then redacts each profane word, side-by-side, in every strategy.
No backend, no SignalR — just JavaScript mirroring
MatchEvaluators.cs.
All 14 strategies — updating live, every keystroke
Identical logic to MatchEvaluators in the WebApi.
-
asteriskAsterisk Classic asterisks
-
random-asteriskRandom asterisk Random count, 1–N
-
middle-asteriskMiddle asterisk Keep first + last
-
first-letter-then-asteriskFirst letter + asterisk Keep first only
-
vowel-asteriskVowel asterisk Asterisk the vowels
-
emojiEmoji Random expressive emoji
-
anger-emojiAnger emoji Random anger emoji
-
middle-swear-emojiMiddle swear emoji First + 🤬 + last
-
bleepBleep Literal "bleep"
-
redacted-rectangleRedacted rectangle Solid █ blocks
-
strike-throughStrike through Wraps in <del>
-
underscoresUnderscores Underscores match length
-
grawlixGrawlix Comic-book symbols
-
bold-grawlixBold grawlix Grawlix, but louder
Text alternative — what the live demo shows
- A typewriter animation enters a sample sentence (e.g.
This shit is broken, what the hell are we doing here?
) into the input panel at the top, one character at a time. - Beneath the input is a grid of 14 cards, one per replacement strategy. Each card shows the strategy's slug, a friendly label, and a one-line description.
- On every keystroke, every card re-renders the input with that card's strategy applied. Profane words are matched as whole words (case-insensitive).
- For example:
asteriskturnsshitinto****,middle-asteriskturns it intos**t,bleepreplaces it with the literal wordbleep, andmiddle-swear-emojiturns it intos🤬t. - When the sentence finishes typing, the demo pauses briefly, clears, and starts typing a new sentence. The toggle button in the top-right lets you pause or resume the animation.
- The filtering logic is a faithful port of
MatchEvaluators.csin the .NET library — the same code that powers the GitHub Action and the WebApi container.
Prefer the original SignalR-driven recording? It now lives next to the
WebApi container README
— same Aspire AppHost in
playground/apphost.cs, streaming text over a SignalR
hub
and client.
Not every contributor is sunshine and rainbows .
Open source is a public-facing space, and the tone of a project sets the tone of its community. Potty Mouth quietly catches the rough edges — rewriting profane content, flagging the issue, and leaving a clean audit trail behind — so you can keep building without playing comment-thread cop.
With this action in your workflow, your repo can be 🌈 inviting and 🐎 swift.
- Live rewrite — comments stay readable
- Auto-label issues for triage
- Audit-friendly job summaries
this 💩 broke prod again — what the 🤬 is going on with this 😡 CI 🙄
Everything you need. Nothing you don't.
One step in your workflow, fourteen strategies, nine languages, and a clean job summary on every run.
9 languages, 4,900+ words
Curated word lists across English, Spanish, French, German, Italian, Portuguese, Russian, Arabic, and Chinese — kept up to date in plain text files anyone can audit.
14 replacement strategies
Pick the vibe — from classic **** asterisks to playful 😡 anger emojis or full ████ redactions.
Native AOT performance
Built with .NET 10 and Native AOT — instant cold starts, tiny binaries, and no .NET runtime to install on the runner.
Drop-in step
A single GitHub Action step. Add it to a new workflow or paste it into an existing one — no scripts, no infrastructure, no maintenance.
Workflow job summaries
Every run produces a clean, detailed summary table showing exactly what was found and how it was replaced — perfect for audits.
Bring your own words
Extend the dictionary with a comma-separated list or pull from your own URL. Works alongside the built-in filters automatically.
14 ways to say that word.
Pick the strategy that fits your project's tone — from buttoned-up to playful.
asterisk **** Classic asterisks — the safe default.
emoji 💩 A random expressive emoji per match.
grawlix #%$! Comic-book style symbol soup.
bold-grawlix #%$! Grawlix, but louder.
bleep bleep Replaces with the literal word "bleep".
redacted-rectangle ████ Top-secret redaction blocks.
anger-emoji 😡 A random anger-themed emoji.
middle-asterisk f**k Keeps first and last letters intact.
middle-swear-emoji f🤬k A swear emoji in the middle.
random-asterisk * — **** Random number of asterisks.
first-letter-then-asterisk f*** Keep the first letter only.
vowel-asterisk sh*t Replaces only the vowels.
strike-through Wraps content in <del> tags.
underscores ____ Replaces with underscores.
More than a GitHub Action.
The same engine ships as a containerized Aspire resource. Drop
AddProfanityFilter
into your AppHost — in C# or TypeScript — and you have a fast, local-first
HTTP filter alongside the rest of your services.
// apphost.cs
var builder = DistributedApplication.CreateBuilder(args);
var filter = builder.AddProfanityFilter("profanity-filter")
.WithCustomDataBindMount("./CustomData");
builder.AddProject<Projects.MyApi>("api")
.WithReference(filter)
.WaitFor(filter);
builder.Build().Run(); Ready to clean up your repo?
Two minutes from this page to a working workflow. No registration, no infrastructure, no excuses.