Two images. One filter. Wherever you ship.
Every release publishes two distroless Linux images to GitHub Container Registry — one packaged as a GitHub Action, one as a standalone HTTP API. Both are built from the same Native AOT engine and tagged in lockstep.
Action container
ghcr.io/ievangelist/profanity-filter —
the runner image used by the GitHub Action step. You usually don’t pull this directly;
GitHub does it for you when a workflow says uses: IEvangelist/profanity-filter@main.
API container
ghcr.io/ievangelist/profanity-filter-api —
the standalone HTTP API. Powers the Aspire integration, the
ProfanityFilter.Client NuGet, and any standalone deployment.
Action container
View on GHCR
The Action container packages the runner the workflow step uses. Powered by
.NET 10 Native AOT, it cold-starts in milliseconds, has no .NET runtime to install,
and is what makes a single
uses:
line work end-to-end.
Pull
docker pull ghcr.io/ievangelist/profanity-filter:13.3.0 API container
View on GHCRA standalone ASP.NET Core minimal-API surface over the same filter engine, plus a SignalR hub for live streaming. Same image the Aspire integration pulls.
Pull
docker pull ghcr.io/ievangelist/profanity-filter-api:13.3.0 Run it standalone
The API listens on :8080
inside the container. Map the port and you’re live.
# Run the API on http://localhost:8080
docker run --rm \
--name profanity-filter-api \
-p 8080:8080 \
ghcr.io/ievangelist/profanity-filter-api:13.3.0
# Optional — mount your own *.txt word lists, merged with the
# built-in 4,900+ word dictionary at startup:
docker run --rm \
--name profanity-filter-api \
-p 8080:8080 \
-v "$(pwd)/CustomData":/app/CustomData:ro \
ghcr.io/ievangelist/profanity-filter-api:13.3.0 Or with Compose
# compose.yaml
services:
profanity-filter:
image: ghcr.io/ievangelist/profanity-filter-api:13.3.0
container_name: profanity-filter-api
ports:
- "8080:8080"
volumes:
- ./CustomData:/app/CustomData:ro
restart: unless-stopped HTTP surface
All routes return JSON. The container also serves an interactive
Scalar
reference at /scalar
and an OpenAPI document at /openapi/v1.json.
| Method | Path | Description |
|---|---|---|
| POST | /profanity/filter | Apply the filter to a body of text. Returns the filtered output, the matched words, and the per-step trace. |
| GET | /profanity/strategies | List the 14 replacement strategies (Emoji, RedactedRectangle, AngerEmoji, …). |
| GET | /profanity/targets | List the supported filter targets. |
| GET | /profanity/data | List the available word-list data set names (one per language plus any custom mounts). |
| GET | /profanity/data/{name} | Return the words in a single data set. |
| WS | /profanity/hub | SignalR hub — bi-directional streaming for live UIs (WebSockets / SSE / long-polling). |
Try it
curl -X POST http://localhost:8080/profanity/filter \
-H "content-type: application/json" \
-d '{
"text": "What the heck, dude?",
"strategy": "Emoji"
}'