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.
- nothx-0.1.0/.context/attachments/PR instructions.md +18 -0
- nothx-0.1.0/.context/notes.md +0 -0
- nothx-0.1.0/.context/plans/nothx-upgrade-checklist.md +167 -0
- nothx-0.1.0/.context/todos.md +0 -0
- nothx-0.1.0/.git +1 -0
- nothx-0.1.0/.github/workflows/ci.yml +82 -0
- nothx-0.1.0/.gitignore +55 -0
- nothx-0.1.0/.gitkeep +0 -0
- nothx-0.1.0/CLAUDE.md +106 -0
- nothx-0.1.0/LICENSE +21 -0
- nothx-0.1.0/PKG-INFO +363 -0
- nothx-0.1.0/README.md +317 -0
- nothx-0.1.0/nothx/__init__.py +7 -0
- nothx-0.1.0/nothx/classifier/__init__.py +19 -0
- nothx-0.1.0/nothx/classifier/ai.py +736 -0
- nothx-0.1.0/nothx/classifier/engine.py +263 -0
- nothx-0.1.0/nothx/classifier/heuristics.py +258 -0
- nothx-0.1.0/nothx/classifier/learner.py +366 -0
- nothx-0.1.0/nothx/classifier/patterns.py +138 -0
- nothx-0.1.0/nothx/classifier/providers/__init__.py +6 -0
- nothx-0.1.0/nothx/classifier/providers/anthropic_provider.py +86 -0
- nothx-0.1.0/nothx/classifier/providers/base.py +103 -0
- nothx-0.1.0/nothx/classifier/providers/factory.py +95 -0
- nothx-0.1.0/nothx/classifier/providers/gemini_provider.py +94 -0
- nothx-0.1.0/nothx/classifier/providers/ollama_provider.py +158 -0
- nothx-0.1.0/nothx/classifier/providers/openai_provider.py +97 -0
- nothx-0.1.0/nothx/classifier/rules.py +126 -0
- nothx-0.1.0/nothx/classifier/utils.py +51 -0
- nothx-0.1.0/nothx/cli.py +1740 -0
- nothx-0.1.0/nothx/config.py +236 -0
- nothx-0.1.0/nothx/db.py +722 -0
- nothx-0.1.0/nothx/errors.py +339 -0
- nothx-0.1.0/nothx/imap.py +359 -0
- nothx-0.1.0/nothx/logging.py +197 -0
- nothx-0.1.0/nothx/models.py +175 -0
- nothx-0.1.0/nothx/scanner.py +137 -0
- nothx-0.1.0/nothx/scheduler.py +299 -0
- nothx-0.1.0/nothx/theme.py +80 -0
- nothx-0.1.0/nothx/unsubscriber.py +245 -0
- nothx-0.1.0/patterns/defaults.json +62 -0
- nothx-0.1.0/pyproject.toml +96 -0
- nothx-0.1.0/tests/__init__.py +1 -0
- nothx-0.1.0/tests/test_classifier.py +189 -0
- nothx-0.1.0/tests/test_cli.py +941 -0
- nothx-0.1.0/tests/test_config.py +198 -0
- nothx-0.1.0/tests/test_db.py +434 -0
- nothx-0.1.0/tests/test_engine.py +235 -0
- nothx-0.1.0/tests/test_heuristics_learning.py +217 -0
- nothx-0.1.0/tests/test_learner.py +573 -0
- 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.
|