thisshitbroke prod again — what thehellis going on with thisdamnCI 🙄
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: emojiLive 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.
asteriskAsteriskClassic asterisks
random-asteriskRandom asteriskRandom count, 1–N
middle-asteriskMiddle asteriskKeep first + last
first-letter-then-asteriskFirst letter + asteriskKeep first only
vowel-asteriskVowel asteriskAsterisk the vowels
emojiEmojiRandom expressive emoji
anger-emojiAnger emojiRandom anger emoji
middle-swear-emojiMiddle swear emojiFirst + 🤬 + last
bleepBleepLiteral "bleep"
redacted-rectangleRedacted rectangleSolid █ blocks
strike-throughStrike throughWraps in <del>
underscoresUnderscoresUnderscores match length
grawlixGrawlixComic-book symbols
bold-grawlixBold grawlixGrawlix, 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).
- The moment the input contains a completed profane word, a GitHub-style
profane content 🤬label appears above the input — emulating the label the GitHub Action applies to flagged issues and pull requests. It links to the label documentation, and disappears again if the input clears to something clean. - 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 issunshine 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🌈 invitingand🐎 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, twenty-eight languages, and a clean job summary on every run.
28 languages, 6,500+ words
Curated word lists across 28 languages — English, Spanish, French, German, Italian, Portuguese, Russian, Dutch, Polish, Turkish, Japanese, Korean, Arabic, Chinese, Hindi, and more — 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.
bleepbleepReplaces with the literal word "bleep".
redacted-rectangle████Top-secret redaction blocks.
anger-emoji😡A random anger-themed emoji.
middle-asteriskf**kKeeps first and last letters intact.
middle-swear-emojif🤬kA swear emoji in the middle.
random-asterisk* — ****Random number of asterisks.
first-letter-then-asteriskf***Keep the first letter only.
vowel-asterisksh*tReplaces only the vowels.
strike-throughWraps content in <del> tags.
underscores____Replaces with underscores.
More than a GitHub Action.
The same engine ships as a containerized Aspire resource. DropAddProfanityFilterinto 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.