nothx 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 (50) hide show
  1. nothx-0.1.0/.context/attachments/PR instructions.md +18 -0
  2. nothx-0.1.0/.context/notes.md +0 -0
  3. nothx-0.1.0/.context/plans/nothx-upgrade-checklist.md +167 -0
  4. nothx-0.1.0/.context/todos.md +0 -0
  5. nothx-0.1.0/.git +1 -0
  6. nothx-0.1.0/.github/workflows/ci.yml +82 -0
  7. nothx-0.1.0/.gitignore +55 -0
  8. nothx-0.1.0/.gitkeep +0 -0
  9. nothx-0.1.0/CLAUDE.md +106 -0
  10. nothx-0.1.0/LICENSE +21 -0
  11. nothx-0.1.0/PKG-INFO +363 -0
  12. nothx-0.1.0/README.md +317 -0
  13. nothx-0.1.0/nothx/__init__.py +7 -0
  14. nothx-0.1.0/nothx/classifier/__init__.py +19 -0
  15. nothx-0.1.0/nothx/classifier/ai.py +736 -0
  16. nothx-0.1.0/nothx/classifier/engine.py +263 -0
  17. nothx-0.1.0/nothx/classifier/heuristics.py +258 -0
  18. nothx-0.1.0/nothx/classifier/learner.py +366 -0
  19. nothx-0.1.0/nothx/classifier/patterns.py +138 -0
  20. nothx-0.1.0/nothx/classifier/providers/__init__.py +6 -0
  21. nothx-0.1.0/nothx/classifier/providers/anthropic_provider.py +86 -0
  22. nothx-0.1.0/nothx/classifier/providers/base.py +103 -0
  23. nothx-0.1.0/nothx/classifier/providers/factory.py +95 -0
  24. nothx-0.1.0/nothx/classifier/providers/gemini_provider.py +94 -0
  25. nothx-0.1.0/nothx/classifier/providers/ollama_provider.py +158 -0
  26. nothx-0.1.0/nothx/classifier/providers/openai_provider.py +97 -0
  27. nothx-0.1.0/nothx/classifier/rules.py +126 -0
  28. nothx-0.1.0/nothx/classifier/utils.py +51 -0
  29. nothx-0.1.0/nothx/cli.py +1740 -0
  30. nothx-0.1.0/nothx/config.py +236 -0
  31. nothx-0.1.0/nothx/db.py +722 -0
  32. nothx-0.1.0/nothx/errors.py +339 -0
  33. nothx-0.1.0/nothx/imap.py +359 -0
  34. nothx-0.1.0/nothx/logging.py +197 -0
  35. nothx-0.1.0/nothx/models.py +175 -0
  36. nothx-0.1.0/nothx/scanner.py +137 -0
  37. nothx-0.1.0/nothx/scheduler.py +299 -0
  38. nothx-0.1.0/nothx/theme.py +80 -0
  39. nothx-0.1.0/nothx/unsubscriber.py +245 -0
  40. nothx-0.1.0/patterns/defaults.json +62 -0
  41. nothx-0.1.0/pyproject.toml +96 -0
  42. nothx-0.1.0/tests/__init__.py +1 -0
  43. nothx-0.1.0/tests/test_classifier.py +189 -0
  44. nothx-0.1.0/tests/test_cli.py +941 -0
  45. nothx-0.1.0/tests/test_config.py +198 -0
  46. nothx-0.1.0/tests/test_db.py +434 -0
  47. nothx-0.1.0/tests/test_engine.py +235 -0
  48. nothx-0.1.0/tests/test_heuristics_learning.py +217 -0
  49. nothx-0.1.0/tests/test_learner.py +573 -0
  50. nothx-0.1.0/tests/test_utils.py +105 -0
@@ -0,0 +1,18 @@
1
+ The user likes the state of the code.
2
+
3
+ There are 11 uncommitted changes.
4
+ The current branch is sainihas/code-review.
5
+ The target branch is origin/main.
6
+
7
+ There is no upstream branch yet.
8
+ The user requested a PR.
9
+
10
+ Follow these **exact steps** to create a PR:
11
+
12
+ - Run `git diff` to review uncommitted changes
13
+ - Commit them. Follow any instructions the user gave you about writing commit messages.
14
+ - Push to origin.
15
+ - Use the `mcp__conductor__GetWorkspaceDiff` tool to review the PR diff
16
+ - Use `gh pr create --base main` to create a PR onto the target branch. Keep the title under 80 characters and the description under five sentences (unless the user has given you other instructions).
17
+
18
+ If any of these steps fail, ask the user for help.
File without changes
@@ -0,0 +1,167 @@
1
+ # nothx Upgrade Checklist
2
+
3
+ ## Priority 1: Critical (Ship Blockers)
4
+
5
+ ### Error Handling
6
+ - [ ] Replace all `except Exception` with specific exception types
7
+ - [ ] Add retry logic with exponential backoff for AI provider calls (ai.py:131-151)
8
+ - [ ] Add retry logic for IMAP connections (imap.py)
9
+ - [ ] Return structured error types instead of empty `{}` on AI failures
10
+ - [ ] Add error context to all `logger.error()` calls (include domain, operation, stack trace)
11
+ - [ ] Validate AI response confidence is in [0.0, 1.0] range (ai.py:209)
12
+ - [ ] Log when falling back from AI to heuristics (and why)
13
+
14
+ ### Testing
15
+ - [ ] Create `tests/test_cli.py` - full coverage for cli.py (61KB untested)
16
+ - [ ] Add integration test: full pipeline from IMAP fetch → classification → unsubscribe
17
+ - [ ] Add test for concurrent database access
18
+ - [ ] Add test for IMAP connection failures and recovery
19
+ - [ ] Add test for AI provider timeout handling
20
+ - [ ] Add test for malformed AI responses
21
+
22
+ ### Security
23
+ - [ ] Move API keys to system keyring (use `keyring` package) or environment variables
24
+ - [ ] Add option to encrypt config.json at rest
25
+ - [ ] Sanitize domain/subject data before embedding in AI prompts (prompt injection risk)
26
+ - [ ] Add rate limiting for HTTP unsubscribe requests
27
+ - [ ] Add rate limiting for AI API calls
28
+
29
+ ---
30
+
31
+ ## Priority 2: High (Production Readiness)
32
+
33
+ ### Observability
34
+ - [ ] Add structured logging (JSON format option for log aggregation)
35
+ - [ ] Track metrics: classification source distribution (rules/patterns/AI/heuristics/review)
36
+ - [ ] Track metrics: AI fallback rate and reasons
37
+ - [ ] Track metrics: classification latency per layer
38
+ - [ ] Track metrics: unsubscribe success/failure rates by method
39
+ - [ ] Add correlation IDs to trace a sender through the pipeline
40
+ - [ ] Add `--verbose` and `--debug` flags to CLI
41
+
42
+ ### Configuration
43
+ - [ ] Extract all magic numbers to `ThresholdConfig`:
44
+ - [ ] Base score (currently hardcoded 50)
45
+ - [ ] Open rate adjustments (+25, +15, +5, -20, -30)
46
+ - [ ] Volume adjustments (+10, +5)
47
+ - [ ] Subject pattern weights (+5, -10, +15)
48
+ - [ ] Domain pattern weights (+10, -10)
49
+ - [ ] Confidence thresholds for each layer
50
+ - [ ] Add config validation on load (reject invalid values)
51
+ - [ ] Add `nothx config validate` command
52
+ - [ ] Document all config options with defaults and valid ranges
53
+
54
+ ### Bug Fixes
55
+ - [ ] Fix open rate scoring gap (25-50% has no adjustment) in heuristics.py:76-85
56
+ - [ ] Fix UTF-8 truncation in response snippets (unsubscriber.py:68) - use `textwrap` or char-aware slicing
57
+ - [ ] Fix cache thrashing in learner (batch updates instead of invalidate-per-action)
58
+ - [ ] Add validation for rule actions in rules.py (don't silently skip invalid rules)
59
+
60
+ ---
61
+
62
+ ## Priority 3: Medium (Quality of Life)
63
+
64
+ ### Performance
65
+ - [ ] Pre-compile all regex patterns at module load time
66
+ - [ ] Add batch database operations for bulk classifications
67
+ - [ ] Implement incremental cache updates in learner (not full reload)
68
+ - [ ] Add connection pooling for IMAP
69
+ - [ ] Profile and add benchmarks for batch classification (100, 1000, 10000 senders)
70
+
71
+ ### Features Missing for Real Use
72
+ - [ ] Add `--dry-run` flag with diff output ("would unsubscribe from X, Y, Z")
73
+ - [ ] Add undo capability (store unsubscribe actions, provide reversal where possible)
74
+ - [ ] Add audit log command (`nothx history` or `nothx log`)
75
+ - [ ] Add scheduling support (cron-friendly mode, or built-in scheduler)
76
+ - [ ] Add multi-account aggregation view
77
+ - [ ] Add export/import for rules and preferences
78
+
79
+ ### Pattern Matching Improvements
80
+ - [ ] Implement pattern specificity ranking (`*.bank.com` beats `*bank*`)
81
+ - [ ] Add negative patterns support (`keep *.bank.com except fraudulent-bank.com`)
82
+ - [ ] Add pattern conflict detection (warn when domain matches multiple patterns)
83
+ - [ ] Make default patterns configurable (not hardcoded in patterns.py)
84
+
85
+ ### AI System Improvements
86
+ - [ ] Add provider rate limiting (respect API limits)
87
+ - [ ] Track and log token usage for cost monitoring
88
+ - [ ] Validate configured model exists for selected provider
89
+ - [ ] Add timeout configuration for AI calls
90
+ - [ ] Cache AI classifications for identical senders (short TTL)
91
+
92
+ ---
93
+
94
+ ## Priority 4: Low (Nice to Have)
95
+
96
+ ### Learning System
97
+ - [ ] Implement domain generalization (recognize "financial institutions" category, not just individual banks)
98
+ - [ ] Use sliding window for preference updates (recent actions matter more)
99
+ - [ ] Merge AI insight path with incremental learner (resolve conflicts)
100
+ - [ ] Add temporal decay to sender scores (inactive senders score differently)
101
+ - [ ] Add `nothx learn reset` command to start fresh
102
+
103
+ ### Code Quality
104
+ - [ ] Add dependency injection for `RulesMatcher` (remove direct DB coupling)
105
+ - [ ] Split cli.py into submodules by command group
106
+ - [ ] Add `py.typed` marker for PEP 561 compliance
107
+ - [ ] Add pre-commit hooks (black, ruff, mypy)
108
+ - [ ] Add GitHub Actions CI/CD workflow
109
+ - [ ] Add coverage reporting with minimum threshold (80%+)
110
+
111
+ ### Documentation
112
+ - [ ] Add architecture decision records (ADRs) for key decisions
113
+ - [ ] Document the scoring algorithm with examples
114
+ - [ ] Add troubleshooting guide for common IMAP issues
115
+ - [ ] Add API documentation for programmatic use
116
+ - [ ] Add changelog
117
+
118
+ ### Developer Experience
119
+ - [ ] Add `nothx debug classify <domain>` - show full classification trace
120
+ - [ ] Add `nothx debug score <domain>` - show heuristic scoring breakdown
121
+ - [ ] Add `nothx stats` - show classification distribution, success rates
122
+ - [ ] Add `--json` output flag for all commands (machine-readable)
123
+
124
+ ---
125
+
126
+ ## File-by-File Fixes
127
+
128
+ | File | Issues |
129
+ |------|--------|
130
+ | `cli.py` | Needs tests, split into submodules, add --verbose/--debug |
131
+ | `ai.py:131-151` | Add retry logic, structured errors |
132
+ | `ai.py:209` | Validate confidence range |
133
+ | `ai.py:214-215` | Don't silently swallow JSON parse errors |
134
+ | `heuristics.py:76-85` | Fix 25-50% gap |
135
+ | `heuristics.py:113-126` | Extract magic numbers to config |
136
+ | `heuristics.py` | Pre-compile regex patterns |
137
+ | `learner.py:51-53` | Batch cache updates |
138
+ | `rules.py:35-40` | Don't silently skip invalid rules |
139
+ | `unsubscriber.py:68` | UTF-8 safe truncation |
140
+ | `imap.py:121` | Specific exceptions, not bare except |
141
+ | `config.py` | Add validation, secrets management |
142
+ | `patterns.py:10-82` | Make defaults configurable |
143
+
144
+ ---
145
+
146
+ ## Quick Wins (Do These First)
147
+
148
+ 1. [ ] Pre-compile regex patterns (30 min, immediate perf win)
149
+ 2. [ ] Fix open rate 25-50% gap (10 min, bug fix)
150
+ 3. [ ] Add `--dry-run` to unsubscribe command (1 hr, safety feature)
151
+ 4. [ ] Extract magic numbers to constants with comments (1 hr, readability)
152
+ 5. [ ] Add retry decorator to AI calls (30 min, reliability)
153
+ 6. [ ] Log classification source in output (30 min, debuggability)
154
+ 7. [ ] Add basic CLI tests for main commands (2 hr, coverage)
155
+
156
+ ---
157
+
158
+ ## Definition of "Leveled Up"
159
+
160
+ When complete, this codebase should:
161
+ - Never fail silently - all errors logged with context
162
+ - Be observable - know what's happening without reading code
163
+ - Be configurable - tune behavior without editing source
164
+ - Be testable - 80%+ coverage including CLI
165
+ - Be debuggable - trace any classification decision
166
+ - Be production-safe - rate limits, retries, timeouts
167
+ - Be secure - no plaintext secrets, sanitized inputs
File without changes
nothx-0.1.0/.git ADDED
@@ -0,0 +1 @@
1
+ gitdir: /Users/sai/conductor/repos/nothx/.git/worktrees/milan
@@ -0,0 +1,82 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [main]
6
+ push:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ name: Test (Python ${{ matrix.python-version }})
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ python-version: ["3.11", "3.12"]
17
+
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+
21
+ - name: Set up Python ${{ matrix.python-version }}
22
+ uses: actions/setup-python@v5
23
+ with:
24
+ python-version: ${{ matrix.python-version }}
25
+
26
+ - name: Install dependencies
27
+ run: |
28
+ python -m pip install --upgrade pip
29
+ pip install -e ".[dev]"
30
+
31
+ - name: Run tests with coverage
32
+ run: pytest --cov=nothx --cov-report=xml --cov-fail-under=25
33
+
34
+ - name: Upload coverage reports
35
+ uses: codecov/codecov-action@v4
36
+ if: matrix.python-version == '3.12'
37
+ with:
38
+ files: ./coverage.xml
39
+ fail_ci_if_error: false
40
+
41
+ lint:
42
+ name: Lint & Format
43
+ runs-on: ubuntu-latest
44
+
45
+ steps:
46
+ - uses: actions/checkout@v4
47
+
48
+ - name: Set up Python
49
+ uses: actions/setup-python@v5
50
+ with:
51
+ python-version: "3.12"
52
+
53
+ - name: Install dependencies
54
+ run: |
55
+ python -m pip install --upgrade pip
56
+ pip install -e ".[dev]"
57
+
58
+ - name: Check formatting with ruff
59
+ run: ruff format --check .
60
+
61
+ - name: Lint with ruff
62
+ run: ruff check .
63
+
64
+ typecheck:
65
+ name: Type Check
66
+ runs-on: ubuntu-latest
67
+
68
+ steps:
69
+ - uses: actions/checkout@v4
70
+
71
+ - name: Set up Python
72
+ uses: actions/setup-python@v5
73
+ with:
74
+ python-version: "3.12"
75
+
76
+ - name: Install dependencies
77
+ run: |
78
+ python -m pip install --upgrade pip
79
+ pip install -e ".[dev]"
80
+
81
+ - name: Run mypy
82
+ run: mypy nothx
nothx-0.1.0/.gitignore ADDED
@@ -0,0 +1,55 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ *.egg-info/
20
+ .installed.cfg
21
+ *.egg
22
+
23
+ # Virtual environments
24
+ .venv/
25
+ venv/
26
+ ENV/
27
+ env/
28
+
29
+ # IDE
30
+ .idea/
31
+ .vscode/
32
+ *.swp
33
+ *.swo
34
+ *~
35
+
36
+ # Testing
37
+ .pytest_cache/
38
+ .coverage
39
+ htmlcov/
40
+ .tox/
41
+ .nox/
42
+
43
+ # nothx local data
44
+ .nothx/
45
+
46
+ # macOS
47
+ .DS_Store
48
+
49
+ # Logs
50
+ *.log
51
+
52
+ # Secrets (never commit)
53
+ *.env
54
+ .env.*
55
+ config.json
nothx-0.1.0/.gitkeep ADDED
File without changes
nothx-0.1.0/CLAUDE.md ADDED
@@ -0,0 +1,106 @@
1
+ # CLAUDE.md
2
+
3
+ Guidelines for AI assistants working with this codebase.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ pip install -e ".[dev]" # Install with dev dependencies
9
+ pytest # Run tests
10
+ python -m nothx # Run CLI
11
+ ```
12
+
13
+ ## Architecture
14
+
15
+ **5-layer classification pipeline** — each layer can decide or defer:
16
+
17
+ 1. **User Rules** (`classifier/rules.py`) — Custom patterns, highest priority
18
+ 2. **Preset Patterns** (`classifier/patterns.py`) — Known marketing/safe domains
19
+ 3. **AI Classification** (`classifier/ai.py`) — LLM analyzes email headers
20
+ 4. **Heuristics** (`classifier/heuristics.py`) — Rule-based scoring (0-100)
21
+ 5. **Review Queue** — Uncertain cases for manual review
22
+
23
+ ```
24
+ IMAP Inbox → Scanner → Classifier Engine → Unsubscriber or Review Queue
25
+ ```
26
+
27
+ ## Project Structure
28
+
29
+ ```
30
+ nothx/
31
+ ├── cli.py # Click commands, entry point
32
+ ├── config.py # Dataclasses for configuration
33
+ ├── models.py # Core enums (Action, EmailType, etc.)
34
+ ├── db.py # SQLite layer
35
+ ├── imap.py # Email fetching
36
+ ├── scanner.py # Inbox scanning
37
+ ├── unsubscriber.py # Unsubscribe execution (RFC 8058, GET, mailto)
38
+ ├── theme.py # Rich console theme
39
+ └── classifier/
40
+ ├── engine.py # Orchestrates the 5 layers
41
+ ├── ai.py # AI classification
42
+ ├── providers/ # Anthropic, OpenAI, Gemini, Ollama
43
+ ├── heuristics.py # Scoring logic
44
+ ├── learner.py # User preference learning
45
+ └── patterns.py # Pattern matching
46
+ ```
47
+
48
+ ## Common Tasks
49
+
50
+ ### Adding a CLI command
51
+
52
+ ```python
53
+ @main.command()
54
+ @click.option('--flag', help='Description')
55
+ def new_command(flag: bool):
56
+ """Command description."""
57
+ # Implementation
58
+ ```
59
+
60
+ ### Adding an AI provider
61
+
62
+ 1. Create `classifier/providers/your_provider.py`
63
+ 2. Extend `BaseAIProvider`
64
+ 3. Register in `classifier/providers/factory.py`
65
+
66
+ ### Adding a classification layer
67
+
68
+ 1. Create module in `classifier/`
69
+ 2. Implement `classify(stats: SenderStats) -> Optional[Classification]`
70
+ 3. Return `None` to defer to next layer
71
+ 4. Register in `classifier/engine.py`
72
+
73
+ ## Code Style
74
+
75
+ - **Type hints**: All functions must have complete annotations
76
+ - **Dataclasses**: Use for data structures
77
+ - **Imports**: stdlib → third-party → local
78
+ - **Naming**: `snake_case` functions, `PascalCase` classes, `UPPER_CASE` constants
79
+
80
+ ## Important Rules
81
+
82
+ ### Do:
83
+ - Mock external services (IMAP, HTTP, AI APIs) in tests
84
+ - Use temporary databases for test isolation
85
+ - Gracefully degrade (AI → heuristics → review)
86
+ - Use parameterized queries for SQLite
87
+
88
+ ### Don't:
89
+ - Read email bodies — only headers (From, Subject, Date, List-Unsubscribe)
90
+ - Log sensitive data (passwords, API keys)
91
+ - Auto-unsubscribe protected domains (banks, .gov, healthcare)
92
+ - Crash on external failures
93
+
94
+ ## Testing
95
+
96
+ ```bash
97
+ pytest # All tests
98
+ pytest --cov=nothx # With coverage
99
+ pytest tests/test_classifier.py -v # Specific file
100
+ ```
101
+
102
+ ## Runtime Paths
103
+
104
+ - Config: `~/.nothx/config.json`
105
+ - Database: `~/.nothx/nothx.db`
106
+ - Logs: `~/.nothx/logs/`
nothx-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 nothx 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.