better-dontforget 1.0.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 (45) hide show
  1. better_dontforget-1.0.0/.github/workflows/ci.yml +29 -0
  2. better_dontforget-1.0.0/.github/workflows/publish.yml +83 -0
  3. better_dontforget-1.0.0/.gitignore +20 -0
  4. better_dontforget-1.0.0/.python-version +1 -0
  5. better_dontforget-1.0.0/AGENTS.md +92 -0
  6. better_dontforget-1.0.0/Justfile +43 -0
  7. better_dontforget-1.0.0/PKG-INFO +103 -0
  8. better_dontforget-1.0.0/PRD.md +234 -0
  9. better_dontforget-1.0.0/README.md +90 -0
  10. better_dontforget-1.0.0/ROADMAP.md +84 -0
  11. better_dontforget-1.0.0/better_dontforget/__init__.py +3 -0
  12. better_dontforget-1.0.0/better_dontforget/__main__.py +8 -0
  13. better_dontforget-1.0.0/better_dontforget/cli.py +392 -0
  14. better_dontforget-1.0.0/better_dontforget/cli_helpers.py +17 -0
  15. better_dontforget-1.0.0/better_dontforget/core/__init__.py +7 -0
  16. better_dontforget-1.0.0/better_dontforget/core/ai.py +78 -0
  17. better_dontforget-1.0.0/better_dontforget/core/app.py +90 -0
  18. better_dontforget-1.0.0/better_dontforget/core/config.py +132 -0
  19. better_dontforget-1.0.0/better_dontforget/core/crypto.py +56 -0
  20. better_dontforget-1.0.0/better_dontforget/core/db.py +284 -0
  21. better_dontforget-1.0.0/better_dontforget/core/models.py +33 -0
  22. better_dontforget-1.0.0/better_dontforget/core/notifications.py +56 -0
  23. better_dontforget-1.0.0/better_dontforget/core/paths.py +43 -0
  24. better_dontforget-1.0.0/better_dontforget/core/providers.py +235 -0
  25. better_dontforget-1.0.0/better_dontforget/core/reminder_parser.py +194 -0
  26. better_dontforget-1.0.0/better_dontforget/core/reminders.py +46 -0
  27. better_dontforget-1.0.0/better_dontforget/tui/app.py +327 -0
  28. better_dontforget-1.0.0/docs/config.md +135 -0
  29. better_dontforget-1.0.0/docs/docs.md +237 -0
  30. better_dontforget-1.0.0/legacy/main.py +269 -0
  31. better_dontforget-1.0.0/legacy/mem-cli +96 -0
  32. better_dontforget-1.0.0/packaging/better-dontforget-notify.service +12 -0
  33. better_dontforget-1.0.0/packaging/better-dontforget-notify.timer +10 -0
  34. better_dontforget-1.0.0/pyproject.toml +51 -0
  35. better_dontforget-1.0.0/tests/conftest.py +123 -0
  36. better_dontforget-1.0.0/tests/test_ai.py +80 -0
  37. better_dontforget-1.0.0/tests/test_cli.py +78 -0
  38. better_dontforget-1.0.0/tests/test_config.py +62 -0
  39. better_dontforget-1.0.0/tests/test_crypto.py +27 -0
  40. better_dontforget-1.0.0/tests/test_db.py +88 -0
  41. better_dontforget-1.0.0/tests/test_models.py +56 -0
  42. better_dontforget-1.0.0/tests/test_providers.py +68 -0
  43. better_dontforget-1.0.0/tests/test_reminder_parser.py +74 -0
  44. better_dontforget-1.0.0/tests/test_reminders.py +63 -0
  45. better_dontforget-1.0.0/uv.lock +1161 -0
@@ -0,0 +1,29 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+
8
+ jobs:
9
+ check:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+
14
+ - name: Install uv
15
+ uses: astral-sh/setup-uv@v5
16
+ with:
17
+ enable-cache: true
18
+
19
+ - name: Set up Python
20
+ run: uv python install
21
+
22
+ - name: Install just
23
+ uses: extractions/setup-just@v2
24
+
25
+ - name: Sync dependencies
26
+ run: uv sync
27
+
28
+ - name: Run quality gate (just check)
29
+ run: just check
@@ -0,0 +1,83 @@
1
+ # Publish to PyPI. Supports a TestPyPI dry run via manual dispatch.
2
+ # Uses PyPI Trusted Publishing (OIDC) — no token secret required.
3
+ # One-time setup in PyPI: Account settings -> Publishing -> add pending publisher
4
+ # (project: better-dontforget, owner: vaproh, repo: dontforget,
5
+ # workflow: publish.yml, environment: pypi).
6
+ # For TestPyPI: register an equivalent publisher on test.pypi.org with environment "testpypi".
7
+
8
+ name: Publish to PyPI
9
+
10
+ on:
11
+ release:
12
+ types: [published]
13
+ workflow_dispatch:
14
+ inputs:
15
+ target:
16
+ description: "Publish target"
17
+ required: true
18
+ default: "pypi"
19
+ type: choice
20
+ options:
21
+ - pypi
22
+ - testpypi
23
+
24
+ permissions:
25
+ # Required for PyPI trusted publishing (OIDC).
26
+ id-token: write
27
+ contents: read
28
+
29
+ jobs:
30
+ build:
31
+ name: Build distributions
32
+ runs-on: ubuntu-latest
33
+ steps:
34
+ - uses: actions/checkout@v4
35
+
36
+ - name: Install uv
37
+ uses: astral-sh/setup-uv@v5
38
+ with:
39
+ enable-cache: true
40
+
41
+ - name: Set up Python
42
+ run: uv python install
43
+
44
+ - name: Build distributions
45
+ run: uv build
46
+
47
+ - name: Upload distributions
48
+ uses: actions/upload-artifact@v4
49
+ with:
50
+ name: dist
51
+ path: dist/*
52
+
53
+ publish-pypi:
54
+ name: Publish to PyPI
55
+ if: github.event_name == 'release' || inputs.target == 'pypi'
56
+ needs: build
57
+ runs-on: ubuntu-latest
58
+ environment: pypi
59
+ steps:
60
+ - uses: actions/download-artifact@v4
61
+ with:
62
+ name: dist
63
+ path: dist
64
+
65
+ - name: Publish to PyPI (trusted publishing)
66
+ uses: pypa/gh-action-pypi-publish@release/v1
67
+
68
+ publish-testpypi:
69
+ name: Publish to TestPyPI (dry run)
70
+ if: github.event_name == 'workflow_dispatch' && inputs.target == 'testpypi'
71
+ needs: build
72
+ runs-on: ubuntu-latest
73
+ environment: testpypi
74
+ steps:
75
+ - uses: actions/download-artifact@v4
76
+ with:
77
+ name: dist
78
+ path: dist
79
+
80
+ - name: Publish to TestPyPI (trusted publishing)
81
+ uses: pypa/gh-action-pypi-publish@release/v1
82
+ with:
83
+ repository-url: https://test.pypi.org/legacy/
@@ -0,0 +1,20 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+ .idea/
9
+
10
+ # Virtual environments
11
+ .venv
12
+ .env
13
+ app.log
14
+ agents.db
15
+ aisys_cli.egg-info
16
+ service_account.json
17
+ key.json
18
+ dontforget.db
19
+ memory.db
20
+ *.db
@@ -0,0 +1 @@
1
+ 3.13
@@ -0,0 +1,92 @@
1
+ # AGENTS.md — Engineering Operating Manual
2
+
3
+ This file is the operating manual for autonomous coding agents working on
4
+ **Better Dontforget** (`better-dontforget`). Follow it precisely.
5
+
6
+ ## Read first
7
+
8
+ Before editing anything, read in order:
9
+
10
+ 1. `PRD.md` — product requirements and scope (source of truth for *what*).
11
+ 2. `ROADMAP.md` — implementation progress and dependency order.
12
+ 3. `docs/docs.md` and `docs/config.md` — documented user behavior.
13
+ 4. The relevant source under `better_dontforget/` — inspect before changing.
14
+
15
+ ## Golden rules
16
+
17
+ * Preserve upstream behavior unless intentionally changing it (document why).
18
+ * Prefer the smallest coherent change: **extend → refactor → replace (justified)**.
19
+ * Avoid speculative abstractions and unnecessary dependencies.
20
+ * Keep reminders **optional** and encryption **optional + explicit**.
21
+ * Respect XDG conventions; never dump files into `$HOME` directly.
22
+ * Never turn the project into a calendar, task manager, or full notes app.
23
+ * Never silently expand scope beyond `PRD.md`.
24
+
25
+ ## Workflow
26
+
27
+ 1. Inspect relevant code before editing.
28
+ 2. Implement the smallest coherent solution for the milestone in `ROADMAP.md`.
29
+ 3. Add/update tests for behavioral changes.
30
+ 4. Update affected docs alongside behavior changes.
31
+ 5. Run focused tests during development.
32
+ 6. Before declaring done: run the canonical quality gate.
33
+
34
+ ## Quality gate
35
+
36
+ The single canonical full-project verification command is:
37
+
38
+ ```text
39
+ just check
40
+ ```
41
+
42
+ `just check` runs formatting verification, linting, static analysis, the test
43
+ suite, and build verification. Never claim completion while `just check` fails.
44
+
45
+ ## Testing discipline
46
+
47
+ * Tests must not require real API keys, paid services, network, or a graphical
48
+ desktop notification server.
49
+ * Mock external AI providers (inject a fake `AIProvider`).
50
+ * Mock/abstract the notifier (`Notifier`) for notification tests.
51
+ * Use temp XDG dirs and temp DB files in tests.
52
+ * Do not overmock pure internal logic into meaningless tests.
53
+ * Cover: capture, provider selection, provider failure, malformed responses,
54
+ config persistence, XDG env + fallback, reminder persistence, due/overdue
55
+ detection, duplicate prevention, notification success/failure state,
56
+ encryption round-trip, wrong-passphrase, CLI behavior, migration.
57
+
58
+ ## Reliability invariants (must hold)
59
+
60
+ 1. A quick note is never silently lost.
61
+ 2. AI failure does not destroy user input.
62
+ 3. A normal note needs no reminder.
63
+ 4. A normal note needs no encryption.
64
+ 5. Encryption only when explicitly requested.
65
+ 6. Reminder state persists across exits/restarts.
66
+ 7. A reminder missed while the machine is off stays pending.
67
+ 8. A notification counts as delivered only after delivery succeeds.
68
+ 9. Delivered reminders are not re-notified without cause.
69
+ 10. Config persists in an XDG-compliant location.
70
+ 11. User data is not silently discarded during migration.
71
+ 12. API keys never appear in ordinary displayed config output.
72
+ 13. Tests never depend on external paid services.
73
+ 14. The project stays a focused improvement of `dontforget`.
74
+
75
+ ## Compatibility / secrets
76
+
77
+ * Preserve upstream `memory.db` via migration; never silently destroy data.
78
+ * Document intentional compatibility breaks in `ROADMAP.md` and PRD.
79
+ * Never print secrets; `config show` masks keys as `configured`.
80
+ * Never send encrypted note content to external AI.
81
+
82
+ ## ROADMAP maintenance
83
+
84
+ Keep `ROADMAP.md` updated continuously. A task is complete only when
85
+ implementation exists, tests pass, docs are updated, and no known regression
86
+ remains in scope. Use status markers: `[ ]` not started, `[~]` in progress,
87
+ `[x]` complete, `[!]` blocked.
88
+
89
+ ## Justfile workflow
90
+
91
+ Use `just` recipes: `just build`, `just run`, `just fmt`, `just lint`,
92
+ `just test`, `just check`. See `Justfile` for details.
@@ -0,0 +1,43 @@
1
+ # Justfile — Better Dontforget development workflow
2
+ #
3
+ # Canonical quality gate: `just check`
4
+
5
+ # Show available recipes.
6
+ default:
7
+ @just --list
8
+
9
+ # Install dependencies (uv-managed virtual environment).
10
+ install:
11
+ uv sync
12
+
13
+ # Build a distributable wheel/sdist.
14
+ build:
15
+ uv build
16
+
17
+ # Run the application (opens TUI when no arguments are given).
18
+ run *ARGS:
19
+ uv run better-dontforget {{ARGS}}
20
+
21
+ # Format all Python sources.
22
+ fmt:
23
+ uv run ruff format .
24
+
25
+ # Lint (ruff check).
26
+ lint:
27
+ uv run ruff check .
28
+
29
+ # Type-check (mypy) on the package.
30
+ type:
31
+ uv run mypy better_dontforget
32
+
33
+ # Run the test suite.
34
+ test:
35
+ uv run pytest
36
+
37
+ # Canonical full-project verification.
38
+ check:
39
+ uv run ruff format --check .
40
+ uv run ruff check .
41
+ uv run mypy better_dontforget
42
+ uv run pytest
43
+ uv build
@@ -0,0 +1,103 @@
1
+ Metadata-Version: 2.4
2
+ Name: better-dontforget
3
+ Version: 1.0.0
4
+ Summary: AI-assisted terminal tool for quick personal memory dumps: better TUI, multiple AI providers, optional reminders with desktop notifications, optional per-note encryption, XDG storage, CLI/TUI config.
5
+ Requires-Python: >=3.11
6
+ Requires-Dist: cryptography>=42.0.0
7
+ Requires-Dist: google-genai>=1.0.0
8
+ Requires-Dist: openai>=1.0.0
9
+ Requires-Dist: rich>=13.0.0
10
+ Requires-Dist: textual>=8.0.0
11
+ Requires-Dist: tomli-w>=1.0.0
12
+ Description-Content-Type: text/markdown
13
+
14
+ # 🧠 Better Dontforget
15
+
16
+ > 🍴 **A fork of [`bugswriter/dontforget`](https://github.com/bugswriter/dontforget).**
17
+
18
+ **Better Dontforget** is a focused improvement of the upstream `dontforget`
19
+ project: an AI-assisted terminal tool for quickly capturing and retrieving small
20
+ personal memory dumps, enhanced with a better TUI, configurable AI providers,
21
+ optional reminders with persistent desktop notifications, optional per-note
22
+ encryption, XDG-compliant storage, and CLI/TUI-based configuration.
23
+
24
+ > It is a quick personal memory-dump tool. Reminders and encryption are optional
25
+ > and per-note. It is **not** a calendar, task manager, or full notes application.
26
+
27
+ ## 📦 Install
28
+
29
+ From [PyPI](https://pypi.org/project/better-dontforget/):
30
+
31
+ ```bash
32
+ pip install better-dontforget
33
+ better-dontforget config set provider gemini
34
+ better-dontforget config set api_key "$GEMINI_API_KEY"
35
+ ```
36
+
37
+ Or, for development from source:
38
+
39
+ ```bash
40
+ uv sync
41
+ better-dontforget "anything"
42
+ ```
43
+
44
+ ## ✨ Features
45
+
46
+ * **⚡ Zero-friction capture:** `better-dontforget "anything"`. Works offline; AI
47
+ tagging is best-effort and never loses your input.
48
+ * **🔍 Search & AI recall:** full-text search (`search`) and AI-assisted answers
49
+ (`remind`) over your memories (SQLite + FTS5).
50
+ * **🤖 Multiple AI providers:** Gemini (default) and OpenAI-compatible
51
+ (OpenAI, OpenRouter, self-hosted), behind a small provider abstraction.
52
+ * **🖥️ Improved TUI:** view/add/edit/delete/search, reminders, encryption, and
53
+ settings — all keyboard-driven.
54
+ * **⏰ Optional reminders:** attach a due time to a note via `--remind` or natural
55
+ language ("remind me tomorrow to …").
56
+ * **🔔 Desktop notifications:** due reminders notify via `notify-send` (libnotify),
57
+ with a one-shot `notify-pending` command and optional systemd user timer that
58
+ survives restarts.
59
+ * **🔐 Optional per-note encryption:** authenticated (Fernet + PBKDF2), passphrase
60
+ based, explicit per note; encrypted content is never sent to AI.
61
+ * **📁 XDG-compliant storage** and **CLI/TUI configuration** (no manual file editing).
62
+
63
+ ## 🚀 Quick start
64
+
65
+ ```bash
66
+ uv sync
67
+ better-dontforget config set provider gemini
68
+ better-dontforget config set api_key "$GEMINI_API_KEY"
69
+
70
+ better-dontforget "ratatui was that rust tui library"
71
+ better-dontforget "remind me tomorrow 9am to check that library"
72
+ better-dontforget search "rust tui"
73
+ better-dontforget tui
74
+ ```
75
+
76
+ The short alias **`bdf`** is also installed (`bdf "ratatui was that rust tui library"`, `bdf search "rust tui"`, …).
77
+
78
+ See [`docs/docs.md`](docs/docs.md) for full usage and
79
+ [`docs/config.md`](docs/config.md) for configuration.
80
+
81
+ ## 🛠️ Development
82
+
83
+ ```bash
84
+ just install # uv sync
85
+ just check # format + lint + type + tests + build (canonical gate)
86
+ just test
87
+ just lint
88
+ just fmt
89
+ just type
90
+ ```
91
+
92
+ ## 📄 License
93
+
94
+ GPL-3. Upstream `dontforget` by Suraj Kushwah; legacy server/client retained under
95
+ `legacy/` for attribution.
96
+
97
+ ## 🙏 Credits
98
+
99
+ Better Dontforget is a fork of [`bugswriter/dontforget`](https://github.com/bugswriter/dontforget)
100
+ by **Suraj Kushwah**. The original SQLite + FTS5 storage engine and AI-assisted
101
+ capture/recall concept are carried over and extended; the legacy FastAPI
102
+ server and bash `curl` client are preserved under `legacy/` for reference.
103
+
@@ -0,0 +1,234 @@
1
+ # PRD — Better Dontforget
2
+
3
+ ## Project name
4
+
5
+ **Better Dontforget** (repository: `better-dontforget`)
6
+
7
+ ## Project summary
8
+
9
+ Better Dontforget is a focused improvement of the upstream `bugswriter/dontforget`
10
+ (author Suraj Kushwah) project. It is an AI-assisted terminal tool for quickly
11
+ capturing and retrieving small personal memory dumps, enhanced with a better TUI,
12
+ configurable AI providers, optional reminders with persistent desktop
13
+ notifications, optional per-note encryption, XDG-compliant storage, and
14
+ CLI/TUI-based configuration.
15
+
16
+ ## Relationship to upstream `dontforget`
17
+
18
+ The upstream project is a Python **FastAPI server** (`main.py`) plus a bash
19
+ **curl client** (`mem-cli`). It stores raw notes in SQLite with an FTS5 full-text
20
+ index, uses Google Gemini to auto-generate search tags on capture and to
21
+ synthesize answers on query, and requires a long-running server plus a secret key.
22
+
23
+ Better Dontforget **preserves**:
24
+
25
+ * the SQLite + FTS5 storage engine and its data (with backward-compatible migration);
26
+ * the quick-capture + AI-assisted-tagging workflow;
27
+ * the AI-assisted retrieval / synthesis workflow;
28
+ * the Gemini provider (kept as a first-class provider).
29
+
30
+ Better Dontforget **changes the runtime shape** with demonstrated justification:
31
+ the upstream client/server model forces a running server and makes capture
32
+ synchronously dependent on AI (a failed AI call loses the note). The requested
33
+ improvements — reliable notifications while the CLI/TUI is closed, an interactive
34
+ TUI, per-note encryption, XDG storage, and config without manual file editing —
35
+ are a poor fit for a required-running HTTP server driven by a bash `curl` script.
36
+ Better Dontforget is therefore a **self-contained CLI + TUI application** that
37
+ talks directly to local storage and to AI providers, while keeping the storage
38
+ format and useful AI behavior intact. The legacy server/client files are retained
39
+ under `legacy/` for reference and attribution; they are not part of the shipped
40
+ application.
41
+
42
+ ## Product philosophy
43
+
44
+ > The primary product is a quick personal memory-dump tool. Reminders are an
45
+ > optional capability attached to a note, not the primary abstraction. Encryption
46
+ > is also optional and explicitly selected per note. Better Dontforget must not
47
+ > evolve into a calendar, task manager, project manager, full notes application,
48
+ > knowledge base, or second-brain system.
49
+
50
+ > The goal is to improve the existing upstream project with the smallest coherent
51
+ > changes. A ground-up rewrite is not desired unless repository inspection
52
+ > demonstrates that preserving the existing implementation would make the
53
+ > requirements substantially harder, less reliable, or less maintainable.
54
+
55
+ ## Target use case
56
+
57
+ Fast, low-friction capture and later retrieval of small personal facts:
58
+
59
+ ```text
60
+ the rust tui library was called ratatui
61
+ wifi password is written behind the router
62
+ John recommended Severance
63
+ remind me tomorrow to check that library
64
+ ```
65
+
66
+ ## Existing upstream behavior being preserved
67
+
68
+ * SQLite + FTS5 storage and schema (`memories` + `memories_idx`).
69
+ * AI-assisted capture tags.
70
+ * AI-assisted query synthesis over retrieved memories.
71
+ * The `remember` / `remind` / `delete` conceptual operations.
72
+
73
+ ## Improvements introduced by Better Dontforget
74
+
75
+ 1. Improved TUI.
76
+ 2. Multiple configurable AI/LLM providers (Gemini + OpenAI-compatible).
77
+ 3. Optional reminders attached to quick notes.
78
+ 4. Desktop notifications for due reminders.
79
+ 5. Reliable background notification processing.
80
+ 6. Persistent reminders that survive application exits and machine restarts.
81
+ 7. Optional per-note encryption.
82
+ 8. XDG-compliant application paths.
83
+ 9. Configuration through CLI and TUI rather than manual file editing.
84
+ 10. Better project documentation and agentic development infrastructure.
85
+
86
+ ## v1 requirements
87
+
88
+ * Self-contained CLI + TUI (no required server).
89
+ * Quick capture works without AI; AI failure never loses user input.
90
+ * Multiple AI providers behind a small abstraction; OpenAI-compatible covers
91
+ OpenAI and OpenRouter via a configurable base URL.
92
+ * Optional reminders persisted per note; due/overdue detection.
93
+ * Desktop notifications via the platform mechanism (`notify-send`/libnotify).
94
+ * One-shot `notify-pending` command + optional systemd user timer/service for
95
+ reliable processing while the interactive app is closed and after restarts.
96
+ * Optional per-note encryption (authenticated, passphrase-derived key).
97
+ * XDG-compliant config/data paths.
98
+ * CLI `config` subcommand and TUI settings; no manual file editing required.
99
+ * Backward-compatible migration of existing upstream `memory.db`.
100
+
101
+ ## Explicit non-goals
102
+
103
+ * Calendar, task manager, project manager, to-do app, document editor.
104
+ * Personal wiki, knowledge graph, second-brain, kanban, Markdown knowledge base.
105
+ * Cloud sync, collaboration, user accounts, team features, mobile apps.
106
+ * Vector databases, embeddings, semantic-search/RAG pipelines.
107
+ * Recurring reminder engines / complex recurrence rules (v1).
108
+ * Custom daemons, IPC, RPC, socket servers, or service frameworks.
109
+ * Telegram/ntfy/email/SMS/mobile push/webhook notification transports (v1).
110
+
111
+ ## Quick-note behavior
112
+
113
+ * `better-dontforget "anything"` captures a note instantly.
114
+ * Capture is synchronous and local; AI tagging is best-effort and failures are
115
+ non-fatal (note is still saved, possibly without tags).
116
+ * A normal note never requires a reminder or encryption.
117
+ * Optional flags: `--encrypt` (encrypted note), `--remind "<when>"` (attach
118
+ reminder). Encrypted notes are not sent to AI.
119
+
120
+ ## AI behavior
121
+
122
+ * On capture: AI generates search tags (best-effort).
123
+ * On query (`remind`/`ask`): AI extracts keywords, FTS retrieves candidates, AI
124
+ synthesizes an answer. If AI is unavailable, falls back to raw FTS listing.
125
+ * On `search`: direct FTS listing (no AI).
126
+ * Only the content needed for the requested operation is sent to the provider.
127
+
128
+ ## Multiple-provider behavior
129
+
130
+ * Providers: `gemini` (default), `openai` (OpenAI-compatible: OpenAI, OpenRouter),
131
+ `groq` (OpenAI-compatible: Groq).
132
+ * Selected via `config set provider <name>`.
133
+ * Credentials read from config or environment (`GEMINI_API_KEY`, `OPENAI_API_KEY`).
134
+ * `openai` provider supports a configurable `base_url` for OpenRouter/self-hosted.
135
+ * Provider calls are mockable; tests never use real keys.
136
+
137
+ ## Optional-reminder behavior
138
+
139
+ * A reminder is an optional `reminder_at` timestamp on a note.
140
+ * Set via `--remind "<spec>"` or from natural-language intent ("remind me
141
+ tomorrow to …") parsed by a deterministic heuristic.
142
+ * Ordinary notes remain ordinary notes.
143
+ * No calendar semantics, recurrence, or task-completion workflow in v1.
144
+
145
+ ## Desktop-notification behavior
146
+
147
+ * When a reminder becomes due, a local desktop notification is sent via
148
+ `notify-send` (libnotify), the established Linux mechanism.
149
+ * Notification is attempted only for due, not-yet-delivered reminders.
150
+ * Marked delivered only after successful delivery; duplicates avoided.
151
+
152
+ ## Persistent missed-reminder behavior
153
+
154
+ * Reminders are persisted in the database.
155
+ * A reminder due while the machine is off cannot notify at that instant.
156
+ * On next `notify-pending` run (e.g. after login via systemd timer), due and
157
+ unnotified reminders (including overdue ones) are detected and notified.
158
+ * Policy: all due unnotified reminders are notified; no recurrence, so volume is
159
+ naturally bounded. No silent discarding.
160
+
161
+ ## Optional per-note encryption
162
+
163
+ * Explicit only: `--encrypt` flag or TUI explicit action.
164
+ * Uses `cryptography` Fernet (authenticated) with PBKDF2 key derivation from a
165
+ passphrase (prompted at runtime, never stored).
166
+ * Encrypted content is not sent to external AI.
167
+ * Plaintext is never persisted; decrypted content is never logged.
168
+ * Incorrect passphrase fails closed (decryption error surfaced, no leak).
169
+
170
+ ## TUI requirements
171
+
172
+ * View, add, edit, delete notes; search/filter; inspect reminder state; attach/
173
+ remove reminder; create encrypted note; unlock/decrypt; access settings.
174
+ * Keyboard-driven; handles resize and ordinary errors gracefully.
175
+ * Not a full notes editor: no analytics, kanban, calendar, nested trees.
176
+
177
+ ## CLI requirements
178
+
179
+ * `better-dontforget "text"` quick capture; `--encrypt`, `--remind`.
180
+ * Subcommands: `remind`/`ask`, `search`, `list`, `delete`, `tui`, `config`,
181
+ `notify-pending`.
182
+ * Backward-compatible intent with upstream `mem` (remember/remind/delete).
183
+
184
+ ## Configuration behavior
185
+
186
+ * Stored as TOML in `$XDG_CONFIG_HOME/better-dontforget/config.toml`.
187
+ * Managed via `config show|set|reset` and TUI settings.
188
+ * `config show` masks secrets ("API key: configured").
189
+ * No manual file editing required.
190
+
191
+ ## XDG requirements
192
+
193
+ * Config: `$XDG_CONFIG_HOME/better-dontforget/`
194
+ * Data (DB): `$XDG_DATA_HOME/better-dontforget/`
195
+ * State/cache/runtime only if actually needed (not created speculatively).
196
+ * Fallbacks to `~/.config`, `~/.local/share` when base vars unset.
197
+ * Existing `./memory.db` is migrated into the XDG data dir on first run.
198
+
199
+ ## Reliability requirements
200
+
201
+ See "Reliability invariants" in the mission. Key: capture never lost; AI failure
202
+ non-fatal; reminder/encryption optional and explicit; notification success gated
203
+ on delivery; config + data in XDG; no secret leakage.
204
+
205
+ ## Error-handling expectations
206
+
207
+ * Missing/invalid credentials: clear message; capture and local search still work.
208
+ * AI rate limits/timeouts/malformed responses: degrade gracefully, never lose input.
209
+ * Notification failure: leave reminder unnotified, retry next run.
210
+ * Wrong encryption passphrase: fail closed.
211
+
212
+ ## Compatibility expectations
213
+
214
+ * Existing upstream `memory.db` data is preserved via migration.
215
+ * Upstream behavior (tags, FTS retrieval) preserved.
216
+ * Legacy `mem`/server retained under `legacy/` for attribution only.
217
+
218
+ ## Acceptance criteria
219
+
220
+ 1. Quick capture works offline and without AI.
221
+ 2. `just check` passes (fmt, lint, type, tests, build).
222
+ 3. Multiple providers work; tests mock providers, no real keys.
223
+ 4. Reminders persist; due + overdue detection works; no duplicate notify.
224
+ 5. `notify-pending` works while app closed; systemd user unit documented.
225
+ 6. Per-note encryption round-trips; wrong passphrase fails closed.
226
+ 7. XDG paths used; config via CLI/TUI; secrets masked.
227
+ 8. TUI supports required operations.
228
+ 9. Docs match implementation; scope not expanded.
229
+
230
+ ## Definition of done
231
+
232
+ All items in the mission's Definition of Done are satisfied: `just check` passes,
233
+ PRD/AGENTS/ROADMAP/docs consistent, features implemented and tested, scope
234
+ preserved as a focused improvement of `dontforget`.