Guidance for AI coding agents working on this repository. Human contributors should read CONTRIBUTING.md and README.md first — this file is the condensed, machine-facing version.
SafeChat Slack Bot is a Slack bot (Slack Bolt, Socket Mode) that detects PII — Brazilian CPF, email addresses and Brazilian phone numbers — in channel messages and replies in-thread asking the author not to share sensitive data. Python 3.11, Poetry, Docker-first, i18n via gettext.
src/bot.py entrypoint: builds AsyncApp, starts AsyncSocketModeHandler
src/listeners/register.py registers every listener
src/listeners/messages/regex_message.py new messages matching the compiled pattern
src/listeners/messages/message_changed.py edited messages (subtype message_changed)
src/rules/constants.py the regex patterns
src/rules/pattern.py Pattern singleton: compiles the rules, find_all(text) -> int
src/config/settings.py settings.conf + ENV via ConfigParser
src/config/language.py gettext wrapper: language.translate(msgid)
src/locales/{en,pt_BR}/LC_MESSAGES/base.po translations
tests/ mirrors src/
Prerequisites: Python 3.11, Docker + Docker Compose, gettext (provides msgfmt), Poetry.
make docker/install — recommended, and what CI runs.make local/install — local Poetry install.Both targets create .env from env.template if absent and compile the .mo files.
.env and *.mo are gitignored and must stay that way — never commit either.
| Task | Docker (canonical) | Local |
|---|---|---|
| install | make docker/install |
make local/install |
| tests | make docker/test |
make local/tests |
| lint | make docker/lint |
make local/lint |
| lint + autofix | make docker/lint/fix |
make local/lint/fix |
| run | make docker/run |
make local/run |
| compile translations | make generate-mo-files |
make generate-mo-files |
CI (.github/workflows/pull_request.yml) runs
make docker/install → make docker/lint → make docker/test. See the Makefile for
every target.
Ruff, configured in pyproject.toml: line-length = 120, target-version = py311,
4-space indent, double quotes. Lint rules: E, F, W (pycodestyle/pyflakes), I (isort),
N (pep8-naming), S (flake8-bandit). Run make local/lint/fix before committing.
Project ethos from CONTRIBUTING.md: be pythonic, DRY, KISS.
pytest with testpaths = ["tests"] and pythonpath = ["src"].
unittest.TestCase / IsolatedAsyncioTestCase classes with
unittest.mock (AsyncMock, MagicMock, patch) — not bare pytest functions. Follow the
existing style.test_if_text_can_be_a_cpf_with_success.fail_under = 100 (src/bot.py omitted). New code without
tests breaks the build.pytest-asyncio is installed but no asyncio_mode is configured — write async tests with
IsolatedAsyncioTestCase.src/rules/constants.py.self.rules in Pattern.__init__ (src/rules/pattern.py).tests/rules/test_pattern.py.Watch for over-matching: the rules are joined with | into one pattern, and the current CPF regex
matches any run of 11 digits — a phone number counts as a CPF. Assert exact find_all counts.
User-facing strings must go through language.translate("..."). Add the msgid to both
src/locales/en/LC_MESSAGES/base.po and src/locales/pt_BR/LC_MESSAGES/base.po, then run
make generate-mo-files. Adding a new locale also requires a msgfmt line in the
Dockerfile.
feat:, fix:, docs:,
chore:, refactor:, test:. (History predates this convention and is inconsistent — follow the
convention going forward.)Co-Authored-By lines or any AI / “Generated with” attribution to commits or PR
bodies.main — always work on a branch.closes #NN.The tag and the GitHub Release are created automatically by
.github/workflows/release.yml when a version without a tag lands
on main. CONTRIBUTING.md has the full process.
X.Y.Z, without a v prefix, always derived from tool.poetry.version in
pyproject.toml.version in pyproject.toml and add the
matching ## [X.Y.Z] - YYYY-MM-DD section to CHANGELOG.md. Without both, the
release never fires.This bot handles credentials and PII by definition. Treat these as hard rules:
SLACK_BOT_TOKEN and SLACK_APP_TOKEN come from environment variables only. Never hardcode a
token, never log one, and never paste a real value into docs, tests or fixtures — reference
env.template and the variable names instead.S (bandit) findings with # noqa without a written justification.