tidyline 0.2.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.
- tidyline-0.2.0/LICENSE +21 -0
- tidyline-0.2.0/PKG-INFO +248 -0
- tidyline-0.2.0/README.md +223 -0
- tidyline-0.2.0/pyproject.toml +69 -0
- tidyline-0.2.0/pyproject.toml.orig +55 -0
- tidyline-0.2.0/src/tidyline/__init__.py +3 -0
- tidyline-0.2.0/src/tidyline/anonymise.py +301 -0
- tidyline-0.2.0/src/tidyline/checks/__init__.py +21 -0
- tidyline-0.2.0/src/tidyline/checks/active_project_no_open_tasks.py +38 -0
- tidyline-0.2.0/src/tidyline/checks/dated_in_someday_project.py +38 -0
- tidyline-0.2.0/src/tidyline/checks/finding.py +52 -0
- tidyline-0.2.0/src/tidyline/checks/leftover_templates.py +29 -0
- tidyline-0.2.0/src/tidyline/checks/open_in_trashed_project.py +35 -0
- tidyline-0.2.0/src/tidyline/checks/outside_heading.py +41 -0
- tidyline-0.2.0/src/tidyline/checks/possible_duplicates.py +60 -0
- tidyline-0.2.0/src/tidyline/checks/recurrence_not_recognised.py +27 -0
- tidyline-0.2.0/src/tidyline/checks/registry.py +70 -0
- tidyline-0.2.0/src/tidyline/checks/scope.py +52 -0
- tidyline-0.2.0/src/tidyline/checks/someday_in_active_project.py +35 -0
- tidyline-0.2.0/src/tidyline/checks/title_hygiene.py +50 -0
- tidyline-0.2.0/src/tidyline/checks/unfiled_open.py +32 -0
- tidyline-0.2.0/src/tidyline/cli.py +778 -0
- tidyline-0.2.0/src/tidyline/dates.py +71 -0
- tidyline-0.2.0/src/tidyline/db/__init__.py +0 -0
- tidyline-0.2.0/src/tidyline/db/locate.py +77 -0
- tidyline-0.2.0/src/tidyline/db/schema.py +180 -0
- tidyline-0.2.0/src/tidyline/db/snapshot.py +127 -0
- tidyline-0.2.0/src/tidyline/decode.py +101 -0
- tidyline-0.2.0/src/tidyline/llm/__init__.py +2 -0
- tidyline-0.2.0/src/tidyline/llm/audit_prompt.md +164 -0
- tidyline-0.2.0/src/tidyline/llm/prompt.py +214 -0
- tidyline-0.2.0/src/tidyline/model.py +157 -0
- tidyline-0.2.0/src/tidyline/read.py +323 -0
- tidyline-0.2.0/src/tidyline/recurrence.py +448 -0
- tidyline-0.2.0/src/tidyline/render/__init__.py +0 -0
- tidyline-0.2.0/src/tidyline/render/check_out.py +100 -0
- tidyline-0.2.0/src/tidyline/render/json_out.py +197 -0
- tidyline-0.2.0/src/tidyline/render/recurrence_out.py +144 -0
- tidyline-0.2.0/src/tidyline/render/text.py +234 -0
- tidyline-0.2.0/src/tidyline/status.py +67 -0
tidyline-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Laxman Rathod
|
|
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.
|
tidyline-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tidyline
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Offline, read-only audit of a Things 3 database on macOS.
|
|
5
|
+
Keywords: things,things3,gtd,audit,cli,macos,offline
|
|
6
|
+
Author: Laxman Rathod
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
12
|
+
Classifier: Operating System :: MacOS
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Utilities
|
|
19
|
+
Requires-Dist: things-py>=1.0.1
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Project-URL: Homepage, https://github.com/rathodlaxman/tidyline
|
|
22
|
+
Project-URL: Source, https://github.com/rathodlaxman/tidyline
|
|
23
|
+
Project-URL: Issues, https://github.com/rathodlaxman/tidyline/issues
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# tidyline
|
|
27
|
+
|
|
28
|
+
An offline, read-only command-line tool that audits a Things 3 database on macOS.
|
|
29
|
+
|
|
30
|
+
> **Unofficial.** tidyline is not affiliated with or endorsed by Cultured Code.
|
|
31
|
+
> "Things" is a trademark of its owner. This project uses the name only to say
|
|
32
|
+
> which app it reads. It uses no logo or icon.
|
|
33
|
+
|
|
34
|
+
## Your data is personal
|
|
35
|
+
|
|
36
|
+
The Things database, the JSON export, the text report and any decoded file
|
|
37
|
+
contain your personal data: task titles, notes, checklists and dates. Never
|
|
38
|
+
commit them to a repository, and never post them in a public issue.
|
|
39
|
+
|
|
40
|
+
Anonymised exports reduce the risk. They cannot remove all of it.
|
|
41
|
+
|
|
42
|
+
- `light` keeps titles but replaces emails, phone numbers, URLs, money amounts
|
|
43
|
+
and long digit runs with placeholders. It removes notes. It is a best-effort
|
|
44
|
+
scrub. It cannot catch names, addresses or alphanumeric account numbers.
|
|
45
|
+
- `strict` replaces every title and name with a label such as `Task k3f9az`. It
|
|
46
|
+
removes notes and replaces checklist items with a count. Only `strict`
|
|
47
|
+
removes all titles.
|
|
48
|
+
- At every level, ids are kept. Anyone who also has your database can map them
|
|
49
|
+
back to titles. Dates, counts and findings stay too, and they reveal how you
|
|
50
|
+
work.
|
|
51
|
+
|
|
52
|
+
## What it does
|
|
53
|
+
|
|
54
|
+
tidyline reads your Things database and reports on it: counts, health checks,
|
|
55
|
+
a decoded view of your repeating tasks, a JSON export, and an anonymised
|
|
56
|
+
prompt you can give to an AI assistant yourself.
|
|
57
|
+
|
|
58
|
+
What it does not do:
|
|
59
|
+
|
|
60
|
+
- It never writes to the Things database.
|
|
61
|
+
- It never reads the database file directly. It makes a private copy (a
|
|
62
|
+
snapshot) with the SQLite backup API and reads that, then deletes the copy.
|
|
63
|
+
Things can stay open while it runs.
|
|
64
|
+
- It makes no network calls. None of the current commands needs a network.
|
|
65
|
+
- It never reads or exports the URL-scheme auth token.
|
|
66
|
+
- It never changes, completes or opens anything in Things.
|
|
67
|
+
|
|
68
|
+
## Install
|
|
69
|
+
|
|
70
|
+
From source:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
git clone https://github.com/rathodlaxman/tidyline.git
|
|
74
|
+
cd tidyline
|
|
75
|
+
uv sync
|
|
76
|
+
uv run tidyline --version
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
You need [uv](https://docs.astral.sh/uv/) and Python 3.10 or later.
|
|
80
|
+
|
|
81
|
+
Once published: `pipx install tidyline` or `uv tool install tidyline`.
|
|
82
|
+
|
|
83
|
+
macOS may block Terminal from reading Things' data folder. If `doctor` says so,
|
|
84
|
+
open System Settings, Privacy & Security, Full Disk Access, turn it on for your
|
|
85
|
+
terminal app, then quit and reopen the terminal.
|
|
86
|
+
|
|
87
|
+
## Quick start
|
|
88
|
+
|
|
89
|
+
Run these from the folder you cloned. Write outputs outside any git folder, so
|
|
90
|
+
they cannot be committed by accident. The examples use `~/tidyline-out/`, which
|
|
91
|
+
must exist first:
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
mkdir -p -m 700 ~/tidyline-out
|
|
95
|
+
uv run tidyline doctor
|
|
96
|
+
uv run tidyline report
|
|
97
|
+
uv run tidyline check
|
|
98
|
+
uv run tidyline recurrence
|
|
99
|
+
uv run tidyline export --out ~/tidyline-out/export.json
|
|
100
|
+
uv run tidyline prompt --out ~/tidyline-out/prompt
|
|
101
|
+
uv run tidyline decode ~/tidyline-out/answer.md --out ~/tidyline-out/answer-decoded.md
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
- `doctor` finds the database and checks permissions, the schema and versions.
|
|
105
|
+
- `report` prints a text summary. It shows counts only, except for repeating
|
|
106
|
+
templates, which are listed with their titles.
|
|
107
|
+
- `check` runs the health checks.
|
|
108
|
+
- `recurrence` lists every repeating template with its readable rule.
|
|
109
|
+
- `export` writes a JSON export. Add `--anonymise light` or `--anonymise strict`
|
|
110
|
+
to anonymise it.
|
|
111
|
+
- `prompt` and `decode` are described below.
|
|
112
|
+
|
|
113
|
+
Every command accepts `--db PATH` for a database in a non-standard place. You
|
|
114
|
+
can also set the `THINGSDB` environment variable. Add `--verbose` before the
|
|
115
|
+
command for more detail when something fails.
|
|
116
|
+
|
|
117
|
+
## Commands
|
|
118
|
+
|
|
119
|
+
| Command | What it does | Options |
|
|
120
|
+
|---|---|---|
|
|
121
|
+
| `doctor` | Finds the database and checks permissions, schema and versions. | `--db` |
|
|
122
|
+
| `report` | Prints a text summary, or writes it to a new file. | `--out PATH`, `--include-completed`, `--no-color`, `--db` |
|
|
123
|
+
| `check` | Runs the health checks. | `--only ID [ID ...]`, `--pattern REGEX [REGEX ...]`, `--json`, `--db` |
|
|
124
|
+
| `export` | Writes a JSON export to a new file. | `--out PATH` (required), `--anonymise {none,light,strict}`, `--db` |
|
|
125
|
+
| `recurrence` | Lists every repeating template with its readable rule. | `--raw`, `--db` |
|
|
126
|
+
| `prompt` | Writes an anonymised payload and a filled audit prompt. | `--anonymise {light,strict}`, `--context FILE`, `--out DIR`, `--copy`, `--db` |
|
|
127
|
+
| `decode` | Replaces `strict` labels in an answer with your real titles. | `ANSWER_FILE`, `--out FILE`, `--db` |
|
|
128
|
+
|
|
129
|
+
Files written with `--out` get mode 0600, and an existing file is never
|
|
130
|
+
overwritten.
|
|
131
|
+
|
|
132
|
+
Exit codes:
|
|
133
|
+
|
|
134
|
+
| Code | Meaning |
|
|
135
|
+
|---|---|
|
|
136
|
+
| 0 | Success. For `check`: no warnings. |
|
|
137
|
+
| 1 | Only `check` uses this: at least one warning-level finding. |
|
|
138
|
+
| 2 | Usage error, such as a bad option, a bad regular expression or an output path that already exists. |
|
|
139
|
+
| 3 | The run failed: the database could not be found or read, or a file could not be written. |
|
|
140
|
+
|
|
141
|
+
## Using an AI assistant without sending anything automatically
|
|
142
|
+
|
|
143
|
+
tidyline never sends your data anywhere. `prompt` prepares two files, and you
|
|
144
|
+
decide whether to attach or paste them into an assistant yourself.
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
uv run tidyline prompt --context my-context.txt --out ~/tidyline-out/prompt
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
- The default is `--anonymise strict`. There is no `none` option for `prompt`.
|
|
151
|
+
- `--context FILE` is a plain text file with sections labelled `Role:`,
|
|
152
|
+
`Priorities:` and `Dates:`. It is added to the prompt exactly as you wrote it.
|
|
153
|
+
A section you leave out stays as a visible placeholder, and the preview warns
|
|
154
|
+
you.
|
|
155
|
+
- `--out DIR` writes `tidyline_payload.json` (the anonymised export) and
|
|
156
|
+
`tidyline_prompt.md` (the filled prompt). `--copy` puts the prompt on the
|
|
157
|
+
clipboard with `pbcopy`. With neither option, nothing is written.
|
|
158
|
+
- `prompt` always prints a preview first: the level, the counts, what was
|
|
159
|
+
removed or replaced, and your context text. The last line says nothing has
|
|
160
|
+
been sent anywhere.
|
|
161
|
+
- The text report is never part of the output.
|
|
162
|
+
|
|
163
|
+
At `strict`, titles are hidden, so the assistant cannot judge how your tasks are
|
|
164
|
+
worded. The prompt tells it to skip that part. Use `--anonymise light` if you
|
|
165
|
+
want task wording reviewed, and accept that `light` leaves titles in place.
|
|
166
|
+
|
|
167
|
+
To turn the answer back into real titles, save it to a file and run:
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
uv run tidyline decode ~/tidyline-out/answer.md
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
`decode` recomputes each label from the current database, so it needs no
|
|
174
|
+
mapping file. Labels it cannot match stay as they are, and it reports how many.
|
|
175
|
+
It needs the same database the prompt was made from, and `light` output needs no
|
|
176
|
+
decoding. Titles go in exactly as stored, so a title containing `|` can break a
|
|
177
|
+
markdown table cell. The decoded text contains real titles, so treat it as
|
|
178
|
+
personal data.
|
|
179
|
+
|
|
180
|
+
## Health checks
|
|
181
|
+
|
|
182
|
+
`tidyline check` exits with 1 if any warning is found. Info findings do not
|
|
183
|
+
change the exit code. Findings carry ids and fixed messages, never titles. The
|
|
184
|
+
text output shows titles on your own screen only. `check --json` prints ids
|
|
185
|
+
only.
|
|
186
|
+
|
|
187
|
+
| Check | Severity | What it finds |
|
|
188
|
+
|---|---|---|
|
|
189
|
+
| `open_in_trashed_project` | warning | Open to-dos inside a trashed project. The other checks leave these out. |
|
|
190
|
+
| `unfiled_open` | warning | Open to-dos with no area and no project, outside the Inbox. |
|
|
191
|
+
| `title_hygiene` | warning | A stray `·` at either end, leading or trailing spaces, doubled spaces, and matches of your own `--pattern` regular expressions. |
|
|
192
|
+
| `possible_duplicates` | warning | Open to-dos whose titles match after Unicode normalisation, case folding, apostrophes removed and other punctuation treated as spaces. |
|
|
193
|
+
| `dated_in_someday_project` | warning | To-dos with a start date inside a Someday project. They will never surface. |
|
|
194
|
+
| `active_project_no_open_tasks` | warning | Active projects with no open to-dos and no live repeating template. |
|
|
195
|
+
| `recurrence_not_recognised` | warning | Repeating templates whose rule tidyline cannot read or does not recognise. |
|
|
196
|
+
| `leftover_templates` | info | Repeating templates whose project is trashed or missing. |
|
|
197
|
+
| `someday_in_active_project` | info | Someday to-dos inside active projects. |
|
|
198
|
+
| `outside_heading` | info | To-dos outside any heading in projects that use headings. |
|
|
199
|
+
|
|
200
|
+
A finding for one of your own patterns says only "matches user pattern N".
|
|
201
|
+
The text output on your screen shows the pattern next to it; the JSON does not.
|
|
202
|
+
|
|
203
|
+
## Things does not document its database
|
|
204
|
+
|
|
205
|
+
tidyline reads columns that Things does not document, because there is no
|
|
206
|
+
public API for this. These include:
|
|
207
|
+
|
|
208
|
+
- the repeating-task columns `rt1_recurrenceRule`, `rt1_repeatingTemplate` and
|
|
209
|
+
`rt1_instanceCreationPaused`;
|
|
210
|
+
- `startBucket`, which marks This Evening;
|
|
211
|
+
- `deadlineSuppressionDate`, which keeps an overdue deadline out of Today.
|
|
212
|
+
|
|
213
|
+
Repeat rules are stored as property lists whose meaning was worked out by
|
|
214
|
+
comparing them with what Things shows. A rule tidyline does not understand is
|
|
215
|
+
reported as not recognised. It is never guessed.
|
|
216
|
+
|
|
217
|
+
Before reading, tidyline checks that the tables and columns it needs exist. If
|
|
218
|
+
they do not, it stops with a message that names what is missing, the versions
|
|
219
|
+
it was tested with, and what to do next. See
|
|
220
|
+
[docs/COMPATIBILITY.md](https://github.com/rathodlaxman/tidyline/blob/main/docs/COMPATIBILITY.md) for what has been tested and
|
|
221
|
+
what has not.
|
|
222
|
+
|
|
223
|
+
Not yet built: the HTML report and the opt-in model integration.
|
|
224
|
+
|
|
225
|
+
## Development
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
uv sync
|
|
229
|
+
uv run pytest
|
|
230
|
+
uv run ruff check .
|
|
231
|
+
uv run ruff format --check .
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Tests use only a synthetic database built by `tests/fixtures/build_fixture.py`.
|
|
235
|
+
The real Things database is never used in tests, and no database, export or
|
|
236
|
+
report is ever committed. Network sockets are blocked while the tests run.
|
|
237
|
+
|
|
238
|
+
Golden files under `tests/fixtures/` are regenerated with
|
|
239
|
+
`TIDYLINE_UPDATE_GOLDEN=1 uv run pytest`. Review the diff before committing.
|
|
240
|
+
|
|
241
|
+
The design and the decisions behind it are in [docs/DESIGN.md](https://github.com/rathodlaxman/tidyline/blob/main/docs/DESIGN.md).
|
|
242
|
+
How repeat rules are read is in [docs/RECURRENCE.md](https://github.com/rathodlaxman/tidyline/blob/main/docs/RECURRENCE.md).
|
|
243
|
+
|
|
244
|
+
## Licence
|
|
245
|
+
|
|
246
|
+
MIT. See [LICENSE](https://github.com/rathodlaxman/tidyline/blob/main/LICENSE). tidyline depends on
|
|
247
|
+
[things.py](https://github.com/thingsapi/things.py), which is licensed under
|
|
248
|
+
Apache 2.0.
|
tidyline-0.2.0/README.md
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# tidyline
|
|
2
|
+
|
|
3
|
+
An offline, read-only command-line tool that audits a Things 3 database on macOS.
|
|
4
|
+
|
|
5
|
+
> **Unofficial.** tidyline is not affiliated with or endorsed by Cultured Code.
|
|
6
|
+
> "Things" is a trademark of its owner. This project uses the name only to say
|
|
7
|
+
> which app it reads. It uses no logo or icon.
|
|
8
|
+
|
|
9
|
+
## Your data is personal
|
|
10
|
+
|
|
11
|
+
The Things database, the JSON export, the text report and any decoded file
|
|
12
|
+
contain your personal data: task titles, notes, checklists and dates. Never
|
|
13
|
+
commit them to a repository, and never post them in a public issue.
|
|
14
|
+
|
|
15
|
+
Anonymised exports reduce the risk. They cannot remove all of it.
|
|
16
|
+
|
|
17
|
+
- `light` keeps titles but replaces emails, phone numbers, URLs, money amounts
|
|
18
|
+
and long digit runs with placeholders. It removes notes. It is a best-effort
|
|
19
|
+
scrub. It cannot catch names, addresses or alphanumeric account numbers.
|
|
20
|
+
- `strict` replaces every title and name with a label such as `Task k3f9az`. It
|
|
21
|
+
removes notes and replaces checklist items with a count. Only `strict`
|
|
22
|
+
removes all titles.
|
|
23
|
+
- At every level, ids are kept. Anyone who also has your database can map them
|
|
24
|
+
back to titles. Dates, counts and findings stay too, and they reveal how you
|
|
25
|
+
work.
|
|
26
|
+
|
|
27
|
+
## What it does
|
|
28
|
+
|
|
29
|
+
tidyline reads your Things database and reports on it: counts, health checks,
|
|
30
|
+
a decoded view of your repeating tasks, a JSON export, and an anonymised
|
|
31
|
+
prompt you can give to an AI assistant yourself.
|
|
32
|
+
|
|
33
|
+
What it does not do:
|
|
34
|
+
|
|
35
|
+
- It never writes to the Things database.
|
|
36
|
+
- It never reads the database file directly. It makes a private copy (a
|
|
37
|
+
snapshot) with the SQLite backup API and reads that, then deletes the copy.
|
|
38
|
+
Things can stay open while it runs.
|
|
39
|
+
- It makes no network calls. None of the current commands needs a network.
|
|
40
|
+
- It never reads or exports the URL-scheme auth token.
|
|
41
|
+
- It never changes, completes or opens anything in Things.
|
|
42
|
+
|
|
43
|
+
## Install
|
|
44
|
+
|
|
45
|
+
From source:
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
git clone https://github.com/rathodlaxman/tidyline.git
|
|
49
|
+
cd tidyline
|
|
50
|
+
uv sync
|
|
51
|
+
uv run tidyline --version
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
You need [uv](https://docs.astral.sh/uv/) and Python 3.10 or later.
|
|
55
|
+
|
|
56
|
+
Once published: `pipx install tidyline` or `uv tool install tidyline`.
|
|
57
|
+
|
|
58
|
+
macOS may block Terminal from reading Things' data folder. If `doctor` says so,
|
|
59
|
+
open System Settings, Privacy & Security, Full Disk Access, turn it on for your
|
|
60
|
+
terminal app, then quit and reopen the terminal.
|
|
61
|
+
|
|
62
|
+
## Quick start
|
|
63
|
+
|
|
64
|
+
Run these from the folder you cloned. Write outputs outside any git folder, so
|
|
65
|
+
they cannot be committed by accident. The examples use `~/tidyline-out/`, which
|
|
66
|
+
must exist first:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
mkdir -p -m 700 ~/tidyline-out
|
|
70
|
+
uv run tidyline doctor
|
|
71
|
+
uv run tidyline report
|
|
72
|
+
uv run tidyline check
|
|
73
|
+
uv run tidyline recurrence
|
|
74
|
+
uv run tidyline export --out ~/tidyline-out/export.json
|
|
75
|
+
uv run tidyline prompt --out ~/tidyline-out/prompt
|
|
76
|
+
uv run tidyline decode ~/tidyline-out/answer.md --out ~/tidyline-out/answer-decoded.md
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
- `doctor` finds the database and checks permissions, the schema and versions.
|
|
80
|
+
- `report` prints a text summary. It shows counts only, except for repeating
|
|
81
|
+
templates, which are listed with their titles.
|
|
82
|
+
- `check` runs the health checks.
|
|
83
|
+
- `recurrence` lists every repeating template with its readable rule.
|
|
84
|
+
- `export` writes a JSON export. Add `--anonymise light` or `--anonymise strict`
|
|
85
|
+
to anonymise it.
|
|
86
|
+
- `prompt` and `decode` are described below.
|
|
87
|
+
|
|
88
|
+
Every command accepts `--db PATH` for a database in a non-standard place. You
|
|
89
|
+
can also set the `THINGSDB` environment variable. Add `--verbose` before the
|
|
90
|
+
command for more detail when something fails.
|
|
91
|
+
|
|
92
|
+
## Commands
|
|
93
|
+
|
|
94
|
+
| Command | What it does | Options |
|
|
95
|
+
|---|---|---|
|
|
96
|
+
| `doctor` | Finds the database and checks permissions, schema and versions. | `--db` |
|
|
97
|
+
| `report` | Prints a text summary, or writes it to a new file. | `--out PATH`, `--include-completed`, `--no-color`, `--db` |
|
|
98
|
+
| `check` | Runs the health checks. | `--only ID [ID ...]`, `--pattern REGEX [REGEX ...]`, `--json`, `--db` |
|
|
99
|
+
| `export` | Writes a JSON export to a new file. | `--out PATH` (required), `--anonymise {none,light,strict}`, `--db` |
|
|
100
|
+
| `recurrence` | Lists every repeating template with its readable rule. | `--raw`, `--db` |
|
|
101
|
+
| `prompt` | Writes an anonymised payload and a filled audit prompt. | `--anonymise {light,strict}`, `--context FILE`, `--out DIR`, `--copy`, `--db` |
|
|
102
|
+
| `decode` | Replaces `strict` labels in an answer with your real titles. | `ANSWER_FILE`, `--out FILE`, `--db` |
|
|
103
|
+
|
|
104
|
+
Files written with `--out` get mode 0600, and an existing file is never
|
|
105
|
+
overwritten.
|
|
106
|
+
|
|
107
|
+
Exit codes:
|
|
108
|
+
|
|
109
|
+
| Code | Meaning |
|
|
110
|
+
|---|---|
|
|
111
|
+
| 0 | Success. For `check`: no warnings. |
|
|
112
|
+
| 1 | Only `check` uses this: at least one warning-level finding. |
|
|
113
|
+
| 2 | Usage error, such as a bad option, a bad regular expression or an output path that already exists. |
|
|
114
|
+
| 3 | The run failed: the database could not be found or read, or a file could not be written. |
|
|
115
|
+
|
|
116
|
+
## Using an AI assistant without sending anything automatically
|
|
117
|
+
|
|
118
|
+
tidyline never sends your data anywhere. `prompt` prepares two files, and you
|
|
119
|
+
decide whether to attach or paste them into an assistant yourself.
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
uv run tidyline prompt --context my-context.txt --out ~/tidyline-out/prompt
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
- The default is `--anonymise strict`. There is no `none` option for `prompt`.
|
|
126
|
+
- `--context FILE` is a plain text file with sections labelled `Role:`,
|
|
127
|
+
`Priorities:` and `Dates:`. It is added to the prompt exactly as you wrote it.
|
|
128
|
+
A section you leave out stays as a visible placeholder, and the preview warns
|
|
129
|
+
you.
|
|
130
|
+
- `--out DIR` writes `tidyline_payload.json` (the anonymised export) and
|
|
131
|
+
`tidyline_prompt.md` (the filled prompt). `--copy` puts the prompt on the
|
|
132
|
+
clipboard with `pbcopy`. With neither option, nothing is written.
|
|
133
|
+
- `prompt` always prints a preview first: the level, the counts, what was
|
|
134
|
+
removed or replaced, and your context text. The last line says nothing has
|
|
135
|
+
been sent anywhere.
|
|
136
|
+
- The text report is never part of the output.
|
|
137
|
+
|
|
138
|
+
At `strict`, titles are hidden, so the assistant cannot judge how your tasks are
|
|
139
|
+
worded. The prompt tells it to skip that part. Use `--anonymise light` if you
|
|
140
|
+
want task wording reviewed, and accept that `light` leaves titles in place.
|
|
141
|
+
|
|
142
|
+
To turn the answer back into real titles, save it to a file and run:
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
uv run tidyline decode ~/tidyline-out/answer.md
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
`decode` recomputes each label from the current database, so it needs no
|
|
149
|
+
mapping file. Labels it cannot match stay as they are, and it reports how many.
|
|
150
|
+
It needs the same database the prompt was made from, and `light` output needs no
|
|
151
|
+
decoding. Titles go in exactly as stored, so a title containing `|` can break a
|
|
152
|
+
markdown table cell. The decoded text contains real titles, so treat it as
|
|
153
|
+
personal data.
|
|
154
|
+
|
|
155
|
+
## Health checks
|
|
156
|
+
|
|
157
|
+
`tidyline check` exits with 1 if any warning is found. Info findings do not
|
|
158
|
+
change the exit code. Findings carry ids and fixed messages, never titles. The
|
|
159
|
+
text output shows titles on your own screen only. `check --json` prints ids
|
|
160
|
+
only.
|
|
161
|
+
|
|
162
|
+
| Check | Severity | What it finds |
|
|
163
|
+
|---|---|---|
|
|
164
|
+
| `open_in_trashed_project` | warning | Open to-dos inside a trashed project. The other checks leave these out. |
|
|
165
|
+
| `unfiled_open` | warning | Open to-dos with no area and no project, outside the Inbox. |
|
|
166
|
+
| `title_hygiene` | warning | A stray `·` at either end, leading or trailing spaces, doubled spaces, and matches of your own `--pattern` regular expressions. |
|
|
167
|
+
| `possible_duplicates` | warning | Open to-dos whose titles match after Unicode normalisation, case folding, apostrophes removed and other punctuation treated as spaces. |
|
|
168
|
+
| `dated_in_someday_project` | warning | To-dos with a start date inside a Someday project. They will never surface. |
|
|
169
|
+
| `active_project_no_open_tasks` | warning | Active projects with no open to-dos and no live repeating template. |
|
|
170
|
+
| `recurrence_not_recognised` | warning | Repeating templates whose rule tidyline cannot read or does not recognise. |
|
|
171
|
+
| `leftover_templates` | info | Repeating templates whose project is trashed or missing. |
|
|
172
|
+
| `someday_in_active_project` | info | Someday to-dos inside active projects. |
|
|
173
|
+
| `outside_heading` | info | To-dos outside any heading in projects that use headings. |
|
|
174
|
+
|
|
175
|
+
A finding for one of your own patterns says only "matches user pattern N".
|
|
176
|
+
The text output on your screen shows the pattern next to it; the JSON does not.
|
|
177
|
+
|
|
178
|
+
## Things does not document its database
|
|
179
|
+
|
|
180
|
+
tidyline reads columns that Things does not document, because there is no
|
|
181
|
+
public API for this. These include:
|
|
182
|
+
|
|
183
|
+
- the repeating-task columns `rt1_recurrenceRule`, `rt1_repeatingTemplate` and
|
|
184
|
+
`rt1_instanceCreationPaused`;
|
|
185
|
+
- `startBucket`, which marks This Evening;
|
|
186
|
+
- `deadlineSuppressionDate`, which keeps an overdue deadline out of Today.
|
|
187
|
+
|
|
188
|
+
Repeat rules are stored as property lists whose meaning was worked out by
|
|
189
|
+
comparing them with what Things shows. A rule tidyline does not understand is
|
|
190
|
+
reported as not recognised. It is never guessed.
|
|
191
|
+
|
|
192
|
+
Before reading, tidyline checks that the tables and columns it needs exist. If
|
|
193
|
+
they do not, it stops with a message that names what is missing, the versions
|
|
194
|
+
it was tested with, and what to do next. See
|
|
195
|
+
[docs/COMPATIBILITY.md](https://github.com/rathodlaxman/tidyline/blob/main/docs/COMPATIBILITY.md) for what has been tested and
|
|
196
|
+
what has not.
|
|
197
|
+
|
|
198
|
+
Not yet built: the HTML report and the opt-in model integration.
|
|
199
|
+
|
|
200
|
+
## Development
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
uv sync
|
|
204
|
+
uv run pytest
|
|
205
|
+
uv run ruff check .
|
|
206
|
+
uv run ruff format --check .
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Tests use only a synthetic database built by `tests/fixtures/build_fixture.py`.
|
|
210
|
+
The real Things database is never used in tests, and no database, export or
|
|
211
|
+
report is ever committed. Network sockets are blocked while the tests run.
|
|
212
|
+
|
|
213
|
+
Golden files under `tests/fixtures/` are regenerated with
|
|
214
|
+
`TIDYLINE_UPDATE_GOLDEN=1 uv run pytest`. Review the diff before committing.
|
|
215
|
+
|
|
216
|
+
The design and the decisions behind it are in [docs/DESIGN.md](https://github.com/rathodlaxman/tidyline/blob/main/docs/DESIGN.md).
|
|
217
|
+
How repeat rules are read is in [docs/RECURRENCE.md](https://github.com/rathodlaxman/tidyline/blob/main/docs/RECURRENCE.md).
|
|
218
|
+
|
|
219
|
+
## Licence
|
|
220
|
+
|
|
221
|
+
MIT. See [LICENSE](https://github.com/rathodlaxman/tidyline/blob/main/LICENSE). tidyline depends on
|
|
222
|
+
[things.py](https://github.com/thingsapi/things.py), which is licensed under
|
|
223
|
+
Apache 2.0.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "tidyline"
|
|
3
|
+
version = "0.2.0"
|
|
4
|
+
description = "Offline, read-only audit of a Things 3 database on macOS."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
requires-python = ">=3.10"
|
|
9
|
+
keywords = [
|
|
10
|
+
"things",
|
|
11
|
+
"things3",
|
|
12
|
+
"gtd",
|
|
13
|
+
"audit",
|
|
14
|
+
"cli",
|
|
15
|
+
"macos",
|
|
16
|
+
"offline",
|
|
17
|
+
]
|
|
18
|
+
classifiers = [
|
|
19
|
+
"Development Status :: 3 - Alpha",
|
|
20
|
+
"Environment :: Console",
|
|
21
|
+
"Intended Audience :: End Users/Desktop",
|
|
22
|
+
"Operating System :: MacOS",
|
|
23
|
+
"Programming Language :: Python :: 3",
|
|
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 :: Utilities",
|
|
29
|
+
]
|
|
30
|
+
dependencies = ["things-py>=1.0.1"]
|
|
31
|
+
|
|
32
|
+
[[project.authors]]
|
|
33
|
+
name = "Laxman Rathod"
|
|
34
|
+
|
|
35
|
+
[project.urls]
|
|
36
|
+
Homepage = "https://github.com/rathodlaxman/tidyline"
|
|
37
|
+
Source = "https://github.com/rathodlaxman/tidyline"
|
|
38
|
+
Issues = "https://github.com/rathodlaxman/tidyline/issues"
|
|
39
|
+
|
|
40
|
+
[project.scripts]
|
|
41
|
+
tidyline = "tidyline.cli:main"
|
|
42
|
+
|
|
43
|
+
[build-system]
|
|
44
|
+
requires = ["uv_build>=0.13.0,<0.14.0"]
|
|
45
|
+
build-backend = "uv_build"
|
|
46
|
+
|
|
47
|
+
[dependency-groups]
|
|
48
|
+
dev = [
|
|
49
|
+
"pytest>=9.1.1",
|
|
50
|
+
"pytest-socket>=0.8.1",
|
|
51
|
+
"ruff>=0.17.0",
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
[tool.pytest.ini_options]
|
|
55
|
+
addopts = "--disable-socket"
|
|
56
|
+
testpaths = ["tests"]
|
|
57
|
+
|
|
58
|
+
[tool.ruff]
|
|
59
|
+
line-length = 88
|
|
60
|
+
target-version = "py310"
|
|
61
|
+
|
|
62
|
+
[tool.ruff.lint]
|
|
63
|
+
select = [
|
|
64
|
+
"E",
|
|
65
|
+
"F",
|
|
66
|
+
"I",
|
|
67
|
+
"UP",
|
|
68
|
+
"B",
|
|
69
|
+
]
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "tidyline"
|
|
3
|
+
version = "0.2.0"
|
|
4
|
+
description = "Offline, read-only audit of a Things 3 database on macOS."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
requires-python = ">=3.10"
|
|
9
|
+
authors = [{ name = "Laxman Rathod" }]
|
|
10
|
+
keywords = ["things", "things3", "gtd", "audit", "cli", "macos", "offline"]
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Development Status :: 3 - Alpha",
|
|
13
|
+
"Environment :: Console",
|
|
14
|
+
"Intended Audience :: End Users/Desktop",
|
|
15
|
+
"Operating System :: MacOS",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3.10",
|
|
18
|
+
"Programming Language :: Python :: 3.11",
|
|
19
|
+
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Programming Language :: Python :: 3.13",
|
|
21
|
+
"Topic :: Utilities",
|
|
22
|
+
]
|
|
23
|
+
dependencies = [
|
|
24
|
+
"things-py>=1.0.1",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[project.urls]
|
|
28
|
+
Homepage = "https://github.com/rathodlaxman/tidyline"
|
|
29
|
+
Source = "https://github.com/rathodlaxman/tidyline"
|
|
30
|
+
Issues = "https://github.com/rathodlaxman/tidyline/issues"
|
|
31
|
+
|
|
32
|
+
[project.scripts]
|
|
33
|
+
tidyline = "tidyline.cli:main"
|
|
34
|
+
|
|
35
|
+
[build-system]
|
|
36
|
+
requires = ["uv_build>=0.13.0,<0.14.0"]
|
|
37
|
+
build-backend = "uv_build"
|
|
38
|
+
|
|
39
|
+
[dependency-groups]
|
|
40
|
+
dev = [
|
|
41
|
+
"pytest>=9.1.1",
|
|
42
|
+
"pytest-socket>=0.8.1",
|
|
43
|
+
"ruff>=0.17.0",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
[tool.pytest.ini_options]
|
|
47
|
+
addopts = "--disable-socket"
|
|
48
|
+
testpaths = ["tests"]
|
|
49
|
+
|
|
50
|
+
[tool.ruff]
|
|
51
|
+
line-length = 88
|
|
52
|
+
target-version = "py310"
|
|
53
|
+
|
|
54
|
+
[tool.ruff.lint]
|
|
55
|
+
select = ["E", "F", "I", "UP", "B"]
|