baldanders 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. baldanders-0.1.0/.gitignore +38 -0
  2. baldanders-0.1.0/LICENSE +21 -0
  3. baldanders-0.1.0/PKG-INFO +205 -0
  4. baldanders-0.1.0/README.md +160 -0
  5. baldanders-0.1.0/pyproject.toml +76 -0
  6. baldanders-0.1.0/src/baldanders/__init__.py +3 -0
  7. baldanders-0.1.0/src/baldanders/cli.py +365 -0
  8. baldanders-0.1.0/src/baldanders/config.py +133 -0
  9. baldanders-0.1.0/src/baldanders/history.py +127 -0
  10. baldanders-0.1.0/src/baldanders/mapping.py +111 -0
  11. baldanders-0.1.0/src/baldanders/model_manager.py +93 -0
  12. baldanders-0.1.0/src/baldanders/providers/__init__.py +1 -0
  13. baldanders-0.1.0/src/baldanders/providers/anthropic.py +57 -0
  14. baldanders-0.1.0/src/baldanders/providers/base.py +96 -0
  15. baldanders-0.1.0/src/baldanders/providers/claude_code.py +101 -0
  16. baldanders-0.1.0/src/baldanders/providers/codex.py +133 -0
  17. baldanders-0.1.0/src/baldanders/providers/grok.py +88 -0
  18. baldanders-0.1.0/src/baldanders/providers/openai.py +56 -0
  19. baldanders-0.1.0/src/baldanders/scrubber/__init__.py +1 -0
  20. baldanders-0.1.0/src/baldanders/scrubber/engine.py +146 -0
  21. baldanders-0.1.0/src/baldanders/scrubber/ner.py +291 -0
  22. baldanders-0.1.0/src/baldanders/scrubber/regex.py +575 -0
  23. baldanders-0.1.0/tests/conftest.py +22 -0
  24. baldanders-0.1.0/tests/test_cli.py +39 -0
  25. baldanders-0.1.0/tests/test_engine.py +124 -0
  26. baldanders-0.1.0/tests/test_history.py +54 -0
  27. baldanders-0.1.0/tests/test_mapping.py +117 -0
  28. baldanders-0.1.0/tests/test_ner.py +156 -0
  29. baldanders-0.1.0/tests/test_providers.py +179 -0
  30. baldanders-0.1.0/tests/test_regex.py +316 -0
@@ -0,0 +1,38 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.egg-info/
6
+ *.egg
7
+ .eggs/
8
+ dist/
9
+ build/
10
+ .venv/
11
+ venv/
12
+ .pytest_cache/
13
+ .mypy_cache/
14
+ .ruff_cache/
15
+ .coverage
16
+ htmlcov/
17
+ *.onnx
18
+
19
+ # App data
20
+ .baldanders/
21
+
22
+ # OS / editor junk
23
+ .DS_Store
24
+ ._*
25
+ Thumbs.db
26
+ ehthumbs.db
27
+ Desktop.ini
28
+ $RECYCLE.BIN/
29
+ *.swp
30
+ *.swo
31
+ *~
32
+ .idea/
33
+ .vscode/
34
+
35
+ # Archives accidentally dropped in the repo
36
+ *.zip
37
+ *.tar
38
+ *.tar.gz
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Baldanders contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,205 @@
1
+ Metadata-Version: 2.5
2
+ Name: baldanders
3
+ Version: 0.1.0
4
+ Summary: Local personal-data firewall for cloud LLMs — scrubs names, emails, IDs and other private details before they leave your machine
5
+ Project-URL: Homepage, https://github.com/Nahuel990/Baldanders
6
+ Project-URL: Repository, https://github.com/Nahuel990/Baldanders
7
+ Project-URL: Issues, https://github.com/Nahuel990/Baldanders/issues
8
+ Author: Baldanders contributors
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: anonymization,cli,gdpr,llm,personal-data,pii,privacy,redaction
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: End Users/Desktop
16
+ Classifier: Natural Language :: English
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3 :: Only
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Topic :: Security
25
+ Classifier: Topic :: Text Processing :: Filters
26
+ Requires-Python: >=3.10
27
+ Requires-Dist: click>=8.0
28
+ Requires-Dist: httpx>=0.27
29
+ Requires-Dist: phonenumbers>=8.13
30
+ Requires-Dist: python-stdnum>=1.20
31
+ Requires-Dist: pyyaml>=6.0
32
+ Requires-Dist: rich>=13.0
33
+ Provides-Extra: all
34
+ Requires-Dist: anthropic>=1.15; extra == 'all'
35
+ Requires-Dist: gliner[onnx]>=0.2.29; extra == 'all'
36
+ Provides-Extra: anthropic
37
+ Requires-Dist: anthropic>=1.15; extra == 'anthropic'
38
+ Provides-Extra: dev
39
+ Requires-Dist: build>=1.2; extra == 'dev'
40
+ Requires-Dist: pytest>=8.0; extra == 'dev'
41
+ Requires-Dist: twine>=6.0; extra == 'dev'
42
+ Provides-Extra: ner
43
+ Requires-Dist: gliner[onnx]>=0.2.29; extra == 'ner'
44
+ Description-Content-Type: text/markdown
45
+
46
+ <p align="center">
47
+ <img src="https://raw.githubusercontent.com/Nahuel990/Baldanders/main/baldanders.svg" alt="Baldanders" width="320">
48
+ </p>
49
+
50
+ # Baldanders
51
+
52
+ [![PyPI](https://img.shields.io/pypi/v/baldanders)](https://pypi.org/project/baldanders/)
53
+ [![Python](https://img.shields.io/pypi/pyversions/baldanders)](https://pypi.org/project/baldanders/)
54
+ [![CI](https://github.com/Nahuel990/Baldanders/actions/workflows/ci.yml/badge.svg)](https://github.com/Nahuel990/Baldanders/actions/workflows/ci.yml)
55
+
56
+ Local personal-data firewall for cloud LLMs. Chat with Claude, ChatGPT, Grok and others while your names, emails, ID numbers, bank details and secrets stay on your machine.
57
+
58
+ ```
59
+ You: Hola, soy Nahuel Nucera, mi DNI es 30.123.456 y mi mail nahuel@gmail.com
60
+ Sent to AI: Hola, soy [PERSON_1], mi DNI es [NATIONAL_ID_1] y mi mail [EMAIL_1]
61
+ AI replied: Hola [PERSON_1], ...
62
+ You see: Hola Nahuel Nucera, ...
63
+ ```
64
+
65
+ ## How it works
66
+
67
+ You type normally. Baldanders finds personal details, swaps each one for a token like `[PERSON_1]`, and sends only the cleaned text to the AI. When the reply comes back, the tokens are swapped back to the real values. The AI never sees your data, and the token map never leaves your computer.
68
+
69
+ Detection is local and runs in layers:
70
+
71
+ 1. **Your rules**: terms and patterns from your config that must always be hidden.
72
+ 2. **Deterministic detectors**: emails, phones (any country), cards, IBANs, 55+ national ID formats, secrets. Each one is checksum-validated where the format has a checksum.
73
+ 3. **A multilingual AI model** (optional) for names and street addresses in 20+ languages.
74
+
75
+ ## Install
76
+
77
+ ```bash
78
+ pip install baldanders # core: regex/checksum detectors, all providers except the API ones
79
+ pip install "baldanders[ner]" # + name & address model (pulls in PyTorch, ~1 GB)
80
+ pip install "baldanders[anthropic]" # + direct Claude API provider
81
+ pip install "baldanders[all]" # everything
82
+ ```
83
+
84
+ [pipx](https://pipx.pypa.io) keeps it isolated: `pipx install "baldanders[all]"`.
85
+
86
+ For name and address detection, download the model once (about 320 MB, checksum-verified). After that it runs fully offline:
87
+
88
+ ```bash
89
+ baldanders download
90
+ ```
91
+
92
+ ## Usage
93
+
94
+ ```bash
95
+ baldanders # Claude, via your Claude Code login (no API key)
96
+ baldanders -p chatgpt # ChatGPT, via your Codex CLI login (no API key)
97
+ baldanders -p grok # Grok, via grok-cli (SuperGrok / X Premium+, no API key)
98
+
99
+ baldanders -p anthropic-api # Claude API (ANTHROPIC_API_KEY or `ant auth login`)
100
+ baldanders -p openai-api # OPENAI_API_KEY
101
+ baldanders -p deepseek # DEEPSEEK_API_KEY
102
+ baldanders -p groq # GROQ_API_KEY
103
+ baldanders -p openai-api --base-url http://localhost:11434/v1 -m llama3 # any OpenAI-compatible API
104
+
105
+ baldanders -v # show exactly what leaves your machine
106
+ baldanders --no-save # don't write this conversation to disk
107
+ baldanders sessions # list saved sessions
108
+ baldanders --resume 20261002-143022
109
+ baldanders sessions --delete 20261002-143022
110
+ ```
111
+
112
+ Scrub text without talking to any AI (useful in scripts and pipelines):
113
+
114
+ ```bash
115
+ echo "Call me on +54 9 11 4567-8901" | baldanders scrub
116
+ # Call me on [PHONE_1]
117
+ baldanders scrub --json "IBAN DE89 3704 0044 0532 0130 00"
118
+ ```
119
+
120
+ ### Commands inside the chat
121
+
122
+ | Command | What it does |
123
+ |---------|-------------|
124
+ | `/paste` | Multi-line input (end with `.` on its own line) |
125
+ | `/map` | Show which token stands for which real value |
126
+ | `/raw` | Toggle scrubbing off/on for messages with nothing sensitive |
127
+ | `/clear` | Start a fresh conversation (keeps the token map) |
128
+ | `/help` | Show commands |
129
+ | `/quit` | Exit |
130
+
131
+ ## What gets scrubbed
132
+
133
+ **Everywhere:** emails (including non-Latin addresses), phone numbers from any country (Google's libphonenumber), credit cards (Luhn-checked), IBANs for 89 countries (length and mod-97 checked), IPv4/IPv6 and MAC addresses, crypto wallets, dates of birth, passport numbers next to a keyword, and names and street addresses with the model installed.
134
+
135
+ **Secrets:** API keys (AWS, GitHub, GitLab, Slack, Stripe, Google, OpenAI, Anthropic, Hugging Face, npm), JWTs, private keys, passwords in `password: …` / `contraseña = …` / database URLs.
136
+
137
+ **National IDs and tax numbers**, validated with [python-stdnum](https://arthurdejong.org/python-stdnum/) where a checksum exists:
138
+
139
+ | Region | Identifiers |
140
+ |--------|-------------|
141
+ | Americas | US SSN/ITIN · Canada SIN · Brazil CPF/CNPJ · Argentina DNI/CUIT/CUIL · Chile RUT · Mexico CURP/RFC · Colombia NIT · Ecuador cédula · Uruguay RUT |
142
+ | Europe | UK NINO/NHS · Spain DNI/NIE · Portugal NIF · France NIR · Italy codice fiscale · Germany Steuer-ID · Netherlands BSN · Belgium national number · Poland PESEL · Sweden/Norway/Denmark/Finland personal numbers · Switzerland AHV · Austria SVNR · Ireland PPS · Czech/Slovak birth number · Romania CNP · Bulgaria EGN · Croatia OIB · Greece AMKA · Estonia · Lithuania · Turkey TC Kimlik · Russia INN · Ukraine RNTRC |
143
+ | Asia & Pacific | India Aadhaar/PAN · Pakistan CNIC · China resident ID · Hong Kong HKID · Taiwan ID · Japan My Number · South Korea RRN · Malaysia MyKad · Singapore NRIC · Indonesia NIK · Thailand ID · Israel ID · Australia TFN · New Zealand IRD |
144
+ | Africa | South Africa ID |
145
+ | Anywhere | Any ID-shaped number right after a keyword like *DNI, cédula, ID number, Ausweis, 身份证, …* |
146
+
147
+ Some IDs are just a run of digits with no distinctive shape, like a BSN, PESEL or Steuer-ID. Those are scrubbed when a keyword is nearby ("BSN 111222333"). If you set `paranoid: true`, they're scrubbed on checksum alone.
148
+
149
+ Ordinary text is left alone: code, SQL, version numbers, order numbers, amounts, ordinary dates and city names. If something is over-scrubbed anyway, the AI only sees a token and you still get the real value back in the reply.
150
+
151
+ ## Configuration
152
+
153
+ `~/.baldanders/config.yaml` is created on first run:
154
+
155
+ ```yaml
156
+ regions: [AR, US] # local phone formats to recognise; empty = guess from OS locale
157
+ paranoid: false # scrub checksum-valid IDs even without a keyword nearby
158
+ # ner_threshold: 0.6 # name/address model confidence (default: names 0.7, addresses 0.4)
159
+ save_sessions: true
160
+
161
+ allowlist: # never scrub these
162
+ - my-s3-bucket-name
163
+
164
+ denylist: # always scrub these (case-insensitive) as the given type
165
+ "Project Falcon": PROJECT
166
+
167
+ custom_patterns: # extra regexes; first capturing group is scrubbed if present
168
+ customer_id: "CID-\\d{8}"
169
+ ```
170
+
171
+ Set `BALDANDERS_HOME` to keep config, sessions and the model somewhere other than `~/.baldanders`.
172
+
173
+ ## Privacy notes
174
+
175
+ - **What is sent:** only the scrubbed text, plus a short instruction telling the AI to keep the tokens intact. Run with `-v` to see every byte.
176
+ - **What stays local:** the token map, the model, and your config. Saved sessions (`~/.baldanders/sessions/`) contain the real values so `--resume` works. They are readable only by your user. Turn them off with `--no-save` or `save_sessions: false`.
177
+ - **Subscription CLIs:** Baldanders runs `claude` and `codex` in an empty private directory. For Claude Code, all tools and MCP servers are disabled, so the AI can't read your files. Codex runs in its read-only sandbox, so it can still read files outside that directory if it chooses to. Prefer `-p claude` or an API provider for sensitive work. These CLIs add their own context to each request (OS, working directory path, and for Claude Code your personal `~/.claude/CLAUDE.md` if you have one). Baldanders doesn't control that context.
178
+ - **No detector is perfect.** Unusual names, free-form addresses, or IDs written in unexpected ways can slip through. Check `-v` output when it matters, and add anything specific to your work to the `denylist`.
179
+
180
+ ## Requirements
181
+
182
+ - Python 3.10+
183
+ - For `-p claude`: [Claude Code](https://docs.anthropic.com/en/docs/claude-code), logged in
184
+ - For `-p chatgpt`: [Codex CLI](https://github.com/openai/codex) (`npm install -g @openai/codex`, then `codex login`)
185
+ - For `-p grok`: [grok-cli](https://github.com/Moore-developers/grok-cli) (`grok-cli login`)
186
+
187
+ ## Development
188
+
189
+ ```bash
190
+ pip install -e ".[dev,ner,anthropic]"
191
+ baldanders download # optional: enables the NER integration tests
192
+ pytest
193
+ ```
194
+
195
+ ### Releasing
196
+
197
+ Releases go to PyPI from GitHub Actions via [trusted publishing](https://docs.pypi.org/trusted-publishers/), so no API token is stored anywhere.
198
+
199
+ 1. One-time setup: on PyPI, add a pending publisher for project `baldanders`, owner `Nahuel990`, repo `Baldanders`, workflow `release.yml`, environment `pypi`. On GitHub, create an environment named `pypi`.
200
+ 2. Bump `__version__` in `src/baldanders/__init__.py` and commit.
201
+ 3. Tag and push: `git tag v0.1.0 && git push origin v0.1.0`.
202
+
203
+ ## License
204
+
205
+ MIT
@@ -0,0 +1,160 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/Nahuel990/Baldanders/main/baldanders.svg" alt="Baldanders" width="320">
3
+ </p>
4
+
5
+ # Baldanders
6
+
7
+ [![PyPI](https://img.shields.io/pypi/v/baldanders)](https://pypi.org/project/baldanders/)
8
+ [![Python](https://img.shields.io/pypi/pyversions/baldanders)](https://pypi.org/project/baldanders/)
9
+ [![CI](https://github.com/Nahuel990/Baldanders/actions/workflows/ci.yml/badge.svg)](https://github.com/Nahuel990/Baldanders/actions/workflows/ci.yml)
10
+
11
+ Local personal-data firewall for cloud LLMs. Chat with Claude, ChatGPT, Grok and others while your names, emails, ID numbers, bank details and secrets stay on your machine.
12
+
13
+ ```
14
+ You: Hola, soy Nahuel Nucera, mi DNI es 30.123.456 y mi mail nahuel@gmail.com
15
+ Sent to AI: Hola, soy [PERSON_1], mi DNI es [NATIONAL_ID_1] y mi mail [EMAIL_1]
16
+ AI replied: Hola [PERSON_1], ...
17
+ You see: Hola Nahuel Nucera, ...
18
+ ```
19
+
20
+ ## How it works
21
+
22
+ You type normally. Baldanders finds personal details, swaps each one for a token like `[PERSON_1]`, and sends only the cleaned text to the AI. When the reply comes back, the tokens are swapped back to the real values. The AI never sees your data, and the token map never leaves your computer.
23
+
24
+ Detection is local and runs in layers:
25
+
26
+ 1. **Your rules**: terms and patterns from your config that must always be hidden.
27
+ 2. **Deterministic detectors**: emails, phones (any country), cards, IBANs, 55+ national ID formats, secrets. Each one is checksum-validated where the format has a checksum.
28
+ 3. **A multilingual AI model** (optional) for names and street addresses in 20+ languages.
29
+
30
+ ## Install
31
+
32
+ ```bash
33
+ pip install baldanders # core: regex/checksum detectors, all providers except the API ones
34
+ pip install "baldanders[ner]" # + name & address model (pulls in PyTorch, ~1 GB)
35
+ pip install "baldanders[anthropic]" # + direct Claude API provider
36
+ pip install "baldanders[all]" # everything
37
+ ```
38
+
39
+ [pipx](https://pipx.pypa.io) keeps it isolated: `pipx install "baldanders[all]"`.
40
+
41
+ For name and address detection, download the model once (about 320 MB, checksum-verified). After that it runs fully offline:
42
+
43
+ ```bash
44
+ baldanders download
45
+ ```
46
+
47
+ ## Usage
48
+
49
+ ```bash
50
+ baldanders # Claude, via your Claude Code login (no API key)
51
+ baldanders -p chatgpt # ChatGPT, via your Codex CLI login (no API key)
52
+ baldanders -p grok # Grok, via grok-cli (SuperGrok / X Premium+, no API key)
53
+
54
+ baldanders -p anthropic-api # Claude API (ANTHROPIC_API_KEY or `ant auth login`)
55
+ baldanders -p openai-api # OPENAI_API_KEY
56
+ baldanders -p deepseek # DEEPSEEK_API_KEY
57
+ baldanders -p groq # GROQ_API_KEY
58
+ baldanders -p openai-api --base-url http://localhost:11434/v1 -m llama3 # any OpenAI-compatible API
59
+
60
+ baldanders -v # show exactly what leaves your machine
61
+ baldanders --no-save # don't write this conversation to disk
62
+ baldanders sessions # list saved sessions
63
+ baldanders --resume 20261002-143022
64
+ baldanders sessions --delete 20261002-143022
65
+ ```
66
+
67
+ Scrub text without talking to any AI (useful in scripts and pipelines):
68
+
69
+ ```bash
70
+ echo "Call me on +54 9 11 4567-8901" | baldanders scrub
71
+ # Call me on [PHONE_1]
72
+ baldanders scrub --json "IBAN DE89 3704 0044 0532 0130 00"
73
+ ```
74
+
75
+ ### Commands inside the chat
76
+
77
+ | Command | What it does |
78
+ |---------|-------------|
79
+ | `/paste` | Multi-line input (end with `.` on its own line) |
80
+ | `/map` | Show which token stands for which real value |
81
+ | `/raw` | Toggle scrubbing off/on for messages with nothing sensitive |
82
+ | `/clear` | Start a fresh conversation (keeps the token map) |
83
+ | `/help` | Show commands |
84
+ | `/quit` | Exit |
85
+
86
+ ## What gets scrubbed
87
+
88
+ **Everywhere:** emails (including non-Latin addresses), phone numbers from any country (Google's libphonenumber), credit cards (Luhn-checked), IBANs for 89 countries (length and mod-97 checked), IPv4/IPv6 and MAC addresses, crypto wallets, dates of birth, passport numbers next to a keyword, and names and street addresses with the model installed.
89
+
90
+ **Secrets:** API keys (AWS, GitHub, GitLab, Slack, Stripe, Google, OpenAI, Anthropic, Hugging Face, npm), JWTs, private keys, passwords in `password: …` / `contraseña = …` / database URLs.
91
+
92
+ **National IDs and tax numbers**, validated with [python-stdnum](https://arthurdejong.org/python-stdnum/) where a checksum exists:
93
+
94
+ | Region | Identifiers |
95
+ |--------|-------------|
96
+ | Americas | US SSN/ITIN · Canada SIN · Brazil CPF/CNPJ · Argentina DNI/CUIT/CUIL · Chile RUT · Mexico CURP/RFC · Colombia NIT · Ecuador cédula · Uruguay RUT |
97
+ | Europe | UK NINO/NHS · Spain DNI/NIE · Portugal NIF · France NIR · Italy codice fiscale · Germany Steuer-ID · Netherlands BSN · Belgium national number · Poland PESEL · Sweden/Norway/Denmark/Finland personal numbers · Switzerland AHV · Austria SVNR · Ireland PPS · Czech/Slovak birth number · Romania CNP · Bulgaria EGN · Croatia OIB · Greece AMKA · Estonia · Lithuania · Turkey TC Kimlik · Russia INN · Ukraine RNTRC |
98
+ | Asia & Pacific | India Aadhaar/PAN · Pakistan CNIC · China resident ID · Hong Kong HKID · Taiwan ID · Japan My Number · South Korea RRN · Malaysia MyKad · Singapore NRIC · Indonesia NIK · Thailand ID · Israel ID · Australia TFN · New Zealand IRD |
99
+ | Africa | South Africa ID |
100
+ | Anywhere | Any ID-shaped number right after a keyword like *DNI, cédula, ID number, Ausweis, 身份证, …* |
101
+
102
+ Some IDs are just a run of digits with no distinctive shape, like a BSN, PESEL or Steuer-ID. Those are scrubbed when a keyword is nearby ("BSN 111222333"). If you set `paranoid: true`, they're scrubbed on checksum alone.
103
+
104
+ Ordinary text is left alone: code, SQL, version numbers, order numbers, amounts, ordinary dates and city names. If something is over-scrubbed anyway, the AI only sees a token and you still get the real value back in the reply.
105
+
106
+ ## Configuration
107
+
108
+ `~/.baldanders/config.yaml` is created on first run:
109
+
110
+ ```yaml
111
+ regions: [AR, US] # local phone formats to recognise; empty = guess from OS locale
112
+ paranoid: false # scrub checksum-valid IDs even without a keyword nearby
113
+ # ner_threshold: 0.6 # name/address model confidence (default: names 0.7, addresses 0.4)
114
+ save_sessions: true
115
+
116
+ allowlist: # never scrub these
117
+ - my-s3-bucket-name
118
+
119
+ denylist: # always scrub these (case-insensitive) as the given type
120
+ "Project Falcon": PROJECT
121
+
122
+ custom_patterns: # extra regexes; first capturing group is scrubbed if present
123
+ customer_id: "CID-\\d{8}"
124
+ ```
125
+
126
+ Set `BALDANDERS_HOME` to keep config, sessions and the model somewhere other than `~/.baldanders`.
127
+
128
+ ## Privacy notes
129
+
130
+ - **What is sent:** only the scrubbed text, plus a short instruction telling the AI to keep the tokens intact. Run with `-v` to see every byte.
131
+ - **What stays local:** the token map, the model, and your config. Saved sessions (`~/.baldanders/sessions/`) contain the real values so `--resume` works. They are readable only by your user. Turn them off with `--no-save` or `save_sessions: false`.
132
+ - **Subscription CLIs:** Baldanders runs `claude` and `codex` in an empty private directory. For Claude Code, all tools and MCP servers are disabled, so the AI can't read your files. Codex runs in its read-only sandbox, so it can still read files outside that directory if it chooses to. Prefer `-p claude` or an API provider for sensitive work. These CLIs add their own context to each request (OS, working directory path, and for Claude Code your personal `~/.claude/CLAUDE.md` if you have one). Baldanders doesn't control that context.
133
+ - **No detector is perfect.** Unusual names, free-form addresses, or IDs written in unexpected ways can slip through. Check `-v` output when it matters, and add anything specific to your work to the `denylist`.
134
+
135
+ ## Requirements
136
+
137
+ - Python 3.10+
138
+ - For `-p claude`: [Claude Code](https://docs.anthropic.com/en/docs/claude-code), logged in
139
+ - For `-p chatgpt`: [Codex CLI](https://github.com/openai/codex) (`npm install -g @openai/codex`, then `codex login`)
140
+ - For `-p grok`: [grok-cli](https://github.com/Moore-developers/grok-cli) (`grok-cli login`)
141
+
142
+ ## Development
143
+
144
+ ```bash
145
+ pip install -e ".[dev,ner,anthropic]"
146
+ baldanders download # optional: enables the NER integration tests
147
+ pytest
148
+ ```
149
+
150
+ ### Releasing
151
+
152
+ Releases go to PyPI from GitHub Actions via [trusted publishing](https://docs.pypi.org/trusted-publishers/), so no API token is stored anywhere.
153
+
154
+ 1. One-time setup: on PyPI, add a pending publisher for project `baldanders`, owner `Nahuel990`, repo `Baldanders`, workflow `release.yml`, environment `pypi`. On GitHub, create an environment named `pypi`.
155
+ 2. Bump `__version__` in `src/baldanders/__init__.py` and commit.
156
+ 3. Tag and push: `git tag v0.1.0 && git push origin v0.1.0`.
157
+
158
+ ## License
159
+
160
+ MIT
@@ -0,0 +1,76 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.27"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "baldanders"
7
+ dynamic = ["version"]
8
+ description = "Local personal-data firewall for cloud LLMs — scrubs names, emails, IDs and other private details before they leave your machine"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ requires-python = ">=3.10"
13
+ authors = [{ name = "Baldanders contributors" }]
14
+ keywords = ["privacy", "pii", "llm", "cli", "personal-data", "gdpr", "redaction", "anonymization"]
15
+ classifiers = [
16
+ "Development Status :: 4 - Beta",
17
+ "Environment :: Console",
18
+ "Intended Audience :: Developers",
19
+ "Intended Audience :: End Users/Desktop",
20
+ "Natural Language :: English",
21
+ "Operating System :: OS Independent",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3 :: Only",
24
+ "Programming Language :: Python :: 3.10",
25
+ "Programming Language :: Python :: 3.11",
26
+ "Programming Language :: Python :: 3.12",
27
+ "Programming Language :: Python :: 3.13",
28
+ "Topic :: Security",
29
+ "Topic :: Text Processing :: Filters",
30
+ ]
31
+ dependencies = [
32
+ "click>=8.0",
33
+ "rich>=13.0",
34
+ "httpx>=0.27",
35
+ "pyyaml>=6.0",
36
+ "phonenumbers>=8.13",
37
+ "python-stdnum>=1.20",
38
+ ]
39
+
40
+ [project.optional-dependencies]
41
+ # Multilingual name/address detection (pulls in PyTorch; ~1 GB installed)
42
+ ner = ["gliner[onnx]>=0.2.29"]
43
+ # Direct Claude API provider (-p anthropic-api)
44
+ anthropic = ["anthropic>=1.15"]
45
+ all = ["baldanders[ner,anthropic]"]
46
+ dev = [
47
+ "pytest>=8.0",
48
+ "build>=1.2",
49
+ "twine>=6.0",
50
+ ]
51
+
52
+ [project.urls]
53
+ Homepage = "https://github.com/Nahuel990/Baldanders"
54
+ Repository = "https://github.com/Nahuel990/Baldanders"
55
+ Issues = "https://github.com/Nahuel990/Baldanders/issues"
56
+
57
+ [project.scripts]
58
+ baldanders = "baldanders.cli:main"
59
+
60
+ [tool.hatch.version]
61
+ path = "src/baldanders/__init__.py"
62
+
63
+ [tool.hatch.build.targets.wheel]
64
+ packages = ["src/baldanders"]
65
+
66
+ [tool.hatch.build.targets.sdist]
67
+ include = [
68
+ "/src",
69
+ "/tests",
70
+ "/README.md",
71
+ "/LICENSE",
72
+ ]
73
+
74
+ [tool.pytest.ini_options]
75
+ testpaths = ["tests"]
76
+ pythonpath = ["src"]
@@ -0,0 +1,3 @@
1
+ """Baldanders — local personal-data firewall for cloud LLMs."""
2
+
3
+ __version__ = "0.1.0"